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.
498 lines
14 KiB
498 lines
14 KiB
![]()
4 years ago
|
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||
|
//
|
||
|
// Purpose:
|
||
|
//
|
||
|
// $NoKeywords: $
|
||
|
//=============================================================================//
|
||
|
#include "cbase.h"
|
||
|
#include "basetfplayer_shared.h"
|
||
|
#include "basetfcombatweapon_shared.h"
|
||
|
#include "weapon_twohandedcontainer.h"
|
||
|
|
||
|
#if !defined( CLIENT_DLL )
|
||
|
#include "soundent.h"
|
||
|
#else
|
||
|
#include "functionproxy.h"
|
||
|
#include "ivrenderview.h"
|
||
|
#include "cl_animevent.h"
|
||
|
#include "fx.h"
|
||
|
#endif
|
||
|
|
||
|
CBaseTFCombatWeapon::CBaseTFCombatWeapon ( void )
|
||
|
{
|
||
|
m_bReflectViewModelAnimations = false;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CBaseTFCombatWeapon::Precache( void )
|
||
|
{
|
||
|
BaseClass::Precache();
|
||
|
|
||
|
#if !defined( CLIENT_DLL )
|
||
|
// Connect to my CVars
|
||
|
m_pDamageCVar = cvar->FindVar( UTIL_VarArgs( "%s_damage", GetClassname() ) );
|
||
|
m_pRangeCVar = cvar->FindVar( UTIL_VarArgs( "%s_range", GetClassname() ) );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
int CBaseTFCombatWeapon::GetPrimaryAmmo( void )
|
||
|
{
|
||
|
// Get the local player
|
||
|
CBasePlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
|
||
|
if ( pPlayer == NULL )
|
||
|
return 0;
|
||
|
|
||
|
return pPlayer->GetAmmoCount( m_iPrimaryAmmoType );
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Checks if the owner is EMPed
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CBaseTFCombatWeapon::IsOwnerEMPed()
|
||
|
{
|
||
|
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
|
||
|
if ((!pPlayer) || (!pPlayer->GetPlayerClass()))
|
||
|
return false;
|
||
|
|
||
|
return ( pPlayer->HasPowerup(POWERUP_EMP) );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Temporarily remove disguise
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CBaseTFCombatWeapon::CheckRemoveDisguise( void )
|
||
|
{
|
||
|
#if !defined( CLIENT_DLL )
|
||
|
CBaseTFPlayer *player = static_cast< CBaseTFPlayer * >( GetOwner());
|
||
|
if ( player )
|
||
|
{
|
||
|
// Always remove camo
|
||
|
player->ClearCamouflage();
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Factor in the player's anim speed to the sequence duration for weapons
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float CBaseTFCombatWeapon::SequenceDuration( int iSequence )
|
||
|
{
|
||
|
float flDuration = BaseClass::SequenceDuration( iSequence );
|
||
|
CBaseTFPlayer *pOwner = (CBaseTFPlayer *)GetOwner();
|
||
|
if ( pOwner )
|
||
|
{
|
||
|
flDuration /= pOwner->GetDefaultAnimSpeed();
|
||
|
}
|
||
|
|
||
|
return flDuration;
|
||
|
}
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Override weapon sound. TF doesn't use ATTN_GUNFIRE for it's weapon attenuations.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CBaseTFCombatWeapon::WeaponSound( WeaponSound_t shoot_type, float soundtime /*= 0.0f*/ )
|
||
|
{
|
||
|
#if !defined( CLIENT_DLL )
|
||
|
// HACKHACK: Force a combat sound to alert NPCs, for antlion prototype
|
||
|
CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 600, 0.1 );
|
||
|
#endif
|
||
|
|
||
|
BaseClass::WeaponSound( shoot_type, soundtime );
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Get the point from which to create the weapon's tracer
|
||
|
//-----------------------------------------------------------------------------
|
||
|
Vector CBaseTFCombatWeapon::GetTracerSrc( Vector &vecSrc, Vector &vecFireDir )
|
||
|
{
|
||
|
QAngle vecAngles;
|
||
|
VectorAngles( vecFireDir, vecAngles );
|
||
|
Vector right;
|
||
|
AngleVectors( vecAngles, NULL, &right, NULL );
|
||
|
return (vecSrc + Vector ( 0,0,-4 ) + right * 2 + vecFireDir * 16);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input : activity -
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CBaseTFCombatWeapon::PlayAttackAnimation( int activity )
|
||
|
{
|
||
|
SendWeaponAnim( activity );
|
||
|
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
|
||
|
if ( pPlayer )
|
||
|
{
|
||
|
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
||
|
pPlayer->SetLastAttackTime( gpGlobals->curtime );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input : sequence -
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CBaseTFCombatWeapon::SendWeaponAnim( int iActivity )
|
||
|
{
|
||
|
CBaseTFPlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
|
||
|
if ( !pPlayer )
|
||
|
return false;
|
||
|
|
||
|
CBaseTFCombatWeapon *pOther = NULL;
|
||
|
|
||
|
// See if we are wielding multiple weapons
|
||
|
CWeaponTwoHandedContainer *pContainer = dynamic_cast< CWeaponTwoHandedContainer * >( pPlayer->GetActiveWeapon() );
|
||
|
if ( pContainer )
|
||
|
{
|
||
|
// Make sure they exist
|
||
|
CBaseTFCombatWeapon *left = static_cast< CBaseTFCombatWeapon * >( pContainer->GetLeftWeapon() );
|
||
|
CBaseTFCombatWeapon *right = static_cast< CBaseTFCombatWeapon * >( pContainer->GetRightWeapon() );
|
||
|
if ( !left || !right )
|
||
|
return false;
|
||
|
|
||
|
// Make sure one of them is this!!!
|
||
|
if ( left != this && right != this )
|
||
|
return false;
|
||
|
|
||
|
// Get pointer to other one
|
||
|
pOther = left;
|
||
|
if ( left == this )
|
||
|
{
|
||
|
pOther = right;
|
||
|
}
|
||
|
|
||
|
Assert(pOther);
|
||
|
|
||
|
// Now ask our other weapon if it would like to stomp my animation attempt
|
||
|
iActivity = pOther->ReplaceOtherWeaponsActivity( iActivity );
|
||
|
if ( iActivity == -1 )
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// Always pass through to base
|
||
|
BaseClass::SendWeaponAnim( iActivity );
|
||
|
|
||
|
if ( !IsReflectingAnimations() )
|
||
|
return false;
|
||
|
|
||
|
// See if we are wielding multiple weapons
|
||
|
if ( !pContainer )
|
||
|
return false;
|
||
|
|
||
|
Assert(pOther);
|
||
|
// Send our other weapon the activity code
|
||
|
iActivity = GetOtherWeaponsActivity( iActivity );
|
||
|
if ( iActivity != -1 )
|
||
|
{
|
||
|
pOther->SendWeaponAnim( iActivity );
|
||
|
|
||
|
// Remember it for weapon switching
|
||
|
m_iLastReflectedActivity = iActivity;
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Input : reflect -
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CBaseTFCombatWeapon::SetReflectViewModelAnimations( bool reflect )
|
||
|
{
|
||
|
m_bReflectViewModelAnimations = reflect;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Output : Returns true on success, false on failure.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CBaseTFCombatWeapon::IsReflectingAnimations( void ) const
|
||
|
{
|
||
|
return m_bReflectViewModelAnimations;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CBaseTFCombatWeapon::IsCamouflaged( void )
|
||
|
{
|
||
|
CBaseTFPlayer *pPlayer = (CBaseTFPlayer *)GetOwner();
|
||
|
if ( pPlayer && pPlayer->IsCamouflaged() )
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
#if defined( CLIENT_DLL )
|
||
|
static ConVar cl_bobcycle( "cl_bobcycle","0.8" );
|
||
|
static ConVar cl_bob( "cl_bob","0.002" );
|
||
|
static ConVar cl_bobup( "cl_bobup","0.5" );
|
||
|
|
||
|
// Register these cvars if needed for easy tweaking
|
||
|
static ConVar v_iyaw_cycle( "v_iyaw_cycle", "2"/*, FCVAR_UNREGISTERED*/ );
|
||
|
static ConVar v_iroll_cycle( "v_iroll_cycle", "0.5"/*, FCVAR_UNREGISTERED*/ );
|
||
|
static ConVar v_ipitch_cycle( "v_ipitch_cycle", "1"/*, FCVAR_UNREGISTERED*/ );
|
||
|
static ConVar v_iyaw_level( "v_iyaw_level", "0.3"/*, FCVAR_UNREGISTERED*/ );
|
||
|
static ConVar v_iroll_level( "v_iroll_level", "0.1"/*, FCVAR_UNREGISTERED*/ );
|
||
|
static ConVar v_ipitch_level( "v_ipitch_level", "0.3"/*, FCVAR_UNREGISTERED*/ );
|
||
|
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Output : float
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float CBaseTFCombatWeapon::CalcViewmodelBob( void )
|
||
|
{
|
||
|
static double bobtime;
|
||
|
static float bob;
|
||
|
float cycle;
|
||
|
|
||
|
CBasePlayer *player = ToBasePlayer( GetOwner() );
|
||
|
if ( !player )
|
||
|
return 0.0f;
|
||
|
|
||
|
if ( ( player->GetGroundEntity() == NULL ) || !gpGlobals->frametime )
|
||
|
{
|
||
|
return bob; // just use old value
|
||
|
}
|
||
|
|
||
|
bobtime += gpGlobals->frametime;
|
||
|
|
||
|
cycle = bobtime - (int)(bobtime/cl_bobcycle.GetFloat())*cl_bobcycle.GetFloat();
|
||
|
cycle /= cl_bobcycle.GetFloat();
|
||
|
|
||
|
if (cycle < cl_bobup.GetFloat())
|
||
|
{
|
||
|
cycle = M_PI * cycle / cl_bobup.GetFloat();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cycle = M_PI + M_PI*(cycle-cl_bobup.GetFloat())/(1.0 - cl_bobup.GetFloat());
|
||
|
}
|
||
|
|
||
|
// bob is proportional to simulated velocity in the xy plane
|
||
|
// (don't count Z, or jumping messes it up)
|
||
|
bob = player->GetAbsVelocity().Length2D() * cl_bob.GetFloat();
|
||
|
|
||
|
bob = bob*0.3 + bob*0.7*sin(cycle);
|
||
|
|
||
|
bob = MIN( 4.0, bob );
|
||
|
bob = MAX( -7.0, bob );
|
||
|
return bob;
|
||
|
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Output : float
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CBaseTFCombatWeapon::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
|
||
|
{
|
||
|
float fIdleScale = 2.0f;
|
||
|
|
||
|
// Bias so view models aren't all synced to each other
|
||
|
//float curtime = gpGlobals->curtime + ( viewmodelindex * 2 * M_PI / GetViewModelCount() );
|
||
|
|
||
|
float curtime = gpGlobals->curtime + ( viewmodel->entindex() * 2 * M_PI );
|
||
|
|
||
|
origin[ROLL] -= fIdleScale * sin(curtime*v_iroll_cycle.GetFloat()) * v_iroll_level.GetFloat();
|
||
|
origin[PITCH] -= fIdleScale * sin(curtime*v_ipitch_cycle.GetFloat()) * (v_ipitch_level.GetFloat() * 0.5);
|
||
|
origin[YAW] -= fIdleScale * sin(curtime*v_iyaw_cycle.GetFloat()) * v_iyaw_level.GetFloat();
|
||
|
|
||
|
Vector forward;
|
||
|
AngleVectors( angles, &forward, NULL, NULL );
|
||
|
|
||
|
float flBob = CalcViewmodelBob();
|
||
|
|
||
|
// Apply bob, but scaled down to 40%
|
||
|
VectorMA( origin, flBob * 0.4, forward, origin );
|
||
|
|
||
|
// Z bob a bit more
|
||
|
origin[2] += flBob;
|
||
|
|
||
|
// throw in a little tilt.
|
||
|
angles[ YAW ] -= flBob * 0.6;
|
||
|
angles[ ROLL ] -= flBob * 0.5;
|
||
|
angles[ PITCH ] -= flBob * 0.4;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: TF specific weapon anim events
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CBaseTFCombatWeapon::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
|
||
|
{
|
||
|
switch( event )
|
||
|
{
|
||
|
case CL_EVENT_MUZZLEFLASH0:
|
||
|
case CL_EVENT_MUZZLEFLASH1:
|
||
|
case CL_EVENT_MUZZLEFLASH2:
|
||
|
case CL_EVENT_MUZZLEFLASH3:
|
||
|
{
|
||
|
int iAttachment = -1;
|
||
|
Vector attachOrigin;
|
||
|
QAngle attachAngles;
|
||
|
|
||
|
// First person muzzle flashes
|
||
|
switch (event)
|
||
|
{
|
||
|
case CL_EVENT_MUZZLEFLASH0:
|
||
|
iAttachment = 0;
|
||
|
break;
|
||
|
|
||
|
case CL_EVENT_MUZZLEFLASH1:
|
||
|
iAttachment = 1;
|
||
|
break;
|
||
|
|
||
|
case CL_EVENT_MUZZLEFLASH2:
|
||
|
iAttachment = 2;
|
||
|
break;
|
||
|
|
||
|
case CL_EVENT_MUZZLEFLASH3:
|
||
|
iAttachment = 3;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Did we find it?
|
||
|
if ( pViewModel->GetAttachment( iAttachment+1, attachOrigin, attachAngles ) )
|
||
|
{
|
||
|
//int iType = atoi( options );
|
||
|
|
||
|
// Is our owner boosted?
|
||
|
CBasePlayer *pPlayer = ToBaseTFPlayer( GetOwner() );
|
||
|
if ( pPlayer && pPlayer->HasPowerup(POWERUP_BOOST) )
|
||
|
{
|
||
|
unsigned char color[3];
|
||
|
color[0] = 50;
|
||
|
color[1] = 255;
|
||
|
color[2] = 50;
|
||
|
FX_MuzzleEffect( attachOrigin, attachAngles, 1.0, GetRefEHandle(), &color[0] );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
FX_MuzzleEffect( attachOrigin, attachAngles, 1.0, GetRefEHandle() );
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//============================================================================================================
|
||
|
// OWNER BOOSTED PROXY FOR WEAPONS / PLAYERS
|
||
|
//============================================================================================================
|
||
|
class CPlayerBoostedProxy : public CResultProxy
|
||
|
{
|
||
|
public:
|
||
|
bool Init( IMaterial *pMaterial, KeyValues *pKeyValues );
|
||
|
void OnBind( void *pC_BaseEntity );
|
||
|
|
||
|
private:
|
||
|
CFloatInput m_Factor;
|
||
|
};
|
||
|
|
||
|
bool CPlayerBoostedProxy::Init( IMaterial *pMaterial, KeyValues *pKeyValues )
|
||
|
{
|
||
|
if (!CResultProxy::Init( pMaterial, pKeyValues ))
|
||
|
return false;
|
||
|
|
||
|
if (!m_Factor.Init( pMaterial, pKeyValues, "scale", 1 ))
|
||
|
return false;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void CPlayerBoostedProxy::OnBind( void *pRenderable )
|
||
|
{
|
||
|
// Find the view angle between the player and this entity....
|
||
|
IClientRenderable *pRend = (IClientRenderable *)pRenderable;
|
||
|
C_BaseEntity *pEntity = pRend->GetIClientUnknown()->GetBaseEntity();
|
||
|
CBaseTFPlayer *pPlayer = NULL;
|
||
|
C_BaseViewModel *pViewModel = dynamic_cast<C_BaseViewModel*>(pEntity);
|
||
|
if ( pViewModel )
|
||
|
{
|
||
|
pPlayer = C_BaseTFPlayer::GetLocalPlayer();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CBaseTFCombatWeapon *pWeapon = dynamic_cast<CBaseTFCombatWeapon*>(pEntity);
|
||
|
if ( pWeapon )
|
||
|
{
|
||
|
pPlayer = ToBaseTFPlayer( pWeapon->GetOwner() );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pPlayer = dynamic_cast<CBaseTFPlayer*>(pEntity);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Find him?
|
||
|
if ( pPlayer )
|
||
|
{
|
||
|
float flBoosted = (int)pPlayer->HasPowerup( POWERUP_BOOST );
|
||
|
SetFloatResult( flBoosted * m_Factor.GetFloat() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EXPOSE_INTERFACE( CPlayerBoostedProxy, IMaterialProxy, "PlayerBoosted" IMATERIAL_PROXY_INTERFACE_VERSION );
|
||
|
|
||
|
|
||
|
#else
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Output : float
|
||
|
//-----------------------------------------------------------------------------
|
||
|
float CBaseTFCombatWeapon::CalcViewmodelBob( void )
|
||
|
{
|
||
|
return 0.0f;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose:
|
||
|
// Output : float
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CBaseTFCombatWeapon::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
LINK_ENTITY_TO_CLASS( basetfcombatweapon, CBaseTFCombatWeapon );
|
||
|
|
||
|
IMPLEMENT_NETWORKCLASS_ALIASED( BaseTFCombatWeapon , DT_BaseTFCombatWeapon )
|
||
|
|
||
|
BEGIN_NETWORK_TABLE( CBaseTFCombatWeapon , DT_BaseTFCombatWeapon )
|
||
|
#if !defined( CLIENT_DLL )
|
||
|
|
||
|
// Don't network any animation stuff to client
|
||
|
SendPropExclude( "DT_AnimTimeMustBeFirst", "m_flAnimTime" ),
|
||
|
SendPropExclude( "DT_BaseAnimating", "m_flCycle" ),
|
||
|
|
||
|
SendPropInt( SENDINFO( m_bReflectViewModelAnimations ), 1, SPROP_UNSIGNED ),
|
||
|
#else
|
||
|
RecvPropInt( RECVINFO( m_bReflectViewModelAnimations ) ),
|
||
|
#endif
|
||
|
END_NETWORK_TABLE()
|
||
|
|
||
|
BEGIN_PREDICTION_DATA( CBaseTFCombatWeapon )
|
||
|
|
||
|
// If true, reflect and weapon animations to all view models
|
||
|
DEFINE_PRED_FIELD( m_bReflectViewModelAnimations, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
|
||
|
DEFINE_FIELD( m_iLastReflectedActivity, FIELD_INTEGER )
|
||
|
|
||
|
END_PREDICTION_DATA()
|