mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-25 23:56:50 +00:00
1918 lines
50 KiB
C++
1918 lines
50 KiB
C++
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Laser Rifle & Shield combo
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "in_buttons.h"
|
|
#include "takedamageinfo.h"
|
|
#include "weapon_csbase.h"
|
|
#include "ammodef.h"
|
|
#include "cs_gamerules.h"
|
|
|
|
#define ALLOW_WEAPON_SPREAD_DISPLAY 0
|
|
|
|
#if defined( CLIENT_DLL )
|
|
|
|
#include "vgui/ISurface.h"
|
|
#include "vgui_controls/Controls.h"
|
|
#include "c_cs_player.h"
|
|
#include "hud_crosshair.h"
|
|
#include "c_te_effect_dispatch.h"
|
|
#include "c_te_legacytempents.h"
|
|
|
|
extern IVModelInfoClient* modelinfo;
|
|
|
|
#else
|
|
|
|
#include "cs_player.h"
|
|
#include "te_effect_dispatch.h"
|
|
#include "KeyValues.h"
|
|
#include "cs_ammodef.h"
|
|
|
|
extern IVModelInfo* modelinfo;
|
|
|
|
#endif
|
|
|
|
|
|
ConVar weapon_accuracy_model( "weapon_accuracy_model", "2", FCVAR_REPLICATED | FCVAR_DEVELOPMENTONLY | FCVAR_ARCHIVE );
|
|
|
|
|
|
// ----------------------------------------------------------------------------- //
|
|
// Global functions.
|
|
// ----------------------------------------------------------------------------- //
|
|
|
|
|
|
|
|
struct WeaponAliasTranslationInfoStruct
|
|
{
|
|
const char* alias;
|
|
const char* translatedAlias;
|
|
};
|
|
|
|
static const WeaponAliasTranslationInfoStruct s_WeaponAliasTranslationInfo[] =
|
|
{
|
|
{ "cv47", "ak47" },
|
|
{ "defender", "galil" },
|
|
{ "krieg552", "sg552" },
|
|
{ "magnum", "awp" },
|
|
{ "d3au1", "g3sg1" },
|
|
{ "clarion", "famas" },
|
|
{ "bullpup", "aug" },
|
|
{ "krieg550", "sg550" },
|
|
{ "9x19mm", "glock" },
|
|
{ "km45", "usp" },
|
|
{ "228compact", "p228" },
|
|
{ "nighthawk", "deagle" },
|
|
{ "elites", "elite" },
|
|
{ "fn57", "fiveseven" },
|
|
{ "12gauge", "m3" },
|
|
{ "autoshotgun", "xm1014" },
|
|
{ "mp", "tmp" },
|
|
{ "smg", "mp5navy" },
|
|
{ "mp5", "mp5navy" },
|
|
{ "c90", "p90" },
|
|
{ "vest", "kevlar" },
|
|
{ "vesthelm", "assaultsuit" },
|
|
{ "smokegrenade", "sgren" },
|
|
{ "smokegrenade", "sgren" },
|
|
{ "nvgs", "nightvision" },
|
|
|
|
{ "", "" } // this needs to be last
|
|
};
|
|
|
|
|
|
struct WeaponAliasInfo
|
|
{
|
|
CSWeaponID id;
|
|
const char* alias;
|
|
};
|
|
|
|
WeaponAliasInfo s_weaponAliasInfo[] =
|
|
{
|
|
{ WEAPON_P228, "p228" },
|
|
{ WEAPON_GLOCK, "glock" },
|
|
{ WEAPON_SCOUT, "scout" },
|
|
{ WEAPON_XM1014, "xm1014" },
|
|
{ WEAPON_MAC10, "mac10" },
|
|
{ WEAPON_AUG, "aug" },
|
|
{ WEAPON_ELITE, "elite" },
|
|
{ WEAPON_FIVESEVEN, "fiveseven" },
|
|
{ WEAPON_UMP45, "ump45" },
|
|
{ WEAPON_SG550, "sg550" },
|
|
{ WEAPON_GALIL, "galil" },
|
|
{ WEAPON_FAMAS, "famas" },
|
|
{ WEAPON_USP, "usp" },
|
|
{ WEAPON_AWP, "awp" },
|
|
{ WEAPON_MP5NAVY, "mp5navy" },
|
|
{ WEAPON_M249, "m249" },
|
|
{ WEAPON_M3, "m3" },
|
|
{ WEAPON_M4A1, "m4a1" },
|
|
{ WEAPON_TMP, "tmp" },
|
|
{ WEAPON_G3SG1, "g3sg1" },
|
|
{ WEAPON_DEAGLE, "deagle" },
|
|
{ WEAPON_SG552, "sg552" },
|
|
{ WEAPON_AK47, "ak47" },
|
|
{ WEAPON_P90, "p90" },
|
|
|
|
{ WEAPON_KNIFE, "knife" },
|
|
{ WEAPON_C4, "c4" },
|
|
{ WEAPON_FLASHBANG, "flashbang" },
|
|
{ WEAPON_SMOKEGRENADE, "smokegrenade" },
|
|
{ WEAPON_SMOKEGRENADE, "sgren" },
|
|
{ WEAPON_HEGRENADE, "hegrenade" },
|
|
{ WEAPON_HEGRENADE, "hegren" },
|
|
|
|
// not sure any of these are needed
|
|
{ WEAPON_SHIELDGUN, "shield" },
|
|
{ WEAPON_SHIELDGUN, "shieldgun" },
|
|
{ WEAPON_KEVLAR, "kevlar" },
|
|
{ WEAPON_ASSAULTSUIT, "assaultsuit" },
|
|
{ WEAPON_NVG, "nightvision" },
|
|
{ WEAPON_NVG, "nvg" },
|
|
|
|
{ WEAPON_NONE, "none" },
|
|
};
|
|
|
|
|
|
bool IsAmmoType( int iAmmoType, const char *pAmmoName )
|
|
{
|
|
return GetAmmoDef()->Index( pAmmoName ) == iAmmoType;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------
|
|
//
|
|
// Given an alias, return the translated alias.
|
|
//
|
|
const char * GetTranslatedWeaponAlias( const char *szAlias )
|
|
{
|
|
for ( int i = 0; i < ARRAYSIZE(s_WeaponAliasTranslationInfo); ++i )
|
|
{
|
|
if ( Q_stricmp(s_WeaponAliasTranslationInfo[i].alias, szAlias) == 0 )
|
|
{
|
|
return s_WeaponAliasTranslationInfo[i].translatedAlias;
|
|
}
|
|
}
|
|
|
|
return szAlias;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------
|
|
//
|
|
// Given a translated alias, return the alias.
|
|
//
|
|
const char * GetWeaponAliasFromTranslated(const char *translatedAlias)
|
|
{
|
|
int i = 0;
|
|
const WeaponAliasTranslationInfoStruct *info = &(s_WeaponAliasTranslationInfo[i]);
|
|
|
|
while (info->alias[0] != 0)
|
|
{
|
|
if (Q_stricmp(translatedAlias, info->translatedAlias) == 0)
|
|
{
|
|
return info->alias;
|
|
}
|
|
info = &(s_WeaponAliasTranslationInfo[++i]);
|
|
}
|
|
|
|
return translatedAlias;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------
|
|
//
|
|
// Given an alias, return the associated weapon ID
|
|
//
|
|
CSWeaponID AliasToWeaponID( const char *szAlias )
|
|
{
|
|
if ( szAlias )
|
|
{
|
|
for ( int i=0; i < ARRAYSIZE(s_weaponAliasInfo); ++i)
|
|
{
|
|
if ( Q_stricmp( s_weaponAliasInfo[i].alias, szAlias) == 0 )
|
|
return s_weaponAliasInfo[i].id;
|
|
}
|
|
}
|
|
|
|
return WEAPON_NONE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------
|
|
//
|
|
// Given a weapon ID, return its alias
|
|
//
|
|
const char *WeaponIDToAlias( int id )
|
|
{
|
|
for ( int i=0; i < ARRAYSIZE(s_weaponAliasInfo); ++i)
|
|
{
|
|
if ( s_weaponAliasInfo[i].id == id )
|
|
return s_weaponAliasInfo[i].alias;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------
|
|
//
|
|
// Return true if given weapon ID is a primary weapon
|
|
//
|
|
bool IsPrimaryWeapon( CSWeaponID id )
|
|
{
|
|
const CCSWeaponInfo* pWeaponInfo = GetWeaponInfo( id );
|
|
if ( pWeaponInfo )
|
|
{
|
|
return pWeaponInfo->iSlot == WEAPON_SLOT_RIFLE;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------------------
|
|
//
|
|
// Return true if given weapon ID is a secondary weapon
|
|
//
|
|
bool IsSecondaryWeapon( CSWeaponID id )
|
|
{
|
|
const CCSWeaponInfo* pWeaponInfo = GetWeaponInfo( id );
|
|
if ( pWeaponInfo )
|
|
return pWeaponInfo->iSlot == WEAPON_SLOT_PISTOL;
|
|
|
|
return false;
|
|
}
|
|
|
|
#ifdef CLIENT_DLL
|
|
int GetShellForAmmoType( const char *ammoname )
|
|
{
|
|
if ( !Q_strcmp( BULLET_PLAYER_762MM, ammoname ) )
|
|
return CS_SHELL_762NATO;
|
|
|
|
if ( !Q_strcmp( BULLET_PLAYER_556MM, ammoname ) )
|
|
return CS_SHELL_556;
|
|
|
|
if ( !Q_strcmp( BULLET_PLAYER_338MAG, ammoname ) )
|
|
return CS_SHELL_338MAG;
|
|
|
|
if ( !Q_strcmp( BULLET_PLAYER_BUCKSHOT, ammoname ) )
|
|
return CS_SHELL_12GAUGE;
|
|
|
|
if ( !Q_strcmp( BULLET_PLAYER_57MM, ammoname ) )
|
|
return CS_SHELL_57;
|
|
|
|
// default 9 mm
|
|
return CS_SHELL_9MM;
|
|
}
|
|
#endif
|
|
|
|
|
|
// ----------------------------------------------------------------------------- //
|
|
// CWeaponCSBase tables.
|
|
// ----------------------------------------------------------------------------- //
|
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCSBase, DT_WeaponCSBase )
|
|
|
|
BEGIN_NETWORK_TABLE( CWeaponCSBase, DT_WeaponCSBase )
|
|
#if !defined( CLIENT_DLL )
|
|
SendPropInt( SENDINFO( m_weaponMode ), 1, SPROP_UNSIGNED ),
|
|
SendPropFloat(SENDINFO(m_fAccuracyPenalty) ),
|
|
// world weapon models have no aminations
|
|
SendPropExclude( "DT_AnimTimeMustBeFirst", "m_flAnimTime" ),
|
|
SendPropExclude( "DT_BaseAnimating", "m_nSequence" ),
|
|
// SendPropExclude( "DT_LocalActiveWeaponData", "m_flTimeWeaponIdle" ),
|
|
#else
|
|
RecvPropInt( RECVINFO( m_weaponMode ) ),
|
|
RecvPropFloat( RECVINFO(m_fAccuracyPenalty)),
|
|
#endif
|
|
END_NETWORK_TABLE()
|
|
|
|
#if defined(CLIENT_DLL)
|
|
BEGIN_PREDICTION_DATA( CWeaponCSBase )
|
|
DEFINE_PRED_FIELD( m_flTimeWeaponIdle, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
|
|
DEFINE_PRED_FIELD( m_flNextPrimaryAttack, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
|
|
DEFINE_PRED_FIELD( m_flNextSecondaryAttack, FIELD_FLOAT, FTYPEDESC_OVERRIDE | FTYPEDESC_NOERRORCHECK ),
|
|
DEFINE_PRED_FIELD( m_bDelayFire, FIELD_BOOLEAN, 0 ),
|
|
DEFINE_PRED_FIELD( m_flAccuracy, FIELD_FLOAT, 0 ),
|
|
DEFINE_PRED_FIELD( m_weaponMode, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD_TOL( m_fAccuracyPenalty, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, 0.00005f ),
|
|
END_PREDICTION_DATA()
|
|
#endif
|
|
|
|
|
|
LINK_ENTITY_TO_CLASS( weapon_cs_base, CWeaponCSBase );
|
|
|
|
|
|
#ifdef GAME_DLL
|
|
|
|
BEGIN_DATADESC( CWeaponCSBase )
|
|
|
|
//DEFINE_FUNCTION( DefaultTouch ),
|
|
DEFINE_THINKFUNC( FallThink )
|
|
|
|
END_DATADESC()
|
|
|
|
#endif
|
|
|
|
#if defined( CLIENT_DLL )
|
|
ConVar cl_crosshaircolor( "cl_crosshaircolor", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Set crosshair color: 0=green, 1=red, 2=blue, 3=yellow, 4=cyan, 5=custom" );
|
|
ConVar cl_dynamiccrosshair( "cl_dynamiccrosshair", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Enables dynamic crosshair; 0=off, 1=normal behavior (based on actual weapon accuracy), 2=legacy simulated dynamic behavior, 3=legacy simulated static behavior" );
|
|
ConVar cl_crosshairspreadscale( "cl_crosshairspreadscale", "0.3", FCVAR_CLIENTDLL | FCVAR_ARCHIVE);
|
|
ConVar cl_scalecrosshair( "cl_scalecrosshair", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Enable crosshair scaling (deprecated)" );
|
|
ConVar cl_crosshairscale( "cl_crosshairscale", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Crosshair scaling factor (deprecated)" );
|
|
ConVar cl_crosshairalpha( "cl_crosshairalpha", "200", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
|
|
ConVar cl_crosshairusealpha( "cl_crosshairusealpha", "1", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
|
|
ConVar cl_crosshairsize( "cl_crosshairsize", "5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
|
|
ConVar cl_crosshairthickness( "cl_crosshairthickness", "0.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
|
|
ConVar cl_crosshairdot( "cl_crosshairdot", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
|
|
ConVar cl_crosshaircolor_r( "cl_crosshaircolor_r", "50", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
|
|
ConVar cl_crosshaircolor_g( "cl_crosshaircolor_g", "250", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
|
|
ConVar cl_crosshaircolor_b( "cl_crosshaircolor_b", "50", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
|
|
|
|
#if ALLOW_WEAPON_SPREAD_DISPLAY
|
|
ConVar weapon_debug_spread_show( "weapon_debug_spread_show", "0", FCVAR_CLIENTDLL | FCVAR_DEVELOPMENTONLY, "Enables display of weapon accuracy; 1: show accuracy box, 2: show box with recoil offset" );
|
|
ConVar weapon_debug_spread_gap( "weapon_debug_spread_gap", "0.67", FCVAR_CLIENTDLL | FCVAR_DEVELOPMENTONLY );
|
|
#endif
|
|
|
|
// [paquin] make sure crosshair scales independent of frame rate
|
|
// unless legacy cvar is set
|
|
ConVar cl_legacy_crosshair_recoil( "cl_legacy_crosshair_recoil", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Enable legacy framerate dependent crosshair recoil");
|
|
|
|
// use old scaling behavior
|
|
ConVar cl_legacy_crosshair_scale( "cl_legacy_crosshair_scale", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Enable legacy crosshair scaling");
|
|
|
|
void DrawCrosshairRect( int x0, int y0, int x1, int y1, bool bAdditive )
|
|
{
|
|
if ( bAdditive )
|
|
{
|
|
vgui::surface()->DrawTexturedRect( x0, y0, x1, y1 );
|
|
}
|
|
else
|
|
{
|
|
// Alpha-blended crosshair
|
|
vgui::surface()->DrawFilledRect( x0, y0, x1, y1 );
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
// must be included after the above macros
|
|
#ifndef CLIENT_DLL
|
|
#include "cs_bot.h"
|
|
#endif
|
|
|
|
|
|
// ----------------------------------------------------------------------------- //
|
|
// CWeaponCSBase implementation.
|
|
// ----------------------------------------------------------------------------- //
|
|
CWeaponCSBase::CWeaponCSBase()
|
|
{
|
|
SetPredictionEligible( true );
|
|
m_bDelayFire = true;
|
|
m_nextPrevOwnerTouchTime = 0.0;
|
|
m_prevOwner = NULL;
|
|
AddSolidFlags( FSOLID_TRIGGER ); // Nothing collides with these but it gets touches.
|
|
|
|
#ifdef CLIENT_DLL
|
|
m_iCrosshairTextureID = 0;
|
|
#else
|
|
m_iDefaultExtraAmmo = 0;
|
|
#endif
|
|
|
|
m_fAccuracyPenalty = 0.0f;
|
|
|
|
m_weaponMode = Primary_Mode;
|
|
}
|
|
|
|
|
|
#ifndef CLIENT_DLL
|
|
bool CWeaponCSBase::KeyValue( const char *szKeyName, const char *szValue )
|
|
{
|
|
if ( !BaseClass::KeyValue( szKeyName, szValue ) )
|
|
{
|
|
if ( FStrEq( szKeyName, "ammo" ) )
|
|
{
|
|
int bullets = atoi( szValue );
|
|
if ( bullets < 0 )
|
|
return false;
|
|
|
|
m_iDefaultExtraAmmo = bullets;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
|
|
bool CWeaponCSBase::IsPredicted() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CWeaponCSBase::IsPistol() const
|
|
{
|
|
return GetCSWpnData().m_WeaponType == WEAPONTYPE_PISTOL;
|
|
}
|
|
|
|
|
|
bool CWeaponCSBase::IsFullAuto() const
|
|
{
|
|
return GetCSWpnData().m_bFullAuto;
|
|
}
|
|
|
|
|
|
bool CWeaponCSBase::PlayEmptySound()
|
|
{
|
|
//MIKETODO: certain weapons should override this to make it empty:
|
|
// C4
|
|
// Flashbang
|
|
// HE Grenade
|
|
// Smoke grenade
|
|
|
|
CPASAttenuationFilter filter( this );
|
|
filter.UsePredictionRules();
|
|
|
|
if ( IsPistol() )
|
|
{
|
|
EmitSound( filter, entindex(), "Default.ClipEmpty_Pistol" );
|
|
}
|
|
else
|
|
{
|
|
EmitSound( filter, entindex(), "Default.ClipEmpty_Rifle" );
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
CCSPlayer* CWeaponCSBase::GetPlayerOwner() const
|
|
{
|
|
return dynamic_cast< CCSPlayer* >( GetOwner() );
|
|
}
|
|
|
|
//=============================================================================
|
|
// HPE_BEGIN:
|
|
//=============================================================================
|
|
|
|
//[dwenger] Accessors for the prior owner list
|
|
void CWeaponCSBase::AddToPriorOwnerList(CCSPlayer* pPlayer)
|
|
{
|
|
if ( !IsAPriorOwner( pPlayer ) )
|
|
{
|
|
// Add player to prior owner list
|
|
m_PriorOwners.AddToTail( pPlayer );
|
|
}
|
|
}
|
|
|
|
bool CWeaponCSBase::IsAPriorOwner(CCSPlayer* pPlayer)
|
|
{
|
|
return (m_PriorOwners.Find( pPlayer ) != -1);
|
|
}
|
|
|
|
//=============================================================================
|
|
// HPE_END
|
|
//=============================================================================
|
|
|
|
|
|
void CWeaponCSBase::SecondaryAttack( void )
|
|
{
|
|
#ifndef CLIENT_DLL
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
if ( pPlayer->HasShield() == false )
|
|
BaseClass::SecondaryAttack();
|
|
else
|
|
{
|
|
pPlayer->SetShieldDrawnState( !pPlayer->IsShieldDrawn() );
|
|
|
|
if ( pPlayer->IsShieldDrawn() )
|
|
SendWeaponAnim( ACT_SHIELD_UP );
|
|
else
|
|
SendWeaponAnim( ACT_SHIELD_DOWN );
|
|
|
|
m_flNextSecondaryAttack = gpGlobals->curtime + 0.4;
|
|
m_flNextPrimaryAttack = gpGlobals->curtime + 0.4;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool CWeaponCSBase::SendWeaponAnim( int iActivity )
|
|
{
|
|
#ifdef CS_SHIELD_ENABLED
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
|
|
if ( pPlayer && pPlayer->HasShield() )
|
|
{
|
|
CBaseViewModel *vm = pPlayer->GetViewModel( 1 );
|
|
|
|
if ( vm == NULL )
|
|
return false;
|
|
|
|
vm->SetWeaponModel( SHIELD_VIEW_MODEL, this );
|
|
|
|
int idealSequence = vm->SelectWeightedSequence( (Activity)iActivity );
|
|
|
|
if ( idealSequence >= 0 )
|
|
{
|
|
vm->SendViewModelMatchingSequence( idealSequence );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return BaseClass::SendWeaponAnim( iActivity );
|
|
}
|
|
|
|
|
|
void CWeaponCSBase::ItemPostFrame()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
UpdateAccuracyPenalty();
|
|
|
|
UpdateShieldState();
|
|
|
|
if ((m_bInReload) && (pPlayer->m_flNextAttack <= gpGlobals->curtime))
|
|
{
|
|
// complete the reload.
|
|
int j = MIN( GetMaxClip1() - m_iClip1, pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) );
|
|
|
|
// Add them to the clip
|
|
m_iClip1 += j;
|
|
pPlayer->RemoveAmmo( j, m_iPrimaryAmmoType );
|
|
|
|
m_bInReload = false;
|
|
}
|
|
|
|
if ((pPlayer->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime))
|
|
{
|
|
if ( pPlayer->HasShield() )
|
|
CWeaponCSBase::SecondaryAttack();
|
|
else
|
|
SecondaryAttack();
|
|
|
|
pPlayer->m_nButtons &= ~IN_ATTACK2;
|
|
}
|
|
else if ((pPlayer->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime ))
|
|
{
|
|
if ( CSGameRules()->IsFreezePeriod() ) // Can't shoot during the freeze period
|
|
return;
|
|
|
|
if ( pPlayer->m_bIsDefusing )
|
|
return;
|
|
|
|
if ( pPlayer->State_Get() != STATE_ACTIVE )
|
|
return;
|
|
|
|
if ( pPlayer->IsShieldDrawn() )
|
|
return;
|
|
|
|
// we have to reset the FireOnEmpty flag before we can fire on an empty clip
|
|
if ( m_iClip1 == 0 && !m_bFireOnEmpty )
|
|
return;
|
|
|
|
// don't repeat fire if this is not a full auto weapon
|
|
if ( pPlayer->m_iShotsFired > 0 && !IsFullAuto() )
|
|
return;
|
|
|
|
#if !defined(CLIENT_DLL)
|
|
// allow the bots to react to the gunfire
|
|
if ( GetCSWpnData().m_WeaponType != WEAPONTYPE_GRENADE )
|
|
{
|
|
IGameEvent * event = gameeventmanager->CreateEvent( (HasAmmo()) ? "weapon_fire" : "weapon_fire_on_empty" );
|
|
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
|
|
PrimaryAttack();
|
|
}
|
|
else if ( pPlayer->m_nButtons & IN_RELOAD && GetMaxClip1() != WEAPON_NOCLIP && !m_bInReload && m_flNextPrimaryAttack < gpGlobals->curtime)
|
|
{
|
|
// reload when reload is pressed, or if no buttons are down and weapon is empty.
|
|
|
|
//MIKETODO: add code for shields...
|
|
//if ( !FBitSet( m_iWeaponState, WPNSTATE_SHIELD_DRAWN ) )
|
|
|
|
if ( !pPlayer->IsShieldDrawn() )
|
|
{
|
|
if ( Reload() )
|
|
{
|
|
#ifndef CLIENT_DLL
|
|
// allow the bots to react to the reload
|
|
IGameEvent * event = gameeventmanager->CreateEvent( "weapon_reload" );
|
|
if( event )
|
|
{
|
|
event->SetInt( "userid", pPlayer->GetUserID() );
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
else if ( !(pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2) ) )
|
|
{
|
|
if ( weapon_accuracy_model.GetInt() == 2 )
|
|
{
|
|
// Fire button not down -- reset the shots fired count
|
|
if ( pPlayer->m_iShotsFired > 0 && ( !IsFullAuto() || m_iClip1 == 0 ) )
|
|
{
|
|
pPlayer->m_iShotsFired = 0;
|
|
}
|
|
}
|
|
|
|
// The following code prevents the player from tapping the firebutton repeatedly
|
|
// to simulate full auto and retaining the single shot accuracy of single fire
|
|
if ( m_bDelayFire )
|
|
{
|
|
m_bDelayFire = false;
|
|
|
|
if (pPlayer->m_iShotsFired > 15)
|
|
pPlayer->m_iShotsFired = 15;
|
|
|
|
m_flDecreaseShotsFired = gpGlobals->curtime + 0.4;
|
|
}
|
|
|
|
m_bFireOnEmpty = true;
|
|
|
|
// if it's a pistol then set the shots fired to 0 after the player releases a button
|
|
if ( IsPistol() )
|
|
{
|
|
pPlayer->m_iShotsFired = 0;
|
|
}
|
|
else
|
|
{
|
|
if ( (pPlayer->m_iShotsFired > 0) && (m_flDecreaseShotsFired < gpGlobals->curtime) )
|
|
{
|
|
m_flDecreaseShotsFired = gpGlobals->curtime + 0.0225;
|
|
pPlayer->m_iShotsFired--;
|
|
}
|
|
}
|
|
|
|
if ( (!IsUseable() && m_flNextPrimaryAttack < gpGlobals->curtime) )
|
|
{
|
|
// Intentionally blank -- used to switch weapons here
|
|
}
|
|
else
|
|
{
|
|
// weapon is useable. Reload if empty and weapon has waited as long as it has to after firing
|
|
if ( m_iClip1 == 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime )
|
|
{
|
|
Reload();
|
|
return;
|
|
}
|
|
}
|
|
|
|
WeaponIdle( );
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void CWeaponCSBase::ItemBusyFrame()
|
|
{
|
|
UpdateAccuracyPenalty();
|
|
|
|
BaseClass::ItemBusyFrame();
|
|
}
|
|
|
|
|
|
float CWeaponCSBase::GetInaccuracy() const
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return 0.0f;
|
|
|
|
const CCSWeaponInfo& weaponInfo = GetCSWpnData();
|
|
|
|
float fMaxSpeed = GetMaxSpeed();
|
|
if ( fMaxSpeed == 0.0f )
|
|
fMaxSpeed = GetCSWpnData().m_flMaxSpeed;
|
|
|
|
return m_fAccuracyPenalty +
|
|
RemapValClamped(pPlayer->GetAbsVelocity().Length2D(),
|
|
fMaxSpeed * CS_PLAYER_SPEED_DUCK_MODIFIER,
|
|
fMaxSpeed * 0.95f, // max out at 95% of run speed to avoid jitter near max speed
|
|
0.0f, weaponInfo.m_fInaccuracyMove[m_weaponMode]);
|
|
}
|
|
|
|
|
|
float CWeaponCSBase::GetSpread() const
|
|
{
|
|
if ( weapon_accuracy_model.GetInt() == 1 )
|
|
return 0.0f;
|
|
|
|
return GetCSWpnData().m_fSpread[m_weaponMode];
|
|
}
|
|
|
|
|
|
float CWeaponCSBase::GetMaxSpeed() const
|
|
{
|
|
// The weapon should have set this in its constructor.
|
|
float flRet = GetCSWpnData().m_flMaxSpeed;
|
|
Assert( flRet > 1 );
|
|
return flRet;
|
|
}
|
|
|
|
const CCSWeaponInfo &CWeaponCSBase::GetCSWpnData() const
|
|
{
|
|
const FileWeaponInfo_t *pWeaponInfo = &GetWpnData();
|
|
const CCSWeaponInfo *pCSInfo;
|
|
|
|
#ifdef _DEBUG
|
|
pCSInfo = dynamic_cast< const CCSWeaponInfo* >( pWeaponInfo );
|
|
Assert( pCSInfo );
|
|
#else
|
|
pCSInfo = static_cast< const CCSWeaponInfo* >( pWeaponInfo );
|
|
#endif
|
|
|
|
return *pCSInfo;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
const char *CWeaponCSBase::GetViewModel( int /*viewmodelindex = 0 -- this is ignored in the base class here*/ ) const
|
|
{
|
|
CCSPlayer *pOwner = GetPlayerOwner();
|
|
|
|
if ( pOwner == NULL )
|
|
return BaseClass::GetViewModel();
|
|
|
|
if ( pOwner->HasShield() && GetCSWpnData().m_bCanUseWithShield )
|
|
return GetCSWpnData().m_szShieldViewModel;
|
|
else
|
|
return GetWpnData().szViewModel;
|
|
|
|
return BaseClass::GetViewModel();
|
|
|
|
}
|
|
|
|
void CWeaponCSBase::Precache( void )
|
|
{
|
|
BaseClass::Precache();
|
|
|
|
#ifdef CS_SHIELD_ENABLED
|
|
if ( GetCSWpnData().m_bCanUseWithShield )
|
|
{
|
|
PrecacheModel( GetCSWpnData().m_szShieldViewModel );
|
|
}
|
|
#endif
|
|
|
|
PrecacheScriptSound( "Default.ClipEmpty_Pistol" );
|
|
PrecacheScriptSound( "Default.ClipEmpty_Rifle" );
|
|
|
|
PrecacheScriptSound( "Default.Zoom" );
|
|
}
|
|
|
|
Activity CWeaponCSBase::GetDeployActivity( void )
|
|
{
|
|
return ACT_VM_DRAW;
|
|
}
|
|
|
|
bool CWeaponCSBase::DefaultDeploy( char *szViewModel, char *szWeaponModel, int iActivity, char *szAnimExt )
|
|
{
|
|
// Msg( "deploy %s at %f\n", GetClassname(), gpGlobals->curtime );
|
|
CCSPlayer *pOwner = GetPlayerOwner();
|
|
if ( !pOwner )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
pOwner->SetAnimationExtension( szAnimExt );
|
|
|
|
SetViewModel();
|
|
SendWeaponAnim( GetDeployActivity() );
|
|
|
|
pOwner->SetNextAttack( gpGlobals->curtime + SequenceDuration() );
|
|
m_flNextPrimaryAttack = gpGlobals->curtime;
|
|
m_flNextSecondaryAttack = gpGlobals->curtime;
|
|
|
|
SetWeaponVisible( true );
|
|
pOwner->SetShieldDrawnState( false );
|
|
|
|
if ( pOwner->HasShield() == true )
|
|
SetWeaponModelIndex( SHIELD_WORLD_MODEL);
|
|
else
|
|
SetWeaponModelIndex( szWeaponModel );
|
|
|
|
return true;
|
|
}
|
|
|
|
void CWeaponCSBase::UpdateShieldState( void )
|
|
{
|
|
//empty by default.
|
|
CCSPlayer *pOwner = GetPlayerOwner();
|
|
|
|
if ( pOwner == NULL )
|
|
return;
|
|
|
|
//ADRIANTODO
|
|
//Make the hitbox set switches here!!!
|
|
if ( pOwner->HasShield() == false )
|
|
{
|
|
|
|
pOwner->SetShieldDrawnState( false );
|
|
//pOwner->SetHitBoxSet( 0 );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
//pOwner->SetHitBoxSet( 1 );
|
|
}
|
|
}
|
|
|
|
void CWeaponCSBase::SetWeaponModelIndex( const char *pName )
|
|
{
|
|
m_iWorldModelIndex = modelinfo->GetModelIndex( pName );
|
|
}
|
|
|
|
bool CWeaponCSBase::CanBeSelected( void )
|
|
{
|
|
if ( !VisibleInWeaponSelection() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CWeaponCSBase::CanDeploy( void )
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return false;
|
|
|
|
if ( pPlayer->HasShield() && GetCSWpnData().m_bCanUseWithShield == false )
|
|
return false;
|
|
|
|
return BaseClass::CanDeploy();
|
|
}
|
|
|
|
float CWeaponCSBase::CalculateNextAttackTime( float fCycleTime )
|
|
{
|
|
float fCurAttack = m_flNextPrimaryAttack;
|
|
float fDeltaAttack = gpGlobals->curtime - fCurAttack;
|
|
if ( fDeltaAttack < 0 || fDeltaAttack > gpGlobals->interval_per_tick )
|
|
{
|
|
fCurAttack = gpGlobals->curtime;
|
|
}
|
|
m_flNextSecondaryAttack = m_flNextPrimaryAttack = fCurAttack + fCycleTime;
|
|
|
|
return fCurAttack;
|
|
}
|
|
|
|
bool CWeaponCSBase::Holster( CBaseCombatWeapon *pSwitchingTo )
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return false;
|
|
|
|
if ( pPlayer )
|
|
pPlayer->SetFOV( pPlayer, 0 ); // reset the default FOV.
|
|
|
|
if ( pPlayer )
|
|
pPlayer->SetShieldDrawnState( false );
|
|
|
|
return BaseClass::Holster( pSwitchingTo );
|
|
}
|
|
|
|
bool CWeaponCSBase::Deploy()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
|
|
#ifdef CLIENT_DLL
|
|
m_iAlpha = 80;
|
|
if ( pPlayer )
|
|
{
|
|
pPlayer->m_iLastZoom = 0;
|
|
pPlayer->SetFOV( pPlayer, 0 );
|
|
}
|
|
#else
|
|
|
|
m_flDecreaseShotsFired = gpGlobals->curtime;
|
|
|
|
|
|
if ( pPlayer )
|
|
{
|
|
pPlayer->m_iShotsFired = 0;
|
|
pPlayer->m_bResumeZoom = false;
|
|
pPlayer->m_iLastZoom = 0;
|
|
pPlayer->SetFOV( pPlayer, 0 );
|
|
}
|
|
#endif
|
|
|
|
m_fAccuracyPenalty = 0.0f;
|
|
|
|
return BaseClass::Deploy();
|
|
}
|
|
|
|
#ifndef CLIENT_DLL
|
|
bool CWeaponCSBase::IsRemoveable()
|
|
{
|
|
if ( BaseClass::IsRemoveable() == true )
|
|
{
|
|
if ( m_nextPrevOwnerTouchTime > gpGlobals->curtime )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return BaseClass::IsRemoveable();
|
|
}
|
|
#endif
|
|
|
|
void CWeaponCSBase::Drop(const Vector &vecVelocity)
|
|
{
|
|
|
|
#ifdef CLIENT_DLL
|
|
BaseClass::Drop(vecVelocity);
|
|
return;
|
|
#else
|
|
|
|
// Once somebody drops a gun, it's fair game for removal when/if
|
|
// a game_weapon_manager does a cleanup on surplus weapons in the
|
|
// world.
|
|
SetRemoveable( true );
|
|
|
|
StopAnimation();
|
|
StopFollowingEntity( );
|
|
SetMoveType( MOVETYPE_FLYGRAVITY );
|
|
// clear follow stuff, setup for collision
|
|
SetGravity(1.0);
|
|
m_iState = WEAPON_NOT_CARRIED;
|
|
RemoveEffects( EF_NODRAW );
|
|
FallInit();
|
|
SetGroundEntity( NULL );
|
|
|
|
m_bInReload = false; // stop reloading
|
|
|
|
SetThink( NULL );
|
|
m_nextPrevOwnerTouchTime = gpGlobals->curtime + 0.8f;
|
|
m_prevOwner = GetPlayerOwner();
|
|
|
|
SetTouch(&CWeaponCSBase::DefaultTouch);
|
|
|
|
IPhysicsObject *pObj = VPhysicsGetObject();
|
|
if ( pObj != NULL )
|
|
{
|
|
AngularImpulse angImp( 200, 200, 200 );
|
|
pObj->AddVelocity( &vecVelocity, &angImp );
|
|
}
|
|
else
|
|
{
|
|
SetAbsVelocity( vecVelocity );
|
|
}
|
|
|
|
SetNextThink( gpGlobals->curtime );
|
|
|
|
SetOwnerEntity( NULL );
|
|
SetOwner( NULL );
|
|
#endif
|
|
}
|
|
|
|
// whats going on here is that if the player drops this weapon, they shouldn't take it back themselves
|
|
// for a little while. But if they throw it at someone else, the other player should get it immediately.
|
|
void CWeaponCSBase::DefaultTouch(CBaseEntity *pOther)
|
|
{
|
|
if ((m_prevOwner != NULL) && (pOther == m_prevOwner) && (gpGlobals->curtime < m_nextPrevOwnerTouchTime))
|
|
{
|
|
return;
|
|
}
|
|
|
|
BaseClass::DefaultTouch(pOther);
|
|
}
|
|
|
|
#if defined( CLIENT_DLL )
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Draw the weapon's crosshair
|
|
//-----------------------------------------------------------------------------
|
|
void CWeaponCSBase::DrawCrosshair()
|
|
{
|
|
if ( !crosshair.GetInt() )
|
|
return;
|
|
|
|
CHudCrosshair *pCrosshair = GET_HUDELEMENT( CHudCrosshair );
|
|
|
|
if ( !pCrosshair )
|
|
return;
|
|
|
|
// clear crosshair
|
|
pCrosshair->SetCrosshair( 0, Color( 255, 255, 255, 255 ) );
|
|
|
|
CCSPlayer* pPlayer = (CCSPlayer*)C_BasePlayer::GetLocalPlayer();
|
|
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
// localplayer must be owner if not in Spec mode
|
|
Assert( (pPlayer == GetPlayerOwner()) || ( pPlayer->GetObserverMode()==OBS_MODE_IN_EYE) );
|
|
|
|
// Draw the targeting zone around the pCrosshair
|
|
if ( pPlayer->IsInVGuiInputMode() )
|
|
return;
|
|
|
|
int r, g, b;
|
|
switch ( cl_crosshaircolor.GetInt() )
|
|
{
|
|
case 0 : r = 50; g = 250; b = 50; break;
|
|
case 1 : r = 250; g = 50; b = 50; break;
|
|
case 2 : r = 50; g = 50; b = 250; break;
|
|
case 3 : r = 250; g = 250; b = 50; break;
|
|
case 4 : r = 50; g = 250; b = 250; break;
|
|
case 5 :
|
|
r = cl_crosshaircolor_r.GetInt();
|
|
g = cl_crosshaircolor_g.GetInt();
|
|
b = cl_crosshaircolor_b.GetInt();
|
|
break;
|
|
default : r = 50; g = 250; b = 50; break;
|
|
}
|
|
|
|
// if user is using nightvision, make the crosshair red.
|
|
if (pPlayer->m_bNightVisionOn)
|
|
{
|
|
r = 250;
|
|
g = 50;
|
|
b = 50;
|
|
}
|
|
|
|
int alpha = clamp( cl_crosshairalpha.GetInt(), 0, 255 );
|
|
vgui::surface()->DrawSetColor( r, g, b, alpha );
|
|
|
|
if ( !m_iCrosshairTextureID )
|
|
{
|
|
CHudTexture *pTexture = gHUD.GetIcon( "whiteAdditive" );
|
|
if ( pTexture )
|
|
{
|
|
m_iCrosshairTextureID = pTexture->textureId;
|
|
}
|
|
}
|
|
|
|
bool bAdditive = !cl_crosshairusealpha.GetBool() && !pPlayer->m_bNightVisionOn;
|
|
if ( bAdditive )
|
|
{
|
|
vgui::surface()->DrawSetColor( r, g, b, 200 );
|
|
vgui::surface()->DrawSetTexture( m_iCrosshairTextureID );
|
|
}
|
|
|
|
if ( pPlayer->HasShield() && pPlayer->IsShieldDrawn() == true )
|
|
return;
|
|
|
|
// no crosshair for sniper rifles
|
|
bool bCrosshairVisible = crosshair.GetBool() && GetCSWpnData().m_WeaponType != WEAPONTYPE_SNIPER_RIFLE;
|
|
|
|
if ( !bCrosshairVisible
|
|
#if ALLOW_WEAPON_SPREAD_DISPLAY
|
|
&& !weapon_debug_spread_show.GetBool()
|
|
#endif
|
|
)
|
|
return;
|
|
|
|
float fHalfFov = DEG2RAD(pPlayer->GetFOV()) * 0.5f;
|
|
|
|
int iCrosshairDistance;
|
|
int iBarSize = RoundFloatToInt(YRES(cl_crosshairsize.GetFloat()));
|
|
int iBarThickness = MAX( 1, RoundFloatToInt(YRES(cl_crosshairthickness.GetFloat())));
|
|
|
|
switch ( cl_dynamiccrosshair.GetInt() )
|
|
{
|
|
case 0:
|
|
default:
|
|
{
|
|
// static crosshair
|
|
float fSpread = (GetCSWpnData().m_fSpread[m_weaponMode] + GetCSWpnData().m_fInaccuracyStand[m_weaponMode]) * 320.0f / tanf(fHalfFov);
|
|
iCrosshairDistance = MAX( 0, RoundFloatToInt( YRES( fSpread * cl_crosshairspreadscale.GetFloat() ) ) );
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
{
|
|
float fSpread = (GetInaccuracy() + GetSpread()) * 320.0f / tanf(fHalfFov);
|
|
iCrosshairDistance = MAX( 0, RoundFloatToInt( YRES( fSpread * cl_crosshairspreadscale.GetFloat() ) ) );
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
case 3:
|
|
{
|
|
float fCrosshairDistanceGoal = GetCSWpnData().m_iCrosshairMinDistance; // The minimum distance the crosshair can achieve...
|
|
|
|
// legacy dynamic crosshair
|
|
if ( cl_dynamiccrosshair.GetInt() == 2 )
|
|
{
|
|
if ( !( pPlayer->GetFlags() & FL_ONGROUND ) )
|
|
fCrosshairDistanceGoal *= 2.0f;
|
|
else if ( pPlayer->GetFlags() & FL_DUCKING )
|
|
fCrosshairDistanceGoal *= 0.5f;
|
|
else if ( pPlayer->GetAbsVelocity().Length() > 100 )
|
|
fCrosshairDistanceGoal *= 1.5f;
|
|
}
|
|
|
|
// [jpaquin] changed to only bump up the crosshair size if the player is still shooting or is spectating someone else
|
|
int iDeltaDistance = GetCSWpnData().m_iCrosshairDeltaDistance; // Amount by which the crosshair expands when shooting (per frame)
|
|
if ( pPlayer->m_iShotsFired > m_iAmmoLastCheck && (pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2)) )
|
|
fCrosshairDistanceGoal += iDeltaDistance;
|
|
|
|
m_iAmmoLastCheck = pPlayer->m_iShotsFired;
|
|
|
|
if ( m_flCrosshairDistance > fCrosshairDistanceGoal )
|
|
{
|
|
// [jpaquin] if we're not in legacy crosshair mode, use an exponential decay function so
|
|
// that the crosshair shrinks at the same rate regardless of the frame rate
|
|
if ( !cl_legacy_crosshair_recoil.GetBool() )
|
|
{
|
|
// .44888 on the next line makes the decay very close to what old method produces at 100fps.
|
|
m_flCrosshairDistance = Lerp(expf(-gpGlobals->frametime / 0.44888f), fCrosshairDistanceGoal, m_flCrosshairDistance);
|
|
}
|
|
else
|
|
{
|
|
m_flCrosshairDistance -= 0.1f + m_flCrosshairDistance * 0.013;
|
|
}
|
|
}
|
|
|
|
// clamp max crosshair expansion
|
|
m_flCrosshairDistance = clamp(m_flCrosshairDistance, fCrosshairDistanceGoal, 25.0f);
|
|
|
|
if ( cl_legacy_crosshair_scale.GetBool() )
|
|
{
|
|
//scale bar size to the resolution
|
|
int crosshairScale = cl_crosshairscale.GetInt();
|
|
if ( crosshairScale < 1 )
|
|
{
|
|
if ( ScreenHeight() <= 600 )
|
|
{
|
|
crosshairScale = 600;
|
|
}
|
|
else if ( ScreenHeight() <= 768 )
|
|
{
|
|
crosshairScale = 768;
|
|
}
|
|
else
|
|
{
|
|
crosshairScale = 1200;
|
|
}
|
|
}
|
|
|
|
float scale;
|
|
if( cl_scalecrosshair.GetBool() == false )
|
|
{
|
|
scale = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
scale = (float)ScreenHeight() / (float)crosshairScale;
|
|
}
|
|
|
|
// calculate the inner distance of the crosshair in current screen units
|
|
iCrosshairDistance = (int)ceil( m_flCrosshairDistance * scale );
|
|
|
|
iBarSize = XRES(5); // + (iCrosshairDistance - fCrosshairDistanceGoal) / 2;
|
|
iBarSize = MAX( 1, (int)( (float)iBarSize * scale ) );
|
|
iBarThickness = MAX( 1, (int)floor( scale + 0.5f ) );
|
|
}
|
|
else
|
|
{
|
|
iCrosshairDistance = RoundFloatToInt(m_flCrosshairDistance * ScreenHeight() / 1200.0f);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
int iCenterX = ScreenWidth() / 2;
|
|
int iCenterY = ScreenHeight() / 2;
|
|
|
|
if ( bCrosshairVisible )
|
|
{
|
|
// draw horizontal crosshair lines
|
|
int iInnerLeft = iCenterX - iCrosshairDistance - iBarThickness / 2;
|
|
int iInnerRight = iInnerLeft + 2 * iCrosshairDistance + iBarThickness;
|
|
int iOuterLeft = iInnerLeft - iBarSize;
|
|
int iOuterRight = iInnerRight + iBarSize;
|
|
int y0 = iCenterY - iBarThickness / 2;
|
|
int y1 = y0 + iBarThickness;
|
|
DrawCrosshairRect( iOuterLeft, y0, iInnerLeft, y1, bAdditive );
|
|
DrawCrosshairRect( iInnerRight, y0, iOuterRight, y1, bAdditive );
|
|
|
|
// draw vertical crosshair lines
|
|
int iInnerTop = iCenterY - iCrosshairDistance - iBarThickness / 2;
|
|
int iInnerBottom = iInnerTop + 2 * iCrosshairDistance + iBarThickness;
|
|
int iOuterTop = iInnerTop - iBarSize;
|
|
int iOuterBottom = iInnerBottom + iBarSize;
|
|
int x0 = iCenterX - iBarThickness / 2;
|
|
int x1 = x0 + iBarThickness;
|
|
DrawCrosshairRect( x0, iOuterTop, x1, iInnerTop, bAdditive );
|
|
DrawCrosshairRect( x0, iInnerBottom, x1, iOuterBottom, bAdditive );
|
|
|
|
// draw dot
|
|
if ( cl_crosshairdot.GetBool() )
|
|
{
|
|
int x0 = iCenterX - iBarThickness / 2;
|
|
int x1 = x0 + iBarThickness;
|
|
int y0 = iCenterY - iBarThickness / 2;
|
|
int y1 = y0 + iBarThickness;
|
|
DrawCrosshairRect( x0, y0, x1, y1, bAdditive );
|
|
}
|
|
}
|
|
|
|
#if ALLOW_WEAPON_SPREAD_DISPLAY
|
|
// show accuracy brackets
|
|
if ( weapon_debug_spread_show.GetInt() == 1 || weapon_debug_spread_show.GetInt() == 2 )
|
|
{
|
|
if ( weapon_debug_spread_show.GetInt() == 2 )
|
|
{
|
|
const QAngle& punchAngles = pPlayer->GetPunchAngle();
|
|
Vector vecDirShooting;
|
|
AngleVectors( punchAngles, &vecDirShooting );
|
|
|
|
float iOffsetX = RoundFloatToInt(YRES(vecDirShooting.y * 320.0f / tanf(fHalfFov)));
|
|
float iOffsetY = RoundFloatToInt(YRES(vecDirShooting.z * 320.0f / tanf(fHalfFov)));
|
|
|
|
iCenterX -= iOffsetX;
|
|
iCenterY -= iOffsetY;
|
|
}
|
|
|
|
// colors
|
|
r = 250;
|
|
g = 250;
|
|
b = 50;
|
|
vgui::surface()->DrawSetColor( r, g, b, alpha );
|
|
|
|
int iBarThickness = MAX( 1, RoundFloatToInt(YRES(cl_crosshairthickness.GetFloat())));
|
|
|
|
float fSpreadDistance = (GetInaccuracy() + GetSpread()) * 320.0f / tanf(fHalfFov);
|
|
int iSpreadDistance = RoundFloatToInt(YRES(fSpreadDistance));
|
|
|
|
// draw vertical spread lines
|
|
int iInnerLeft = iCenterX - iSpreadDistance;
|
|
int iInnerRight = iCenterX + iSpreadDistance;
|
|
int iOuterLeft = iInnerLeft - iBarThickness;
|
|
int iOuterRight = iInnerRight + iBarThickness;
|
|
int iInnerTop = iCenterY - iSpreadDistance;
|
|
int iInnerBottom = iCenterY + iSpreadDistance;
|
|
int iOuterTop = iInnerTop - iBarThickness;
|
|
int iOuterBottom = iInnerBottom + iBarThickness;
|
|
|
|
int iGap = RoundFloatToInt(weapon_debug_spread_gap.GetFloat() * iSpreadDistance);
|
|
|
|
// draw horizontal lines
|
|
DrawCrosshairRect( iOuterLeft, iOuterTop, iCenterX - iGap, iInnerTop, bAdditive );
|
|
DrawCrosshairRect( iCenterX + iGap, iOuterTop, iOuterRight, iInnerTop, bAdditive );
|
|
DrawCrosshairRect( iOuterLeft, iInnerBottom, iCenterX - iGap, iOuterBottom, bAdditive );
|
|
DrawCrosshairRect( iCenterX + iGap, iInnerBottom, iOuterRight, iOuterBottom, bAdditive );
|
|
|
|
// draw vertical lines
|
|
DrawCrosshairRect( iOuterLeft, iOuterTop, iInnerLeft, iCenterY - iGap, bAdditive );
|
|
DrawCrosshairRect( iOuterLeft, iCenterY + iGap, iInnerLeft, iOuterBottom, bAdditive );
|
|
DrawCrosshairRect( iInnerRight, iOuterTop, iOuterRight, iCenterY - iGap, bAdditive );
|
|
DrawCrosshairRect( iInnerRight, iCenterY + iGap, iOuterRight, iOuterBottom, bAdditive );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void CWeaponCSBase::OnDataChanged( DataUpdateType_t type )
|
|
{
|
|
BaseClass::OnDataChanged( type );
|
|
|
|
if ( GetPredictable() && !ShouldPredict() )
|
|
ShutdownPredictable();
|
|
}
|
|
|
|
|
|
bool CWeaponCSBase::ShouldPredict()
|
|
{
|
|
if ( GetOwner() && GetOwner() == C_BasePlayer::GetLocalPlayer() )
|
|
return true;
|
|
|
|
return BaseClass::ShouldPredict();
|
|
}
|
|
|
|
void CWeaponCSBase::ProcessMuzzleFlashEvent()
|
|
{
|
|
// This is handled from the player's animstate, so it can match up to the beginning of the fire animation
|
|
}
|
|
|
|
|
|
bool CWeaponCSBase::OnFireEvent( C_BaseViewModel *pViewModel, const Vector& origin, const QAngle& angles, int event, const char *options )
|
|
{
|
|
if( event == 5001 )
|
|
{
|
|
C_CSPlayer *pPlayer = ToCSPlayer( GetOwner() );
|
|
if( pPlayer && pPlayer->GetFOV() < pPlayer->GetDefaultFOV() && HideViewModelWhenZoomed() )
|
|
return true;
|
|
|
|
CEffectData data;
|
|
data.m_fFlags = 0;
|
|
data.m_hEntity = pViewModel->GetRefEHandle();
|
|
data.m_nAttachmentIndex = 1;
|
|
data.m_flScale = GetCSWpnData().m_flMuzzleScale;
|
|
|
|
switch( GetMuzzleFlashStyle() )
|
|
{
|
|
case CS_MUZZLEFLASH_NONE:
|
|
break;
|
|
|
|
case CS_MUZZLEFLASH_X:
|
|
{
|
|
DispatchEffect( "CS_MuzzleFlash_X", data );
|
|
}
|
|
break;
|
|
|
|
case CS_MUZZLEFLASH_NORM:
|
|
default:
|
|
{
|
|
DispatchEffect( "CS_MuzzleFlash", data );
|
|
}
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return BaseClass::OnFireEvent( pViewModel, origin, angles, event, options );
|
|
}
|
|
|
|
int CWeaponCSBase::GetMuzzleFlashStyle( void )
|
|
{
|
|
return GetCSWpnData().m_iMuzzleFlashStyle;
|
|
}
|
|
|
|
int CWeaponCSBase::GetMuzzleAttachment( void )
|
|
{
|
|
return LookupAttachment( "muzzle_flash" );
|
|
}
|
|
|
|
#else
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Get the accuracy derived from weapon and player, and return it
|
|
//-----------------------------------------------------------------------------
|
|
const Vector& CWeaponCSBase::GetBulletSpread()
|
|
{
|
|
static Vector cone = VECTOR_CONE_8DEGREES;
|
|
return cone;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Match the anim speed to the weapon speed while crouching
|
|
//-----------------------------------------------------------------------------
|
|
float CWeaponCSBase::GetDefaultAnimSpeed()
|
|
{
|
|
return 1.0;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Draw the laser rifle effect
|
|
//-----------------------------------------------------------------------------
|
|
void CWeaponCSBase::BulletWasFired( const Vector &vecStart, const Vector &vecEnd )
|
|
{
|
|
}
|
|
|
|
|
|
bool CWeaponCSBase::ShouldRemoveOnRoundRestart()
|
|
{
|
|
if ( GetPlayerOwner() )
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// HPE_BEGIN:
|
|
// [dwenger] Handle round restart processing for the weapon.
|
|
//=============================================================================
|
|
|
|
void CWeaponCSBase::OnRoundRestart()
|
|
{
|
|
// Clear out the list of prior owners
|
|
m_PriorOwners.RemoveAll();
|
|
}
|
|
|
|
//=============================================================================
|
|
// HPE_END
|
|
//=============================================================================
|
|
|
|
//=========================================================
|
|
// Materialize - make a CWeaponCSBase visible and tangible
|
|
//=========================================================
|
|
void CWeaponCSBase::Materialize()
|
|
{
|
|
if ( IsEffectActive( EF_NODRAW ) )
|
|
{
|
|
// changing from invisible state to visible.
|
|
RemoveEffects( EF_NODRAW );
|
|
DoMuzzleFlash();
|
|
}
|
|
|
|
AddSolidFlags( FSOLID_TRIGGER );
|
|
|
|
//SetTouch( &CWeaponCSBase::DefaultTouch );
|
|
|
|
SetThink( NULL );
|
|
|
|
}
|
|
|
|
//=========================================================
|
|
// AttemptToMaterialize - the item is trying to rematerialize,
|
|
// should it do so now or wait longer?
|
|
//=========================================================
|
|
void CWeaponCSBase::AttemptToMaterialize()
|
|
{
|
|
float time = g_pGameRules->FlWeaponTryRespawn( this );
|
|
|
|
if ( time == 0 )
|
|
{
|
|
Materialize();
|
|
return;
|
|
}
|
|
|
|
SetNextThink( gpGlobals->curtime + time );
|
|
}
|
|
|
|
//=========================================================
|
|
// CheckRespawn - a player is taking this weapon, should
|
|
// it respawn?
|
|
//=========================================================
|
|
void CWeaponCSBase::CheckRespawn()
|
|
{
|
|
//GOOSEMAN : Do not respawn weapons!
|
|
return;
|
|
}
|
|
|
|
|
|
//=========================================================
|
|
// Respawn- this item is already in the world, but it is
|
|
// invisible and intangible. Make it visible and tangible.
|
|
//=========================================================
|
|
CBaseEntity* CWeaponCSBase::Respawn()
|
|
{
|
|
// make a copy of this weapon that is invisible and inaccessible to players (no touch function). The weapon spawn/respawn code
|
|
// will decide when to make the weapon visible and touchable.
|
|
CBaseEntity *pNewWeapon = CBaseEntity::Create( GetClassname(), g_pGameRules->VecWeaponRespawnSpot( this ), GetAbsAngles(), GetOwner() );
|
|
|
|
if ( pNewWeapon )
|
|
{
|
|
pNewWeapon->AddEffects( EF_NODRAW );// invisible for now
|
|
pNewWeapon->SetTouch( NULL );// no touch
|
|
pNewWeapon->SetThink( &CWeaponCSBase::AttemptToMaterialize );
|
|
|
|
UTIL_DropToFloor( this, MASK_SOLID );
|
|
|
|
// not a typo! We want to know when the weapon the player just picked up should respawn! This new entity we created is the replacement,
|
|
// but when it should respawn is based on conditions belonging to the weapon that was taken.
|
|
pNewWeapon->SetNextThink( gpGlobals->curtime + g_pGameRules->FlWeaponRespawnTime( this ) );
|
|
}
|
|
else
|
|
{
|
|
Msg( "Respawn failed to create %s!\n", GetClassname() );
|
|
}
|
|
|
|
return pNewWeapon;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
//-----------------------------------------------------------------------------
|
|
void CWeaponCSBase::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
|
|
{
|
|
CBasePlayer *pPlayer = ToBasePlayer( pActivator );
|
|
|
|
if ( pPlayer )
|
|
{
|
|
m_OnPlayerUse.FireOutput( pActivator, pCaller );
|
|
}
|
|
}
|
|
|
|
bool CWeaponCSBase::Reload()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return false;
|
|
|
|
pPlayer->m_iShotsFired = 0;
|
|
|
|
bool retval = BaseClass::Reload();
|
|
|
|
return retval;
|
|
}
|
|
|
|
void CWeaponCSBase::Spawn()
|
|
{
|
|
BaseClass::Spawn();
|
|
|
|
// Override the bloat that our base class sets as it's a little bit bigger than we want.
|
|
// If it's too big, you drop a weapon and its box is so big that you're still touching it
|
|
// when it falls and you pick it up again right away.
|
|
CollisionProp()->UseTriggerBounds( true, 30 );
|
|
|
|
// Set this here to allow players to shoot dropped weapons
|
|
SetCollisionGroup( COLLISION_GROUP_WEAPON );
|
|
|
|
SetExtraAmmoCount( m_iDefaultExtraAmmo ); //Start with no additional ammo
|
|
|
|
m_nextPrevOwnerTouchTime = 0.0;
|
|
m_prevOwner = NULL;
|
|
|
|
//=============================================================================
|
|
// HPE_BEGIN:
|
|
//=============================================================================
|
|
|
|
// [tj] initialize donor of this weapon
|
|
m_donor = NULL;
|
|
m_donated = false;
|
|
|
|
m_weaponMode = Primary_Mode;
|
|
|
|
//=============================================================================
|
|
// HPE_END
|
|
//=============================================================================
|
|
}
|
|
|
|
bool CWeaponCSBase::DefaultReload( int iClipSize1, int iClipSize2, int iActivity )
|
|
{
|
|
if ( BaseClass::DefaultReload( iClipSize1, iClipSize2, iActivity ) )
|
|
{
|
|
SendReloadEvents();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void CWeaponCSBase::SendReloadEvents()
|
|
{
|
|
CCSPlayer *pPlayer = dynamic_cast< CCSPlayer* >( GetOwner() );
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
// Send a message to any clients that have this entity to play the reload.
|
|
CPASFilter filter( pPlayer->GetAbsOrigin() );
|
|
filter.RemoveRecipient( pPlayer );
|
|
|
|
UserMessageBegin( filter, "ReloadEffect" );
|
|
WRITE_SHORT( pPlayer->entindex() );
|
|
MessageEnd();
|
|
|
|
// Make the player play his reload animation.
|
|
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_RELOAD );
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
bool CWeaponCSBase::DefaultPistolReload()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return false;
|
|
|
|
if (pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0)
|
|
return true;
|
|
|
|
if ( !DefaultReload( GetCSWpnData().iDefaultClip1, 0, ACT_VM_RELOAD ) )
|
|
return false;
|
|
|
|
pPlayer->m_iShotsFired = 0;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CWeaponCSBase::IsUseable()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return false;
|
|
|
|
if ( Clip1() <= 0 )
|
|
{
|
|
if ( pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) <= 0 && GetMaxClip1() != -1 )
|
|
{
|
|
// clip is empty (or nonexistant) and the player has no more ammo of this type.
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
#if defined( CLIENT_DLL )
|
|
|
|
float g_lateralBob = 0;
|
|
float g_verticalBob = 0;
|
|
|
|
static ConVar cl_bobcycle( "cl_bobcycle","0.8", FCVAR_CHEAT );
|
|
static ConVar cl_bob( "cl_bob","0.002", FCVAR_CHEAT );
|
|
static ConVar cl_bobup( "cl_bobup","0.5", FCVAR_CHEAT );
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Output : float
|
|
//-----------------------------------------------------------------------------
|
|
float CWeaponCSBase::CalcViewmodelBob( void )
|
|
{
|
|
static float bobtime;
|
|
static float lastbobtime;
|
|
static float lastspeed;
|
|
float cycle;
|
|
|
|
CBasePlayer *player = ToBasePlayer( GetOwner() );
|
|
//Assert( player );
|
|
|
|
//NOTENOTE: For now, let this cycle continue when in the air, because it snaps badly without it
|
|
|
|
if ( ( !gpGlobals->frametime ) ||
|
|
( player == NULL ) ||
|
|
( cl_bobcycle.GetFloat() <= 0.0f ) ||
|
|
( cl_bobup.GetFloat() <= 0.0f ) ||
|
|
( cl_bobup.GetFloat() >= 1.0f ) )
|
|
{
|
|
//NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
|
|
return 0.0f;// just use old value
|
|
}
|
|
|
|
//Find the speed of the player
|
|
float speed = player->GetLocalVelocity().Length2D();
|
|
float flmaxSpeedDelta = MAX( 0, (gpGlobals->curtime - lastbobtime) * 320.0f );
|
|
|
|
// don't allow too big speed changes
|
|
speed = clamp( speed, lastspeed-flmaxSpeedDelta, lastspeed+flmaxSpeedDelta );
|
|
speed = clamp( speed, -320, 320 );
|
|
|
|
lastspeed = speed;
|
|
|
|
//FIXME: This maximum speed value must come from the server.
|
|
// MaxSpeed() is not sufficient for dealing with sprinting - jdw
|
|
|
|
|
|
|
|
float bob_offset = RemapVal( speed, 0, 320, 0.0f, 1.0f );
|
|
|
|
bobtime += ( gpGlobals->curtime - lastbobtime ) * bob_offset;
|
|
lastbobtime = gpGlobals->curtime;
|
|
|
|
//Calculate the vertical bob
|
|
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());
|
|
}
|
|
|
|
g_verticalBob = speed*0.005f;
|
|
g_verticalBob = g_verticalBob*0.3 + g_verticalBob*0.7*sin(cycle);
|
|
|
|
g_verticalBob = clamp( g_verticalBob, -7.0f, 4.0f );
|
|
|
|
//Calculate the lateral bob
|
|
cycle = bobtime - (int)(bobtime/cl_bobcycle.GetFloat()*2)*cl_bobcycle.GetFloat()*2;
|
|
cycle /= cl_bobcycle.GetFloat()*2;
|
|
|
|
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());
|
|
}
|
|
|
|
g_lateralBob = speed*0.005f;
|
|
g_lateralBob = g_lateralBob*0.3 + g_lateralBob*0.7*sin(cycle);
|
|
g_lateralBob = clamp( g_lateralBob, -7.0f, 4.0f );
|
|
|
|
//NOTENOTE: We don't use this return value in our case (need to restructure the calculation function setup!)
|
|
return 0.0f;
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : &origin -
|
|
// &angles -
|
|
// viewmodelindex -
|
|
//-----------------------------------------------------------------------------
|
|
void CWeaponCSBase::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
|
|
{
|
|
Vector forward, right;
|
|
AngleVectors( angles, &forward, &right, NULL );
|
|
|
|
CalcViewmodelBob();
|
|
|
|
// Apply bob, but scaled down to 40%
|
|
VectorMA( origin, g_verticalBob * 0.4f, forward, origin );
|
|
|
|
// Z bob a bit more
|
|
origin[2] += g_verticalBob * 0.1f;
|
|
|
|
// bob the angles
|
|
angles[ ROLL ] += g_verticalBob * 0.5f;
|
|
angles[ PITCH ] -= g_verticalBob * 0.4f;
|
|
|
|
angles[ YAW ] -= g_lateralBob * 0.3f;
|
|
|
|
// VectorMA( origin, g_lateralBob * 0.2f, right, origin );
|
|
}
|
|
|
|
#else
|
|
|
|
void CWeaponCSBase::AddViewmodelBob( CBaseViewModel *viewmodel, Vector &origin, QAngle &angles )
|
|
{
|
|
|
|
}
|
|
|
|
float CWeaponCSBase::CalcViewmodelBob( void )
|
|
{
|
|
return 0.0f;
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifndef CLIENT_DLL
|
|
bool CWeaponCSBase::PhysicsSplash( const Vector ¢erPoint, const Vector &normal, float rawSpeed, float scaledSpeed )
|
|
{
|
|
if ( rawSpeed > 20 )
|
|
{
|
|
|
|
float size = 4.0f;
|
|
if ( !IsPistol() )
|
|
size += 2.0f;
|
|
|
|
// adjust splash size based on speed
|
|
size += RemapValClamped( rawSpeed, 0, 400, 0, 3 );
|
|
|
|
CEffectData data;
|
|
data.m_vOrigin = centerPoint;
|
|
data.m_vNormal = normal;
|
|
data.m_flScale = random->RandomFloat( size, size + 1.0f );
|
|
|
|
if ( GetWaterType() & CONTENTS_SLIME )
|
|
{
|
|
data.m_fFlags |= FX_WATER_IN_SLIME;
|
|
}
|
|
|
|
DispatchEffect( "gunshotsplash", data );
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif // !CLIENT_DLL
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *pPicker -
|
|
//-----------------------------------------------------------------------------
|
|
void CWeaponCSBase::OnPickedUp( CBaseCombatCharacter *pNewOwner )
|
|
{
|
|
#if !defined( CLIENT_DLL )
|
|
RemoveEffects( EF_ITEM_BLINK );
|
|
|
|
if( pNewOwner->IsPlayer() && pNewOwner->IsAlive() )
|
|
{
|
|
m_OnPlayerPickup.FireOutput(pNewOwner, this);
|
|
|
|
// Play the pickup sound for 1st-person observers
|
|
CRecipientFilter filter;
|
|
for ( int i=0; i<gpGlobals->maxClients; ++i )
|
|
{
|
|
CBasePlayer *player = UTIL_PlayerByIndex(i);
|
|
if ( player && !player->IsAlive() && player->GetObserverMode() == OBS_MODE_IN_EYE )
|
|
{
|
|
filter.AddRecipient( player );
|
|
}
|
|
}
|
|
if ( filter.GetRecipientCount() )
|
|
{
|
|
CBaseEntity::EmitSound( filter, pNewOwner->entindex(), "Player.PickupWeapon" );
|
|
}
|
|
|
|
// Robin: We don't want to delete weapons the player has picked up, so
|
|
// clear the name of the weapon. This prevents wildcards that are meant
|
|
// to find NPCs finding weapons dropped by the NPCs as well.
|
|
SetName( NULL_STRING );
|
|
}
|
|
|
|
// Someone picked me up, so make it so that I can't be removed.
|
|
SetRemoveable( false );
|
|
#endif
|
|
}
|
|
|
|
|
|
void CWeaponCSBase::UpdateAccuracyPenalty()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
const CCSWeaponInfo& weaponInfo = GetCSWpnData();
|
|
|
|
float fNewPenalty = 0.0f;
|
|
|
|
// on ladder?
|
|
if ( pPlayer->GetMoveType() == MOVETYPE_LADDER )
|
|
{
|
|
fNewPenalty += weaponInfo.m_fInaccuracyStand[m_weaponMode] + weaponInfo.m_fInaccuracyLadder[m_weaponMode];
|
|
}
|
|
// in the air?
|
|
// else if ( !FBitSet( pPlayer->GetFlags(), FL_ONGROUND ) )
|
|
// {
|
|
// fNewPenalty += weaponInfo.m_fInaccuracyStand[m_weaponMode] + weaponInfo.m_fInaccuracyJump[m_weaponMode];
|
|
// }
|
|
else if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING) )
|
|
{
|
|
fNewPenalty += weaponInfo.m_fInaccuracyCrouch[m_weaponMode];
|
|
}
|
|
else
|
|
{
|
|
fNewPenalty += weaponInfo.m_fInaccuracyStand[m_weaponMode];
|
|
}
|
|
|
|
if ( m_bInReload )
|
|
{
|
|
fNewPenalty += weaponInfo.m_fInaccuracyReload;
|
|
}
|
|
|
|
if ( fNewPenalty > m_fAccuracyPenalty )
|
|
{
|
|
m_fAccuracyPenalty = fNewPenalty;
|
|
}
|
|
else
|
|
{
|
|
float fDecayFactor;
|
|
|
|
if ( pPlayer->GetMoveType() == MOVETYPE_LADDER )
|
|
{
|
|
fDecayFactor = logf(10.0f) / weaponInfo.m_fRecoveryTimeStand;
|
|
}
|
|
else if ( !FBitSet(pPlayer->GetFlags(), FL_ONGROUND) ) // in air
|
|
{
|
|
// enforce a large recovery speed penalty (300%) for players in the air; this helps to provide
|
|
// comparable in-air accuracy to the old weapon model
|
|
fDecayFactor = logf(10.0f) / (weaponInfo.m_fRecoveryTimeCrouch * 3.0f);
|
|
}
|
|
else if ( FBitSet(pPlayer->GetFlags(), FL_DUCKING) )
|
|
{
|
|
fDecayFactor = logf(10.0f) / weaponInfo.m_fRecoveryTimeCrouch;
|
|
}
|
|
else
|
|
{
|
|
fDecayFactor = logf(10.0f) / weaponInfo.m_fRecoveryTimeStand;
|
|
}
|
|
m_fAccuracyPenalty = Lerp(expf(TICK_INTERVAL * -fDecayFactor), fNewPenalty, (float)m_fAccuracyPenalty);
|
|
}
|
|
}
|
|
|
|
|
|
const float kJumpVelocity = sqrtf(2.0f * 800.0f * 57.0f); // see CCSGameMovement::CheckJumpButton()
|
|
|
|
void CWeaponCSBase::OnJump( float fImpulse )
|
|
{
|
|
m_fAccuracyPenalty += GetCSWpnData().m_fInaccuracyJump[m_weaponMode] * fImpulse / kJumpVelocity;
|
|
}
|
|
|
|
void CWeaponCSBase::OnLand( float fVelocity )
|
|
{
|
|
float fPenalty = GetCSWpnData().m_fInaccuracyLand[m_weaponMode] * fVelocity / kJumpVelocity;
|
|
m_fAccuracyPenalty += fPenalty;
|
|
|
|
/*
|
|
// this bit of code is only if we want to punch the player view on all landings
|
|
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
QAngle angle = pPlayer->GetPunchAngle();
|
|
float fVKick = RAD2DEG(asinf(fPenalty)) * 0.4f;
|
|
float fHKick = SharedRandomFloat("LandPunchAngleYaw", -1.0f, +1.0f) * fVKick * 0.1f;
|
|
|
|
angle.x += fVKick; // pitch
|
|
angle.y += fHKick; // yaw
|
|
pPlayer->SetPunchAngle( angle );
|
|
*/
|
|
}
|