summaryrefslogtreecommitdiff
path: root/game/shared/tf2/grenade_limpetmine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/tf2/grenade_limpetmine.cpp')
-rw-r--r--game/shared/tf2/grenade_limpetmine.cpp406
1 files changed, 406 insertions, 0 deletions
diff --git a/game/shared/tf2/grenade_limpetmine.cpp b/game/shared/tf2/grenade_limpetmine.cpp
new file mode 100644
index 0000000..098d626
--- /dev/null
+++ b/game/shared/tf2/grenade_limpetmine.cpp
@@ -0,0 +1,406 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "tf_player.h"
+#include "tf_basecombatweapon.h"
+#include "basegrenade_shared.h"
+#include "weapon_limpetmine.h"
+#include "engine/IEngineSound.h"
+#include "grenade_limpetmine.h"
+#include "tf_shareddefs.h"
+#include "IEffects.h"
+#include "player.h"
+#include "basetfvehicle.h"
+
+#define LIMPET_LIVE_TIME 0.5 // Time it takes before a limpet can be detonated after placement
+#define LIMPET_LIFETIME 120 // After this time, limpets fizzle naturally
+#define LIMPET_FIZZLE_DURATION 2.0f
+#define LIMPET_MINS Vector(-5, -5, 0)
+#define LIMPET_MAXS Vector( 5, 5, 10)
+
+// Damage CVars
+ConVar weapon_limpetmine_grenade_damage( "weapon_limpetmine_grenade_damage","0", FCVAR_NONE, "Limpet Mine's grenade maximum damage" );
+ConVar weapon_limpetmine_grenade_radius( "weapon_limpetmine_grenade_radius","0", FCVAR_NONE, "Limpet Mine's grenade splash radius" );
+
+// Global Savedata for friction modifier
+BEGIN_DATADESC( CLimpetMine )
+ // Function Pointers
+ DEFINE_THINKFUNC( LiveThink ),
+ DEFINE_ENTITYFUNC( StickyTouch ),
+ DEFINE_THINKFUNC( LimpetThink ),
+END_DATADESC()
+
+
+IMPLEMENT_SERVERCLASS_ST(CLimpetMine, DT_LimpetMine)
+ SendPropInt(SENDINFO(m_bLive), 1, SPROP_UNSIGNED ),
+END_SEND_TABLE()
+
+LINK_ENTITY_TO_CLASS( grenade_limpetmine, CLimpetMine );
+
+//-----------------------------------------------------------------------------
+// Static initializers:
+//-----------------------------------------------------------------------------
+CLimpetMine* CLimpetMine::allLimpets = NULL;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CLimpetMine::CLimpetMine( void )
+{
+ UseClientSideAnimation();
+
+ // ---------------------------------
+ // Add to linked list of limpets
+ // ---------------------------------
+ nextLimpet = CLimpetMine::allLimpets;
+ CLimpetMine::allLimpets = this;
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CLimpetMine::~CLimpetMine( void )
+{
+ // --------------------------------------
+ // Remove from linked list of limpets
+ // --------------------------------------
+ CLimpetMine *pLimpet = CLimpetMine::allLimpets;
+ if (pLimpet == this)
+ {
+ CLimpetMine::allLimpets = pLimpet->nextLimpet;
+ }
+ else
+ {
+ while (pLimpet)
+ {
+ if (pLimpet->nextLimpet == this)
+ {
+ pLimpet->nextLimpet = pLimpet->nextLimpet->nextLimpet;
+ break;
+ }
+ pLimpet = pLimpet->nextLimpet;
+ }
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLimpetMine::Precache( void )
+{
+ PrecacheModel( "models/projectiles/grenade_limpet.mdl" );
+ PrecacheScriptSound( "LimpetMine.Beep" );
+ PrecacheScriptSound( "LimpetMine.Fizzle" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLimpetMine::Spawn( void )
+{
+ SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
+ SetSolid( SOLID_BBOX );
+ SetGravity( 1.0 );
+ SetFriction( 1.25 );
+ SetModel( "models/projectiles/grenade_limpet.mdl");
+ UTIL_SetSize( this, LIMPET_MINS, LIMPET_MAXS );
+ m_bLive = false;
+ m_bFizzleInit = false;
+ m_bEMPed = false;
+ SetThink( LiveThink );
+ SetNextThink( gpGlobals->curtime + LIMPET_LIVE_TIME );
+ SetTouch( StickyTouch );
+
+ // Causes these to collide with everything but NPCs and players
+ SetCollisionGroup( TFCOLLISION_GROUP_GRENADE );
+
+ AddFlag( FL_OBJECT );
+ // Prevent sentry guns detecting these.
+ AddFlag( FL_NOTARGET );
+
+ // Set my damages to the cvar values
+ SetDamage( weapon_limpetmine_grenade_damage.GetFloat() );
+ SetDamageRadius( weapon_limpetmine_grenade_radius.GetFloat() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return true if this limpet mine can be detonated yet
+//-----------------------------------------------------------------------------
+bool CLimpetMine::IsLive( void )
+{
+ return m_bLive;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLimpetMine::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
+{
+ Assert( pCaller );
+
+ // USE_SET Means we're being asked to fizzle out and dielf
+ if ( useType == USE_SET )
+ {
+ if ( !m_bFizzleInit )
+ {
+ // Set the defuse - fizzle think
+ m_flFizzleDuration = gpGlobals->curtime + 0.3;
+ SetThink( LimpetThink );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+ m_bFizzleInit = true;
+ }
+ }
+ else if ( IsLive() )
+ {
+ // Get the TF2 player that owns this limpet:
+ CBaseTFPlayer *pPlayer = NULL;
+ if ( m_hLauncher )
+ {
+ pPlayer = ToBaseTFPlayer( m_hLauncher->GetOwner() );
+ }
+
+ // Get the TF2 player that is calling this object, if any:
+ CBaseTFPlayer *pCallerPlayer = NULL;
+ if ( pCaller )
+ {
+ pCallerPlayer = ToBaseTFPlayer( pCaller );
+ }
+
+ // If the owning player is directly using the limpet, then pick it up:
+ if( pPlayer && pCallerPlayer && pPlayer->IsSameClass( pCallerPlayer ) )
+ {
+ if ( m_hLauncher )
+ {
+ pPlayer->GiveAmmo( 1, m_hLauncher->m_iPrimaryAmmoType );
+ m_hLauncher->DecrementLimpets();
+ }
+ UTIL_Remove( this );
+ }
+ else if ( pActivator && !pActivator->InSameTeam( this ) )
+ {
+ // only the owning player can detonate his own limpets, so return if this isn't the owner.
+ return;
+ }
+
+ // We're being detonated
+
+ // If are EMPed then we cannot be detonated.
+ else if ( !IsEMPed() )
+ {
+ // Beep and detonate soon afterwards
+ EmitSound( "LimpetMine.Beep" );
+
+ SetThink( Detonate );
+ SetNextThink( gpGlobals->curtime + 0.5f );
+
+ // Pretend I'm not live anymore so I don't get exploded again
+ m_bLive = false;
+
+ if ( m_hLauncher )
+ {
+ m_hLauncher->DecrementLimpets();
+ }
+
+ }
+
+
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CLimpetMine::TakeEMPDamage( float duration )
+{
+ if ( !m_bFizzleInit )
+ {
+ // Set the defuse - fizzle think
+ float flDuration = MIN( duration, LIMPET_FIZZLE_DURATION );
+ m_flFizzleDuration = gpGlobals->curtime + ( flDuration - 1.0f );
+ SetThink( LimpetThink );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+ m_bFizzleInit = true;
+ m_bEMPed = true;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a limpet mine
+//-----------------------------------------------------------------------------
+CLimpetMine* CLimpetMine::Create( const Vector &vecOrigin, const Vector &vecForward, CBasePlayer *pOwner )
+{
+ CLimpetMine *pGrenade = (CLimpetMine*)CreateEntityByName("grenade_limpetmine");
+
+ pGrenade->Teleport( &vecOrigin, NULL, NULL );
+ pGrenade->Spawn();
+ pGrenade->SetOwnerEntity( pOwner );
+ pGrenade->SetThrower( pOwner );
+ pGrenade->SetAbsVelocity( vecForward );
+ pGrenade->ChangeTeam( pOwner->GetTeamNumber() );
+
+ return pGrenade;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Keep a pointer to the launcher (parent)
+//-----------------------------------------------------------------------------
+void CLimpetMine::SetLauncher( CWeaponLimpetmine *pLauncher )
+{
+ m_hLauncher = pLauncher;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Go Live
+//-----------------------------------------------------------------------------
+void CLimpetMine::LiveThink( void )
+{
+ m_bLive = true;
+
+ // Remove myself after a while
+ m_flFizzleDuration = gpGlobals->curtime + LIMPET_LIFETIME + 0.3;
+ SetNextThink( gpGlobals->curtime + 0.1f );
+ SetThink( LimpetThink );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Make the grenade stick to whatever it touches
+//-----------------------------------------------------------------------------
+void CLimpetMine::StickyTouch( CBaseEntity *pOther )
+{
+ Assert( pOther );
+ if ( !pOther->IsSolid() )
+ return;
+
+ if ( !pOther->IsBSPModel() && !pOther->GetBaseAnimating() )
+ return;
+
+ BounceSound();
+ m_bStuckToTarget = false;
+
+ // Bounce off of shields
+ if ( pOther->GetCollisionGroup() == TFCOLLISION_GROUP_SHIELD )
+ {
+ // Move away from the shield...
+ // Fling it out a little extra along the plane normal
+ Vector vecNewVelocity;
+ Vector vecCenter;
+ AngleVectors( pOther->GetAbsAngles(), &vecCenter );
+ VectorMultiply( vecCenter, 400.0f, vecNewVelocity );
+ SetAbsVelocity( vecNewVelocity );
+ return;
+ }
+
+ // Only stick to non-moving entities
+ if ( !pOther->GetBaseAnimating() )
+ return;
+
+ // Don't stick to team members
+ if ( InSameTeam( pOther ) )
+ return;
+
+ // ROBIN: Removed stick to enemies for now
+ {
+ SetAbsVelocity( vec3_origin );
+ SetMoveType( MOVETYPE_NONE );
+ return;
+ }
+
+ m_bStuckToTarget = true;
+
+ // Orient to stick to the wall I just hit
+ trace_t tr;
+ Vector vecPrev = GetLocalOrigin() - (GetAbsVelocity() * 0.1);
+ UTIL_TraceLine( vecPrev, vecPrev + (GetAbsVelocity() * 2), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+ if ( tr.fraction != 1 )
+ {
+ // Orient the *up* axis to be along the plane normal
+ Vector perp( 1, 0, 0 );
+ Vector forward, right;
+ CrossProduct( perp, tr.plane.normal, forward );
+ if (forward.LengthSqr() < 0.1f)
+ {
+ perp.Init( 0, 1, 0 );
+ CrossProduct( perp, tr.plane.normal, forward );
+ }
+ VectorNormalize( forward );
+ CrossProduct( tr.plane.normal, forward, right );
+
+ VMatrix orientation( forward, right, tr.plane.normal );
+
+ QAngle angles;
+ MatrixToAngles( orientation, angles );
+ SetAbsAngles( angles );
+ }
+
+ SetAbsVelocity( vec3_origin );
+ SetMoveType( MOVETYPE_NONE );
+
+ // At this point, it shouldn't affect player movement
+ SetCollisionGroup( COLLISION_GROUP_DEBRIS );
+ BounceSound();
+
+ SetParent( pOther );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Once the limpet's active, it starts running this
+//-----------------------------------------------------------------------------
+void CLimpetMine::LimpetThink( void )
+{
+ SetNextThink( gpGlobals->curtime + 0.1f );
+
+ // If I'm not ready to fizzle yet, make sure my parent's still there.
+ if ( m_bStuckToTarget )
+ {
+ // Lost our parent?
+ if ( !GetMoveParent() )
+ {
+ m_bStuckToTarget = false;
+ // Fall to the ground
+ SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_CUSTOM );
+ SetTouch( StickyTouch );
+ }
+ }
+
+ float flDeltaTime = m_flFizzleDuration - gpGlobals->curtime;
+
+ // Not ready to fizzle yet?
+ if ( flDeltaTime > 0.3 )
+ return;
+
+ // Start fizzling
+ if ( flDeltaTime > 0.0f )
+ {
+ // Emit a fizzle sound
+ EmitSound( "LimpetMine.Fizzle" );
+
+ g_pEffects->Sparks( GetAbsOrigin() );
+
+ // Smoke.
+ UTIL_Smoke( GetAbsOrigin(), random->RandomInt( 1, 3), 10 );
+ }
+ else
+ {
+ // Done fizzling - no more sound.
+ StopSound( "LimpetMine.Fizzle" );
+ UTIL_Remove( this );
+
+ // Remove this limpet mine from the launcher deployment count.
+ if ( m_hLauncher )
+ {
+ m_hLauncher->DecrementLimpets();
+ }
+
+ return;
+ }
+}