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.
284 lines
7.7 KiB
284 lines
7.7 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $Workfile: $ |
|
// $Date: $ |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "grenade_spit.h" |
|
#include "soundent.h" |
|
#include "decals.h" |
|
#include "smoke_trail.h" |
|
#include "hl2_shareddefs.h" |
|
#include "vstdlib/random.h" |
|
#include "engine/IEngineSound.h" |
|
#include "particle_parse.h" |
|
#include "particle_system.h" |
|
#include "soundenvelope.h" |
|
#include "ai_utils.h" |
|
#include "te_effect_dispatch.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
ConVar sk_antlion_worker_spit_grenade_dmg ( "sk_antlion_worker_spit_grenade_dmg", "20", FCVAR_NONE, "Total damage done by an individual antlion worker loogie."); |
|
ConVar sk_antlion_worker_spit_grenade_radius ( "sk_antlion_worker_spit_grenade_radius","40", FCVAR_NONE, "Radius of effect for an antlion worker spit grenade."); |
|
ConVar sk_antlion_worker_spit_grenade_poison_ratio ( "sk_antlion_worker_spit_grenade_poison_ratio","0.3", FCVAR_NONE, "Percentage of an antlion worker's spit damage done as poison (which regenerates)"); |
|
|
|
LINK_ENTITY_TO_CLASS( grenade_spit, CGrenadeSpit ); |
|
|
|
BEGIN_DATADESC( CGrenadeSpit ) |
|
|
|
DEFINE_FIELD( m_bPlaySound, FIELD_BOOLEAN ), |
|
|
|
// Function pointers |
|
DEFINE_ENTITYFUNC( GrenadeSpitTouch ), |
|
|
|
END_DATADESC() |
|
|
|
CGrenadeSpit::CGrenadeSpit( void ) : m_bPlaySound( true ), m_pHissSound( NULL ) |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CGrenadeSpit::Spawn( void ) |
|
{ |
|
Precache( ); |
|
SetSolid( SOLID_BBOX ); |
|
SetMoveType( MOVETYPE_FLYGRAVITY ); |
|
SetSolidFlags( FSOLID_NOT_STANDABLE ); |
|
|
|
SetModel( "models/spitball_large.mdl" ); |
|
UTIL_SetSize( this, vec3_origin, vec3_origin ); |
|
|
|
SetUse( &CBaseGrenade::DetonateUse ); |
|
SetTouch( &CGrenadeSpit::GrenadeSpitTouch ); |
|
SetNextThink( gpGlobals->curtime + 0.1f ); |
|
|
|
m_flDamage = sk_antlion_worker_spit_grenade_dmg.GetFloat(); |
|
m_DmgRadius = sk_antlion_worker_spit_grenade_radius.GetFloat(); |
|
m_takedamage = DAMAGE_NO; |
|
m_iHealth = 1; |
|
|
|
SetGravity( UTIL_ScaleForGravity( SPIT_GRAVITY ) ); |
|
SetFriction( 0.8f ); |
|
|
|
SetCollisionGroup( HL2COLLISION_GROUP_SPIT ); |
|
|
|
AddEFlags( EFL_FORCE_CHECK_TRANSMIT ); |
|
|
|
// We're self-illuminating, so we don't take or give shadows |
|
AddEffects( EF_NOSHADOW|EF_NORECEIVESHADOW ); |
|
|
|
// Create the dust effect in place |
|
m_hSpitEffect = (CParticleSystem *) CreateEntityByName( "info_particle_system" ); |
|
if ( m_hSpitEffect != NULL ) |
|
{ |
|
// Setup our basic parameters |
|
m_hSpitEffect->KeyValue( "start_active", "1" ); |
|
m_hSpitEffect->KeyValue( "effect_name", "antlion_spit_trail" ); |
|
m_hSpitEffect->SetParent( this ); |
|
m_hSpitEffect->SetLocalOrigin( vec3_origin ); |
|
DispatchSpawn( m_hSpitEffect ); |
|
if ( gpGlobals->curtime > 0.5f ) |
|
m_hSpitEffect->Activate(); |
|
} |
|
} |
|
|
|
|
|
void CGrenadeSpit::SetSpitSize( int nSize ) |
|
{ |
|
switch (nSize) |
|
{ |
|
case SPIT_LARGE: |
|
{ |
|
m_bPlaySound = true; |
|
SetModel( "models/spitball_large.mdl" ); |
|
break; |
|
} |
|
case SPIT_MEDIUM: |
|
{ |
|
m_bPlaySound = true; |
|
m_flDamage *= 0.5f; |
|
SetModel( "models/spitball_medium.mdl" ); |
|
break; |
|
} |
|
case SPIT_SMALL: |
|
{ |
|
m_bPlaySound = false; |
|
m_flDamage *= 0.25f; |
|
SetModel( "models/spitball_small.mdl" ); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
void CGrenadeSpit::Event_Killed( const CTakeDamageInfo &info ) |
|
{ |
|
Detonate( ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Handle spitting |
|
//----------------------------------------------------------------------------- |
|
void CGrenadeSpit::GrenadeSpitTouch( CBaseEntity *pOther ) |
|
{ |
|
if ( pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS | FSOLID_TRIGGER) ) |
|
{ |
|
// Some NPCs are triggers that can take damage (like antlion grubs). We should hit them. |
|
if ( ( pOther->m_takedamage == DAMAGE_NO ) || ( pOther->m_takedamage == DAMAGE_EVENTS_ONLY ) ) |
|
return; |
|
} |
|
|
|
// Don't hit other spit |
|
if ( pOther->GetCollisionGroup() == HL2COLLISION_GROUP_SPIT ) |
|
return; |
|
|
|
// We want to collide with water |
|
const trace_t *pTrace = &CBaseEntity::GetTouchTrace(); |
|
|
|
// copy out some important things about this trace, because the first TakeDamage |
|
// call below may cause another trace that overwrites the one global pTrace points |
|
// at. |
|
bool bHitWater = ( ( pTrace->contents & CONTENTS_WATER ) != 0 ); |
|
CBaseEntity *const pTraceEnt = pTrace->m_pEnt; |
|
const Vector tracePlaneNormal = pTrace->plane.normal; |
|
|
|
if ( bHitWater ) |
|
{ |
|
// Splash! |
|
CEffectData data; |
|
data.m_fFlags = 0; |
|
data.m_vOrigin = pTrace->endpos; |
|
data.m_vNormal = Vector( 0, 0, 1 ); |
|
data.m_flScale = 8.0f; |
|
|
|
DispatchEffect( "watersplash", data ); |
|
} |
|
else |
|
{ |
|
// Make a splat decal |
|
trace_t *pNewTrace = const_cast<trace_t*>( pTrace ); |
|
UTIL_DecalTrace( pNewTrace, "BeerSplash" ); |
|
} |
|
|
|
// Part normal damage, part poison damage |
|
float poisonratio = sk_antlion_worker_spit_grenade_poison_ratio.GetFloat(); |
|
|
|
// Take direct damage if hit |
|
// NOTE: assume that pTrace is invalidated from this line forward! |
|
if ( pTraceEnt ) |
|
{ |
|
pTraceEnt->TakeDamage( CTakeDamageInfo( this, GetThrower(), m_flDamage * (1.0f-poisonratio), DMG_ACID ) ); |
|
pTraceEnt->TakeDamage( CTakeDamageInfo( this, GetThrower(), m_flDamage * poisonratio, DMG_POISON ) ); |
|
} |
|
|
|
CSoundEnt::InsertSound( SOUND_DANGER, GetAbsOrigin(), m_DmgRadius * 2.0f, 0.5f, GetThrower() ); |
|
|
|
QAngle vecAngles; |
|
VectorAngles( tracePlaneNormal, vecAngles ); |
|
|
|
if ( pOther->IsPlayer() || bHitWater ) |
|
{ |
|
// Do a lighter-weight effect if we just hit a player |
|
DispatchParticleEffect( "antlion_spit_player", GetAbsOrigin(), vecAngles ); |
|
} |
|
else |
|
{ |
|
DispatchParticleEffect( "antlion_spit", GetAbsOrigin(), vecAngles ); |
|
} |
|
|
|
Detonate(); |
|
} |
|
|
|
void CGrenadeSpit::Detonate(void) |
|
{ |
|
m_takedamage = DAMAGE_NO; |
|
|
|
EmitSound( "GrenadeSpit.Hit" ); |
|
|
|
// Stop our hissing sound |
|
if ( m_pHissSound != NULL ) |
|
{ |
|
CSoundEnvelopeController::GetController().SoundDestroy( m_pHissSound ); |
|
m_pHissSound = NULL; |
|
} |
|
|
|
if ( m_hSpitEffect ) |
|
{ |
|
UTIL_Remove( m_hSpitEffect ); |
|
} |
|
|
|
UTIL_Remove( this ); |
|
} |
|
|
|
void CGrenadeSpit::InitHissSound( void ) |
|
{ |
|
if ( m_bPlaySound == false ) |
|
return; |
|
|
|
CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController(); |
|
if ( m_pHissSound == NULL ) |
|
{ |
|
CPASAttenuationFilter filter( this ); |
|
m_pHissSound = controller.SoundCreate( filter, entindex(), "NPC_Antlion.PoisonBall" ); |
|
controller.Play( m_pHissSound, 1.0f, 100 ); |
|
} |
|
} |
|
|
|
void CGrenadeSpit::Think( void ) |
|
{ |
|
InitHissSound(); |
|
if ( m_pHissSound == NULL ) |
|
return; |
|
|
|
// Add a doppler effect to the balls as they travel |
|
CBaseEntity *pPlayer = AI_GetSinglePlayer(); |
|
if ( pPlayer != NULL ) |
|
{ |
|
Vector dir; |
|
VectorSubtract( pPlayer->GetAbsOrigin(), GetAbsOrigin(), dir ); |
|
VectorNormalize(dir); |
|
|
|
float velReceiver = DotProduct( pPlayer->GetAbsVelocity(), dir ); |
|
float velTransmitter = -DotProduct( GetAbsVelocity(), dir ); |
|
|
|
// speed of sound == 13049in/s |
|
int iPitch = 100 * ((1 - velReceiver / 13049) / (1 + velTransmitter / 13049)); |
|
|
|
// clamp pitch shifts |
|
if ( iPitch > 250 ) |
|
{ |
|
iPitch = 250; |
|
} |
|
if ( iPitch < 50 ) |
|
{ |
|
iPitch = 50; |
|
} |
|
|
|
// Set the pitch we've calculated |
|
CSoundEnvelopeController::GetController().SoundChangePitch( m_pHissSound, iPitch, 0.1f ); |
|
} |
|
|
|
// Set us up to think again shortly |
|
SetNextThink( gpGlobals->curtime + 0.05f ); |
|
} |
|
|
|
void CGrenadeSpit::Precache( void ) |
|
{ |
|
// m_nSquidSpitSprite = PrecacheModel("sprites/greenglow1.vmt");// client side spittle. |
|
|
|
PrecacheModel( "models/spitball_large.mdl" ); |
|
PrecacheModel("models/spitball_medium.mdl"); |
|
PrecacheModel("models/spitball_small.mdl"); |
|
|
|
PrecacheScriptSound( "GrenadeSpit.Hit" ); |
|
|
|
PrecacheParticleSystem( "antlion_spit_player" ); |
|
PrecacheParticleSystem( "antlion_spit" ); |
|
}
|
|
|