diff options
Diffstat (limited to 'game/shared/tf2/grenade_limpetmine.cpp')
| -rw-r--r-- | game/shared/tf2/grenade_limpetmine.cpp | 406 |
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; + } +} |