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.
257 lines
8.4 KiB
257 lines
8.4 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "mortar_round.h" |
|
#include "engine/IEngineSound.h" |
|
#include "tf_gamerules.h" |
|
#include "tf_team.h" |
|
|
|
|
|
|
|
// Damage CVars |
|
ConVar weapon_mortar_shell_damage( "weapon_mortar_shell_damage","0", FCVAR_NONE, "Mortar's standard shell maximum damage" ); |
|
ConVar weapon_mortar_shell_radius( "weapon_mortar_shell_radius","0", FCVAR_NONE, "Mortar's standard shell splash radius" ); |
|
ConVar weapon_mortar_starburst_damage( "weapon_mortar_starburst_damage","0", FCVAR_NONE, "Mortar's starburst maximum damage" ); |
|
ConVar weapon_mortar_starburst_radius( "weapon_mortar_starburst_radius","0", FCVAR_NONE, "Mortar's starburst splash radius" ); |
|
ConVar weapon_mortar_cluster_shells( "weapon_mortar_cluster_shells","0", FCVAR_NONE, "Number of shells a mortar cluster round bursts into" ); |
|
|
|
//===================================================================================================== |
|
// MORTAR ROUND |
|
//===================================================================================================== |
|
BEGIN_DATADESC( CMortarRound ) |
|
|
|
// Function Pointers |
|
DEFINE_FUNCTION( MissileTouch ), |
|
DEFINE_FUNCTION( FallThink ), |
|
|
|
END_DATADESC() |
|
|
|
LINK_ENTITY_TO_CLASS( mortar_round, CMortarRound ); |
|
PRECACHE_WEAPON_REGISTER(mortar_round); |
|
|
|
CMortarRound::CMortarRound() |
|
{ |
|
m_pSmokeTrail = NULL; |
|
m_pLauncher = NULL; |
|
m_iRoundType = MA_SHELL; |
|
UseClientSideAnimation(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CMortarRound::Precache( void ) |
|
{ |
|
PrecacheModel( "models/weapons/w_grenade.mdl" ); |
|
|
|
PrecacheScriptSound( "MortarRound.StopSound" ); |
|
PrecacheScriptSound( "MortarRound.IncomingSound" ); |
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CMortarRound::Spawn( void ) |
|
{ |
|
Precache(); |
|
|
|
SetMoveType( MOVETYPE_FLYGRAVITY ); |
|
SetSolid( SOLID_BBOX ); |
|
SetModel( "models/weapons/w_grenade.mdl" ); |
|
UTIL_SetSize( this, vec3_origin, vec3_origin ); |
|
|
|
SetTouch( MissileTouch ); |
|
SetCollisionGroup( TFCOLLISION_GROUP_WEAPON ); |
|
|
|
// Trail smoke |
|
m_pSmokeTrail = SmokeTrail::CreateSmokeTrail(); |
|
if ( m_pSmokeTrail ) |
|
{ |
|
m_pSmokeTrail->m_SpawnRate = 90; |
|
m_pSmokeTrail->m_ParticleLifetime = 1.5; |
|
m_pSmokeTrail->m_StartColor.Init(0.0, 0.0, 0.0); |
|
m_pSmokeTrail->m_EndColor.Init( 0.5,0.5,0.5 ); |
|
m_pSmokeTrail->m_StartSize = 10; |
|
m_pSmokeTrail->m_EndSize = 50; |
|
m_pSmokeTrail->m_SpawnRadius = 1; |
|
m_pSmokeTrail->m_MinSpeed = 15; |
|
m_pSmokeTrail->m_MaxSpeed = 25; |
|
m_pSmokeTrail->SetLifetime(15); |
|
m_pSmokeTrail->FollowEntity( this ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CMortarRound::MissileTouch( CBaseEntity *pOther ) |
|
{ |
|
CMortarRound *pRound = dynamic_cast< CMortarRound* >(pOther); |
|
if ( pRound ) |
|
return; |
|
|
|
// Stop emitting smoke/sound |
|
m_pSmokeTrail->SetEmit(false); |
|
EmitSound( "MortarRound.StopSound" ); |
|
|
|
// Create an explosion. |
|
if ( m_iRoundType == MA_STARBURST ) |
|
{ |
|
// Small explosion, blind people in the area |
|
float flBlind = 0; |
|
|
|
// Shift it up a bit for the explosion |
|
SetLocalOrigin( GetAbsOrigin() + Vector(0,0,32) ); |
|
CPASFilter filter( GetAbsOrigin() ); |
|
te->Explosion( filter, 0.0, &GetAbsOrigin(), g_sModelIndexFireball, 3.0, 15, TE_EXPLFLAG_NONE, 512, 100 ); |
|
RadiusDamage( CTakeDamageInfo( this, GetOwnerEntity(), weapon_mortar_starburst_damage.GetFloat(), DMG_BLAST ), GetAbsOrigin(), weapon_mortar_starburst_radius.GetFloat(), CLASS_NONE, NULL ); |
|
|
|
// Blind all players nearby |
|
for ( int i = 1; i <= gpGlobals->maxClients; i++ ) |
|
{ |
|
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( UTIL_PlayerByIndex(i) ); |
|
if ( pPlayer ) |
|
{ |
|
Vector vecSrc = pPlayer->EyePosition(); |
|
Vector vecToTarget = (vecSrc - GetAbsOrigin()); |
|
float flLength = VectorNormalize( vecToTarget ); |
|
// If the player's looking at the grenade, blind him a lot |
|
if ( flLength < 2048 ) |
|
{ |
|
Vector forward, right, up; |
|
AngleVectors( pPlayer->pl.v_angle, &forward, &right, &up ); |
|
float flDot = DotProduct( vecToTarget, forward ); |
|
|
|
// Msg( "Dot: %f\n", flDot ); |
|
|
|
// Make sure it's in front of the player |
|
if ( flDot < 0.0f ) |
|
{ |
|
flDot = fabs( DotProduct(vecToTarget, right ) ) + fabs( DotProduct(vecToTarget, up ) ); |
|
|
|
// Open LOS? |
|
trace_t tr; |
|
UTIL_TraceLine( vecSrc, GetAbsOrigin(), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); |
|
if ( ( tr.fraction == 1.0f ) || ( tr.m_pEnt == pPlayer ) ) |
|
{ |
|
flBlind = flDot; |
|
} |
|
else |
|
{ |
|
// Blocked blind is only half as effective |
|
flBlind = flDot * 0.5; |
|
} |
|
} |
|
else if ( flLength < 512 ) |
|
{ |
|
// Otherwise, if the player's near the grenade blind him a little |
|
flBlind = 0.2; |
|
} |
|
|
|
|
|
// Flash the screen red |
|
color32 white = {255,255,255, 255}; |
|
white.a = MIN( (flBlind * 255), 255 ); |
|
UTIL_ScreenFade( pPlayer, white, 0.3, 5.0, 0 ); |
|
} |
|
} |
|
} |
|
|
|
UTIL_Remove( this ); |
|
} |
|
else |
|
{ |
|
// Large explosion |
|
|
|
// Shift it up a bit for the explosion |
|
SetLocalOrigin( GetAbsOrigin() + Vector(0,0,64) ); |
|
CPASFilter filter( GetAbsOrigin() ); |
|
te->Explosion( filter, 0.0, &GetAbsOrigin(), g_sModelIndexFireball, 10.0, 15, TE_EXPLFLAG_NONE, 512, 300 ); |
|
RadiusDamage( CTakeDamageInfo( this, GetOwnerEntity(), weapon_mortar_shell_damage.GetFloat(), DMG_BLAST ), GetAbsOrigin(), weapon_mortar_shell_radius.GetFloat(), CLASS_NONE, NULL ); |
|
UTIL_Remove( this ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Play a fall sound when the mortar round begins to fall |
|
//----------------------------------------------------------------------------- |
|
void CMortarRound::FallThink( void ) |
|
{ |
|
if ( m_pLauncher ) |
|
{ |
|
CRecipientFilter filter; |
|
filter.AddAllPlayers(); |
|
EmitSound( filter, entindex(), "MortarRound.IncomingSound" ); |
|
|
|
// Cluster bombs split up in the air |
|
if ( m_iRoundType == MA_CLUSTER ) |
|
{ |
|
Vector forward, right; |
|
QAngle angles; |
|
VectorAngles( GetAbsVelocity(), angles ); |
|
SetLocalAngles( angles ); |
|
AngleVectors( GetLocalAngles(), &forward, &right, NULL ); |
|
for ( int i = 0; i < weapon_mortar_cluster_shells.GetInt(); i++ ) |
|
{ |
|
Vector vecVelocity = GetAbsVelocity(); |
|
vecVelocity += forward * random->RandomFloat( -200, 200 ); |
|
vecVelocity += right * random->RandomFloat( -200, 200 ); |
|
|
|
CMortarRound *pRound = CMortarRound::Create( GetAbsOrigin(), vecVelocity, GetOwnerEntity() ? GetOwnerEntity()->edict() : NULL ); |
|
pRound->SetLauncher( m_pLauncher ); |
|
pRound->ChangeTeam( GetTeamNumber() ); |
|
pRound->m_iRoundType = MA_SHELL; |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Keep a pointer to the Launcher |
|
//----------------------------------------------------------------------------- |
|
void CMortarRound::SetLauncher( CVehicleMortar *pLauncher ) |
|
{ |
|
m_pLauncher = pLauncher; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set the point at which we should start playing the fall sound |
|
//----------------------------------------------------------------------------- |
|
void CMortarRound::SetFallTime( float flFallTime ) |
|
{ |
|
SetThink( FallThink ); |
|
SetNextThink( gpGlobals->curtime + flFallTime ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Set the round's type |
|
//----------------------------------------------------------------------------- |
|
void CMortarRound::SetRoundType( int iRoundType ) |
|
{ |
|
m_iRoundType = iRoundType; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Create a missile |
|
//----------------------------------------------------------------------------- |
|
CMortarRound* CMortarRound::Create( const Vector &vecOrigin, const Vector &vecVelocity, edict_t *pentOwner = NULL ) |
|
{ |
|
CMortarRound *pGrenade = (CMortarRound*)CreateEntityByName("mortar_round"); |
|
|
|
UTIL_SetOrigin( pGrenade, vecOrigin ); |
|
pGrenade->SetOwnerEntity( Instance( pentOwner ) ); |
|
pGrenade->Spawn(); |
|
pGrenade->SetAbsVelocity( vecVelocity ); |
|
QAngle angles; |
|
VectorAngles( vecVelocity, angles ); |
|
pGrenade->SetLocalAngles( angles ); |
|
|
|
return pGrenade; |
|
} |
|
|
|
|