Team Fortress 2 Source Code as on 22/4/2020
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.
 
 
 
 
 
 

619 lines
15 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
//
//=============================================================================
#include "cbase.h"
#include "tf_weapon_flaregun.h"
#include "tf_fx_shared.h"
#include "in_buttons.h"
// Client specific.
#ifdef CLIENT_DLL
#include "c_tf_player.h"
#include "soundenvelope.h"
// Server specific.
#else
#include "tf_gamestats.h"
#include "tf_player.h"
#endif
//=============================================================================
//
// Weapon Flare Gun tables.
//
IMPLEMENT_NETWORKCLASS_ALIASED( TFFlareGun, DT_WeaponFlareGun )
BEGIN_NETWORK_TABLE( CTFFlareGun, DT_WeaponFlareGun )
#ifdef CLIENT_DLL
RecvPropFloat( RECVINFO( m_flChargeBeginTime ) ),
#else
SendPropFloat( SENDINFO( m_flChargeBeginTime ) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CTFFlareGun )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( tf_weapon_flaregun, CTFFlareGun );
PRECACHE_WEAPON_REGISTER( tf_weapon_flaregun );
// Server specific.
#ifndef CLIENT_DLL
BEGIN_DATADESC( CTFFlareGun )
END_DATADESC()
#endif
//============================
IMPLEMENT_NETWORKCLASS_ALIASED( TFFlareGun_Revenge, DT_WeaponFlareGun_Revenge )
BEGIN_NETWORK_TABLE( CTFFlareGun_Revenge, DT_WeaponFlareGun_Revenge )
#ifdef CLIENT_DLL
RecvPropFloat( RECVINFO( m_fLastExtinguishTime ) ),
#else
SendPropFloat( SENDINFO( m_fLastExtinguishTime ) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CTFFlareGun_Revenge )
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( tf_weapon_flaregun_revenge, CTFFlareGun_Revenge );
PRECACHE_WEAPON_REGISTER( tf_weapon_flaregun_revenge );
//=============================================================================
//
// Weapon Flare Gun functions.
//
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTFFlareGun::CTFFlareGun()
{
m_bEffectsThinking = false;
m_flLastDenySoundTime = 0.0f;
#ifdef CLIENT_DLL
m_bReadyToFire = false;
#endif
StopCharge();
}
CTFFlareGun::~CTFFlareGun()
{
DestroySounds();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFFlareGun::Precache()
{
BaseClass::Precache();
PrecacheParticleSystem( "stickybombtrail_blue" );
PrecacheParticleSystem( "stickybombtrail_red" );
PrecacheParticleSystem( "critical_grenade_blue" );
PrecacheParticleSystem( "critical_grenade_red" );
}
void CTFFlareGun::DestroySounds( void )
{
StopCharge();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFFlareGun::PrimaryAttack( void )
{
// Get the player owning the weapon.
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() );
if ( !pOwner )
return;
if ( m_flChargeBeginTime > 0.0f )
return;
// Don't attack if we're underwater
if ( pOwner->GetWaterLevel() != WL_Eyes )
{
BaseClass::PrimaryAttack();
}
else
{
if ( gpGlobals->curtime > m_flLastDenySoundTime )
{
WeaponSound( SPECIAL2 );
m_flLastDenySoundTime = gpGlobals->curtime + 1.0f;
}
}
#ifdef CLIENT_DLL
m_bReadyToFire = false;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Detonate flare
//-----------------------------------------------------------------------------
void CTFFlareGun::SecondaryAttack( void )
{
if ( GetFlareGunType() != FLAREGUN_DETONATE )
return;
if ( !CanAttack() )
return;
CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
if ( !pPlayer )
return;
#ifdef GAME_DLL
if ( m_iFlareCount )
{
int iCount = m_Flares.Count();
for ( int i = 0; i < iCount; i++ )
{
CTFProjectile_Flare *pTemp = m_Flares[i];
if ( pTemp )
{
pTemp->Detonate();
}
}
}
#endif // GAME_DLL
}
#ifdef GAME_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFFlareGun::AddFlare( CTFProjectile_Flare *pFlare )
{
FlareHandle hHandle;
hHandle = pFlare;
m_Flares.AddToTail( hHandle );
m_iFlareCount = m_Flares.Count();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFFlareGun::DeathNotice( CBaseEntity *pVictim )
{
Assert( dynamic_cast<CTFProjectile_Flare*>( pVictim ) );
FlareHandle hHandle;
hHandle = (CTFProjectile_Flare*)pVictim;
m_Flares.FindAndRemove( hHandle );
m_iFlareCount = m_Flares.Count();
}
#endif
bool CTFFlareGun::Holster( CBaseCombatWeapon *pSwitchingTo )
{
#ifdef CLIENT_DLL
m_bEffectsThinking = false;
StopCharge();
m_bReadyToFire = false;
#endif
return BaseClass::Holster( pSwitchingTo );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFFlareGun::Deploy( void )
{
#ifdef CLIENT_DLL
m_bEffectsThinking = true;
SetContextThink( &CTFFlareGun::ClientEffectsThink, gpGlobals->curtime + 0.25f, "EFFECTS_THINK" );
m_bReadyToFire = false;
#endif
return BaseClass::Deploy();
}
void CTFFlareGun::WeaponReset( void )
{
BaseClass::WeaponReset();
#if defined( CLIENT_DLL )
StopCharge();
#endif
}
void CTFFlareGun::ItemPostFrame( void )
{
BaseClass::ItemPostFrame();
if ( m_flChargeBeginTime > 0.0f )
{
CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
if ( !pPlayer )
return;
// If we're not holding down the attack button
if ( !(pPlayer->m_nButtons & IN_ATTACK2) )
{
StopCharge();
}
else
{
ChargePostFrame();
}
}
#ifdef CLIENT_DLL
if ( !m_bEffectsThinking )
{
m_bEffectsThinking = true;
SetContextThink( &CTFFlareGun::ClientEffectsThink, gpGlobals->curtime + 0.25f, "EFFECTS_THINK" );
}
#endif
}
#ifdef CLIENT_DLL
void CTFFlareGun::DispatchMuzzleFlash( const char* effectName, C_BaseEntity* pAttachEnt )
{
DispatchParticleEffect( effectName, PATTACH_POINT_FOLLOW, pAttachEnt, "muzzle", GetParticleColor( 1 ), GetParticleColor( 2 ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFFlareGun::ClientEffectsThink( void )
{
CTFPlayer *pPlayer = GetTFPlayerOwner();
if ( !pPlayer )
return;
if ( !pPlayer->IsLocalPlayer() )
return;
if ( !pPlayer->GetViewModel() )
return;
if ( !m_bEffectsThinking )
return;
if ( !GetOwner() || GetOwner()->GetActiveWeapon() != this )
{
m_bEffectsThinking = false;
}
else
{
SetContextThink( &CTFFlareGun::ClientEffectsThink, gpGlobals->curtime + 0.25f, "EFFECTS_THINK" );
}
if ( GetFlareGunType() == FLAREGUN_GRORDBORT && m_flNextPrimaryAttack <= gpGlobals->curtime )
{
ParticleProp()->Init( this );
CNewParticleEffect* pEffect = ParticleProp()->Create( "drg_bison_idle", PATTACH_POINT_FOLLOW, "muzzle" );
if ( pEffect )
{
pEffect->SetControlPoint( CUSTOM_COLOR_CP1, GetParticleColor( 1 ) );
pEffect->SetControlPoint( CUSTOM_COLOR_CP2, GetParticleColor( 2 ) );
}
ParticleProp()->Create( "drg_manmelter_idle", PATTACH_POINT_FOLLOW, "muzzle" );
if ( !m_bReadyToFire )
{
m_bReadyToFire = true;
EmitSound( "Weapon_SniperRailgun.NonScoped" );
}
}
}
void CTFFlareGun::StartChargeEffects()
{
CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
if ( pPlayer )
{
DispatchParticleEffect( GetChargeEffect(), PATTACH_POINT_FOLLOW, GetAppropriateWorldOrViewModel(), "muzzle", GetParticleColor( 1 ), GetParticleColor( 2 ) );
}
}
void CTFFlareGun::StopChargeEffects()
{
CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
if ( pPlayer )
{
GetAppropriateWorldOrViewModel()->ParticleProp()->StopParticlesNamed( GetChargeEffect(), false );
}
}
#endif
void CTFFlareGun::StartCharge( void )
{
StartChargeStartTime();
#ifdef CLIENT_DLL
if ( !m_pChargeLoop )
{
CLocalPlayerFilter filter;
CSoundEnvelopeController &controller = CSoundEnvelopeController::GetController();
m_pChargeLoop = controller.SoundCreate( filter, entindex(), GetShootSound( WPN_DOUBLE ) );
controller.Play( m_pChargeLoop, 1.0, 100 );
}
StartChargeEffects();
#endif
}
void CTFFlareGun::StopCharge( void )
{
m_flChargeBeginTime = 0.0f;
#ifdef CLIENT_DLL
if ( m_pChargeLoop )
{
CSoundEnvelopeController::GetController().SoundDestroy( m_pChargeLoop );
}
m_pChargeLoop = NULL;
StopChargeEffects();
#endif
}
CTFFlareGun_Revenge::CTFFlareGun_Revenge()
{
m_fLastExtinguishTime = 0.0f;
#ifdef CLIENT_DLL
m_nOldRevengeCrits = 0;
#endif
}
void CTFFlareGun_Revenge::Precache()
{
BaseClass::Precache();
PrecacheParticleSystem( "drg_manmelter_vacuum" );
PrecacheParticleSystem( "drg_manmelter_vacuum_flames" );
PrecacheParticleSystem( "drg_manmelter_muzzleflash" );
}
int CTFFlareGun_Revenge::GetCustomDamageType() const
{
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() );
if ( pOwner )
{
int iRevengeCrits = pOwner->m_Shared.GetRevengeCrits();
return iRevengeCrits > 0 ? TF_DMG_CUSTOM_SHOTGUN_REVENGE_CRIT : TF_DMG_CUSTOM_NONE;
}
return TF_DMG_CUSTOM_NONE;
}
bool CTFFlareGun_Revenge::Holster( CBaseCombatWeapon *pSwitchingTo )
{
#ifdef GAME_DLL
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() );
if ( pOwner && pOwner->m_Shared.GetRevengeCrits() )
{
pOwner->m_Shared.RemoveCond( TF_COND_CRITBOOSTED );
}
#endif
StopCharge();
return BaseClass::Holster( pSwitchingTo );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFFlareGun_Revenge::Deploy( void )
{
#ifdef GAME_DLL
CTFPlayer *pOwner = ToTFPlayer( GetOwner() );
if ( pOwner && pOwner->m_Shared.GetRevengeCrits() )
{
pOwner->m_Shared.AddCond( TF_COND_CRITBOOSTED );
}
#endif
StopCharge();
return BaseClass::Deploy();
}
#ifdef GAME_DLL
//-----------------------------------------------------------------------------
// Purpose: Reset revenge crits when the flaregun is changed
//-----------------------------------------------------------------------------
void CTFFlareGun_Revenge::Detach( void )
{
CTFPlayer *pPlayer = GetTFPlayerOwner();
if ( pPlayer )
{
pPlayer->m_Shared.SetRevengeCrits( 0 );
pPlayer->m_Shared.RemoveCond( TF_COND_CRITBOOSTED );
}
BaseClass::Detach();
}
#endif
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CTFFlareGun_Revenge::GetCount( void )
{
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() );
if ( pOwner )
{
return pOwner->m_Shared.GetRevengeCrits();
}
return 0;
}
void CTFFlareGun_Revenge::PrimaryAttack()
{
if ( !CanAttack() )
return;
BaseClass::PrimaryAttack();
// Lower the reveng crit count
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() );
if ( pOwner )
{
int iNewRevengeCrits = MAX( pOwner->m_Shared.GetRevengeCrits() - 1, 0 );
pOwner->m_Shared.SetRevengeCrits( iNewRevengeCrits );
}
}
void CTFFlareGun_Revenge::SecondaryAttack( void )
{
if ( m_flNextSecondaryAttack > gpGlobals->curtime )
{
return;
}
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() );
if ( !pOwner )
return;
if ( GetChargeBeginTime() == 0.0f )
{
StartCharge();
#ifdef GAME_DLL
//SendWeaponAnim( ACT_VM_PULLBACK );
#endif
}
m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f;
}
void CTFFlareGun_Revenge::ChargePostFrame( void )
{
BaseClass::ChargePostFrame();
if ( gpGlobals->curtime > m_fLastExtinguishTime + 0.5f )
{
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() );
if ( pOwner )
{
// Extinguish friends
Vector vecEye = pOwner->EyePosition();
Vector vecForward, vecRight, vecUp;
AngleVectors( pOwner->EyeAngles(), &vecForward, NULL, NULL );
const Vector vHull = Vector( 16.0f, 16.0f, 16.0f );
trace_t tr;
UTIL_TraceHull( vecEye, vecEye + vecForward * 256.0f, -vHull, vHull, MASK_SOLID, pOwner, COLLISION_GROUP_NONE, &tr );
CTFPlayer *pTarget = ToTFPlayer( tr.m_pEnt );
if ( pTarget )
{
#ifdef GAME_DLL
// Get the player that ignited them before we extinguish
CTFPlayer *pBurner = pTarget->m_Shared.GetOriginalBurnAttacker();
#endif
if ( ExtinguishPlayerInternal( pTarget, pOwner ) )
{
m_fLastExtinguishTime = gpGlobals->curtime;
#ifdef GAME_DLL
// Make sure the team isn't burning themselves to earn crits
if ( pBurner && pBurner->GetTeamNumber() != pOwner->GetTeamNumber() )
{
// Grant revenge crits
pOwner->m_Shared.SetRevengeCrits( pOwner->m_Shared.GetRevengeCrits() + 1 );
// Return health to the Pyro.
int iRestoreHealthOnExtinguish = 0;
CALL_ATTRIB_HOOK_INT( iRestoreHealthOnExtinguish, extinguish_restores_health );
if ( iRestoreHealthOnExtinguish > 0 && pOwner->TakeHealth( 20, DMG_GENERIC ) > 0 )
{
IGameEvent *healevent = gameeventmanager->CreateEvent( "player_healonhit" );
if ( healevent )
{
healevent->SetInt( "amount", iRestoreHealthOnExtinguish );
healevent->SetInt( "entindex", pOwner->entindex() );
item_definition_index_t healingItemDef = INVALID_ITEM_DEF_INDEX;
if ( GetAttributeContainer() && GetAttributeContainer()->GetItem() )
{
healingItemDef = GetAttributeContainer()->GetItem()->GetItemDefIndex();
}
healevent->SetInt( "weapon_def_index", healingItemDef );
gameeventmanager->FireEvent( healevent );
}
}
}
#endif
}
}
}
}
}
#ifdef GAME_DLL
extern void ExtinguishPlayer( CEconEntity *pExtinguisher, CTFPlayer *pOwner, CTFPlayer *pTarget, const char *pExtinguisherName );
#endif // GAME_DLL
bool CTFFlareGun_Revenge::ExtinguishPlayerInternal( CTFPlayer *pTarget, CTFPlayer *pOwner )
{
if ( pTarget->GetTeamNumber() == pOwner->GetTeamNumber() )
{
if ( pTarget->m_Shared.InCond( TF_COND_BURNING ) )
{
#ifdef GAME_DLL
ExtinguishPlayer( this, pOwner, pTarget, GetName() );
#endif // GAME_DLL
return true;
}
}
return false;
}
#ifdef CLIENT_DLL
void CTFFlareGun_Revenge::OnDataChanged( DataUpdateType_t type )
{
BaseClass::OnDataChanged( type );
CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() );
if ( pOwner )
{
if ( m_nOldRevengeCrits < pOwner->m_Shared.GetRevengeCrits() )
{
DoAbsorbEffect();
}
m_nOldRevengeCrits = pOwner->m_Shared.GetRevengeCrits();
}
}
void CTFFlareGun_Revenge::DoAbsorbEffect( void )
{
WeaponSound( SPECIAL1 );
CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
if ( pPlayer )
{
DispatchParticleEffect( "drg_manmelter_vacuum_flames", PATTACH_POINT_FOLLOW, GetAppropriateWorldOrViewModel(), "muzzle", GetParticleColor( 1 ), GetParticleColor( 2 ) );
}
}
#endif