mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-10 02:39:35 +00:00
1
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user