You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
390 lines
12 KiB
390 lines
12 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Rockets (Weapon) |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "weapon_grenade_rocket.h" |
|
|
|
#if defined( CLIENT_DLL ) |
|
// Client Only |
|
#include "hud.h" |
|
#include "particles_simple.h" |
|
#else |
|
// Server Only |
|
#include "gameinterface.h" |
|
#include "engine/IEngineSound.h" |
|
#include "explode.h" |
|
#include "tf_team.h" |
|
#include "env_laserdesignation.h" |
|
#include "iservervehicle.h" |
|
#endif |
|
|
|
LINK_ENTITY_TO_CLASS( weapon_grenade_rocket, CWeaponGrenadeRocket ); |
|
BEGIN_PREDICTION_DATA( CWeaponGrenadeRocket ) |
|
END_PREDICTION_DATA() |
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponGrenadeRocket, DT_WeaponGrenadeRocket ) |
|
BEGIN_NETWORK_TABLE( CWeaponGrenadeRocket, DT_WeaponGrenadeRocket ) |
|
//#if !defined( CLIENT_DLL ) |
|
//#else |
|
//#endif |
|
END_NETWORK_TABLE() |
|
|
|
#define WEAPON_GRENADE_ROCKET_VELOCITY 1000 |
|
|
|
#if !defined( CLIENT_DLL ) |
|
// Server Only |
|
ConVar weapon_grenade_rocket_track_range_mod( "weapon_grenade_rocket_track_range_mod","1.5", FCVAR_NONE, "Range multiplier when a rocket's tracking a designated target." ); |
|
ConVar weapon_grenade_rocket_force( "weapon_grenade_rocket_force","150.0", FCVAR_NONE, "Rocket force modifier." ); |
|
#endif |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
//----------------------------------------------------------------------------- |
|
CWeaponGrenadeRocket::CWeaponGrenadeRocket() |
|
{ |
|
m_flDamage = 100.0f; |
|
|
|
#if !defined( CLIENT_DLL ) |
|
// Server Only |
|
UseClientSideAnimation(); |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Deconstructor |
|
//----------------------------------------------------------------------------- |
|
CWeaponGrenadeRocket::~CWeaponGrenadeRocket() |
|
{ |
|
#if defined( CLIENT_DLL ) |
|
StopSound( entindex(), "GrenadeRocket.FlyLoop" ); |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Create a weapon grenade rocket |
|
//----------------------------------------------------------------------------- |
|
CWeaponGrenadeRocket *CWeaponGrenadeRocket::Create( const Vector &vecOrigin, const Vector &vecForward, float flMaxRange, CBaseEntity *pOwner ) |
|
{ |
|
#if !defined( CLIENT_DLL ) |
|
CWeaponGrenadeRocket *pRocket = ( CWeaponGrenadeRocket* )CreateEntityByName( "weapon_grenade_rocket" ); |
|
|
|
UTIL_SetOrigin( pRocket, vecOrigin ); |
|
QAngle angles; |
|
VectorAngles( vecForward, angles ); |
|
pRocket->SetLocalAngles( angles ); |
|
pRocket->Spawn(); |
|
pRocket->SetOwnerEntity( pOwner ); |
|
pRocket->ChangeTeam( pOwner->GetTeamNumber() ); |
|
pRocket->SetMaxRange( flMaxRange ); |
|
|
|
return pRocket; |
|
#else |
|
return NULL; |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CWeaponGrenadeRocket::SetMaxRange( float flRange ) |
|
{ |
|
m_flMaxRange = flRange; |
|
m_flFallingSpeed = 200; // Initial falling speed |
|
|
|
// Reduce max range for upward shots |
|
Vector vecForward; |
|
GetVectors( &vecForward, NULL, NULL ); |
|
if ( vecForward.z > 0 ) |
|
{ |
|
m_flMaxRange = MAX(1, m_flMaxRange - (vecForward.z * 1200)); |
|
} |
|
else |
|
{ |
|
m_flMaxRange -= (vecForward.z * 2400); |
|
} |
|
|
|
#if !defined( CLIENT_DLL ) |
|
if ( m_flMaxRange ) |
|
{ |
|
float flSpeed = GetLocalVelocity().Length(); |
|
Assert( flSpeed ); |
|
m_flExceedRangeTime = gpGlobals->curtime + (m_flMaxRange / flSpeed); |
|
|
|
// Start looking for designators |
|
SetThink( TrackThink ); |
|
SetNextThink( gpGlobals->curtime + 0.1f ); |
|
} |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CWeaponGrenadeRocket::Spawn( void ) |
|
{ |
|
#if !defined( CLIENT_DLL ) |
|
Precache(); |
|
|
|
m_flRadius = 100; |
|
SetMoveType( MOVETYPE_FLY ); |
|
SetSolid( SOLID_BBOX ); |
|
SetModel( "models/weapons/w_missile.mdl" ); |
|
UTIL_SetSize( this, vec3_origin, vec3_origin ); |
|
|
|
SetCollisionGroup( TFCOLLISION_GROUP_WEAPON ); |
|
|
|
// Forward! |
|
Vector forward; |
|
AngleVectors( GetLocalAngles(), &forward, NULL, NULL ); |
|
SetAbsVelocity( forward * WEAPON_GRENADE_ROCKET_VELOCITY ); |
|
|
|
SetTouch( RocketTouch ); |
|
#else |
|
// Start our flying sound loop |
|
CPASAttenuationFilter filter( this ); |
|
filter.MakeReliable(); |
|
EmitSound( filter, entindex(), "GrenadeRocket.FlyLoop" ); |
|
#endif |
|
} |
|
|
|
#if !defined( CLIENT_DLL ) |
|
// Server Only |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return my owner as my scorer |
|
//----------------------------------------------------------------------------- |
|
CBasePlayer *CWeaponGrenadeRocket::GetScorer( void ) |
|
{ |
|
return ToBasePlayer( m_hOwner ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CWeaponGrenadeRocket::Precache( void ) |
|
{ |
|
PrecacheModel( "models/weapons/w_missile.mdl" ); |
|
|
|
PrecacheScriptSound( "GrenadeRocket.FlyLoop" ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: We've exceeded this rocket's range, start heading downward, randomly |
|
//----------------------------------------------------------------------------- |
|
void CWeaponGrenadeRocket::ExceededRangeThink( void ) |
|
{ |
|
Vector vecZ( 0,0,1 ); |
|
Vector vecPerp; |
|
|
|
// Weave drunkely and head down |
|
Vector vecVelocity = GetLocalVelocity(); |
|
CrossProduct( vecVelocity, vecZ, vecPerp ); |
|
VectorNormalize( vecPerp ); |
|
vecPerp *= random->RandomFloat(-100,100); |
|
vecVelocity += vecPerp; |
|
vecVelocity.z -= m_flFallingSpeed; |
|
m_flFallingSpeed += 50; |
|
SetLocalVelocity( vecVelocity ); |
|
|
|
SetAnglesToMatchVelocity(); |
|
SetNextThink( gpGlobals->curtime + 0.3 ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Track towards my my designated target |
|
//----------------------------------------------------------------------------- |
|
void CWeaponGrenadeRocket::TrackThink( void ) |
|
{ |
|
SetNextThink( gpGlobals->curtime + 0.3 ); |
|
|
|
// Have I exceeded my range? |
|
if ( gpGlobals->curtime > m_flExceedRangeTime ) |
|
{ |
|
SetThink( ExceededRangeThink ); |
|
// Start falling immediately |
|
ExceededRangeThink(); |
|
return; |
|
} |
|
|
|
// Look for any laser designators in tracking view |
|
int iTeam = GetTeamNumber(); |
|
int iCount = CEnvLaserDesignation::GetNumLaserDesignators( iTeam ); |
|
if ( !iCount ) |
|
return; |
|
|
|
// Get the potential lock range |
|
float flIncreasedMaxRange = m_flMaxRange * weapon_grenade_rocket_track_range_mod.GetFloat(); |
|
float flNearestDot = 0.95; |
|
Vector vecNearestTarget = vec3_origin; |
|
bool bFoundOne = false; |
|
|
|
// Any valid designated targets? |
|
for ( int i = 0; i < iCount; i++ ) |
|
{ |
|
Vector vecTarget; |
|
if ( !CEnvLaserDesignation::GetLaserDesignation( iTeam, i, &vecTarget ) ) |
|
continue; |
|
|
|
// Check validity of designated target |
|
Vector vecToTarget = ( vecTarget - GetAbsOrigin() ); |
|
float flDistanceSqr = vecToTarget.LengthSqr(); |
|
// Make sure it's not too far |
|
if ( flDistanceSqr > (flIncreasedMaxRange*flIncreasedMaxRange) ) |
|
continue; |
|
|
|
// Make sure it's near my flight path |
|
VectorNormalize(vecToTarget); |
|
Vector vecForward; |
|
GetVectors( &vecForward, NULL, NULL ); |
|
float flDot = DotProduct( vecToTarget, vecForward ); |
|
if ( flDot < flNearestDot ) |
|
continue; |
|
|
|
flNearestDot = flDot; |
|
vecNearestTarget = vecTarget; |
|
bFoundOne = true; |
|
} |
|
|
|
// No valid targets |
|
if ( !bFoundOne ) |
|
return; |
|
|
|
SetNextThink( gpGlobals->curtime + 0.1f ); |
|
|
|
// Turn towards my target |
|
Vector vecToTarget = (vecNearestTarget - GetAbsOrigin()); |
|
VectorNormalize(vecToTarget); |
|
|
|
// Shamelessly ripped from HL1 RPG |
|
float flSpeed = GetAbsVelocity().Length(); |
|
SetAbsVelocity( (GetAbsVelocity() * 0.5) + (vecToTarget * flSpeed * 0.498) ); |
|
|
|
SetAnglesToMatchVelocity(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set angles to match our velocity |
|
//----------------------------------------------------------------------------- |
|
void CWeaponGrenadeRocket::SetAnglesToMatchVelocity( void ) |
|
{ |
|
QAngle angles; |
|
VectorAngles( GetAbsVelocity(), angles ); |
|
SetLocalAngles( angles ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CWeaponGrenadeRocket::RocketTouch( CBaseEntity *pOther ) |
|
{ |
|
Assert( pOther ); |
|
if ( !pOther->IsSolid() ) |
|
return; |
|
|
|
// Apply forces to vehicles. |
|
if ( pOther->GetServerVehicle() ) |
|
{ |
|
ApplyForcesToVehicle( pOther ); |
|
} |
|
|
|
CPASFilter filter( GetAbsOrigin() ); |
|
te->Explosion( filter, 0.0, &GetAbsOrigin(), g_sModelIndexFireball, 2.0, 15, TE_EXPLFLAG_NONE, 100, m_flDamage ); |
|
|
|
// Use the owner's position as the reported position |
|
Vector vecReported = vec3_origin; |
|
if ( GetOwnerEntity() ) |
|
{ |
|
vecReported = GetOwnerEntity()->GetAbsOrigin(); |
|
} |
|
RadiusDamage( CTakeDamageInfo( this, GetOwnerEntity(), vec3_origin, GetAbsOrigin(), GetDamage(), GetDamageType(), 0, &vecReported ), GetAbsOrigin(), GetDamageRadius(), CLASS_NONE, NULL ); |
|
|
|
UTIL_Remove( this ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CWeaponGrenadeRocket::ApplyForcesToVehicle( CBaseEntity *pEntity ) |
|
{ |
|
// Check team - don't apply forces to our own team's vehicles. |
|
if ( pEntity->GetTeam() == GetTeam() ) |
|
return; |
|
|
|
IServerVehicle *pVehicle = pEntity->GetServerVehicle(); |
|
if ( !pVehicle ) |
|
return; |
|
|
|
IPhysicsObject *pPhysObject = pEntity->VPhysicsGetObject(); |
|
if ( pPhysObject ) |
|
{ |
|
//------------------------------------------------------------ |
|
// Rocket the vehicle in the direction of the incoming rocket. |
|
//------------------------------------------------------------ |
|
Vector vecForceDir = GetAbsVelocity(); |
|
vecForceDir.z = 0.0f; |
|
VectorNormalize( vecForceDir ); |
|
|
|
float flForce = pPhysObject->GetMass(); |
|
flForce += ( 4.0f * 100.0f ); // Wheels |
|
flForce *= weapon_grenade_rocket_force.GetFloat(); |
|
|
|
vecForceDir *= flForce; |
|
|
|
pPhysObject->ApplyForceOffset( vecForceDir, GetAbsOrigin() ); |
|
} |
|
} |
|
|
|
#else |
|
// Client Only |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CWeaponGrenadeRocket::OnDataChanged( DataUpdateType_t updateType ) |
|
{ |
|
BaseClass::OnDataChanged( updateType ); |
|
|
|
// Only think when "rocketing." |
|
SetNextClientThink( CLIENT_THINK_ALWAYS ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Spawn rocket effects! |
|
//----------------------------------------------------------------------------- |
|
void CWeaponGrenadeRocket::ClientThink( void ) |
|
{ |
|
// Fire smoke puffs out the side |
|
CSmartPtr<CSimpleEmitter> pSmokeEmitter = CSimpleEmitter::Create( "C_GrenadeRocket::Effect" ); |
|
pSmokeEmitter->SetSortOrigin( GetAbsOrigin() ); |
|
PMaterialHandle hSphereMaterial = pSmokeEmitter->GetPMaterial( "particle/particle_noisesphere" ); |
|
int iSmokeClouds = random->RandomInt( 1,2 ); |
|
for ( int i = 0; i < iSmokeClouds; i++ ) |
|
{ |
|
SimpleParticle *pParticle = ( SimpleParticle* ) pSmokeEmitter->AddParticle( sizeof( SimpleParticle ), hSphereMaterial, GetAbsOrigin() ); |
|
if ( !pParticle ) |
|
return; |
|
|
|
// Particle data. |
|
pParticle->m_flLifetime = 0.0f; |
|
pParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.3f ); |
|
|
|
pParticle->m_uchStartSize = 10; |
|
pParticle->m_uchEndSize = pParticle->m_uchStartSize + 2; |
|
|
|
pParticle->m_vecVelocity = GetAbsVelocity(); |
|
pParticle->m_uchStartAlpha = 255; |
|
pParticle->m_uchEndAlpha = 64; |
|
pParticle->m_flRoll = random->RandomFloat( 180, 360 ); |
|
pParticle->m_flRollDelta = random->RandomFloat( -1, 1 ); |
|
|
|
pParticle->m_uchColor[0] = 50; |
|
pParticle->m_uchColor[1] = 250; |
|
pParticle->m_uchColor[2] = 50; |
|
} |
|
} |
|
|
|
#endif |
|
|
|
|