|
|
//========= 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 ); */ }
|