367 lines
10 KiB
C++
367 lines
10 KiB
C++
|
#include "cbase.h"
|
||
|
#include "asw_weapon_sniper_rifle.h"
|
||
|
#include "in_buttons.h"
|
||
|
|
||
|
#ifdef CLIENT_DLL
|
||
|
#include "c_asw_player.h"
|
||
|
#include "c_asw_weapon.h"
|
||
|
#include "c_asw_marine.h"
|
||
|
#include "dlight.h"
|
||
|
#include "asw_input.h"
|
||
|
#include "iefx.h"
|
||
|
#include "engine/ivdebugoverlay.h"
|
||
|
#include "c_asw_fx.h"
|
||
|
#else
|
||
|
#include "asw_lag_compensation.h"
|
||
|
#include "asw_marine.h"
|
||
|
#include "asw_marine_resource.h"
|
||
|
#include "asw_player.h"
|
||
|
#include "asw_weapon.h"
|
||
|
#include "npcevent.h"
|
||
|
#include "shot_manipulator.h"
|
||
|
#include "asw_shotgun_pellet.h"
|
||
|
#include "asw_marine_speech.h"
|
||
|
#include "asw_weapon_ammo_bag_shared.h"
|
||
|
#endif
|
||
|
#include "asw_marine_skills.h"
|
||
|
#include "asw_weapon_parse.h"
|
||
|
|
||
|
// memdbgon must be the last include file in a .cpp file!!!
|
||
|
#include "tier0/memdbgon.h"
|
||
|
|
||
|
extern ConVar asw_weapon_max_shooting_distance;
|
||
|
extern ConVar sk_plr_dmg_asw_sg;
|
||
|
extern ConVar asw_weapon_force_scale;
|
||
|
|
||
|
IMPLEMENT_NETWORKCLASS_ALIASED( ASW_Weapon_Sniper_Rifle, DT_ASW_Weapon_Sniper_Rifle )
|
||
|
|
||
|
BEGIN_NETWORK_TABLE( CASW_Weapon_Sniper_Rifle, DT_ASW_Weapon_Sniper_Rifle )
|
||
|
#ifdef CLIENT_DLL
|
||
|
// recvprops
|
||
|
RecvPropTime( RECVINFO( m_fSlowTime ) ),
|
||
|
RecvPropBool( RECVINFO( m_bZoomed ) ),
|
||
|
#else
|
||
|
// sendprops
|
||
|
SendPropTime( SENDINFO( m_fSlowTime ) ),
|
||
|
SendPropBool( SENDINFO( m_bZoomed ) ),
|
||
|
#endif
|
||
|
END_NETWORK_TABLE()
|
||
|
|
||
|
|
||
|
#ifdef CLIENT_DLL
|
||
|
BEGIN_PREDICTION_DATA( CASW_Weapon_Sniper_Rifle )
|
||
|
DEFINE_PRED_FIELD_TOL( m_fSlowTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE, TD_MSECTOLERANCE ),
|
||
|
END_PREDICTION_DATA()
|
||
|
|
||
|
#else
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// Purpose: Save Data
|
||
|
//-----------------------------------------------------------------------------//
|
||
|
BEGIN_DATADESC( CASW_Weapon_Sniper_Rifle )
|
||
|
DEFINE_FIELD( m_fSlowTime, FIELD_TIME ),
|
||
|
END_DATADESC()
|
||
|
#endif
|
||
|
|
||
|
LINK_ENTITY_TO_CLASS( asw_weapon_sniper_rifle, CASW_Weapon_Sniper_Rifle );
|
||
|
PRECACHE_WEAPON_REGISTER( asw_weapon_sniper_rifle );
|
||
|
|
||
|
#ifndef CLIENT_DLL
|
||
|
extern ConVar asw_debug_marine_damage;
|
||
|
|
||
|
#endif /* not client */
|
||
|
|
||
|
CASW_Weapon_Sniper_Rifle::CASW_Weapon_Sniper_Rifle()
|
||
|
{
|
||
|
m_fMinRange1 = 0;
|
||
|
m_fMaxRange1 = 512;
|
||
|
|
||
|
m_fMinRange2 = 256;
|
||
|
m_fMaxRange2 = 1024;
|
||
|
|
||
|
m_fSlowTime = 0;
|
||
|
|
||
|
#ifdef CLIENT_DLL
|
||
|
m_pSniperDynamicLight = NULL;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
CASW_Weapon_Sniper_Rifle::~CASW_Weapon_Sniper_Rifle()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
#define PELLET_AIR_VELOCITY 3500
|
||
|
#define PELLET_WATER_VELOCITY 1500
|
||
|
|
||
|
void CASW_Weapon_Sniper_Rifle::PrimaryAttack( void )
|
||
|
{
|
||
|
// If my clip is empty (and I use clips) start reload
|
||
|
if ( UsesClipsForAmmo1() && !m_iClip1 )
|
||
|
{
|
||
|
Reload();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
CASW_Player *pPlayer = GetCommander();
|
||
|
CASW_Marine *pMarine = GetMarine();
|
||
|
if ( !pMarine )
|
||
|
return;
|
||
|
|
||
|
// MUST call sound before removing a round from the clip of a CMachineGun
|
||
|
WeaponSound(SINGLE);
|
||
|
if (m_iClip1 <= AmmoClickPoint())
|
||
|
BaseClass::WeaponSound( EMPTY );
|
||
|
|
||
|
m_bIsFiring = true;
|
||
|
|
||
|
// tell the marine to tell its weapon to draw the muzzle flash
|
||
|
pMarine->DoMuzzleFlash();
|
||
|
|
||
|
// sets the animation on the weapon model iteself
|
||
|
//SendWeaponAnim( GetPrimaryAttackActivity() );
|
||
|
|
||
|
// sets the animation on the marine holding this weapon
|
||
|
//pMarine->SetAnimation( PLAYER_ATTACK1 );
|
||
|
|
||
|
#ifdef GAME_DLL // check for turning on lag compensation
|
||
|
if (pPlayer && pMarine->IsInhabited())
|
||
|
{
|
||
|
CASW_Lag_Compensation::RequestLagCompensation( pPlayer, pPlayer->GetCurrentUserCommand() );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
FireBulletsInfo_t info;
|
||
|
info.m_vecSrc = pMarine->Weapon_ShootPosition( );
|
||
|
if ( pPlayer && pMarine->IsInhabited() )
|
||
|
{
|
||
|
info.m_vecDirShooting = pPlayer->GetAutoaimVectorForMarine(pMarine, GetAutoAimAmount(), GetVerticalAdjustOnlyAutoAimAmount()); // 45 degrees = 0.707106781187
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#ifdef CLIENT_DLL
|
||
|
Msg("Error, clientside firing of a weapon that's being controlled by an AI marine\n");
|
||
|
#else
|
||
|
info.m_vecDirShooting = pMarine->GetActualShootTrajectory( info.m_vecSrc );
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
info.m_iShots = 1;
|
||
|
|
||
|
// Make sure we don't fire more than the amount in the clip
|
||
|
if ( UsesClipsForAmmo1() )
|
||
|
{
|
||
|
info.m_iShots = MIN( info.m_iShots, m_iClip1 );
|
||
|
m_iClip1 -= info.m_iShots;
|
||
|
#ifdef GAME_DLL
|
||
|
CASW_Marine *pMarine = GetMarine();
|
||
|
if (pMarine && m_iClip1 <= 0 && pMarine->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
|
||
|
{
|
||
|
// check he doesn't have ammo in an ammo bay
|
||
|
CASW_Weapon_Ammo_Bag* pAmmoBag = dynamic_cast<CASW_Weapon_Ammo_Bag*>(pMarine->GetASWWeapon(0));
|
||
|
if (!pAmmoBag)
|
||
|
pAmmoBag = dynamic_cast<CASW_Weapon_Ammo_Bag*>(pMarine->GetASWWeapon(1));
|
||
|
if (!pAmmoBag || !pAmmoBag->CanGiveAmmoToWeapon(this))
|
||
|
pMarine->OnWeaponOutOfAmmo(true);
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
info.m_iShots = MIN( info.m_iShots, pMarine->GetAmmoCount( m_iPrimaryAmmoType ) );
|
||
|
pMarine->RemoveAmmo( info.m_iShots, m_iPrimaryAmmoType );
|
||
|
}
|
||
|
|
||
|
info.m_flDistance = asw_weapon_max_shooting_distance.GetFloat();
|
||
|
info.m_iAmmoType = m_iPrimaryAmmoType;
|
||
|
info.m_iTracerFreq = 1;
|
||
|
info.m_flDamageForceScale = asw_weapon_force_scale.GetFloat();
|
||
|
|
||
|
info.m_vecSpread = GetBulletSpread();
|
||
|
info.m_flDamage = GetWeaponDamage();
|
||
|
#ifndef CLIENT_DLL
|
||
|
if (asw_debug_marine_damage.GetBool())
|
||
|
Msg("Weapon dmg = %f\n", info.m_flDamage);
|
||
|
info.m_flDamage *= pMarine->GetMarineResource()->OnFired_GetDamageScale();
|
||
|
#endif
|
||
|
|
||
|
int iPenetration = 1;
|
||
|
if ( pMarine->GetDamageBuffEndTime() > gpGlobals->curtime ) // sniper rifle penetrates more targets when marine is in a damage amp
|
||
|
{
|
||
|
iPenetration = 3;
|
||
|
}
|
||
|
pMarine->FirePenetratingBullets( info, iPenetration, 3.5f, 0, true, NULL, false );
|
||
|
|
||
|
// increment shooting stats
|
||
|
#ifndef CLIENT_DLL
|
||
|
if (pMarine && pMarine->GetMarineResource())
|
||
|
{
|
||
|
pMarine->GetMarineResource()->UsedWeapon(this, 1);
|
||
|
pMarine->OnWeaponFired( this, 1 );
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (m_iClip1 > 0) // only force the fire wait time if we have ammo for another shot
|
||
|
m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
|
||
|
else
|
||
|
m_flNextPrimaryAttack = gpGlobals->curtime;
|
||
|
m_fSlowTime = gpGlobals->curtime + 0.03f;
|
||
|
}
|
||
|
|
||
|
void CASW_Weapon_Sniper_Rifle::Precache()
|
||
|
{
|
||
|
PrecacheModel( "swarm/sprites/whiteglow1.vmt" );
|
||
|
PrecacheModel( "swarm/sprites/greylaser1.vmt" );
|
||
|
PrecacheScriptSound("ASW_Pistol.ReloadA");
|
||
|
PrecacheScriptSound("ASW_Pistol.ReloadB");
|
||
|
|
||
|
BaseClass::Precache();
|
||
|
}
|
||
|
|
||
|
bool CASW_Weapon_Sniper_Rifle::ShouldMarineMoveSlow()
|
||
|
{
|
||
|
return (gpGlobals->curtime < m_fSlowTime) || IsZoomed();
|
||
|
}
|
||
|
|
||
|
void CASW_Weapon_Sniper_Rifle::ItemPostFrame( void )
|
||
|
{
|
||
|
BaseClass::ItemPostFrame();
|
||
|
|
||
|
CASW_Marine *pMarine = GetMarine();
|
||
|
if ( !pMarine )
|
||
|
return;
|
||
|
|
||
|
// AIs switch out of zoom mode
|
||
|
if ( !pMarine->IsInhabited() && IsZoomed() )
|
||
|
{
|
||
|
m_bZoomed = false;
|
||
|
}
|
||
|
|
||
|
bool bAttack1, bAttack2, bReload, bOldReload, bOldAttack1;
|
||
|
GetButtons( bAttack1, bAttack2, bReload, bOldReload, bOldAttack1 );
|
||
|
|
||
|
bool bOldAttack2 = false;
|
||
|
if ( pMarine->IsInhabited() && pMarine->GetCommander() )
|
||
|
{
|
||
|
bOldAttack2 = !!(pMarine->m_nOldButtons & IN_ATTACK2);
|
||
|
}
|
||
|
|
||
|
if ( bAttack2 && !bOldAttack2 )
|
||
|
{
|
||
|
m_bZoomed = !IsZoomed();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float CASW_Weapon_Sniper_Rifle::GetWeaponDamage()
|
||
|
{
|
||
|
float flDamage = GetWeaponInfo()->m_flBaseDamage;
|
||
|
|
||
|
if ( GetMarine() )
|
||
|
{
|
||
|
flDamage += MarineSkills()->GetSkillBasedValueByMarine(GetMarine(), ASW_MARINE_SKILL_ACCURACY, ASW_MARINE_SUBSKILL_ACCURACY_SNIPER_RIFLE_DMG);
|
||
|
}
|
||
|
|
||
|
return flDamage;
|
||
|
}
|
||
|
|
||
|
#ifdef CLIENT_DLL
|
||
|
|
||
|
ConVar asw_sniper_dlight_radius("asw_sniper_dlight_radius", "100", FCVAR_CHEAT, "Radius of the light around the cursor.");
|
||
|
ConVar asw_sniper_dlight_r("asw_sniper_dlight_r", "250", FCVAR_CHEAT, "Red component of flashlight colour");
|
||
|
ConVar asw_sniper_dlight_g("asw_sniper_dlight_g", "250", FCVAR_CHEAT, "Green component of flashlight colour");
|
||
|
ConVar asw_sniper_dlight_b("asw_sniper_dlight_b", "250", FCVAR_CHEAT, "Blue component of flashlight colour");
|
||
|
ConVar asw_sniper_dlight_exponent( "asw_sniper_dlight_exponent", "1", FCVAR_CHEAT );
|
||
|
|
||
|
void CASW_Weapon_Sniper_Rifle::UpdateDynamicLight()
|
||
|
{
|
||
|
// DLIGHT disabled, since it looks bad
|
||
|
return;
|
||
|
|
||
|
C_ASW_Marine *pMarine =GetMarine();
|
||
|
C_ASW_Player *pPlayer = pMarine ? pMarine->GetCommander() : NULL;
|
||
|
|
||
|
if ( !pMarine || pMarine->GetActiveWeapon() != this || !pPlayer || !pMarine->IsInhabited() || !pPlayer->IsLocalPlayer() )
|
||
|
{
|
||
|
if (m_pSniperDynamicLight)
|
||
|
{
|
||
|
m_pSniperDynamicLight->die = gpGlobals->curtime + 0.001;
|
||
|
m_pSniperDynamicLight = NULL;
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( !m_pSniperDynamicLight || (m_pSniperDynamicLight->key != index) )
|
||
|
{
|
||
|
m_pSniperDynamicLight = effects->CL_AllocDlight ( index );
|
||
|
}
|
||
|
|
||
|
//m_fAmbientLight = asw_flashlight_marine_ambient.GetFloat();
|
||
|
//m_fLightingScale = asw_flashlight_marine_lightscale.GetFloat();
|
||
|
|
||
|
Vector vecForward, vecRight, vecUp;
|
||
|
|
||
|
if (m_pSniperDynamicLight)
|
||
|
{
|
||
|
AngleVectors( GetLocalAngles(), &vecForward, &vecRight, &vecUp );
|
||
|
m_pSniperDynamicLight->origin = pPlayer->GetCrosshairTracePos() + Vector( 0, 0, 10 );
|
||
|
Msg( "crosshair trace pos is %f %f %f\n", VectorExpand( pPlayer->GetCrosshairTracePos() ) );
|
||
|
debugoverlay->AddTextOverlay( m_pSniperDynamicLight->origin, 0.01f, "Light" );
|
||
|
m_pSniperDynamicLight->color.r = asw_sniper_dlight_r.GetInt();
|
||
|
m_pSniperDynamicLight->color.g = asw_sniper_dlight_g.GetInt();
|
||
|
m_pSniperDynamicLight->color.b = asw_sniper_dlight_b.GetInt();
|
||
|
m_pSniperDynamicLight->radius = asw_sniper_dlight_radius.GetFloat();
|
||
|
m_pSniperDynamicLight->color.exponent = asw_sniper_dlight_exponent.GetFloat();
|
||
|
//m_pSniperDynamicLight->decay = 0;
|
||
|
m_pSniperDynamicLight->die = gpGlobals->curtime + 30.0f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CASW_Weapon_Sniper_Rifle::OnDataChanged( DataUpdateType_t updateType )
|
||
|
{
|
||
|
BaseClass::OnDataChanged( updateType );
|
||
|
|
||
|
if ( updateType == DATA_UPDATE_CREATED )
|
||
|
{
|
||
|
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CASW_Weapon_Sniper_Rifle::ClientThink()
|
||
|
{
|
||
|
BaseClass::ClientThink();
|
||
|
|
||
|
UpdateDynamicLight();
|
||
|
|
||
|
if ( m_nEjectBrassCount > 0 && gpGlobals->curtime >= m_flEjectBrassTime )
|
||
|
{
|
||
|
int iAttachment = LookupAttachment( "eject1" );
|
||
|
if( iAttachment != -1 )
|
||
|
{
|
||
|
for ( int i = 0; i < m_nEjectBrassCount; i++ )
|
||
|
{
|
||
|
EjectParticleBrass( "weapon_shell_casing_rifle", iAttachment );
|
||
|
}
|
||
|
}
|
||
|
m_nEjectBrassCount = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ConVar asw_sniper_shell_delay( "asw_sniper_shell_delay", "0.7", FCVAR_NONE, "Delay on shell casing after firing rifle" );
|
||
|
|
||
|
void CASW_Weapon_Sniper_Rifle::OnMuzzleFlashed()
|
||
|
{
|
||
|
BaseClass::OnMuzzleFlashed();
|
||
|
|
||
|
Vector attachOrigin;
|
||
|
QAngle attachAngles;
|
||
|
|
||
|
m_nEjectBrassCount++;
|
||
|
m_flEjectBrassTime = gpGlobals->curtime + asw_sniper_shell_delay.GetFloat();
|
||
|
if( GetAttachment( LookupAttachment("muzzle"), attachOrigin, attachAngles ) )
|
||
|
{
|
||
|
FX_ASW_ShotgunSmoke(attachOrigin, attachAngles);
|
||
|
}
|
||
|
}
|
||
|
#endif
|