aboutsummaryrefslogtreecommitdiff
path: root/sp/src/game/server/hl2/grenade_frag.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /sp/src/game/server/hl2/grenade_frag.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'sp/src/game/server/hl2/grenade_frag.cpp')
-rw-r--r--sp/src/game/server/hl2/grenade_frag.cpp453
1 files changed, 453 insertions, 0 deletions
diff --git a/sp/src/game/server/hl2/grenade_frag.cpp b/sp/src/game/server/hl2/grenade_frag.cpp
new file mode 100644
index 00000000..1166236e
--- /dev/null
+++ b/sp/src/game/server/hl2/grenade_frag.cpp
@@ -0,0 +1,453 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "basegrenade_shared.h"
+#include "grenade_frag.h"
+#include "Sprite.h"
+#include "SpriteTrail.h"
+#include "soundent.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define FRAG_GRENADE_BLIP_FREQUENCY 1.0f
+#define FRAG_GRENADE_BLIP_FAST_FREQUENCY 0.3f
+
+#define FRAG_GRENADE_GRACE_TIME_AFTER_PICKUP 1.5f
+#define FRAG_GRENADE_WARN_TIME 1.5f
+
+const float GRENADE_COEFFICIENT_OF_RESTITUTION = 0.2f;
+
+ConVar sk_plr_dmg_fraggrenade ( "sk_plr_dmg_fraggrenade","0");
+ConVar sk_npc_dmg_fraggrenade ( "sk_npc_dmg_fraggrenade","0");
+ConVar sk_fraggrenade_radius ( "sk_fraggrenade_radius", "0");
+
+#define GRENADE_MODEL "models/Weapons/w_grenade.mdl"
+
+class CGrenadeFrag : public CBaseGrenade
+{
+ DECLARE_CLASS( CGrenadeFrag, CBaseGrenade );
+
+#if !defined( CLIENT_DLL )
+ DECLARE_DATADESC();
+#endif
+
+ ~CGrenadeFrag( void );
+
+public:
+ void Spawn( void );
+ void OnRestore( void );
+ void Precache( void );
+ bool CreateVPhysics( void );
+ void CreateEffects( void );
+ void SetTimer( float detonateDelay, float warnDelay );
+ void SetVelocity( const Vector &velocity, const AngularImpulse &angVelocity );
+ int OnTakeDamage( const CTakeDamageInfo &inputInfo );
+ void BlipSound() { EmitSound( "Grenade.Blip" ); }
+ void DelayThink();
+ void VPhysicsUpdate( IPhysicsObject *pPhysics );
+ void OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason );
+ void SetCombineSpawned( bool combineSpawned ) { m_combineSpawned = combineSpawned; }
+ bool IsCombineSpawned( void ) const { return m_combineSpawned; }
+ void SetPunted( bool punt ) { m_punted = punt; }
+ bool WasPunted( void ) const { return m_punted; }
+
+ // this function only used in episodic.
+#if defined(HL2_EPISODIC) && 0 // FIXME: HandleInteraction() is no longer called now that base grenade derives from CBaseAnimating
+ bool HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt);
+#endif
+
+ void InputSetTimer( inputdata_t &inputdata );
+
+protected:
+ CHandle<CSprite> m_pMainGlow;
+ CHandle<CSpriteTrail> m_pGlowTrail;
+
+ float m_flNextBlipTime;
+ bool m_inSolid;
+ bool m_combineSpawned;
+ bool m_punted;
+};
+
+LINK_ENTITY_TO_CLASS( npc_grenade_frag, CGrenadeFrag );
+
+BEGIN_DATADESC( CGrenadeFrag )
+
+ // Fields
+ DEFINE_FIELD( m_pMainGlow, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_pGlowTrail, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_flNextBlipTime, FIELD_TIME ),
+ DEFINE_FIELD( m_inSolid, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_combineSpawned, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_punted, FIELD_BOOLEAN ),
+
+ // Function Pointers
+ DEFINE_THINKFUNC( DelayThink ),
+
+ // Inputs
+ DEFINE_INPUTFUNC( FIELD_FLOAT, "SetTimer", InputSetTimer ),
+
+END_DATADESC()
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CGrenadeFrag::~CGrenadeFrag( void )
+{
+}
+
+void CGrenadeFrag::Spawn( void )
+{
+ Precache( );
+
+ SetModel( GRENADE_MODEL );
+
+ if( GetOwnerEntity() && GetOwnerEntity()->IsPlayer() )
+ {
+ m_flDamage = sk_plr_dmg_fraggrenade.GetFloat();
+ m_DmgRadius = sk_fraggrenade_radius.GetFloat();
+ }
+ else
+ {
+ m_flDamage = sk_npc_dmg_fraggrenade.GetFloat();
+ m_DmgRadius = sk_fraggrenade_radius.GetFloat();
+ }
+
+ m_takedamage = DAMAGE_YES;
+ m_iHealth = 1;
+
+ SetSize( -Vector(4,4,4), Vector(4,4,4) );
+ SetCollisionGroup( COLLISION_GROUP_WEAPON );
+ CreateVPhysics();
+
+ BlipSound();
+ m_flNextBlipTime = gpGlobals->curtime + FRAG_GRENADE_BLIP_FREQUENCY;
+
+ AddSolidFlags( FSOLID_NOT_STANDABLE );
+
+ m_combineSpawned = false;
+ m_punted = false;
+
+ BaseClass::Spawn();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CGrenadeFrag::OnRestore( void )
+{
+ // If we were primed and ready to detonate, put FX on us.
+ if (m_flDetonateTime > 0)
+ CreateEffects();
+
+ BaseClass::OnRestore();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CGrenadeFrag::CreateEffects( void )
+{
+ // Start up the eye glow
+ m_pMainGlow = CSprite::SpriteCreate( "sprites/redglow1.vmt", GetLocalOrigin(), false );
+
+ int nAttachment = LookupAttachment( "fuse" );
+
+ if ( m_pMainGlow != NULL )
+ {
+ m_pMainGlow->FollowEntity( this );
+ m_pMainGlow->SetAttachment( this, nAttachment );
+ m_pMainGlow->SetTransparency( kRenderGlow, 255, 255, 255, 200, kRenderFxNoDissipation );
+ m_pMainGlow->SetScale( 0.2f );
+ m_pMainGlow->SetGlowProxySize( 4.0f );
+ }
+
+ // Start up the eye trail
+ m_pGlowTrail = CSpriteTrail::SpriteTrailCreate( "sprites/bluelaser1.vmt", GetLocalOrigin(), false );
+
+ if ( m_pGlowTrail != NULL )
+ {
+ m_pGlowTrail->FollowEntity( this );
+ m_pGlowTrail->SetAttachment( this, nAttachment );
+ m_pGlowTrail->SetTransparency( kRenderTransAdd, 255, 0, 0, 255, kRenderFxNone );
+ m_pGlowTrail->SetStartWidth( 8.0f );
+ m_pGlowTrail->SetEndWidth( 1.0f );
+ m_pGlowTrail->SetLifeTime( 0.5f );
+ }
+}
+
+bool CGrenadeFrag::CreateVPhysics()
+{
+ // Create the object in the physics system
+ VPhysicsInitNormal( SOLID_BBOX, 0, false );
+ return true;
+}
+
+// this will hit only things that are in newCollisionGroup, but NOT in collisionGroupAlreadyChecked
+class CTraceFilterCollisionGroupDelta : public CTraceFilterEntitiesOnly
+{
+public:
+ // It does have a base, but we'll never network anything below here..
+ DECLARE_CLASS_NOBASE( CTraceFilterCollisionGroupDelta );
+
+ CTraceFilterCollisionGroupDelta( const IHandleEntity *passentity, int collisionGroupAlreadyChecked, int newCollisionGroup )
+ : m_pPassEnt(passentity), m_collisionGroupAlreadyChecked( collisionGroupAlreadyChecked ), m_newCollisionGroup( newCollisionGroup )
+ {
+ }
+
+ virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
+ {
+ if ( !PassServerEntityFilter( pHandleEntity, m_pPassEnt ) )
+ return false;
+ CBaseEntity *pEntity = EntityFromEntityHandle( pHandleEntity );
+
+ if ( pEntity )
+ {
+ if ( g_pGameRules->ShouldCollide( m_collisionGroupAlreadyChecked, pEntity->GetCollisionGroup() ) )
+ return false;
+ if ( g_pGameRules->ShouldCollide( m_newCollisionGroup, pEntity->GetCollisionGroup() ) )
+ return true;
+ }
+
+ return false;
+ }
+
+protected:
+ const IHandleEntity *m_pPassEnt;
+ int m_collisionGroupAlreadyChecked;
+ int m_newCollisionGroup;
+};
+
+void CGrenadeFrag::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 CGrenadeFrag::Precache( void )
+{
+ PrecacheModel( GRENADE_MODEL );
+
+ PrecacheScriptSound( "Grenade.Blip" );
+
+ PrecacheModel( "sprites/redglow1.vmt" );
+ PrecacheModel( "sprites/bluelaser1.vmt" );
+
+ BaseClass::Precache();
+}
+
+void CGrenadeFrag::SetTimer( float detonateDelay, float warnDelay )
+{
+ m_flDetonateTime = gpGlobals->curtime + detonateDelay;
+ m_flWarnAITime = gpGlobals->curtime + warnDelay;
+ SetThink( &CGrenadeFrag::DelayThink );
+ SetNextThink( gpGlobals->curtime );
+
+ CreateEffects();
+}
+
+void CGrenadeFrag::OnPhysGunPickup( CBasePlayer *pPhysGunUser, PhysGunPickup_t reason )
+{
+ SetThrower( pPhysGunUser );
+
+#ifdef HL2MP
+ SetTimer( FRAG_GRENADE_GRACE_TIME_AFTER_PICKUP, FRAG_GRENADE_GRACE_TIME_AFTER_PICKUP / 2);
+
+ BlipSound();
+ m_flNextBlipTime = gpGlobals->curtime + FRAG_GRENADE_BLIP_FAST_FREQUENCY;
+ m_bHasWarnedAI = true;
+#else
+ if( IsX360() )
+ {
+ // Give 'em a couple of seconds to aim and throw.
+ SetTimer( 2.0f, 1.0f);
+ BlipSound();
+ m_flNextBlipTime = gpGlobals->curtime + FRAG_GRENADE_BLIP_FAST_FREQUENCY;
+ }
+#endif
+
+#ifdef HL2_EPISODIC
+ SetPunted( true );
+#endif
+
+ BaseClass::OnPhysGunPickup( pPhysGunUser, reason );
+}
+
+void CGrenadeFrag::DelayThink()
+{
+ if( gpGlobals->curtime > m_flDetonateTime )
+ {
+ Detonate();
+ return;
+ }
+
+ if( !m_bHasWarnedAI && gpGlobals->curtime >= m_flWarnAITime )
+ {
+#if !defined( CLIENT_DLL )
+ CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), 400, 1.5, this );
+#endif
+ m_bHasWarnedAI = true;
+ }
+
+ if( gpGlobals->curtime > m_flNextBlipTime )
+ {
+ BlipSound();
+
+ if( m_bHasWarnedAI )
+ {
+ m_flNextBlipTime = gpGlobals->curtime + FRAG_GRENADE_BLIP_FAST_FREQUENCY;
+ }
+ else
+ {
+ m_flNextBlipTime = gpGlobals->curtime + FRAG_GRENADE_BLIP_FREQUENCY;
+ }
+ }
+
+ SetNextThink( gpGlobals->curtime + 0.1 );
+}
+
+void CGrenadeFrag::SetVelocity( const Vector &velocity, const AngularImpulse &angVelocity )
+{
+ IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
+ if ( pPhysicsObject )
+ {
+ pPhysicsObject->AddVelocity( &velocity, &angVelocity );
+ }
+}
+
+int CGrenadeFrag::OnTakeDamage( const CTakeDamageInfo &inputInfo )
+{
+ // Manually apply vphysics because BaseCombatCharacter takedamage doesn't call back to CBaseEntity OnTakeDamage
+ VPhysicsTakeDamage( inputInfo );
+
+ // Grenades only suffer blast damage and burn damage.
+ if( !(inputInfo.GetDamageType() & (DMG_BLAST|DMG_BURN) ) )
+ return 0;
+
+ return BaseClass::OnTakeDamage( inputInfo );
+}
+
+#if defined(HL2_EPISODIC) && 0 // FIXME: HandleInteraction() is no longer called now that base grenade derives from CBaseAnimating
+extern int g_interactionBarnacleVictimGrab; ///< usually declared in ai_interactions.h but no reason to haul all of that in here.
+extern int g_interactionBarnacleVictimBite;
+extern int g_interactionBarnacleVictimReleased;
+bool CGrenadeFrag::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt)
+{
+ // allow fragnades to be grabbed by barnacles.
+ if ( interactionType == g_interactionBarnacleVictimGrab )
+ {
+ // give the grenade another five seconds seconds so the player can have the satisfaction of blowing up the barnacle with it
+ float timer = m_flDetonateTime - gpGlobals->curtime + 5.0f;
+ SetTimer( timer, timer - FRAG_GRENADE_WARN_TIME );
+
+ return true;
+ }
+ else if ( interactionType == g_interactionBarnacleVictimBite )
+ {
+ // detonate the grenade immediately
+ SetTimer( 0, 0 );
+ return true;
+ }
+ else if ( interactionType == g_interactionBarnacleVictimReleased )
+ {
+ // take the five seconds back off the timer.
+ float timer = MAX(m_flDetonateTime - gpGlobals->curtime - 5.0f,0.0f);
+ SetTimer( timer, timer - FRAG_GRENADE_WARN_TIME );
+ return true;
+ }
+ else
+ {
+ return BaseClass::HandleInteraction( interactionType, data, sourceEnt );
+ }
+}
+#endif
+
+void CGrenadeFrag::InputSetTimer( inputdata_t &inputdata )
+{
+ SetTimer( inputdata.value.Float(), inputdata.value.Float() - FRAG_GRENADE_WARN_TIME );
+}
+
+CBaseGrenade *Fraggrenade_Create( const Vector &position, const QAngle &angles, const Vector &velocity, const AngularImpulse &angVelocity, CBaseEntity *pOwner, float timer, bool combineSpawned )
+{
+ // Don't set the owner here, or the player can't interact with grenades he's thrown
+ CGrenadeFrag *pGrenade = (CGrenadeFrag *)CBaseEntity::Create( "npc_grenade_frag", position, angles, pOwner );
+
+ pGrenade->SetTimer( timer, timer - FRAG_GRENADE_WARN_TIME );
+ pGrenade->SetVelocity( velocity, angVelocity );
+ pGrenade->SetThrower( ToBaseCombatCharacter( pOwner ) );
+ pGrenade->m_takedamage = DAMAGE_EVENTS_ONLY;
+ pGrenade->SetCombineSpawned( combineSpawned );
+
+ return pGrenade;
+}
+
+bool Fraggrenade_WasPunted( const CBaseEntity *pEntity )
+{
+ const CGrenadeFrag *pFrag = dynamic_cast<const CGrenadeFrag *>( pEntity );
+ if ( pFrag )
+ {
+ return pFrag->WasPunted();
+ }
+
+ return false;
+}
+
+bool Fraggrenade_WasCreatedByCombine( const CBaseEntity *pEntity )
+{
+ const CGrenadeFrag *pFrag = dynamic_cast<const CGrenadeFrag *>( pEntity );
+ if ( pFrag )
+ {
+ return pFrag->IsCombineSpawned();
+ }
+
+ return false;
+} \ No newline at end of file