Files
HL2Overcharged/game/server/overcharged/weapon_laserpistol.cpp
2025-05-21 21:20:08 +03:00

493 lines
17 KiB
C++

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Laser pistol - pew,pew :D
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "NPCEvent.h"
#include "basehlcombatweapon.h"
#include "basecombatcharacter.h"
#include "AI_BaseNPC.h"
#include "player.h"
#include "gamerules.h"
#include "in_buttons.h"
#include "soundent.h"
#include "game.h"
#include "vstdlib/random.h"
#include "gamestats.h"
#include "particle_parse.h"
#include "beam_shared.h" /* We will use some of the functions declared this later... */
#include "ammodef.h" /* This is needed for the tracing done later */
// This determines the sprite used by the laser beam
#define PHYSCANNON_BEAM_SPRITE "sprites/orangelight1.vmt"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define Laserpistol_FASTEST_REFIRE_TIME 0.1f
#define Laserpistol_FASTEST_DRY_REFIRE_TIME 0.2f
#define Laserpistol_ACCURACY_SHOT_PENALTY_TIME 0.2f // Applied amount of time each shot adds to the time we must recover from
#define Laserpistol_ACCURACY_MAXIMUM_PENALTY_TIME 1.5f // Maximum penalty to deal out
//ConVar laserpistol_use_new_accuracy( "laserpistol_use_new_accuracy", "1" );
ConVar oc_wpn_laserpistol_shoot_effect( "oc_wpn_laserpistol_shoot_effect", "0", FCVAR_REPLICATED|FCVAR_ARCHIVE, "Shoot effects for laser pistol. var 1-2." );
//-----------------------------------------------------------------------------
// CWeaponLaserpistol
//-----------------------------------------------------------------------------
class CWeaponLaserpistol : public CBaseHLCombatWeapon
{
DECLARE_DATADESC();
public:
DECLARE_CLASS( CWeaponLaserpistol, CBaseHLCombatWeapon );
CWeaponLaserpistol(void);
DECLARE_SERVERCLASS();
void Precache( void );
void ItemPostFrame( void );
void ItemPreFrame( void );
void ItemBusyFrame( void );
void PrimaryAttack( trace_t &tr, int nDamageType, CBaseCombatCharacter *pOperator );
void SecondaryAttack( void ); // L1ght 15: Change effects by mouse clicks too
void DryFire( void );
void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator );
void DrawBeam( const Vector &startPos, const Vector &endPos, float width );
void DoImpactEffect( trace_t &tr, int nDamageType );
void UpdatePenaltyTime( void );
int CapabilitiesGet( void ) { return bits_CAP_WEAPON_RANGE_ATTACK1; }
//Activity GetPrimaryAttackActivity( void );
virtual bool Reload( void );
virtual int GetMinBurst()
{
return 1;
}
virtual int GetMaxBurst()
{
return 3;
}
/*virtual float GetFireRate( void )
{
return 0.5f;
}*/
DECLARE_ACTTABLE();
private:
float m_flSoonestPrimaryAttack;
float m_flLastAttackTime;
float m_flAccuracyPenalty;
int m_nNumShotsFired;
int m_nBulletType;
};
IMPLEMENT_SERVERCLASS_ST(CWeaponLaserpistol, DT_WeaponLaserpistol)
END_SEND_TABLE()
LINK_ENTITY_TO_CLASS( weapon_laserpistol, CWeaponLaserpistol );
PRECACHE_WEAPON_REGISTER( weapon_laserpistol );
BEGIN_DATADESC( CWeaponLaserpistol )
DEFINE_FIELD( m_flSoonestPrimaryAttack, FIELD_TIME ),
DEFINE_FIELD( m_flLastAttackTime, FIELD_TIME ),
DEFINE_FIELD( m_flAccuracyPenalty, FIELD_FLOAT ), //NOTENOTE: This is NOT tracking game time
DEFINE_FIELD( m_nNumShotsFired, FIELD_INTEGER ),
DEFINE_FIELD( m_nBulletType, FIELD_INTEGER ),
END_DATADESC()
acttable_t CWeaponLaserpistol::m_acttable[] =
{
{ ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_PISTOL, false }, // L1ght 15 : MP animstate
{ ACT_HL2MP_RUN, ACT_HL2MP_RUN_PISTOL, false },
{ ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_PISTOL, false },
{ ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_PISTOL, false },
{ ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_PISTOL, false },
{ ACT_HL2MP_GESTURE_RELOAD, ACT_GESTURE_RELOAD_SMG1, false }, //fix
{ ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_PISTOL, false },
//{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_PISTOL, false }, // END
{ ACT_IDLE, ACT_IDLE_PISTOL, true },
{ ACT_IDLE_ANGRY, ACT_IDLE_ANGRY_PISTOL, true },
{ ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_PISTOL, true },
{ ACT_RELOAD, ACT_RELOAD_PISTOL, true },
{ ACT_WALK_AIM, ACT_WALK_AIM_PISTOL, true },
{ ACT_RUN_AIM, ACT_RUN_AIM_PISTOL, true },
{ ACT_COVER_LOW, ACT_COVER_PISTOL_LOW, true },
{ ACT_RANGE_AIM_LOW, ACT_RANGE_AIM_PISTOL_LOW, true },
{ ACT_GESTURE_RANGE_ATTACK1, ACT_GESTURE_RANGE_ATTACK_PISTOL,true },
{ ACT_RELOAD_LOW, ACT_RELOAD_PISTOL_LOW, true },
{ ACT_RANGE_ATTACK1_LOW, ACT_RANGE_ATTACK_PISTOL_LOW, true },
{ ACT_GESTURE_RELOAD, ACT_GESTURE_RELOAD_PISTOL, true },
// Readiness activities (not aiming)
{ ACT_IDLE_RELAXED, ACT_IDLE/*_PISTOL*/, false },//never aims
{ ACT_IDLE_STIMULATED, ACT_IDLE_STIMULATED, false },
{ ACT_IDLE_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims
{ ACT_IDLE_STEALTH, ACT_IDLE_STEALTH_PISTOL, false },
{ ACT_WALK_RELAXED, ACT_WALK, false },//never aims
{ ACT_WALK_STIMULATED, ACT_WALK_STIMULATED, false },
{ ACT_WALK_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims
{ ACT_WALK_STEALTH, ACT_WALK_STEALTH_PISTOL, false },
{ ACT_RUN_RELAXED, ACT_RUN, false },//never aims
{ ACT_RUN_STIMULATED, ACT_RUN_STIMULATED, false },
{ ACT_RUN_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims
{ ACT_RUN_STEALTH, ACT_RUN_STEALTH_PISTOL, false },
// Readiness activities (aiming)
{ ACT_IDLE_AIM_RELAXED, ACT_IDLE_PISTOL, false },//never aims
{ ACT_IDLE_AIM_STIMULATED, ACT_IDLE_ANGRY_PISTOL, false },
{ ACT_IDLE_AIM_AGITATED, ACT_IDLE_ANGRY_PISTOL, false },//always aims
{ ACT_IDLE_AIM_STEALTH, ACT_IDLE_STEALTH_PISTOL, false },
{ ACT_WALK_AIM_RELAXED, ACT_WALK, false },//never aims
{ ACT_WALK_AIM_STIMULATED, ACT_WALK_AIM_PISTOL, false },
{ ACT_WALK_AIM_AGITATED, ACT_WALK_AIM_PISTOL, false },//always aims
{ ACT_WALK_AIM_STEALTH, ACT_WALK_AIM_STEALTH_PISTOL, false },//always aims
{ ACT_RUN_AIM_RELAXED, ACT_RUN, false },//never aims
{ ACT_RUN_AIM_STIMULATED, ACT_RUN_AIM_PISTOL, false },
{ ACT_RUN_AIM_AGITATED, ACT_RUN_AIM_PISTOL, false },//always aims
{ ACT_RUN_AIM_STEALTH, ACT_RUN_AIM_STEALTH_PISTOL, false },//always aims
//End readiness activities
// Crouch activities
{ ACT_CROUCHIDLE_STIMULATED, ACT_CROUCHIDLE_STIMULATED, false },
{ ACT_CROUCHIDLE_AIM_STIMULATED,ACT_RANGE_AIM_PISTOL_LOW, false },//always aims
{ ACT_CROUCHIDLE_AGITATED, ACT_RANGE_AIM_PISTOL_LOW, false },//always aims
// Readiness translations
{ ACT_READINESS_RELAXED_TO_STIMULATED, ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED, false },
{ ACT_READINESS_RELAXED_TO_STIMULATED_WALK, ACT_READINESS_PISTOL_RELAXED_TO_STIMULATED_WALK, false },
{ ACT_READINESS_AGITATED_TO_STIMULATED, ACT_READINESS_PISTOL_AGITATED_TO_STIMULATED, false },
{ ACT_READINESS_STIMULATED_TO_RELAXED, ACT_READINESS_PISTOL_STIMULATED_TO_RELAXED, false },
};
IMPLEMENT_ACTTABLE( CWeaponLaserpistol );
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CWeaponLaserpistol::CWeaponLaserpistol( void )
{
m_flSoonestPrimaryAttack = gpGlobals->curtime;
m_nBulletType = -1;
m_flAccuracyPenalty = 0.0f;
m_fMinRange1 = 24;
m_fMaxRange1 = 1500;
m_fMinRange2 = 24;
m_fMaxRange2 = 200;
m_bFiresUnderwater = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponLaserpistol::Precache( void )
{
//PrecacheParticleSystem( "weapon_muzzle_smoke_long" );
//if (cvar->FindVar("laserpistol_shoot_effect")->GetInt() == 2)
//{
PrecacheParticleSystem( "electrical_arc_01_parent" );
//}
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Purpose:
// Input :
// Output :
//-----------------------------------------------------------------------------
void CWeaponLaserpistol::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator )
{
switch( pEvent->event )
{
case EVENT_WEAPON_PISTOL_FIRE:
{
Vector vecShootOrigin, vecShootDir;
vecShootOrigin = pOperator->Weapon_ShootPosition();
CAI_BaseNPC *npc = pOperator->MyNPCPointer();
ASSERT( npc != NULL );
vecShootDir = npc->GetActualShootTrajectory( vecShootOrigin );
CSoundEnt::InsertSound( SOUND_COMBAT|SOUND_CONTEXT_GUNFIRE, pOperator->GetAbsOrigin(), SOUNDENT_VOLUME_PISTOL, 0.2, pOperator, SOUNDENT_CHANNEL_WEAPON, pOperator->GetEnemy() );
WeaponSound( SINGLE_NPC );
pOperator->FireBullets(1, vecShootOrigin, vecShootDir, pOperator->GetAttackSpread(this), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2);
pOperator->DoMuzzleFlash();
m_iClip1 = m_iClip1 - 1;
}
break;
default:
BaseClass::Operator_HandleAnimEvent( pEvent, pOperator );
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponLaserpistol::DryFire( void )
{
WeaponSound( EMPTY );
SendWeaponAnim( ACT_VM_DRYFIRE );
m_flSoonestPrimaryAttack = gpGlobals->curtime + Laserpistol_FASTEST_DRY_REFIRE_TIME;
m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponLaserpistol::PrimaryAttack( trace_t &tr, int nDamageType, CBaseCombatCharacter *pOperator )
{
CBasePlayer *pOwner = ToBasePlayer(GetOwner());
if (pOwner == NULL)
return;
if ((cvar->FindVar("oc_state_near_wall_standing")->GetInt() == 1) || (cvar->FindVar("oc_state_is_running")->GetInt() == 1))
{
return;
}
if ( ( gpGlobals->curtime - m_flLastAttackTime ) > 0.5f )
{
m_nNumShotsFired = 0;
}
else
{
m_nNumShotsFired++;
}
m_flLastAttackTime = gpGlobals->curtime;
m_flSoonestPrimaryAttack = gpGlobals->curtime + Laserpistol_FASTEST_REFIRE_TIME;
CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), SOUNDENT_VOLUME_PISTOL, 0.2, GetOwner() );
/*if(m_nNumShotsFired >= 5)
{
DispatchParticleEffect( "weapon_muzzle_smoke_long", PATTACH_POINT_FOLLOW, pOwner->GetViewModel(), "muzzle", true);
}*/
BaseClass::PrimaryAttack();
// Add an accuracy penalty which can move past our maximum penalty time if we're really spastic
m_flAccuracyPenalty += Laserpistol_ACCURACY_SHOT_PENALTY_TIME;
m_iPrimaryAttacks++;
gamestats->Event_WeaponFired( pOwner, true, GetClassname() );
Vector vecShootOrigin, vecShootDir;
vecShootOrigin = pOperator->Weapon_ShootPosition();
DrawBeam( vecShootOrigin, tr.endpos, 15.5 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponLaserpistol::UpdatePenaltyTime( void )
{
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner == NULL )
return;
// Check our penalty time decay
if ( ( ( pOwner->m_nButtons & IN_ATTACK ) == false ) && ( m_flSoonestPrimaryAttack < gpGlobals->curtime ) )
{
m_flAccuracyPenalty -= gpGlobals->frametime;
m_flAccuracyPenalty = clamp( m_flAccuracyPenalty, 0.0f, Laserpistol_ACCURACY_MAXIMUM_PENALTY_TIME );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponLaserpistol::ItemPreFrame( void )
{
UpdatePenaltyTime();
BaseClass::ItemPreFrame();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CWeaponLaserpistol::ItemBusyFrame( void )
{
UpdatePenaltyTime();
BaseClass::ItemBusyFrame();
}
//-----------------------------------------------------------------------------
// Purpose: Allows firing as fast as button is pressed
//-----------------------------------------------------------------------------
void CWeaponLaserpistol::ItemPostFrame( void )
{
if (!m_bInReload && ((cvar->FindVar("oc_state_near_wall_standing")->GetInt() == 1) || (cvar->FindVar("oc_state_is_running")->GetInt() == 1)))
{
m_flNextPrimaryAttack = gpGlobals->curtime + 0.15;
m_flNextSecondaryAttack = gpGlobals->curtime + 0.15;
}
BaseClass::ItemPostFrame();
if ( m_bInReload )
return;
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
if ( pOwner == NULL )
return;
//Allow a refire as fast as the player can click
if ( ( ( pOwner->m_nButtons & IN_ATTACK ) == false ) && ( m_flSoonestPrimaryAttack < gpGlobals->curtime ) )
{
m_flNextPrimaryAttack = gpGlobals->curtime - 0.1f;
}
else if ( ( pOwner->m_nButtons & IN_ATTACK ) && ( m_flNextPrimaryAttack < gpGlobals->curtime ) && ( m_iClip1 <= 0 ) )
{
DryFire();
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
/*Activity CWeaponLaserpistol::GetPrimaryAttackActivity( void )
{
if ( m_nNumShotsFired < 1 )
return ACT_VM_PRIMARYATTACK;
if ( m_nNumShotsFired < 2 )
return ACT_VM_RECOIL1;
if ( m_nNumShotsFired < 3 )
return ACT_VM_RECOIL2;
return ACT_VM_RECOIL3;
}*/
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
bool CWeaponLaserpistol::Reload( void )
{
bool fRet = DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
if ( fRet )
{
WeaponSound( RELOAD );
m_flAccuracyPenalty = 0.0f;
}
return fRet;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &startPos - where the beam should begin
// &endPos - where the beam should end
// width - what the diameter of the beam should be (units?)
//-----------------------------------------------------------------------------
void CWeaponLaserpistol::DrawBeam( const Vector &startPos, const Vector &endPos, float width )
{
//Tracer down the middle
UTIL_Tracer( startPos, endPos, 0, TRACER_DONT_USE_ATTACHMENT, 6500, false, "GaussTracer" );
if (cvar->FindVar("oc_wpn_laserpistol_shoot_effect")->GetInt() == 2)
{
CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
DispatchParticleEffect( "electrical_arc_01_parent", PATTACH_POINT_FOLLOW, pOwner->GetViewModel(), "muzzle", true);
}
if (cvar->FindVar("oc_wpn_laserpistol_shoot_effect")->GetInt() == 1)
{
//Draw the main beam shaft
CBeam *pBeam = CBeam::BeamCreate( PHYSCANNON_BEAM_SPRITE, 15.5 );
// It starts at startPos
pBeam->SetStartPos( startPos );
// This sets up some things that the beam uses to figure out where
// it should start and end
pBeam->PointEntInit( endPos, this );
// This makes it so that the laser appears to come from the muzzle of the pistol
pBeam->SetEndAttachment( LookupAttachment("Muzzle") );
pBeam->SetWidth( width );
// pBeam->SetEndWidth( 0.05f );
// Higher brightness means less transparent
pBeam->SetBrightness( 255 );
pBeam->SetColor( 255, 185+random->RandomInt( -16, 16 ), 40 );
pBeam->RelinkBeam();
// The beam should only exist for a very short time
pBeam->LiveForTime( 0.1f );
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &tr - used to figure out where to do the effect
// nDamageType - ???
//-----------------------------------------------------------------------------
void CWeaponLaserpistol::DoImpactEffect( trace_t &tr, int nDamageType )
{
//Draw our beam
DrawBeam( tr.startpos, tr.endpos, 15.5 );
if ( (tr.surface.flags & SURF_SKY) == false )
{
CPVSFilter filter( tr.endpos );
te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 );
m_nBulletType = GetAmmoDef()->Index("GaussEnergy");
UTIL_ImpactTrace( &tr, m_nBulletType );
}
}
void CWeaponLaserpistol::SecondaryAttack( void )
{
CBasePlayer *pPlayer = ToBasePlayer(GetOwner());
if (!pPlayer)
return;
if ((cvar->FindVar("oc_state_near_wall_standing")->GetInt() == 1) || (cvar->FindVar("oc_state_is_running")->GetInt() == 1))
{
return;
}
if (cvar->FindVar("oc_wpn_laserpistol_shoot_effect")->GetInt() == 0)
{
cvar->FindVar("oc_wpn_laserpistol_shoot_effect")->SetValue(1);
}
else
{
cvar->FindVar("oc_wpn_laserpistol_shoot_effect")->SetValue(0);
}
WeaponSound( EMPTY );
SendWeaponAnim( ACT_VM_DRYFIRE );
m_flNextSecondaryAttack = gpGlobals->curtime + 2.0f;
}