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.
497 lines
14 KiB
497 lines
14 KiB
//========= 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()
|
|
|