You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
953 lines
26 KiB
953 lines
26 KiB
//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=============================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "weapon_csbasegun.h"
|
|
#include "fx_cs_shared.h"
|
|
#include "in_buttons.h"
|
|
|
|
#ifdef CLIENT_DLL
|
|
#include "c_cs_player.h"
|
|
#include "cs_client_gamestats.h"
|
|
#include "cdll_client_int.h"
|
|
#else
|
|
#include "cs_player.h"
|
|
#endif
|
|
|
|
// NOTE: This has to be the last file included!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
#define DETACHABLE_SILENCER 1
|
|
#define SILENCER_BODYGROUP_UNSET -2
|
|
|
|
IMPLEMENT_NETWORKCLASS_ALIASED( WeaponCSBaseGun, DT_WeaponCSBaseGun )
|
|
|
|
BEGIN_NETWORK_TABLE( CWeaponCSBaseGun, DT_WeaponCSBaseGun )
|
|
#if defined( GAME_DLL )
|
|
SendPropInt( SENDINFO( m_zoomLevel ), 2, SPROP_UNSIGNED ),
|
|
SendPropInt( SENDINFO( m_iBurstShotsRemaining ) ),
|
|
#else
|
|
RecvPropInt( RECVINFO( m_zoomLevel ) ),
|
|
RecvPropInt( RECVINFO( m_iBurstShotsRemaining ) ),
|
|
#endif
|
|
|
|
END_NETWORK_TABLE()
|
|
|
|
#if defined( CLIENT_DLL )
|
|
BEGIN_PREDICTION_DATA( CWeaponCSBaseGun )
|
|
DEFINE_PRED_FIELD( m_zoomLevel, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_iBurstShotsRemaining, FIELD_INTEGER, FTYPEDESC_INSENDTABLE ),
|
|
DEFINE_PRED_FIELD( m_fNextBurstShot, FIELD_FLOAT, 0 ),
|
|
END_PREDICTION_DATA()
|
|
#endif
|
|
|
|
LINK_ENTITY_TO_CLASS_ALIASED( weapon_csbase_gun, WeaponCSBaseGun );
|
|
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( AK47, WeaponCSBaseGun, DT_WeaponAK47, weapon_ak47 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponAug, WeaponCSBaseGun, DT_WeaponAug, weapon_aug );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponAWP, WeaponCSBaseGun, DT_WeaponAWP, weapon_awp );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponBizon, WeaponCSBaseGun, DT_WeaponBizon, weapon_bizon );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponFamas, WeaponCSBaseGun, DT_WeaponFamas, weapon_famas );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponFiveSeven, WeaponCSBaseGun, DT_WeaponFiveSeven, weapon_fiveseven );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponG3SG1, WeaponCSBaseGun, DT_WeaponG3SG1, weapon_g3sg1 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponGalil, WeaponCSBaseGun, DT_WeaponGalil, weapon_galil );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponGalilAR, WeaponCSBaseGun, DT_WeaponGalilAR, weapon_galilar );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponGlock, WeaponCSBaseGun, DT_WeaponGlock, weapon_glock );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponHKP2000, WeaponCSBaseGun, DT_WeaponHKP2000, weapon_hkp2000 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponM4A1, WeaponCSBaseGun, DT_WeaponM4A1, weapon_m4a1 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponMAC10, WeaponCSBaseGun, DT_WeaponMAC10, weapon_mac10 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponMag7, WeaponCSBaseGun, DT_WeaponMag7, weapon_mag7 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponMP5Navy, WeaponCSBaseGun, DT_WeaponMP5Navy, weapon_mp5navy );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponMP7, WeaponCSBaseGun, DT_WeaponMP7, weapon_mp7 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponMP9, WeaponCSBaseGun, DT_WeaponMP9, weapon_mp9 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponNegev, WeaponCSBaseGun, DT_WeaponNegev, weapon_negev );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponP228, WeaponCSBaseGun, DT_WeaponP228, weapon_p228 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponP250, WeaponCSBaseGun, DT_WeaponP250, weapon_p250 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponP90, WeaponCSBaseGun, DT_WeaponP90, weapon_p90 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( SCAR17, WeaponCSBaseGun, DT_WeaponSCAR17, weapon_scar17 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponSCAR20, WeaponCSBaseGun, DT_WeaponSCAR20, weapon_scar20 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponScout, WeaponCSBaseGun, DT_WeaponScout, weapon_scout );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponSG550, WeaponCSBaseGun, DT_WeaponSG550, weapon_sg550 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponSG556, WeaponCSBaseGun, DT_WeaponSG556, weapon_sg556 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponSSG08, WeaponCSBaseGun, DT_WeaponSSG08, weapon_ssg08 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponTec9, WeaponCSBaseGun, DT_WeaponTec9, weapon_tec9 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponTMP, WeaponCSBaseGun, DT_WeaponTMP, weapon_tmp );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponUMP45, WeaponCSBaseGun, DT_WeaponUMP45, weapon_ump45 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponM249, WeaponCSBaseGun, DT_WeaponM249, weapon_m249 );
|
|
LINK_ENTITY_TO_CLASS_SIMPLE_DERIVED( WeaponUSP, WeaponCSBaseGun, DT_WeaponUSP, weapon_usp );
|
|
|
|
CWeaponCSBaseGun::CWeaponCSBaseGun()
|
|
{
|
|
m_pWeaponInfo = NULL;
|
|
m_zoomLevel = 0;
|
|
m_inPrecache = false;
|
|
#ifdef CLIENT_DLL
|
|
m_iSilencerBodygroup = SILENCER_BODYGROUP_UNSET;
|
|
#endif
|
|
}
|
|
|
|
void CWeaponCSBaseGun::Spawn( )
|
|
{
|
|
BaseClass::Spawn();
|
|
|
|
m_bBurstMode = false;
|
|
m_iBurstShotsRemaining = 0;
|
|
m_fNextBurstShot = 0.0f;
|
|
ResetPostponeFireReadyTime();
|
|
}
|
|
|
|
|
|
void CWeaponCSBaseGun::Precache()
|
|
{
|
|
m_inPrecache = true;
|
|
BaseClass::Precache();
|
|
m_inPrecache = false;
|
|
}
|
|
|
|
|
|
const char * CWeaponCSBaseGun::GetWorldModel( void ) const
|
|
{
|
|
return BaseClass::GetWorldModel();
|
|
}
|
|
|
|
Activity CWeaponCSBaseGun::GetDeployActivity( void )
|
|
{
|
|
if( IsSilenced() )
|
|
{
|
|
return ACT_VM_DRAW_SILENCED;
|
|
}
|
|
else
|
|
{
|
|
return BaseClass::GetDeployActivity();
|
|
}
|
|
}
|
|
|
|
|
|
void CWeaponCSBaseGun::Drop( const Vector &vecVelocity )
|
|
{
|
|
// re-deploying the weapon is punishment enough for canceling a silencer attach/detach before completion
|
|
if ( (GetActivity() == ACT_VM_ATTACH_SILENCER && m_bSilencerOn == false) ||
|
|
(GetActivity() == ACT_VM_DETACH_SILENCER && m_bSilencerOn == true ) )
|
|
{
|
|
m_flDoneSwitchingSilencer = gpGlobals->curtime;
|
|
m_flNextSecondaryAttack = gpGlobals->curtime;
|
|
m_flNextPrimaryAttack = gpGlobals->curtime;
|
|
}
|
|
|
|
//make sure the world-model silencer bodygroup is correct, we might have hidden/unhidden it prematurely to make the 3rd-person animation look correct
|
|
else if ( (GetActivity() == ACT_VM_ATTACH_SILENCER) || (GetActivity() == ACT_VM_DETACH_SILENCER) )
|
|
{
|
|
int iBodyGroup = FindBodygroupByName( "silencer" );
|
|
if ( iBodyGroup != -1 )
|
|
SetBodygroup( iBodyGroup, m_bSilencerOn ? 0 : 1 );
|
|
}
|
|
|
|
BaseClass::Drop( vecVelocity );
|
|
}
|
|
|
|
void CWeaponCSBaseGun::ItemBusyFrame()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
// if we're scoped during a reload, pull us out of the scope for the duration (and set resumezoom so we'll re-zoom when reloading is done)
|
|
if ( HasZoom() && (IsZoomed() || pPlayer->m_bIsScoped) && m_bInReload )
|
|
{
|
|
//m_zoomLevel = 0; //don't affect zoom level, so it'll restore when reloading is done
|
|
pPlayer->m_bIsScoped = false;
|
|
pPlayer->m_bResumeZoom = true;
|
|
pPlayer->SetFOV( pPlayer, GetZoomFOV( 0 ), GetZoomTime( 0 ) );
|
|
m_weaponMode = Primary_Mode;
|
|
}
|
|
|
|
BaseClass::ItemBusyFrame();
|
|
}
|
|
|
|
void CWeaponCSBaseGun::ItemPostFrame()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
// smoother out the accuracy a bit
|
|
//float flFOV = GetFOVForAccuracy();
|
|
|
|
//GOOSEMAN : Return zoom level back to previous zoom level before we fired a shot. This is used only for the AWP.
|
|
// And Scout.
|
|
if ( (m_flNextPrimaryAttack <= gpGlobals->curtime) && (pPlayer->m_bResumeZoom == TRUE)
|
|
&& m_zoomLevel > 0 ) // only need to re-zoom the zoom when there's a zoom to re-zoom to. who knew?
|
|
{
|
|
if ( m_iClip1 != 0 || ( GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD ) )
|
|
{
|
|
m_weaponMode = Secondary_Mode;
|
|
// the zoom amount is taking care of below
|
|
pPlayer->SetFOV( pPlayer, GetZoomFOV( m_zoomLevel ), 0.1f );
|
|
m_fScopeZoomEndTime = gpGlobals->curtime + 0.1;
|
|
pPlayer->m_bIsScoped = true;
|
|
#ifdef CLIENT_DLL
|
|
/*
|
|
ScreenFade_t fade;
|
|
fade.duration = ( unsigned short )( ( float )( 1 << SCREENFADE_FRACBITS ) * 0.175 );
|
|
fade.holdTime = ( unsigned short )( ( float )( 1 << SCREENFADE_FRACBITS ) * 0 );
|
|
|
|
fade.fadeFlags = 0;
|
|
fade.fadeFlags |= FFADE_IN;
|
|
|
|
fade.r = 0;
|
|
fade.g = 0;
|
|
fade.b = 0;
|
|
fade.a = 255;
|
|
|
|
clientdll->View_Fade( &fade );
|
|
*/
|
|
#endif
|
|
}
|
|
|
|
pPlayer->m_bResumeZoom = false;
|
|
}
|
|
|
|
/*
|
|
// do this for sniper rifles only and only when the initial zoom has finished zooming
|
|
if ( GetCSWpnData().m_iZoomLevels >= 2 && (m_fScopeZoomEndTime <= gpGlobals->curtime) && m_weaponMode == Secondary_Mode )
|
|
{
|
|
// if we're zoomed in
|
|
if ( IsZoomed() )
|
|
{
|
|
// this is the zoom we are suppoed to be at if we're standing still
|
|
|
|
float flFOVDiff = MAX( 0, flFOV - pPlayer->GetFOV() );
|
|
|
|
flFOV = ceil( flFOV );
|
|
if ( flFOV < 0 )
|
|
flFOV *= -1;
|
|
|
|
if ( flFOVDiff >= 1.0f )
|
|
{
|
|
flFOVDiff = MIN( flFOVDiff, 10.0f )/50;
|
|
if ( flFOVDiff < 0.05f )
|
|
flFOVDiff = 0;
|
|
|
|
pPlayer->SetFOV( pPlayer, flFOV, flFOVDiff );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
m_fAccuracySmoothedForZoom = 0;
|
|
}
|
|
}
|
|
*/
|
|
|
|
if ( WeaponHasBurst() )
|
|
{
|
|
if ( m_iBurstShotsRemaining > 0 && gpGlobals->curtime >= m_fNextBurstShot )
|
|
{
|
|
BurstFireRemaining();
|
|
}
|
|
}
|
|
|
|
|
|
BaseClass::ItemPostFrame();
|
|
}
|
|
|
|
bool CWeaponCSBaseGun::SendWeaponAnim( int iActivity )
|
|
{
|
|
#ifndef CLIENT_DLL
|
|
// firing or reloading should interrupt weapon inspection
|
|
if ( iActivity == ACT_VM_PRIMARYATTACK || iActivity == ACT_VM_RELOAD || iActivity == ACT_SECONDARY_VM_RELOAD || iActivity == ACT_VM_ATTACH_SILENCER || iActivity == ACT_VM_DETACH_SILENCER )
|
|
{
|
|
if ( CCSPlayer *pPlayer = GetPlayerOwner() )
|
|
{
|
|
pPlayer->StopLookingAtWeapon();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return BaseClass::SendWeaponAnim( iActivity );
|
|
}
|
|
|
|
float CWeaponCSBaseGun::GetFOVForAccuracy( void )
|
|
{
|
|
const CCSWeaponInfo& weaponInfo = GetCSWpnData();
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return 0;
|
|
|
|
float flDefaultAccuracy = weaponInfo.GetInaccuracyStand( GetEconItemView(), m_weaponMode );
|
|
// if ( pPlayer->GetMoveType() == MOVETYPE_LADDER )
|
|
// {
|
|
// flDefaultAccuracy = weaponInfo.GetInaccuracyLadder( m_weaponMode, GetEconItemView() ) + weaponInfo.GetInaccuracyLadder( 0, GetEconItemView() );
|
|
// }
|
|
if ( FBitSet( pPlayer->GetFlags(), FL_DUCKING ) )
|
|
{
|
|
flDefaultAccuracy = weaponInfo.GetInaccuracyCrouch( GetEconItemView(), m_weaponMode );
|
|
}
|
|
|
|
m_fAccuracySmoothedForZoom = Approach( GetInaccuracy(), m_fAccuracySmoothedForZoom, gpGlobals->frametime * 10.0f );
|
|
float flTargetFOVForZoom = GetZoomFOV( m_zoomLevel );
|
|
float flFOV = flTargetFOVForZoom;
|
|
|
|
// and apply it to the player's fov
|
|
if ( m_fAccuracySmoothedForZoom >= 0 )
|
|
{
|
|
flFOV = flTargetFOVForZoom - ( m_fAccuracySmoothedForZoom - flDefaultAccuracy ) * 10;//MIN( flTargetFOVForZoom * ( 1 + ( m_fAccuracySmoothedForZoom*2 ) ), flTargetFOVForZoom * ( 1 + ( m_fAccuracySmoothedForZoom ) ) );
|
|
//Msg( "flFOV = %f\n", flFOV );
|
|
}
|
|
|
|
return flFOV;
|
|
}
|
|
|
|
void CWeaponCSBaseGun::PrimaryAttack()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return;
|
|
|
|
if ( CannotShootUnderwater() )
|
|
{
|
|
PlayEmptySound();
|
|
m_flNextPrimaryAttack = gpGlobals->curtime + 0.15f;
|
|
return;
|
|
}
|
|
|
|
float flCycleTime = GetCycleTime();
|
|
|
|
// change a few things if we're in burst mode
|
|
if ( IsInBurstMode() )
|
|
{
|
|
CALL_ATTRIB_HOOK_FLOAT( flCycleTime, cycletime_when_in_burst_mode );
|
|
|
|
m_iBurstShotsRemaining = 2;
|
|
|
|
m_fNextBurstShot = gpGlobals->curtime;
|
|
CALL_ATTRIB_HOOK_FLOAT( m_fNextBurstShot, time_between_burst_shots );
|
|
}
|
|
|
|
if ( IsZoomed() )
|
|
{
|
|
CALL_ATTRIB_HOOK_FLOAT( flCycleTime, cycletime_when_zoomed );
|
|
}
|
|
|
|
if ( !CSBaseGunFire( flCycleTime, m_weaponMode ) ) // <-- 'PEW PEW' HAPPENS HERE
|
|
return;
|
|
|
|
if ( IsSilenced() )
|
|
SendWeaponAnim( ACT_VM_PRIMARYATTACK_SILENCED );
|
|
|
|
// Does this gun unzoom after a shot, as in a bolt action rifle?
|
|
if ( IsZoomed() && ( DoesUnzoomAfterShot() ) )
|
|
{
|
|
pPlayer->m_bIsScoped = false;
|
|
pPlayer->m_bResumeZoom = true;
|
|
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), 0.05f );
|
|
m_weaponMode = Primary_Mode;
|
|
}
|
|
}
|
|
|
|
void CWeaponCSBaseGun::SecondaryAttack()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( pPlayer == NULL )
|
|
{
|
|
Assert(pPlayer != NULL);
|
|
return;
|
|
}
|
|
|
|
if ( HasZoom() )
|
|
{
|
|
if ( ++m_zoomLevel > GetZoomLevels() )
|
|
m_zoomLevel = 0;
|
|
|
|
bool bIsSniperRifle = GetWeaponType() == WEAPONTYPE_SNIPER_RIFLE;
|
|
|
|
if ( IsZoomed() )
|
|
{
|
|
m_weaponMode = Secondary_Mode;
|
|
|
|
//float flFOV = GetFOVForAccuracy();
|
|
|
|
if ( bIsSniperRifle )
|
|
pPlayer->SetFOV( pPlayer, GetZoomFOV( m_zoomLevel ), GetZoomTime( m_zoomLevel) );
|
|
|
|
m_fAccuracyPenalty += GetCSWpnData().GetInaccuracyAltSwitch();
|
|
m_fAccuracySmoothedForZoom = 0;
|
|
|
|
pPlayer->m_bIsScoped = true;
|
|
|
|
#ifdef IRONSIGHT
|
|
|
|
if ( pPlayer->GetActiveCSWeapon() )
|
|
{
|
|
CIronSightController *pIronSightController = pPlayer->GetActiveCSWeapon()->GetIronSightController();
|
|
if (pIronSightController)
|
|
{
|
|
pPlayer->GetActiveCSWeapon()->UpdateIronSightController();
|
|
pPlayer->SetFOV(pPlayer, pIronSightController->GetIronSightIdealFOV(), pIronSightController->GetIronSightPullUpDuration());
|
|
pIronSightController->SetState( IronSight_should_approach_sighted );
|
|
|
|
//stop looking at weapon when going into ironsights
|
|
#ifndef CLIENT_DLL
|
|
pPlayer->StopLookingAtWeapon();
|
|
|
|
//force idle animation
|
|
CBaseViewModel *pViewModel = pPlayer->GetViewModel();
|
|
if (pViewModel)
|
|
{
|
|
int nSequence = pViewModel->LookupSequence("idle");
|
|
if (nSequence != ACTIVITY_NOT_AVAILABLE)
|
|
{
|
|
pViewModel->ForceCycle(0);
|
|
pViewModel->ResetSequence(nSequence);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
else
|
|
{
|
|
m_weaponMode = Primary_Mode;
|
|
|
|
if ( bIsSniperRifle )
|
|
{
|
|
int iFOV = FBitSet( pPlayer->GetFlags(), FL_DUCKING ) ? pPlayer->GetDefaultCrouchedFOV() : pPlayer->GetDefaultFOV();
|
|
pPlayer->SetFOV( pPlayer, iFOV, GetZoomTime( 0 ));
|
|
}
|
|
|
|
m_fAccuracySmoothedForZoom = 0;
|
|
pPlayer->m_bIsScoped = false;
|
|
|
|
#ifdef IRONSIGHT
|
|
if ( pPlayer->GetActiveCSWeapon() )
|
|
{
|
|
CIronSightController *pIronSightController = pPlayer->GetActiveCSWeapon()->GetIronSightController();
|
|
if (pIronSightController)
|
|
{
|
|
pPlayer->GetActiveCSWeapon()->UpdateIronSightController();
|
|
int iFOV = FBitSet(pPlayer->GetFlags(), FL_DUCKING) ? pPlayer->GetDefaultCrouchedFOV() : pPlayer->GetDefaultFOV();
|
|
pPlayer->SetFOV(pPlayer, iFOV, pIronSightController->GetIronSightPutDownDuration());
|
|
pIronSightController->SetState(IronSight_should_approach_unsighted);
|
|
SendWeaponAnim(ACT_VM_FIDGET);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef CLIENT_DLL
|
|
/*
|
|
if ( GetPlayerOwner() && ( bIsSniperRifle && IsZoomed() && m_zoomLevel == 1 ) )
|
|
{
|
|
ScreenFade_t fade;
|
|
fade.duration = ( unsigned short )( ( float )( 1 << SCREENFADE_FRACBITS ) * 0.22 );
|
|
fade.holdTime = ( unsigned short )( ( float )( 1 << SCREENFADE_FRACBITS ) * 0 );
|
|
|
|
fade.fadeFlags = 0;
|
|
fade.fadeFlags |= FFADE_IN;
|
|
|
|
fade.r = 0;
|
|
fade.g = 0;
|
|
fade.b = 0;
|
|
fade.a = 255;
|
|
|
|
clientdll->View_Fade( &fade );
|
|
}
|
|
*/
|
|
#endif
|
|
|
|
#ifndef CLIENT_DLL
|
|
|
|
|
|
// If this isn't guarded, the sound will be emitted twice, once by the server and once by the client.
|
|
// Let the server play it since if only the client plays it, it's liable to get played twice cause of
|
|
// a prediction error. joy.
|
|
|
|
// [tj] Playing this from the player so that we don't try to play the sound outside the level.
|
|
if ( GetPlayerOwner() )
|
|
{
|
|
if ( IsZoomed() )
|
|
{
|
|
const char *pszZoomSound = GetZoomInSound();
|
|
if ( pszZoomSound && pszZoomSound[0] )
|
|
{
|
|
GetPlayerOwner()->EmitSound( pszZoomSound );
|
|
}
|
|
|
|
//if ( !bIsSniperRifle )
|
|
//{
|
|
// color32 clr = {0, 0, 0, 200};
|
|
// float flZoomTime = weaponInfo.m_fZoomTime[m_zoomLevel];
|
|
// float flBlackTime = MAX( flZoomTime/15, 0.02 );
|
|
// UTIL_ScreenFade( pPlayer, clr, flBlackTime, (flZoomTime - (flZoomTime/5)) - flBlackTime, FFADE_IN );
|
|
//}
|
|
}
|
|
else
|
|
{
|
|
const char *pszZoomSound = GetZoomOutSound();
|
|
if ( pszZoomSound && pszZoomSound[0] )
|
|
{
|
|
GetPlayerOwner()->EmitSound( pszZoomSound );
|
|
}
|
|
|
|
//if ( !bIsSniperRifle )
|
|
//{
|
|
// color32 clr = {0, 0, 0, 175};
|
|
// float flZoomTime = weaponInfo.m_fZoomTime[0];
|
|
// float flBlackTime = MAX( flZoomTime/15, 0.02 );
|
|
// UTIL_ScreenFade( pPlayer, clr, flBlackTime, flZoomTime - flBlackTime, FFADE_OUT );
|
|
//}
|
|
}
|
|
|
|
if ( bIsSniperRifle )
|
|
{
|
|
// let the bots hear the sniper rifle zoom
|
|
IGameEvent * event = gameeventmanager->CreateEvent( "weapon_zoom" );
|
|
if ( event )
|
|
{
|
|
event->SetInt( "userid", pPlayer->GetUserID() );
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// exists for the game instructor to let it know when the player zoomed in with a regular rifle
|
|
// different from the above weapon_zoom because we don't use this event to notify bots
|
|
IGameEvent * event = gameeventmanager->CreateEvent( "weapon_zoom_rifle" );
|
|
if ( event )
|
|
{
|
|
event->SetInt( "userid", pPlayer->GetUserID() );
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
m_fScopeZoomEndTime = gpGlobals->curtime + GetZoomTime( m_zoomLevel );
|
|
}
|
|
#ifndef CLIENT_DLL
|
|
else if ( WeaponHasBurst() )
|
|
{
|
|
if ( IsInBurstMode() )
|
|
{
|
|
pPlayer->HintMessage( "#Cstrike_TitlesTXT_Switch_To_FullAuto", false );
|
|
m_bBurstMode = false;
|
|
m_weaponMode = Primary_Mode;
|
|
}
|
|
else
|
|
{
|
|
pPlayer->HintMessage( "#Cstrike_TitlesTXT_Switch_To_BurstFire", false );
|
|
m_bBurstMode = true;
|
|
m_weaponMode = Secondary_Mode;
|
|
}
|
|
|
|
pPlayer->EmitSound( "Weapon.AutoSemiAutoSwitch" );
|
|
}
|
|
#endif
|
|
#if DETACHABLE_SILENCER
|
|
else if ( HasSilencer() && m_flDoneSwitchingSilencer <= gpGlobals->curtime )
|
|
{
|
|
if ( m_bSilencerOn )
|
|
{
|
|
SendWeaponAnim( ACT_VM_DETACH_SILENCER );
|
|
|
|
#ifndef CLIENT_DLL
|
|
SendActivityEvents( ACT_VM_DETACH_SILENCER );
|
|
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_SILENCER_DETACH );
|
|
|
|
IGameEvent * event = gameeventmanager->CreateEvent( "silencer_detach" );
|
|
if ( event )
|
|
{
|
|
event->SetInt( "userid", pPlayer->GetUserID() );
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
SendWeaponAnim( ACT_VM_ATTACH_SILENCER );
|
|
|
|
#ifndef CLIENT_DLL
|
|
SendActivityEvents( ACT_VM_ATTACH_SILENCER );
|
|
pPlayer->DoAnimationEvent( PLAYERANIMEVENT_SILENCER_ATTACH );
|
|
#endif
|
|
}
|
|
|
|
float nextAttackTime = gpGlobals->curtime + SequenceDuration();
|
|
|
|
m_flDoneSwitchingSilencer = nextAttackTime;
|
|
m_flNextSecondaryAttack = nextAttackTime;
|
|
m_flNextPrimaryAttack = nextAttackTime;
|
|
SetWeaponIdleTime( nextAttackTime );
|
|
|
|
}
|
|
#endif
|
|
else if ( IsRevolver() && m_flNextSecondaryAttack < gpGlobals->curtime )
|
|
{
|
|
float flCycletimeAlt = GetCycleTime( Secondary_Mode );
|
|
m_weaponMode = Secondary_Mode;
|
|
UpdateAccuracyPenalty();
|
|
#ifndef CLIENT_DLL
|
|
// Logic for weapon_fire event mimics weapon_csbase.cpp CWeaponCSBase::ItemPostFrame() primary fire implementation
|
|
IGameEvent * event = gameeventmanager->CreateEvent( ( HasAmmo() ) ? "weapon_fire" : "weapon_fire_on_empty" );
|
|
if ( event )
|
|
{
|
|
const char *weaponName = GetDefinitionName();
|
|
event->SetInt( "userid", pPlayer->GetUserID() );
|
|
event->SetString( "weapon", weaponName );
|
|
event->SetBool( "silenced", IsSilenced() );
|
|
gameeventmanager->FireEvent( event );
|
|
}
|
|
#endif
|
|
CSBaseGunFire( flCycletimeAlt, Secondary_Mode ); // <-- 'PEW PEW' HAPPENS HERE
|
|
m_flNextSecondaryAttack = gpGlobals->curtime + flCycletimeAlt;
|
|
return;
|
|
}
|
|
|
|
else
|
|
{
|
|
BaseClass::SecondaryAttack();
|
|
}
|
|
|
|
m_flNextSecondaryAttack = gpGlobals->curtime + 0.3f;
|
|
}
|
|
|
|
void CWeaponCSBaseGun::BurstFireRemaining()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer || m_iClip1 <= 0 )
|
|
{
|
|
m_iClip1 = 0;
|
|
m_iBurstShotsRemaining = 0;
|
|
m_fNextBurstShot = 0.0f;
|
|
return;
|
|
}
|
|
|
|
uint16 nItemDefIndex = 0;
|
|
|
|
FX_FireBullets(
|
|
pPlayer->entindex(),
|
|
nItemDefIndex,
|
|
pPlayer->Weapon_ShootPosition(),
|
|
pPlayer->GetFinalAimAngle(),
|
|
GetCSWeaponID(),
|
|
Secondary_Mode,
|
|
CBaseEntity::GetPredictionRandomSeed( SERVER_PLATTIME_RNG ) & 255,
|
|
GetInaccuracy(),
|
|
GetSpread(),
|
|
GetAccuracyFishtail(),
|
|
m_fNextBurstShot,
|
|
(HasSilencer() && IsSilenced()) ? SPECIAL1 : SINGLE,
|
|
m_flRecoilIndex );
|
|
|
|
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
|
|
|
pPlayer->DoMuzzleFlash();
|
|
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
--m_iBurstShotsRemaining;
|
|
|
|
if ( m_iBurstShotsRemaining > 0 )
|
|
{
|
|
CALL_ATTRIB_HOOK_FLOAT( m_fNextBurstShot, time_between_burst_shots );
|
|
}
|
|
else
|
|
{
|
|
m_fNextBurstShot = 0.0f;
|
|
}
|
|
|
|
const CCSWeaponInfo& weaponInfo = GetCSWpnData();
|
|
|
|
// update accuracy
|
|
m_fAccuracyPenalty += weaponInfo.GetInaccuracyFire( GetEconItemView(), m_weaponMode );
|
|
|
|
// table driven recoil
|
|
Recoil( Secondary_Mode );
|
|
|
|
++pPlayer->m_iShotsFired;
|
|
m_flRecoilIndex += 1.0f;
|
|
--m_iClip1;
|
|
}
|
|
|
|
bool CWeaponCSBaseGun::CSBaseGunFire( float flCycleTime, CSWeaponMode weaponMode )
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return false;
|
|
|
|
const CCSWeaponInfo& weaponInfo = GetCSWpnData();
|
|
|
|
if ( m_iClip1 == 0 )
|
|
{
|
|
if ( m_bFireOnEmpty )
|
|
{
|
|
PlayEmptySound();
|
|
|
|
m_iNumEmptyAttacks++;
|
|
|
|
// NOTE[pmf]: we don't want to actually play the dry fire animations, as most seem to depict the weapon actually firing.
|
|
// SendWeaponAnim( ACT_VM_DRYFIRE );
|
|
|
|
//++pPlayer->m_iShotsFired; // don't play "auto" empty clicks -- make the player release the trigger before clicking again
|
|
m_flNextPrimaryAttack = gpGlobals->curtime + 0.2f;
|
|
|
|
if ( IsRevolver() )
|
|
{
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + GetCycleTime( weaponMode );
|
|
BaseClass::SendWeaponAnim( ACT_VM_DRYFIRE ); // empty!
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
float flCurAttack = CalculateNextAttackTime( flCycleTime );
|
|
|
|
if ( (GetWeaponType() != WEAPONTYPE_SNIPER_RIFLE && IsZoomed()) || (IsRevolver() && weaponMode == Secondary_Mode) )
|
|
{
|
|
SendWeaponAnim( ACT_VM_SECONDARYATTACK );
|
|
}
|
|
else if ( IsRevolver() )
|
|
{
|
|
BaseClass::SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
|
}
|
|
else
|
|
{
|
|
SendWeaponAnim( ACT_VM_PRIMARYATTACK );
|
|
}
|
|
|
|
// player "shoot" animation
|
|
pPlayer->SetAnimation( PLAYER_ATTACK1 );
|
|
|
|
uint16 nItemDefIndex = 0;
|
|
|
|
FX_FireBullets(
|
|
pPlayer->entindex(),
|
|
nItemDefIndex,
|
|
pPlayer->Weapon_ShootPosition(),
|
|
pPlayer->GetFinalAimAngle(),
|
|
GetCSWeaponID(),
|
|
weaponMode,
|
|
CBaseEntity::GetPredictionRandomSeed( SERVER_PLATTIME_RNG ) & 255,
|
|
GetInaccuracy(),
|
|
GetSpread(),
|
|
GetAccuracyFishtail(),
|
|
flCurAttack,
|
|
(HasSilencer() && IsSilenced()) ? SPECIAL1 : SINGLE,
|
|
m_flRecoilIndex );
|
|
|
|
DoFireEffects();
|
|
|
|
#ifdef IRONSIGHT
|
|
#ifdef CLIENT_DLL
|
|
if ( GetIronSightController() )
|
|
{
|
|
GetIronSightController()->IncreaseDotBlur( RandomFloat( 0.22f, 0.28f ) );
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
SetWeaponIdleTime( gpGlobals->curtime + weaponInfo.GetTimeToIdleAfterFire( GetEconItemView() ) );
|
|
|
|
// update accuracy
|
|
m_fAccuracyPenalty += weaponInfo.GetInaccuracyFire( GetEconItemView(), weaponMode );
|
|
|
|
// table driven recoil
|
|
Recoil( weaponMode );
|
|
|
|
++pPlayer->m_iShotsFired;
|
|
m_flRecoilIndex += 1.0f;
|
|
--m_iClip1;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool CWeaponCSBaseGun::IsFullAuto() const
|
|
{
|
|
if ( BaseClass::IsFullAuto() )
|
|
{
|
|
return !IsInBurstMode();
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void CWeaponCSBaseGun::DoFireEffects()
|
|
{
|
|
if ( IsSilenced() )
|
|
return;
|
|
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
|
|
if ( pPlayer )
|
|
pPlayer->DoMuzzleFlash();
|
|
}
|
|
|
|
bool CWeaponCSBaseGun::Reload()
|
|
{
|
|
CCSPlayer *pPlayer = GetPlayerOwner();
|
|
if ( !pPlayer )
|
|
return false;
|
|
|
|
if ( GetReserveAmmoCount( AMMO_POSITION_PRIMARY ) <= 0 )
|
|
return false;
|
|
|
|
int iResult = 0;
|
|
|
|
iResult = DefaultReload( GetMaxClip1(), GetMaxClip2(), m_iReloadActivityIndex );
|
|
|
|
if ( !iResult )
|
|
return false;
|
|
|
|
pPlayer->SetAnimation( PLAYER_RELOAD );
|
|
|
|
if ( HasZoom() )
|
|
{
|
|
m_zoomLevel = 0;
|
|
m_weaponMode = Primary_Mode;
|
|
}
|
|
|
|
if ( pPlayer->GetFOV() != pPlayer->GetDefaultFOV() && pPlayer->m_bIsScoped)
|
|
{
|
|
pPlayer->SetFOV( pPlayer, pPlayer->GetDefaultFOV(), 0.0f );
|
|
pPlayer->m_bIsScoped = false;
|
|
}
|
|
|
|
pPlayer->m_iShotsFired = 0;
|
|
m_flRecoilIndex += 1.0f;
|
|
|
|
return BaseClass::Reload();
|
|
}
|
|
|
|
void CWeaponCSBaseGun::WeaponIdle()
|
|
{
|
|
if (m_flTimeWeaponIdle > gpGlobals->curtime)
|
|
return;
|
|
|
|
// only idle if the slid isn't back
|
|
if ( m_iClip1 != 0 )
|
|
{
|
|
SetWeaponIdleTime( gpGlobals->curtime + GetCSWpnData().GetIdleInterval( GetEconItemView() ) );
|
|
|
|
//silencers are bodygroups, so there is no longer a silencer-specific idle.
|
|
SendWeaponAnim( ACT_VM_IDLE );
|
|
}
|
|
}
|
|
|
|
bool CWeaponCSBaseGun::Holster( CBaseCombatWeapon *pSwitchingTo )
|
|
{
|
|
// re-deploying the weapon is punishment enough for canceling a silencer attach/detach before completion
|
|
if ( (GetActivity() == ACT_VM_ATTACH_SILENCER && m_bSilencerOn == false) ||
|
|
(GetActivity() == ACT_VM_DETACH_SILENCER && m_bSilencerOn == true ) )
|
|
{
|
|
m_flDoneSwitchingSilencer = gpGlobals->curtime;
|
|
m_flNextSecondaryAttack = gpGlobals->curtime;
|
|
m_flNextPrimaryAttack = gpGlobals->curtime;
|
|
}
|
|
|
|
if ( HasZoom() )
|
|
{
|
|
m_zoomLevel = 0;
|
|
m_weaponMode = Primary_Mode;
|
|
}
|
|
|
|
// not sure we want to fully support animation cancelling
|
|
if ( m_bInReload && !m_bReloadVisuallyComplete )
|
|
{
|
|
m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime;
|
|
}
|
|
return BaseClass::Holster(pSwitchingTo);
|
|
}
|
|
|
|
bool CWeaponCSBaseGun::Deploy()
|
|
{
|
|
// don't allow weapon switching to shortcut cycle time (quickswitch exploit)
|
|
float fOldNextPrimaryAttack = m_flNextPrimaryAttack;
|
|
float fOldNextSecondaryAttack = m_flNextSecondaryAttack;
|
|
|
|
m_flDoneSwitchingSilencer = 0.0f;
|
|
m_iBurstShotsRemaining = 0;
|
|
m_fNextBurstShot = 0.0f;
|
|
|
|
if ( !BaseClass::Deploy() )
|
|
return false;
|
|
|
|
if ( HasZoom() )
|
|
{
|
|
m_zoomLevel = 0;
|
|
m_weaponMode = Primary_Mode;
|
|
}
|
|
|
|
if ( IsRevolver() )
|
|
{
|
|
m_weaponMode = Secondary_Mode;
|
|
}
|
|
|
|
m_flNextPrimaryAttack = Max( m_flNextPrimaryAttack.Get(), fOldNextPrimaryAttack );
|
|
m_flNextSecondaryAttack = Max( m_flNextSecondaryAttack.Get(), fOldNextSecondaryAttack );
|
|
return true;
|
|
}
|
|
|
|
bool CWeaponCSBaseGun::HasZoom()
|
|
{
|
|
return GetZoomLevels() != 0;
|
|
}
|
|
|
|
|
|
#ifdef CLIENT_DLL
|
|
|
|
|
|
const char* CWeaponCSBaseGun::GetMuzzleFlashEffectName_1stPerson( void )
|
|
{
|
|
if ( HasSilencer() && IsSilenced() )
|
|
{
|
|
return GetCSWpnData().GetMuzzleFlashEffectName_1stPersonAlt( GetEconItemView() );
|
|
}
|
|
else
|
|
{
|
|
return GetCSWpnData().GetMuzzleFlashEffectName_1stPerson( GetEconItemView() );
|
|
}
|
|
}
|
|
|
|
const char* CWeaponCSBaseGun::GetMuzzleFlashEffectName_3rdPerson( void )
|
|
{
|
|
if ( HasSilencer() && IsSilenced() )
|
|
{
|
|
return GetCSWpnData().GetMuzzleFlashEffectName_3rdPersonAlt( GetEconItemView() );
|
|
}
|
|
else
|
|
{
|
|
return GetCSWpnData().GetMuzzleFlashEffectName_3rdPerson( GetEconItemView() );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
CCSWeaponInfo const & CWeaponCSBaseGun::GetCSWpnData() const
|
|
{
|
|
if ( m_pWeaponInfo != NULL )
|
|
return *m_pWeaponInfo;
|
|
else
|
|
return BaseClass::GetCSWpnData();
|
|
}
|
|
|
|
bool CWeaponCSBaseGun::IsInBurstMode() const
|
|
{
|
|
return m_bBurstMode;
|
|
}
|
|
|
|
bool CWeaponCSBaseGun::IsZoomed( void ) const
|
|
{
|
|
return ( m_zoomLevel > 0 );
|
|
}
|