Files
source-engine/game/shared/cstrike/weapon_basecsgrenade.cpp
T
2020-04-22 12:56:21 -04:00

439 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "weapon_csbase.h"
#include "gamerules.h"
#include "npcevent.h"
#include "engine/IEngineSound.h"
#include "weapon_basecsgrenade.h"
#include "in_buttons.h"
#include "datacache/imdlcache.h"
#ifdef CLIENT_DLL
#include "c_cs_player.h"
#else
#include "cs_player.h"
#include "items.h"
#include "../../server/cstrike/cs_gamestats.h"
#endif
#define GRENADE_TIMER 1.5f //Seconds
IMPLEMENT_NETWORKCLASS_ALIASED( BaseCSGrenade, DT_BaseCSGrenade )
BEGIN_NETWORK_TABLE(CBaseCSGrenade, DT_BaseCSGrenade)
#ifndef CLIENT_DLL
SendPropBool( SENDINFO(m_bRedraw) ),
SendPropBool( SENDINFO(m_bPinPulled) ),
SendPropFloat( SENDINFO(m_fThrowTime), 0, SPROP_NOSCALE ),
#else
RecvPropBool( RECVINFO(m_bRedraw) ),
RecvPropBool( RECVINFO(m_bPinPulled) ),
RecvPropFloat( RECVINFO(m_fThrowTime) ),
#endif
END_NETWORK_TABLE()
#if defined CLIENT_DLL
BEGIN_PREDICTION_DATA( CBaseCSGrenade )
DEFINE_PRED_FIELD( m_bRedraw, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
DEFINE_PRED_FIELD( m_bRedraw, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
END_PREDICTION_DATA()
#endif
LINK_ENTITY_TO_CLASS( weapon_basecsgrenade, CBaseCSGrenade );
#ifndef CLIENT_DLL
ConVar sv_ignoregrenaderadio( "sv_ignoregrenaderadio", "0", 0, "Turn off Fire in the hole messages" );
#endif
CBaseCSGrenade::CBaseCSGrenade()
{
m_bRedraw = false;
m_bPinPulled = false;
m_fThrowTime = 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseCSGrenade::Precache()
{
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CBaseCSGrenade::Deploy()
{
m_bRedraw = false;
m_bPinPulled = false;
m_fThrowTime = 0;
#ifndef CLIENT_DLL
// if we're officially out of grenades, ditch this weapon
CCSPlayer *pPlayer = GetPlayerOwner();
if ( !pPlayer )
return false;
if( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
{
pPlayer->Weapon_Drop( this, NULL, NULL );
UTIL_Remove(this);
return false;
}
#endif
return BaseClass::Deploy();
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBaseCSGrenade::Holster( CBaseCombatWeapon *pSwitchingTo )
{
m_bRedraw = false;
m_bPinPulled = false; // when this is holstered make sure the pin isnt pulled.
m_fThrowTime = 0;
#ifndef CLIENT_DLL
// If they attempt to switch weapons before the throw animation is done,
// allow it, but kill the weapon if we have to.
CCSPlayer *pPlayer = GetPlayerOwner();
if ( !pPlayer )
return false;
if( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
{
CBaseCombatCharacter *pOwner = (CBaseCombatCharacter *)pPlayer;
pOwner->Weapon_Drop( this );
UTIL_Remove(this);
}
#endif
return BaseClass::Holster( pSwitchingTo );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseCSGrenade::PrimaryAttack()
{
if ( m_bRedraw || m_bPinPulled || m_fThrowTime > 0.0f )
return;
CCSPlayer *pPlayer = GetPlayerOwner();
if ( !pPlayer || pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
return;
// The pull pin animation has to finish, then we wait until they aren't holding the primary
// attack button, then throw the grenade.
SendWeaponAnim( ACT_VM_PULLPIN );
m_bPinPulled = true;
// Don't let weapon idle interfere in the middle of a throw!
MDLCACHE_CRITICAL_SECTION();
SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseCSGrenade::SecondaryAttack()
{
if ( m_bRedraw )
return;
CCSPlayer *pPlayer = GetPlayerOwner();
if ( pPlayer == NULL )
return;
//See if we're ducking
if ( pPlayer->GetFlags() & FL_DUCKING )
{
//Send the weapon animation
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
}
else
{
//Send the weapon animation
SendWeaponAnim( ACT_VM_HAULBACK );
}
// Don't let weapon idle interfere in the middle of a throw!
SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CBaseCSGrenade::Reload()
{
if ( ( m_bRedraw ) && ( m_flNextPrimaryAttack <= gpGlobals->curtime ) && ( m_flNextSecondaryAttack <= gpGlobals->curtime ) )
{
//Redraw the weapon
SendWeaponAnim( ACT_VM_DRAW );
//Update our times
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
//Mark this as done
// m_bRedraw = false;
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseCSGrenade::ItemPostFrame()
{
CCSPlayer *pPlayer = GetPlayerOwner();
if ( !pPlayer )
return;
CBaseViewModel *vm = pPlayer->GetViewModel( m_nViewModelIndex );
if ( !vm )
return;
// If they let go of the fire button, they want to throw the grenade.
if ( m_bPinPulled && !(pPlayer->m_nButtons & IN_ATTACK) )
{
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_THROW_GRENADE );
StartGrenadeThrow();
MDLCACHE_CRITICAL_SECTION();
m_bPinPulled = false;
SendWeaponAnim( ACT_VM_THROW );
SetWeaponIdleTime( gpGlobals->curtime + SequenceDuration() );
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration(); // we're still throwing, so reset our next primary attack
#ifndef CLIENT_DLL
IGameEvent * event = gameeventmanager->CreateEvent( "weapon_fire" );
if( event )
{
const char *weaponName = STRING( m_iClassname );
if ( strncmp( weaponName, "weapon_", 7 ) == 0 )
{
weaponName += 7;
}
event->SetInt( "userid", pPlayer->GetUserID() );
event->SetString( "weapon", weaponName );
gameeventmanager->FireEvent( event );
}
#endif
}
else if ((m_fThrowTime > 0) && (m_fThrowTime < gpGlobals->curtime))
{
// only decrement our ammo when we actually create the projectile
DecrementAmmo( pPlayer );
ThrowGrenade();
}
else if( m_bRedraw )
{
// Has the throw animation finished playing
if( m_flTimeWeaponIdle < gpGlobals->curtime )
{
#ifdef GAME_DLL
// if we're officially out of grenades, ditch this weapon
if( pPlayer->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
{
pPlayer->Weapon_Drop( this, NULL, NULL );
UTIL_Remove(this);
}
else
{
pPlayer->SwitchToNextBestWeapon( this );
}
#endif
return; //don't animate this grenade any more!
}
}
else if( !m_bRedraw )
{
BaseClass::ItemPostFrame();
}
}
#ifdef CLIENT_DLL
void CBaseCSGrenade::DecrementAmmo( CBaseCombatCharacter *pOwner )
{
}
void CBaseCSGrenade::DropGrenade()
{
m_bRedraw = true;
m_fThrowTime = 0.0f;
}
void CBaseCSGrenade::ThrowGrenade()
{
m_bRedraw = true;
m_fThrowTime = 0.0f;
}
void CBaseCSGrenade::StartGrenadeThrow()
{
m_fThrowTime = gpGlobals->curtime + 0.1f;
}
#else
BEGIN_DATADESC( CBaseCSGrenade )
DEFINE_FIELD( m_bRedraw, FIELD_BOOLEAN ),
END_DATADESC()
int CBaseCSGrenade::CapabilitiesGet()
{
return bits_CAP_WEAPON_RANGE_ATTACK1;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : *pOwner -
//-----------------------------------------------------------------------------
void CBaseCSGrenade::DecrementAmmo( CBaseCombatCharacter *pOwner )
{
pOwner->RemoveAmmo( 1, m_iPrimaryAmmoType );
}
void CBaseCSGrenade::StartGrenadeThrow()
{
m_fThrowTime = gpGlobals->curtime + 0.1f;
}
void CBaseCSGrenade::ThrowGrenade()
{
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( !pPlayer )
{
Assert( false );
return;
}
QAngle angThrow = pPlayer->LocalEyeAngles();
Vector vForward, vRight, vUp;
if ( angThrow.x < 0 )
{
angThrow.x += 360; // make sure we have a positive angle from LocalEyeAngles()
}
if ( angThrow.x < 90 )
angThrow.x = -10 + angThrow.x * ((90 + 10) / 90.0);
else
{
angThrow.x = 360.0f - angThrow.x;
angThrow.x = -10 + angThrow.x * -((90 - 10) / 90.0);
}
float flVel = (90 - angThrow.x) * 6;
if (flVel > 750)
flVel = 750;
AngleVectors( angThrow, &vForward, &vRight, &vUp );
Vector vecSrc = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset();
// We want to throw the grenade from 16 units out. But that can cause problems if we're facing
// a thin wall. Do a hull trace to be safe.
trace_t trace;
Vector mins( -2, -2, -2 );
Vector maxs( 2, 2, 2 );
UTIL_TraceHull( vecSrc, vecSrc + vForward * 16, mins, maxs, MASK_SOLID, pPlayer, COLLISION_GROUP_NONE, &trace );
vecSrc = trace.endpos;
Vector vecThrow = vForward * flVel + pPlayer->GetAbsVelocity();
EmitGrenade( vecSrc, vec3_angle, vecThrow, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer );
m_bRedraw = true;
m_fThrowTime = 0.0f;
CCSPlayer *pCSPlayer = ToCSPlayer( pPlayer );
if( pCSPlayer )
{
if ( !sv_ignoregrenaderadio.GetBool() )
{
pCSPlayer->Radio( "Radio.FireInTheHole", "#Cstrike_TitlesTXT_Fire_in_the_hole" );
}
CCS_GameStats.IncrementStat(pCSPlayer, CSSTAT_GRENADES_THROWN, 1);
}
}
void CBaseCSGrenade::DropGrenade()
{
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( !pPlayer )
{
Assert( false );
return;
}
Vector vForward;
pPlayer->EyeVectors( &vForward );
Vector vecSrc = pPlayer->GetAbsOrigin() + pPlayer->GetViewOffset() + vForward * 16;
Vector vecVel = pPlayer->GetAbsVelocity();
EmitGrenade( vecSrc, vec3_angle, vecVel, AngularImpulse(600,random->RandomInt(-1200,1200),0), pPlayer );
CCSPlayer *pCSPlayer = ToCSPlayer( pPlayer );
if( pCSPlayer )
{
CCS_GameStats.IncrementStat(pCSPlayer, CSSTAT_GRENADES_THROWN, 1);
}
m_bRedraw = true;
m_fThrowTime = 0.0f;
}
void CBaseCSGrenade::EmitGrenade( Vector vecSrc, QAngle vecAngles, Vector vecVel, AngularImpulse angImpulse, CBasePlayer *pPlayer )
{
Assert( 0 && "CBaseCSGrenade::EmitGrenade should not be called. Make sure to implement this in your subclass!\n" );
}
bool CBaseCSGrenade::AllowsAutoSwitchFrom( void ) const
{
return !m_bPinPulled;
}
#endif