diff options
Diffstat (limited to 'game/shared/cstrike/weapon_csbase.cpp')
| -rw-r--r-- | game/shared/cstrike/weapon_csbase.cpp | 1917 |
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 ¢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 ); +*/ +} |