summaryrefslogtreecommitdiff
path: root/game/shared/cstrike/weapon_csbase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/cstrike/weapon_csbase.cpp')
-rw-r--r--game/shared/cstrike/weapon_csbase.cpp1917
1 files changed, 1917 insertions, 0 deletions
diff --git a/game/shared/cstrike/weapon_csbase.cpp b/game/shared/cstrike/weapon_csbase.cpp
new file mode 100644
index 0000000..8063b91
--- /dev/null
+++ b/game/shared/cstrike/weapon_csbase.cpp
@@ -0,0 +1,1917 @@
+//========= 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 &centerPoint, 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 );
+*/
+}