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.
377 lines
9.7 KiB
377 lines
9.7 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: TF Base Grenade. |
|
// |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "tf_weaponbase.h" |
|
#include "tf_weaponbase_grenade.h" |
|
#include "tf_gamerules.h" |
|
#include "npcevent.h" |
|
#include "engine/IEngineSound.h" |
|
#include "in_buttons.h" |
|
#include "tf_weaponbase_grenadeproj.h" |
|
#include "eventlist.h" |
|
|
|
// Client specific. |
|
#ifdef CLIENT_DLL |
|
#include "c_tf_player.h" |
|
// Server specific. |
|
#else |
|
#include "tf_player.h" |
|
#include "items.h" |
|
#endif |
|
|
|
#define GRENADE_TIMER 1.5f // seconds |
|
|
|
//============================================================================= |
|
// |
|
// TF Grenade tables. |
|
// |
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( TFWeaponBaseGrenade, DT_TFWeaponBaseGrenade ) |
|
|
|
BEGIN_NETWORK_TABLE( CTFWeaponBaseGrenade, DT_TFWeaponBaseGrenade ) |
|
// Client specific. |
|
#ifdef CLIENT_DLL |
|
RecvPropBool( RECVINFO( m_bPrimed ) ), |
|
RecvPropFloat( RECVINFO( m_flThrowTime ) ), |
|
RecvPropBool( RECVINFO( m_bThrow ) ), |
|
// Server specific. |
|
#else |
|
SendPropBool( SENDINFO( m_bPrimed ) ), |
|
SendPropTime( SENDINFO( m_flThrowTime ) ), |
|
SendPropBool( SENDINFO( m_bThrow ) ), |
|
#endif |
|
END_NETWORK_TABLE() |
|
|
|
BEGIN_PREDICTION_DATA( CTFWeaponBaseGrenade ) |
|
#ifdef CLIENT_DLL |
|
DEFINE_PRED_FIELD( m_bPrimed, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
DEFINE_PRED_FIELD( m_flThrowTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ), |
|
DEFINE_PRED_FIELD( m_bThrow, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
#endif |
|
END_PREDICTION_DATA() |
|
|
|
LINK_ENTITY_TO_CLASS( tf_weaponbase_grenade, CTFWeaponBaseGrenade ); |
|
|
|
//============================================================================= |
|
// |
|
// TF Grenade functions. |
|
// |
|
|
|
CTFWeaponBaseGrenade::CTFWeaponBaseGrenade() |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor. |
|
//----------------------------------------------------------------------------- |
|
void CTFWeaponBaseGrenade::Spawn( void ) |
|
{ |
|
BaseClass::Spawn(); |
|
|
|
SetViewModelIndex( 1 ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFWeaponBaseGrenade::Precache() |
|
{ |
|
BaseClass::Precache(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFWeaponBaseGrenade::IsPrimed( void ) |
|
{ |
|
return m_bPrimed; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFWeaponBaseGrenade::Deploy( void ) |
|
{ |
|
if ( BaseClass::Deploy() ) |
|
{ |
|
Prime(); |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFWeaponBaseGrenade::Prime() |
|
{ |
|
CTFWeaponInfo weaponInfo = GetTFWpnData(); |
|
m_flThrowTime = gpGlobals->curtime + weaponInfo.m_flPrimerTime; |
|
m_bPrimed = true; |
|
|
|
#ifndef CLIENT_DLL |
|
if ( GetWeaponID() != TF_WEAPON_GRENADE_SMOKE_BOMB ) |
|
{ |
|
// Get the player owning the weapon. |
|
CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() ); |
|
if ( !pPlayer ) |
|
return; |
|
|
|
pPlayer->RemoveInvisibility(); |
|
} |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFWeaponBaseGrenade::Throw() |
|
{ |
|
if ( !m_bPrimed ) |
|
return; |
|
|
|
m_bPrimed = false; |
|
m_bThrow = false; |
|
|
|
// Get the owning player. |
|
CTFPlayer *pPlayer = ToTFPlayer( GetOwner() ); |
|
if ( !pPlayer ) |
|
return; |
|
|
|
#ifdef GAME_DLL |
|
// Calculate the time remaining. |
|
float flTime = m_flThrowTime - gpGlobals->curtime; |
|
bool bExplodingInHand = ( flTime <= 0.0f ); |
|
|
|
// Players who are dying may not have their death state set, so check that too |
|
bool bExplodingOnDeath = ( !pPlayer->IsAlive() || pPlayer->StateGet() == TF_STATE_DYING ); |
|
|
|
Vector vecSrc, vecThrow; |
|
vecSrc = pPlayer->Weapon_ShootPosition(); |
|
|
|
if ( bExplodingInHand || bExplodingOnDeath ) |
|
{ |
|
vecThrow = vec3_origin; |
|
} |
|
else |
|
{ |
|
// Determine the throw angle and velocity. |
|
QAngle angThrow = pPlayer->LocalEyeAngles(); |
|
if ( angThrow.x < 90.0f ) |
|
{ |
|
angThrow.x = -10.0f + angThrow.x * ( ( 90.0f + 10.0f ) / 90.0f ); |
|
} |
|
else |
|
{ |
|
angThrow.x = 360.0f - angThrow.x; |
|
angThrow.x = -10.0f + angThrow.x * -( ( 90.0f - 10.0f ) / 90.0f ); |
|
} |
|
|
|
// Adjust for the lowering of the spawn point |
|
angThrow.x -= 10; |
|
|
|
float flVelocity = ( 90.0f - angThrow.x ) * 8.0f; |
|
if ( flVelocity > 950.0f ) |
|
{ |
|
flVelocity = 950.0f; |
|
} |
|
|
|
Vector vForward, vRight, vUp; |
|
AngleVectors( angThrow, &vForward, &vRight, &vUp ); |
|
|
|
// Throw from the player's left hand position. |
|
vecSrc += vForward * 16.0f + vRight * -8.0f + vUp * -20.0f; |
|
|
|
vecThrow = vForward * flVelocity; |
|
} |
|
|
|
#if 0 |
|
// Debug!!! |
|
char str[256]; |
|
Q_snprintf( str, sizeof( str ),"GrenadeTime = %f\n", flTime ); |
|
NDebugOverlay::ScreenText( 0.5f, 0.38f, str, 255, 255, 255, 255, 2.0f ); |
|
#endif |
|
|
|
QAngle vecAngles = RandomAngle( 0, 360 ); |
|
|
|
// Create the projectile and send in the time remaining. |
|
if ( !bExplodingInHand ) |
|
{ |
|
EmitGrenade( vecSrc, vecAngles, vecThrow, AngularImpulse( 600, random->RandomInt( -1200, 1200 ), 0 ), pPlayer, flTime ); |
|
} |
|
else |
|
{ |
|
// We're holding onto an exploding grenade |
|
CTFWeaponBaseGrenadeProj *pGrenade = EmitGrenade( vecSrc, vecAngles, vecThrow, AngularImpulse( 600, random->RandomInt( -1200, 1200 ), 0 ), pPlayer, 0.0 ); |
|
if ( pGrenade ) |
|
{ |
|
pGrenade->Detonate(); |
|
} |
|
} |
|
|
|
// The grenade is about to be destroyed, so it won't be able to holster. |
|
// Handle the viewmodel hiding for it. |
|
if ( bExplodingInHand || bExplodingOnDeath ) |
|
{ |
|
SendWeaponAnim( ACT_VM_IDLE ); |
|
CBaseViewModel *vm = pPlayer->GetViewModel( 1 ); |
|
if ( vm ) |
|
{ |
|
vm->AddEffects( EF_NODRAW ); |
|
} |
|
} |
|
#endif |
|
|
|
// Reset the throw time |
|
m_flThrowTime = 0.0f; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFWeaponBaseGrenade::ShouldDetonate( void ) |
|
{ |
|
return ( m_flThrowTime != 0.0f ) && ( m_flThrowTime < gpGlobals->curtime ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFWeaponBaseGrenade::ItemPostFrame() |
|
{ |
|
CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() ); |
|
if ( !pPlayer ) |
|
return; |
|
|
|
if ( m_bPrimed ) |
|
{ |
|
// Is our timer up? If so, blow up immediately |
|
if ( ShouldDetonate() ) |
|
{ |
|
Throw(); |
|
return; |
|
} |
|
|
|
if ( !m_bThrow && !( pPlayer->m_nButtons & IN_GRENADE1 || pPlayer->m_nButtons & IN_GRENADE2 ) ) |
|
{ |
|
// Start throwing |
|
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_GRENADE ); |
|
m_bThrow = true; |
|
} |
|
} |
|
|
|
if ( m_bThrow ) |
|
{ |
|
if ( GetActivity() != ACT_VM_PRIMARYATTACK ) |
|
{ |
|
// Start the throw animation |
|
if ( !SendWeaponAnim( ACT_VM_PRIMARYATTACK ) ) |
|
{ |
|
Throw(); |
|
} |
|
} |
|
else if ( HasWeaponIdleTimeElapsed() ) |
|
{ |
|
// The Throw call here exists solely to catch the lone case of thirdperson where the |
|
// viewmodel isn't being drawn, and hence the anim event doesn't trigger and force a throw. |
|
// In all other cases, it'll do nothing because the grenade has already been thrown. |
|
Throw(); |
|
} |
|
return; |
|
} |
|
|
|
if ( !m_bPrimed && !m_bThrow ) |
|
{ |
|
// Once we've finished being holstered, we'll be hidden. When that happens, |
|
// tell our player that we're all done with the grenade throw. |
|
if ( IsEffectActive(EF_NODRAW) ) |
|
{ |
|
pPlayer->FinishThrowGrenade(); |
|
return; |
|
} |
|
|
|
// We've been thrown. Go away. |
|
if ( HasWeaponIdleTimeElapsed() ) |
|
{ |
|
Holster(); |
|
} |
|
} |
|
|
|
// Go straight to idle anim when deploy is done |
|
if ( m_flTimeWeaponIdle <= gpGlobals->curtime ) |
|
{ |
|
SendWeaponAnim( ACT_VM_IDLE ); |
|
} |
|
} |
|
|
|
bool CTFWeaponBaseGrenade::ShouldLowerMainWeapon( void ) |
|
{ |
|
return GetTFWpnData().m_bLowerWeapon; |
|
} |
|
|
|
//============================================================================= |
|
// |
|
// Client specific functions. |
|
// |
|
#ifdef CLIENT_DLL |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
bool CTFWeaponBaseGrenade::ShouldDraw( void ) |
|
{ |
|
if ( !BaseClass::ShouldDraw() ) |
|
{ |
|
// Grenades need to be visible whenever they're being primed & thrown |
|
if ( !m_bPrimed ) |
|
return false; |
|
|
|
// Don't draw primed grenades for local player in first person players |
|
if ( !(ToPlayer(GetOwner())->ShouldDrawThisPlayer()) ) |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
//============================================================================= |
|
// |
|
// Server specific functions. |
|
// |
|
#else |
|
|
|
BEGIN_DATADESC( CTFWeaponBaseGrenade ) |
|
END_DATADESC() |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFWeaponBaseGrenade::HandleAnimEvent( animevent_t *pEvent ) |
|
{ |
|
if ( (pEvent->type & AE_TYPE_NEWEVENTSYSTEM) ) |
|
{ |
|
if ( pEvent->event == AE_WPN_PRIMARYATTACK ) |
|
{ |
|
Throw(); |
|
return; |
|
} |
|
} |
|
|
|
BaseClass::HandleAnimEvent( pEvent ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFWeaponBaseGrenadeProj *CTFWeaponBaseGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer, float flTime, int iFlags ) |
|
{ |
|
Assert( 0 && "CBaseCSGrenade::EmitGrenade should not be called. Make sure to implement this in your subclass!\n" ); |
|
return NULL; |
|
} |
|
|
|
#endif |
|
|
|
|