source-engine/game/shared/tf2base/tf_weapon_sniperrifle.cpp
2022-08-10 19:52:28 +03:00

919 lines
23 KiB
C++

//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======//
//
// Purpose: TF Sniper Rifle
//
//=============================================================================//
#include "cbase.h"
#include "tf_fx_shared.h"
#include "tf_weapon_sniperrifle.h"
#include "in_buttons.h"
// Client specific.
#ifdef CLIENT_DLL
#include "view.h"
#include "beamdraw.h"
#include "vgui/ISurface.h"
#include <vgui/ILocalize.h>
#include "vgui_controls/Controls.h"
#include "hud_crosshair.h"
#include "functionproxy.h"
#include "materialsystem/imaterialvar.h"
#include "toolframework_client.h"
#include "input.h"
// forward declarations
void ToolFramework_RecordMaterialParams( IMaterial *pMaterial );
#endif
#define TF_WEAPON_SNIPERRIFLE_CHARGE_PER_SEC 50.0
#define TF_WEAPON_SNIPERRIFLE_UNCHARGE_PER_SEC 75.0
#define TF_WEAPON_SNIPERRIFLE_DAMAGE_MIN 50
#define TF_WEAPON_SNIPERRIFLE_DAMAGE_MAX 150
#define TF_WEAPON_SNIPERRIFLE_RELOAD_TIME 1.5f
#define TF_WEAPON_SNIPERRIFLE_ZOOM_TIME 0.3f
#define TF_WEAPON_SNIPERRIFLE_NO_CRIT_AFTER_ZOOM_TIME 0.2f
#define SNIPER_DOT_SPRITE_RED "effects/sniperdot_red.vmt"
#define SNIPER_DOT_SPRITE_BLUE "effects/sniperdot_blue.vmt"
//=============================================================================
//
// Weapon Sniper Rifles tables.
//
IMPLEMENT_NETWORKCLASS_ALIASED( TFSniperRifle, DT_TFSniperRifle )
BEGIN_NETWORK_TABLE_NOBASE( CTFSniperRifle, DT_SniperRifleLocalData )
#if !defined( CLIENT_DLL )
SendPropFloat( SENDINFO(m_flChargedDamage), 0, SPROP_NOSCALE | SPROP_CHANGES_OFTEN ),
#else
RecvPropFloat( RECVINFO(m_flChargedDamage) ),
#endif
END_NETWORK_TABLE()
BEGIN_NETWORK_TABLE( CTFSniperRifle, DT_TFSniperRifle )
#if !defined( CLIENT_DLL )
SendPropDataTable( "SniperRifleLocalData", 0, &REFERENCE_SEND_TABLE( DT_SniperRifleLocalData ), SendProxy_SendLocalWeaponDataTable ),
#else
RecvPropDataTable( "SniperRifleLocalData", 0, 0, &REFERENCE_RECV_TABLE( DT_SniperRifleLocalData ) ),
#endif
END_NETWORK_TABLE()
BEGIN_PREDICTION_DATA( CTFSniperRifle )
#ifdef CLIENT_DLL
DEFINE_PRED_FIELD( m_flUnzoomTime, FIELD_FLOAT, 0 ),
DEFINE_PRED_FIELD( m_flRezoomTime, FIELD_FLOAT, 0 ),
DEFINE_PRED_FIELD( m_bRezoomAfterShot, FIELD_BOOLEAN, 0 ),
DEFINE_PRED_FIELD( m_flChargedDamage, FIELD_FLOAT, 0 ),
#endif
END_PREDICTION_DATA()
LINK_ENTITY_TO_CLASS( tf_weapon_sniperrifle, CTFSniperRifle );
PRECACHE_WEAPON_REGISTER( tf_weapon_sniperrifle );
//=============================================================================
//
// Weapon Sniper Rifles funcions.
//
//-----------------------------------------------------------------------------
// Purpose: Constructor.
//-----------------------------------------------------------------------------
CTFSniperRifle::CTFSniperRifle()
{
// Server specific.
#ifdef GAME_DLL
m_hSniperDot = NULL;
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Destructor.
//-----------------------------------------------------------------------------
CTFSniperRifle::~CTFSniperRifle()
{
// Server specific.
#ifdef GAME_DLL
DestroySniperDot();
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::Spawn()
{
m_iAltFireHint = HINT_ALTFIRE_SNIPERRIFLE;
BaseClass::Spawn();
ResetTimers();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::Precache()
{
BaseClass::Precache();
PrecacheModel( SNIPER_DOT_SPRITE_RED );
PrecacheModel( SNIPER_DOT_SPRITE_BLUE );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::ResetTimers( void )
{
m_flUnzoomTime = -1;
m_flRezoomTime = -1;
m_bRezoomAfterShot = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFSniperRifle::Reload( void )
{
// We currently don't reload.
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFSniperRifle::CanHolster( void ) const
{
CTFPlayer *pPlayer = GetTFPlayerOwner();
if ( pPlayer )
{
// don't allow us to holster this weapon if we're in the process of zooming and
// we've just fired the weapon (next primary attack is only 1.5 seconds after firing)
if ( ( pPlayer->GetFOV() < pPlayer->GetDefaultFOV() ) && ( m_flNextPrimaryAttack > gpGlobals->curtime ) )
{
return false;
}
}
return BaseClass::CanHolster();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFSniperRifle::Holster( CBaseCombatWeapon *pSwitchingTo )
{
// Server specific.
#ifdef GAME_DLL
// Destroy the sniper dot.
DestroySniperDot();
#endif
CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
if ( pPlayer && pPlayer->m_Shared.InCond( TF_COND_ZOOMED ) )
{
ZoomOut();
}
m_flChargedDamage = 0.0f;
ResetTimers();
return BaseClass::Holster( pSwitchingTo );
}
void CTFSniperRifle::WeaponReset( void )
{
BaseClass::WeaponReset();
ZoomOut();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::HandleZooms( void )
{
// Get the owning player.
CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
if ( !pPlayer )
return;
// Handle the zoom when taunting.
if ( pPlayer->m_Shared.InCond( TF_COND_TAUNTING ) )
{
if ( pPlayer->m_Shared.InCond( TF_COND_AIMING ) )
{
ToggleZoom();
}
//Don't rezoom in the middle of a taunt.
ResetTimers();
}
if ( m_flUnzoomTime > 0 && gpGlobals->curtime > m_flUnzoomTime )
{
if ( m_bRezoomAfterShot )
{
ZoomOutIn();
m_bRezoomAfterShot = false;
}
else
{
ZoomOut();
}
m_flUnzoomTime = -1;
}
if ( m_flRezoomTime > 0 )
{
if ( gpGlobals->curtime > m_flRezoomTime )
{
ZoomIn();
m_flRezoomTime = -1;
}
}
if ( ( pPlayer->m_nButtons & IN_ATTACK2 ) && ( m_flNextSecondaryAttack <= gpGlobals->curtime ) )
{
// If we're in the process of rezooming, just cancel it
if ( m_flRezoomTime > 0 || m_flUnzoomTime > 0 )
{
// Prevent them from rezooming in less time than they would have
m_flNextSecondaryAttack = m_flRezoomTime + TF_WEAPON_SNIPERRIFLE_ZOOM_TIME;
m_flRezoomTime = -1;
}
else
{
Zoom();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::ItemPostFrame( void )
{
// If we're lowered, we're not allowed to fire
if ( m_bLowered )
return;
// Get the owning player.
CTFPlayer *pPlayer = ToTFPlayer( GetOwner() );
if ( !pPlayer )
return;
if ( !CanAttack() )
{
if ( IsZoomed() )
{
ToggleZoom();
}
return;
}
HandleZooms();
#ifdef GAME_DLL
// Update the sniper dot position if we have one
if ( m_hSniperDot )
{
UpdateSniperDot();
}
#endif
// Start charging when we're zoomed in, and allowed to fire
if ( pPlayer->m_Shared.IsJumping() )
{
// Unzoom if we're jumping
if ( IsZoomed() )
{
ToggleZoom();
}
m_flChargedDamage = 0.0f;
m_bRezoomAfterShot = false;
}
else if ( m_flNextSecondaryAttack <= gpGlobals->curtime )
{
// Don't start charging in the time just after a shot before we unzoom to play rack anim.
if ( pPlayer->m_Shared.InCond( TF_COND_AIMING ) && !m_bRezoomAfterShot )
{
m_flChargedDamage = min( m_flChargedDamage + gpGlobals->frametime * TF_WEAPON_SNIPERRIFLE_CHARGE_PER_SEC, TF_WEAPON_SNIPERRIFLE_DAMAGE_MAX );
}
else
{
m_flChargedDamage = max( 0, m_flChargedDamage - gpGlobals->frametime * TF_WEAPON_SNIPERRIFLE_UNCHARGE_PER_SEC );
}
}
// Fire.
if ( pPlayer->m_nButtons & IN_ATTACK )
{
Fire( pPlayer );
}
// Idle.
if ( !( ( pPlayer->m_nButtons & IN_ATTACK) || ( pPlayer->m_nButtons & IN_ATTACK2 ) ) )
{
// No fire buttons down or reloading
if ( !ReloadOrSwitchWeapons() && ( m_bInReload == false ) )
{
WeaponIdle();
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFSniperRifle::Lower( void )
{
if ( BaseClass::Lower() )
{
if ( IsZoomed() )
{
ToggleZoom();
}
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose: Secondary attack.
//-----------------------------------------------------------------------------
void CTFSniperRifle::Zoom( void )
{
// Don't allow the player to zoom in while jumping
CTFPlayer *pPlayer = GetTFPlayerOwner();
if ( pPlayer && pPlayer->m_Shared.IsJumping() )
{
if ( pPlayer->GetFOV() >= 75 )
return;
}
ToggleZoom();
// at least 0.1 seconds from now, but don't stomp a previous value
m_flNextPrimaryAttack = max( m_flNextPrimaryAttack, gpGlobals->curtime + 0.1 );
m_flNextSecondaryAttack = gpGlobals->curtime + TF_WEAPON_SNIPERRIFLE_ZOOM_TIME;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::ZoomOutIn( void )
{
ZoomOut();
CTFPlayer *pPlayer = GetTFPlayerOwner();
if ( pPlayer && pPlayer->ShouldAutoRezoom() )
{
m_flRezoomTime = gpGlobals->curtime + 0.9;
}
else
{
m_flNextSecondaryAttack = gpGlobals->curtime + 1.0f;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::ZoomIn( void )
{
// Start aiming.
CTFPlayer *pPlayer = GetTFPlayerOwner();
if ( !pPlayer )
return;
if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
return;
BaseClass::ZoomIn();
pPlayer->m_Shared.AddCond( TF_COND_AIMING );
pPlayer->TeamFortress_SetSpeed();
#ifdef GAME_DLL
// Create the sniper dot.
CreateSniperDot();
pPlayer->ClearExpression();
#endif
}
bool CTFSniperRifle::IsZoomed( void )
{
CTFPlayer *pPlayer = GetTFPlayerOwner();
if ( pPlayer )
{
return pPlayer->m_Shared.InCond( TF_COND_ZOOMED );
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::ZoomOut( void )
{
BaseClass::ZoomOut();
// Stop aiming
CTFPlayer *pPlayer = GetTFPlayerOwner();
if ( !pPlayer )
return;
pPlayer->m_Shared.RemoveCond( TF_COND_AIMING );
pPlayer->TeamFortress_SetSpeed();
#ifdef GAME_DLL
// Destroy the sniper dot.
DestroySniperDot();
pPlayer->ClearExpression();
#endif
// if we are thinking about zooming, cancel it
m_flUnzoomTime = -1;
m_flRezoomTime = -1;
m_bRezoomAfterShot = false;
m_flChargedDamage = 0.0f;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::Fire( CTFPlayer *pPlayer )
{
// Check the ammo. We don't use clip ammo, check the primary ammo type.
if ( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) <= 0 )
{
HandleFireOnEmpty();
return;
}
if ( m_flNextPrimaryAttack > gpGlobals->curtime )
return;
// Fire the sniper shot.
PrimaryAttack();
if ( IsZoomed() )
{
// If we have more bullets, zoom out, play the bolt animation and zoom back in
if( pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) > 0 )
{
SetRezoom( true, 0.5f ); // zoom out in 0.5 seconds, then rezoom
}
else
{
//just zoom out
SetRezoom( false, 0.5f ); // just zoom out in 0.5 seconds
}
}
else
{
// Prevent primary fire preventing zooms
m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration();
}
m_flChargedDamage = 0.0f;
#ifdef GAME_DLL
if ( m_hSniperDot )
{
m_hSniperDot->ResetChargeTime();
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::SetRezoom( bool bRezoom, float flDelay )
{
m_flUnzoomTime = gpGlobals->curtime + flDelay;
m_bRezoomAfterShot = bRezoom;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : float
//-----------------------------------------------------------------------------
float CTFSniperRifle::GetProjectileDamage( void )
{
// Uncharged? Min damage.
return max( m_flChargedDamage, TF_WEAPON_SNIPERRIFLE_DAMAGE_MIN );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CTFSniperRifle::GetDamageType( void ) const
{
// Only do hit location damage if we're zoomed
CTFPlayer *pPlayer = ToTFPlayer( GetPlayerOwner() );
if ( pPlayer && pPlayer->m_Shared.InCond( TF_COND_ZOOMED ) )
return BaseClass::GetDamageType();
return ( BaseClass::GetDamageType() & ~DMG_USE_HITLOCATIONS );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::CreateSniperDot( void )
{
// Server specific.
#ifdef GAME_DLL
// Check to see if we have already been created?
if ( m_hSniperDot )
return;
// Get the owning player (make sure we have one).
CBaseCombatCharacter *pPlayer = GetOwner();
if ( !pPlayer )
return;
// Create the sniper dot, but do not make it visible yet.
m_hSniperDot = CSniperDot::Create( GetAbsOrigin(), pPlayer, true );
m_hSniperDot->ChangeTeam( pPlayer->GetTeamNumber() );
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::DestroySniperDot( void )
{
// Server specific.
#ifdef GAME_DLL
// Destroy the sniper dot.
if ( m_hSniperDot )
{
UTIL_Remove( m_hSniperDot );
m_hSniperDot = NULL;
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFSniperRifle::UpdateSniperDot( void )
{
// Server specific.
#ifdef GAME_DLL
CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
if ( !pPlayer )
return;
// Get the start and endpoints.
Vector vecMuzzlePos = pPlayer->Weapon_ShootPosition();
Vector forward;
pPlayer->EyeVectors( &forward );
Vector vecEndPos = vecMuzzlePos + ( forward * MAX_TRACE_LENGTH );
trace_t trace;
UTIL_TraceLine( vecMuzzlePos, vecEndPos, ( MASK_SHOT & ~CONTENTS_WINDOW ), GetOwner(), COLLISION_GROUP_NONE, &trace );
// Update the sniper dot.
if ( m_hSniperDot )
{
CBaseEntity *pEntity = NULL;
if ( trace.DidHitNonWorldEntity() )
{
pEntity = trace.m_pEnt;
if ( !pEntity || !pEntity->m_takedamage )
{
pEntity = NULL;
}
}
m_hSniperDot->Update( pEntity, trace.endpos, trace.plane.normal );
}
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFSniperRifle::CanFireCriticalShot( bool bIsHeadshot )
{
// can only fire a crit shot if this is a headshot
if ( !bIsHeadshot )
return false;
CTFPlayer *pPlayer = GetTFPlayerOwner();
if ( pPlayer )
{
// no crits if they're not zoomed
if ( pPlayer->GetFOV() >= pPlayer->GetDefaultFOV() )
{
return false;
}
// no crits for 0.2 seconds after starting to zoom
if ( ( gpGlobals->curtime - pPlayer->GetFOVTime() ) < TF_WEAPON_SNIPERRIFLE_NO_CRIT_AFTER_ZOOM_TIME )
{
return false;
}
}
return true;
}
//=============================================================================
//
// Client specific functions.
//
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
float CTFSniperRifle::GetHUDDamagePerc( void )
{
return (m_flChargedDamage / TF_WEAPON_SNIPERRIFLE_DAMAGE_MAX);
}
//-----------------------------------------------------------------------------
// Returns the sniper chargeup from 0 to 1
//-----------------------------------------------------------------------------
class CProxySniperRifleCharge : public CResultProxy
{
public:
void OnBind( void *pC_BaseEntity );
};
void CProxySniperRifleCharge::OnBind( void *pC_BaseEntity )
{
Assert( m_pResult );
C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
if ( GetSpectatorTarget() != 0 && GetSpectatorMode() == OBS_MODE_IN_EYE )
{
pPlayer = (C_TFPlayer *)UTIL_PlayerByIndex( GetSpectatorTarget() );
}
if ( pPlayer )
{
CTFSniperRifle *pWeapon = assert_cast<CTFSniperRifle*>(pPlayer->GetActiveTFWeapon());
if ( pWeapon )
{
float flChargeValue = ( ( 1.0 - pWeapon->GetHUDDamagePerc() ) * 0.8 ) + 0.6;
VMatrix mat, temp;
Vector2D center( 0.5, 0.5 );
MatrixBuildTranslation( mat, -center.x, -center.y, 0.0f );
// scale
{
Vector2D scale( 1.0f, 0.25f );
MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
MatrixMultiply( temp, mat, mat );
}
MatrixBuildTranslation( temp, center.x, center.y, 0.0f );
MatrixMultiply( temp, mat, mat );
// translation
{
Vector2D translation( 0.0f, flChargeValue );
MatrixBuildTranslation( temp, translation.x, translation.y, 0.0f );
MatrixMultiply( temp, mat, mat );
}
m_pResult->SetMatrixValue( mat );
}
}
if ( ToolsEnabled() )
{
ToolFramework_RecordMaterialParams( GetMaterial() );
}
}
EXPOSE_INTERFACE( CProxySniperRifleCharge, IMaterialProxy, "SniperRifleCharge" IMATERIAL_PROXY_INTERFACE_VERSION );
#endif
//=============================================================================
//
// Laser Dot functions.
//
IMPLEMENT_NETWORKCLASS_ALIASED( SniperDot, DT_SniperDot )
BEGIN_NETWORK_TABLE( CSniperDot, DT_SniperDot )
#ifdef CLIENT_DLL
RecvPropFloat( RECVINFO( m_flChargeStartTime ) ),
#else
SendPropTime( SENDINFO( m_flChargeStartTime ) ),
#endif
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS( env_sniperdot, CSniperDot );
BEGIN_DATADESC( CSniperDot )
DEFINE_FIELD( m_vecSurfaceNormal, FIELD_VECTOR ),
DEFINE_FIELD( m_hTargetEnt, FIELD_EHANDLE ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Purpose: Constructor.
//-----------------------------------------------------------------------------
CSniperDot::CSniperDot( void )
{
m_vecSurfaceNormal.Init();
m_hTargetEnt = NULL;
#ifdef CLIENT_DLL
m_hSpriteMaterial = NULL;
#endif
ResetChargeTime();
}
//-----------------------------------------------------------------------------
// Purpose: Destructor.
//-----------------------------------------------------------------------------
CSniperDot::~CSniperDot( void )
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &origin -
// Output : CSniperDot
//-----------------------------------------------------------------------------
CSniperDot *CSniperDot::Create( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot )
{
// Client specific.
#ifdef CLIENT_DLL
return NULL;
// Server specific.
#else
// Create the sniper dot entity.
CSniperDot *pDot = static_cast<CSniperDot*>( CBaseEntity::Create( "env_sniperdot", origin, QAngle( 0.0f, 0.0f, 0.0f ) ) );
if ( !pDot )
return NULL;
//Create the graphic
pDot->SetMoveType( MOVETYPE_NONE );
pDot->AddSolidFlags( FSOLID_NOT_SOLID );
pDot->AddEffects( EF_NOSHADOW );
UTIL_SetSize( pDot, -Vector( 4.0f, 4.0f, 4.0f ), Vector( 4.0f, 4.0f, 4.0f ) );
// Set owner.
pDot->SetOwnerEntity( pOwner );
// Force updates even though we don't have a model.
pDot->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
return pDot;
#endif
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSniperDot::Update( CBaseEntity *pTarget, const Vector &vecOrigin, const Vector &vecNormal )
{
SetAbsOrigin( vecOrigin );
m_vecSurfaceNormal = vecNormal;
m_hTargetEnt = pTarget;
}
//=============================================================================
//
// Client specific functions.
//
#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
// TFTODO: Make the sniper dot get brighter the more damage it will do.
//-----------------------------------------------------------------------------
int CSniperDot::DrawModel( int flags )
{
// Get the owning player.
C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
if ( !pPlayer )
return -1;
// Get the sprite rendering position.
Vector vecEndPos;
float flSize = 6.0;
if ( !pPlayer->IsDormant() )
{
Vector vecAttachment, vecDir;
QAngle angles;
float flDist = MAX_TRACE_LENGTH;
// Always draw the dot in front of our faces when in first-person.
if ( pPlayer->IsLocalPlayer() )
{
// Take our view position and orientation
vecAttachment = CurrentViewOrigin();
vecDir = CurrentViewForward();
// Clamp the forward distance for the sniper's firstperson
flDist = 384;
flSize = 2.0;
}
else
{
// Take the owning player eye position and direction.
vecAttachment = pPlayer->EyePosition();
QAngle angles = pPlayer->EyeAngles();
AngleVectors( angles, &vecDir );
}
trace_t tr;
UTIL_TraceLine( vecAttachment, vecAttachment + ( vecDir * flDist ), MASK_SHOT, pPlayer, COLLISION_GROUP_NONE, &tr );
// Backup off the hit plane, towards the source
vecEndPos = tr.endpos + vecDir * -4;
}
else
{
// Just use our position if we can't predict it otherwise.
vecEndPos = GetAbsOrigin();
}
// Draw our laser dot in space.
CMatRenderContextPtr pRenderContext( materials );
pRenderContext->Bind( m_hSpriteMaterial, this );
float flLifeTime = gpGlobals->curtime - m_flChargeStartTime;
float flStrength = RemapValClamped( flLifeTime, 0.0, TF_WEAPON_SNIPERRIFLE_DAMAGE_MAX / TF_WEAPON_SNIPERRIFLE_CHARGE_PER_SEC, 0.1, 1.0 );
color32 innercolor = { 255, 255, 255, 255 };
color32 outercolor = { 255, 255, 255, 128 };
DrawSprite( vecEndPos, flSize, flSize, outercolor );
DrawSprite( vecEndPos, flSize * flStrength, flSize * flStrength, innercolor );
// Successful.
return 1;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CSniperDot::ShouldDraw( void )
{
if ( IsEffectActive( EF_NODRAW ) )
return false;
// Don't draw the sniper dot when in thirdperson.
if ( ::input->CAM_IsThirdPerson() )
return false;
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CSniperDot::OnDataChanged( DataUpdateType_t updateType )
{
if ( updateType == DATA_UPDATE_CREATED )
{
if ( GetTeamNumber() == TF_TEAM_BLUE )
{
m_hSpriteMaterial.Init( SNIPER_DOT_SPRITE_BLUE, TEXTURE_GROUP_CLIENT_EFFECTS );
}
else
{
m_hSpriteMaterial.Init( SNIPER_DOT_SPRITE_RED, TEXTURE_GROUP_CLIENT_EFFECTS );
}
}
}
#endif