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.
402 lines
12 KiB
402 lines
12 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// TF Energy Ball |
|
// |
|
//============================================================================= |
|
#include "cbase.h" |
|
#include "tf_projectile_energy_ball.h" |
|
#include "soundent.h" |
|
#include "tf_fx.h" |
|
#include "props.h" |
|
#include "baseobject_shared.h" |
|
#include "SpriteTrail.h" |
|
#include "IEffects.h" |
|
#include "te_effect_dispatch.h" |
|
#include "collisionutils.h" |
|
#include "bone_setup.h" |
|
#include "decals.h" |
|
#include "tf_player.h" |
|
#include "te_effect_dispatch.h" |
|
#include "tf_gamerules.h" |
|
#include "tf_weapon_rocketlauncher.h" |
|
|
|
//============================================================================= |
|
// |
|
// TF Energy Ball Projectile functions (Server specific). |
|
// |
|
#define ENERGY_BALL_MODEL "models/weapons/w_models/w_drg_ball.mdl" |
|
#define ARROW_GRAVITY 0.3f |
|
|
|
#define ENERGY_BALL_THINK_CONTEXT "CTFProjectile_EnergyBallThink" |
|
|
|
//----------------------------------------------------------------------------- |
|
LINK_ENTITY_TO_CLASS( tf_projectile_energy_ball, CTFProjectile_EnergyBall ); |
|
PRECACHE_WEAPON_REGISTER( tf_projectile_energy_ball ); |
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( TFProjectile_EnergyBall, DT_TFProjectile_EnergyBall ) |
|
|
|
BEGIN_NETWORK_TABLE( CTFProjectile_EnergyBall, DT_TFProjectile_EnergyBall ) |
|
SendPropBool( SENDINFO( m_bChargedShot ) ), |
|
SendPropVector( SENDINFO( m_vColor1 ), 8, 0, 0, 1 ), |
|
SendPropVector( SENDINFO( m_vColor2 ), 8, 0, 0, 1 ) |
|
END_NETWORK_TABLE() |
|
|
|
BEGIN_DATADESC( CTFProjectile_EnergyBall ) |
|
//DEFINE_THINKFUNC( ImpactThink ), |
|
END_DATADESC() |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFProjectile_EnergyBall::CTFProjectile_EnergyBall() |
|
{ |
|
m_bChargedShot = false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFProjectile_EnergyBall::~CTFProjectile_EnergyBall() |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFProjectile_EnergyBall *CTFProjectile_EnergyBall::Create( const Vector &vecOrigin, const QAngle &vecAngles, const float fSpeed, const float fGravity, CBaseEntity *pOwner, CBaseEntity *pScorer ) |
|
{ |
|
CTFProjectile_EnergyBall *pBall = static_cast<CTFProjectile_EnergyBall*>( CBaseEntity::Create( "tf_projectile_energy_ball", vecOrigin, vecAngles, pOwner ) ); |
|
if ( pBall ) |
|
{ |
|
pBall->InitEnergyBall( vecOrigin, vecAngles, fSpeed, fGravity, pOwner, pScorer ); |
|
} |
|
|
|
return pBall; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFProjectile_EnergyBall::InitEnergyBall( const Vector &vecOrigin, const QAngle &vecAngles, const float fSpeed, const float fGravity, CBaseEntity *pOwner, CBaseEntity *pScorer ) |
|
{ |
|
// Initialize the owner. |
|
SetOwnerEntity( pOwner ); |
|
|
|
// Set team. |
|
ChangeTeam( pOwner->GetTeamNumber() ); |
|
|
|
// Spawn. |
|
Spawn(); |
|
|
|
SetGravity( fGravity ); |
|
|
|
SetCritical( true ); |
|
|
|
// Setup the initial velocity. |
|
Vector vecForward, vecRight, vecUp; |
|
AngleVectors( vecAngles, &vecForward, &vecRight, &vecUp ); |
|
|
|
Vector vecVelocity = vecForward * fSpeed; |
|
|
|
SetAbsVelocity( vecVelocity ); |
|
SetupInitialTransmittedGrenadeVelocity( vecVelocity ); |
|
|
|
// Setup the initial angles. |
|
QAngle angles; |
|
VectorAngles( vecVelocity, angles ); |
|
SetAbsAngles( angles ); |
|
|
|
// Save the scoring player. |
|
SetScorer( pScorer ); |
|
|
|
if ( pScorer ) |
|
{ |
|
SetTruceValidForEnt( pScorer->IsTruceValidForEnt() ); |
|
} |
|
|
|
m_flInitTime = gpGlobals->curtime; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFProjectile_EnergyBall::Spawn() |
|
{ |
|
SetModel( ENERGY_BALL_MODEL ); |
|
BaseClass::Spawn(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFProjectile_EnergyBall::Precache() |
|
{ |
|
PrecacheParticleSystem( "drg_cow_rockettrail_charged" ); |
|
PrecacheParticleSystem( "drg_cow_rockettrail_charged_blue" ); |
|
PrecacheParticleSystem( "drg_cow_rockettrail_normal" ); |
|
PrecacheParticleSystem( "drg_cow_rockettrail_normal_blue" ); |
|
|
|
PrecacheModel( ENERGY_BALL_MODEL ); |
|
|
|
PrecacheScriptSound( "Weapon_CowMangler.Explode" ); |
|
|
|
BaseClass::Precache(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFProjectile_EnergyBall::SetScorer( CBaseEntity *pScorer ) |
|
{ |
|
m_Scorer = pScorer; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CBasePlayer *CTFProjectile_EnergyBall::GetScorer( void ) |
|
{ |
|
return dynamic_cast<CBasePlayer *>( m_Scorer.Get() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Plays an impact sound. Louder for the attacker. |
|
//----------------------------------------------------------------------------- |
|
void CTFProjectile_EnergyBall::ImpactSound( const char *pszSoundName, bool bLoudForAttacker ) |
|
{ |
|
CTFPlayer *pAttacker = ToTFPlayer( GetScorer() ); |
|
if ( !pAttacker ) |
|
return; |
|
|
|
if ( bLoudForAttacker ) |
|
{ |
|
float soundlen = 0; |
|
EmitSound_t params; |
|
params.m_flSoundTime = 0; |
|
params.m_pSoundName = pszSoundName; |
|
params.m_pflSoundDuration = &soundlen; |
|
CPASFilter filter( GetAbsOrigin() ); |
|
filter.RemoveRecipient( ToTFPlayer(pAttacker) ); |
|
EmitSound( filter, entindex(), params ); |
|
|
|
CSingleUserRecipientFilter attackerFilter( ToTFPlayer(pAttacker) ); |
|
EmitSound( attackerFilter, pAttacker->entindex(), params ); |
|
} |
|
else |
|
{ |
|
EmitSound( pszSoundName ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFProjectile_EnergyBall::FadeOut( int iTime ) |
|
{ |
|
SetMoveType( MOVETYPE_NONE ); |
|
SetAbsVelocity( vec3_origin ); |
|
AddSolidFlags( FSOLID_NOT_SOLID ); |
|
AddEffects( EF_NODRAW ); |
|
|
|
// Start remove timer. |
|
SetContextThink( &CTFProjectile_EnergyBall::RemoveThink, gpGlobals->curtime + iTime, "ENERGY_BALL_REMOVE_THINK" ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFProjectile_EnergyBall::RemoveThink( void ) |
|
{ |
|
UTIL_Remove( this ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Arrow was deflected. |
|
//----------------------------------------------------------------------------- |
|
void CTFProjectile_EnergyBall::Deflected( CBaseEntity *pDeflectedBy, Vector &vecDir ) |
|
{ |
|
CTFPlayer *pTFDeflector = ToTFPlayer( pDeflectedBy ); |
|
if ( !pTFDeflector ) |
|
return; |
|
|
|
ChangeTeam( pTFDeflector->GetTeamNumber() ); |
|
SetLauncher( pTFDeflector->GetActiveWeapon() ); |
|
|
|
CTFPlayer* pOldOwner = ToTFPlayer( GetOwnerEntity() ); |
|
SetOwnerEntity( pTFDeflector ); |
|
|
|
if ( pOldOwner ) |
|
{ |
|
pOldOwner->SpeakConceptIfAllowed( MP_CONCEPT_DEFLECTED, "projectile:1,victim:1" ); |
|
} |
|
|
|
if ( pTFDeflector->m_Shared.IsCritBoosted() ) |
|
{ |
|
SetCritical( true ); |
|
} |
|
|
|
CTFWeaponBase::SendObjectDeflectedEvent( pTFDeflector, pOldOwner, GetWeaponID(), this ); |
|
|
|
IncrementDeflected(); |
|
SetScorer( pTFDeflector ); |
|
|
|
// Change particle color data. |
|
if ( GetTeamNumber() == TF_TEAM_BLUE ) |
|
{ |
|
m_vColor1 = TF_PARTICLE_WEAPON_BLUE_1; |
|
m_vColor2 = TF_PARTICLE_WEAPON_BLUE_2; |
|
} |
|
else |
|
{ |
|
m_vColor1 = TF_PARTICLE_WEAPON_RED_1; |
|
m_vColor2 = TF_PARTICLE_WEAPON_RED_2; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFProjectile_EnergyBall::Explode( trace_t *pTrace, CBaseEntity *pOther ) |
|
{ |
|
if ( ShouldNotDetonate() ) |
|
{ |
|
Destroy( true ); |
|
return; |
|
} |
|
|
|
// Save this entity as enemy, they will take 100% damage. |
|
m_hEnemy = pOther; |
|
|
|
// Invisible. |
|
SetModelName( NULL_STRING ); |
|
AddSolidFlags( FSOLID_NOT_SOLID ); |
|
m_takedamage = DAMAGE_NO; |
|
|
|
// Pull out a bit. |
|
if ( pTrace->fraction != 1.0 ) |
|
{ |
|
SetAbsOrigin( pTrace->endpos + ( pTrace->plane.normal * 1.0f ) ); |
|
} |
|
|
|
// Particle (oriented) |
|
Vector vecOrigin = GetAbsOrigin(); |
|
CPVSFilter filter( vecOrigin ); |
|
QAngle angExplosion( 0.f, 0.f, 0.f ); |
|
VectorAngles( pTrace->plane.normal, angExplosion ); |
|
TE_TFParticleEffect( filter, 0.f, GetExplosionParticleName(), vecOrigin, pTrace->plane.normal, angExplosion, NULL ); |
|
|
|
// Screenshake |
|
if ( m_bChargedShot ) |
|
{ |
|
UTIL_ScreenShake( WorldSpaceCenter(), 25.0, 150.0, 1.0, 750, SHAKE_START ); |
|
} |
|
|
|
// Sound |
|
ImpactSound( "Weapon_CowMangler.Explode" ); |
|
CSoundEnt::InsertSound ( SOUND_COMBAT, vecOrigin, 1024, 3.0 ); |
|
|
|
// Damage. |
|
CBaseEntity *pAttacker = GetOwnerEntity(); |
|
IScorer *pScorerInterface = dynamic_cast<IScorer*>( pAttacker ); |
|
if ( pScorerInterface ) |
|
{ |
|
pAttacker = pScorerInterface->GetScorer(); |
|
} |
|
|
|
float flRadius = GetRadius(); |
|
|
|
if ( pAttacker ) // No attacker, deal no damage. Otherwise we could potentially kill teammates. |
|
{ |
|
CTFPlayer *pTarget = ToTFPlayer( GetEnemy() ); |
|
if ( pTarget ) |
|
{ |
|
// Rocket Specialist |
|
CheckForStunOnImpact( pTarget ); |
|
|
|
if ( pTarget->GetTeamNumber() != pAttacker->GetTeamNumber() ) |
|
{ |
|
IGameEvent *event = gameeventmanager->CreateEvent( "projectile_direct_hit" ); |
|
if ( event ) |
|
{ |
|
event->SetInt( "attacker", pAttacker->entindex() ); |
|
event->SetInt( "victim", pTarget->entindex() ); |
|
|
|
item_definition_index_t ownerWeaponDefIndex = INVALID_ITEM_DEF_INDEX; |
|
CTFWeaponBase *pWeapon = dynamic_cast< CTFWeaponBase * >( GetOriginalLauncher() ); |
|
if ( pWeapon ) |
|
{ |
|
ownerWeaponDefIndex = pWeapon->GetAttributeContainer()->GetItem()->GetItemDefIndex(); |
|
} |
|
event->SetInt( "weapon_def_index", ownerWeaponDefIndex ); |
|
|
|
gameeventmanager->FireEvent( event, true ); |
|
} |
|
} |
|
} |
|
|
|
CTakeDamageInfo info( this, pAttacker, m_hLauncher, vec3_origin, vecOrigin, GetDamage(), GetDamageType(), GetDamageCustom() ); |
|
CTFRadiusDamageInfo radiusinfo( &info, vecOrigin, flRadius, NULL, m_bChargedShot ? TF_ROCKET_RADIUS_FOR_RJS*1.33 : TF_ROCKET_RADIUS_FOR_RJS ); |
|
TFGameRules()->RadiusDamage( radiusinfo ); |
|
} |
|
|
|
// Don't decal players with scorch. |
|
if ( !pOther->IsPlayer() ) |
|
{ |
|
UTIL_DecalTrace( pTrace, "Scorch" ); |
|
} |
|
|
|
// Remove the rocket. |
|
UTIL_Remove( this ); |
|
|
|
return; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
const char *CTFProjectile_EnergyBall::GetExplosionParticleName( void ) |
|
{ |
|
if ( m_bChargedShot ) |
|
{ |
|
return ( GetTeamNumber() == TF_TEAM_RED ) ? "drg_cow_explosioncore_charged" : "drg_cow_explosioncore_charged_blue"; |
|
} |
|
else |
|
{ |
|
return ( GetTeamNumber() == TF_TEAM_RED ) ? "drg_cow_explosioncore_normal" : "drg_cow_explosioncore_normal_blue"; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
float CTFProjectile_EnergyBall::GetDamage() |
|
{ |
|
return m_flDamage; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTFProjectile_EnergyBall::GetDamageType() |
|
{ |
|
int iDamageType; |
|
if ( m_bChargedShot ) |
|
{ |
|
iDamageType = DMG_BLAST | DMG_HALF_FALLOFF | DMG_USEDISTANCEMOD | DMG_IGNITE; |
|
} |
|
else |
|
{ |
|
iDamageType = DMG_BLAST | DMG_HALF_FALLOFF | DMG_USEDISTANCEMOD; |
|
} |
|
|
|
return iDamageType; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTFProjectile_EnergyBall::GetDamageCustom() |
|
{ |
|
return m_bChargedShot ? TF_DMG_CUSTOM_PLASMA_CHARGED : TF_DMG_CUSTOM_PLASMA; |
|
} |
|
|
|
|