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
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
|