summaryrefslogtreecommitdiff
path: root/game/shared/hl1/hl1mp_weapon_rpg.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/hl1/hl1mp_weapon_rpg.cpp')
-rw-r--r--game/shared/hl1/hl1mp_weapon_rpg.cpp1080
1 files changed, 1080 insertions, 0 deletions
diff --git a/game/shared/hl1/hl1mp_weapon_rpg.cpp b/game/shared/hl1/hl1mp_weapon_rpg.cpp
new file mode 100644
index 0000000..98cf2fa
--- /dev/null
+++ b/game/shared/hl1/hl1mp_weapon_rpg.cpp
@@ -0,0 +1,1080 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: RPG
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "npcevent.h"
+#include "in_buttons.h"
+#include "hl1mp_basecombatweapon_shared.h"
+#include "hl1mp_weapon_rpg.h"
+
+#ifdef CLIENT_DLL
+#include "hl1/c_hl1mp_player.h"
+#include "model_types.h"
+#include "beamdraw.h"
+#include "fx_line.h"
+#include "view.h"
+#else
+#include "basecombatcharacter.h"
+#include "movie_explosion.h"
+#include "hl1mp_player.h"
+#include "rope.h"
+#include "soundent.h"
+#include "vstdlib/random.h"
+#include "engine/IEngineSound.h"
+#include "explode.h"
+#include "util.h"
+#include "te_effect_dispatch.h"
+#include "shake.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+extern ConVar sk_plr_dmg_rpg;
+
+
+void TE_BeamFollow( IRecipientFilter& filter, float delay,
+ int iEntIndex, int modelIndex, int haloIndex, float life, float width, float endWidth,
+ float fadeLength,float r, float g, float b, float a );
+
+#define RPG_LASER_SPRITE "sprites/redglow_mp1"
+
+class CLaserDot : public CBaseEntity
+{
+ DECLARE_CLASS( CLaserDot, CBaseEntity );
+public:
+
+ CLaserDot( void );
+ ~CLaserDot( void );
+
+ static CLaserDot *Create( const Vector &origin, CBaseEntity *pOwner = NULL, bool bVisibleDot = true );
+
+ void SetTargetEntity( CBaseEntity *pTarget ) { m_hTargetEnt = pTarget; }
+ CBaseEntity *GetTargetEntity( void ) { return m_hTargetEnt; }
+
+ void SetLaserPosition( const Vector &origin, const Vector &normal );
+ Vector GetChasePosition();
+ void TurnOn( void );
+ void TurnOff( void );
+ bool IsOn() const { return m_bIsOn; }
+
+ void Toggle( void );
+
+ int ObjectCaps() { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; }
+
+ void MakeInvisible( void );
+
+#ifdef CLIENT_DLL
+
+ virtual bool IsTransparent( void ) { return true; }
+ virtual RenderGroup_t GetRenderGroup( void ) { return RENDER_GROUP_TRANSLUCENT_ENTITY; }
+ virtual int DrawModel( int flags );
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual bool ShouldDraw( void ) { return (IsEffectActive(EF_NODRAW)==false); }
+
+ CMaterialReference m_hSpriteMaterial;
+#endif
+
+protected:
+ Vector m_vecSurfaceNormal;
+ EHANDLE m_hTargetEnt;
+ bool m_bVisibleLaserDot;
+// bool m_bIsOn;
+ CNetworkVar( bool, m_bIsOn );
+
+ DECLARE_NETWORKCLASS();
+ DECLARE_DATADESC();
+public:
+ CLaserDot *m_pNext;
+};
+
+
+#ifndef CLIENT_DLL
+
+//=============================================================================
+// RPG Rocket
+//=============================================================================
+
+
+BEGIN_DATADESC( CRpgRocket )
+ DEFINE_FIELD( m_hOwner, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_vecAbsVelocity, FIELD_VECTOR ),
+ DEFINE_FIELD( m_flIgniteTime, FIELD_TIME ),
+ //DEFINE_FIELD( m_iTrail, FIELD_INTEGER ),
+
+ // Function Pointers
+ DEFINE_ENTITYFUNC( RocketTouch ),
+ DEFINE_THINKFUNC( IgniteThink ),
+ DEFINE_THINKFUNC( SeekThink ),
+END_DATADESC()
+
+LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket );
+
+IMPLEMENT_SERVERCLASS_ST(CRpgRocket, DT_RpgRocket)
+END_SEND_TABLE()
+
+CRpgRocket::CRpgRocket()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//
+//
+//-----------------------------------------------------------------------------
+void CRpgRocket::Precache( void )
+{
+ PrecacheModel( "models/rpgrocket.mdl" );
+ PrecacheModel( "sprites/animglow01.vmt" );
+
+ PrecacheScriptSound( "Weapon_RPG.RocketIgnite" );
+
+ m_iTrail = PrecacheModel("sprites/smoke.vmt");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//
+//
+//-----------------------------------------------------------------------------
+void CRpgRocket::Spawn( void )
+{
+ Precache();
+
+ SetSolid( SOLID_BBOX );
+ SetModel("models/rpgrocket.mdl");
+ UTIL_SetSize( this, -Vector(0,0,0), Vector(0,0,0) );
+
+ SetTouch( &CRpgRocket::RocketTouch );
+
+ SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
+ SetThink( &CRpgRocket::IgniteThink );
+
+ SetNextThink( gpGlobals->curtime + 0.4f );
+
+ QAngle angAngs;
+ Vector vecFwd;
+
+ angAngs = GetAbsAngles();
+ angAngs.x -= 30;
+ AngleVectors( angAngs, &vecFwd );
+ SetAbsVelocity( vecFwd * 250 );
+
+ SetGravity( UTIL_ScaleForGravity( 400 ) ); // use a lower gravity for rockets
+
+ m_flDamage = sk_plr_dmg_rpg.GetFloat();
+ m_DmgRadius = m_flDamage * 2.5;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pOther -
+//-----------------------------------------------------------------------------
+void CRpgRocket::RocketTouch( CBaseEntity *pOther )
+{
+ if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
+ return;
+
+ if ( m_hOwner != NULL )
+ {
+ m_hOwner->NotifyRocketDied();
+ }
+
+ StopSound( "Weapon_RPG.RocketIgnite" );
+ ExplodeTouch( pOther );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CRpgRocket::IgniteThink( void )
+{
+ SetMoveType( MOVETYPE_FLY );
+
+ AddEffects( EF_DIMLIGHT );
+
+ EmitSound( "Weapon_RPG.RocketIgnite" );
+
+ SetThink( &CRpgRocket::SeekThink );
+ SetNextThink( gpGlobals->curtime + 0.1f );
+
+ CBroadcastRecipientFilter filter;
+ TE_BeamFollow( filter, 0.0,
+ entindex(),
+ m_iTrail,
+ 0,
+ 4,
+ 5,
+ 5,
+ 0,
+ 224,
+ 224,
+ 255,
+ 255 );
+
+ m_flIgniteTime = gpGlobals->curtime;
+}
+
+#define RPG_HOMING_SPEED 0.125f
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CRpgRocket::SeekThink( void )
+{
+ CBaseEntity *pOther = NULL;
+ Vector vecTarget;
+ Vector vecFwd;
+ Vector vecDir;
+ float flDist, flMax, flDot;
+ trace_t tr;
+
+ AngleVectors( GetAbsAngles(), &vecFwd );
+
+ vecTarget = vecFwd;
+ flMax = 4096;
+
+ // Examine all entities within a reasonable radius
+ while ( (pOther = gEntList.FindEntityByClassname( pOther, "laser_spot" ) ) != NULL)
+ {
+ CLaserDot *pDot = dynamic_cast<CLaserDot*>(pOther);
+
+// if ( pDot->IsActive() )
+ if ( pDot->IsOn() )
+ {
+ UTIL_TraceLine( GetAbsOrigin(), pDot->GetAbsOrigin(), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+ if ( tr.fraction >= 0.90 )
+ {
+ vecDir = pDot->GetAbsOrigin() - GetAbsOrigin();
+ flDist = VectorLength( vecDir );
+ VectorNormalize( vecDir );
+ flDot = DotProduct( vecFwd, vecDir );
+ if ( (flDot > 0) && (flDist * (1 - flDot) < flMax) )
+ {
+ flMax = flDist * (1 - flDot);
+ vecTarget = vecDir;
+ }
+ }
+ }
+ }
+
+ QAngle vecAng;
+ VectorAngles( vecTarget, vecAng );
+ SetAbsAngles( vecAng );
+
+ // this acceleration and turning math is totally wrong, but it seems to respond well so don't change it.
+ float flSpeed = GetAbsVelocity().Length();
+ if ( gpGlobals->curtime - m_flIgniteTime < 1.0 )
+ {
+ SetAbsVelocity( GetAbsVelocity() * 0.2 + vecTarget * (flSpeed * 0.8 + 400) );
+ if ( GetWaterLevel() == 3 )
+ {
+ // go slow underwater
+ if ( GetAbsVelocity().Length() > 300 )
+ {
+ Vector vecVel = GetAbsVelocity();
+ VectorNormalize( vecVel );
+ SetAbsVelocity( vecVel * 300 );
+ }
+
+ UTIL_BubbleTrail( GetAbsOrigin() - GetAbsVelocity() * 0.1, GetAbsOrigin(), 4 );
+ }
+ else
+ {
+ if ( GetAbsVelocity().Length() > 2000 )
+ {
+ Vector vecVel = GetAbsVelocity();
+ VectorNormalize( vecVel );
+ SetAbsVelocity( vecVel * 2000 );
+ }
+ }
+ }
+ else
+ {
+ if ( IsEffectActive( EF_DIMLIGHT ) )
+ {
+ ClearEffects();
+ }
+
+ SetAbsVelocity( GetAbsVelocity() * 0.2 + vecTarget * flSpeed * 0.798 );
+
+ if ( GetWaterLevel() == 0 && GetAbsVelocity().Length() < 1500 )
+ {
+ Detonate();
+ }
+ }
+
+ SetNextThink( gpGlobals->curtime + 0.1f );
+}
+
+void CRpgRocket::Detonate( void )
+{
+ StopSound( "Weapon_RPG.RocketIgnite" );
+ BaseClass::Detonate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//
+// Input : &vecOrigin -
+// &vecAngles -
+// NULL -
+//
+// Output : CRpgRocket
+//-----------------------------------------------------------------------------
+CRpgRocket *CRpgRocket::Create( const Vector &vecOrigin, const QAngle &angAngles, CBasePlayer *pentOwner )
+{
+ CRpgRocket *pRocket = (CRpgRocket *)CreateEntityByName( "rpg_rocket" );
+ UTIL_SetOrigin( pRocket, vecOrigin );
+ pRocket->SetAbsAngles( angAngles );
+ pRocket->Spawn();
+ pRocket->SetOwnerEntity( pentOwner );
+
+ return pRocket;
+}
+
+#endif // endif #ifndef CLIENT_DLL
+
+
+//=============================================================================
+// Laser Dot
+//=============================================================================
+
+IMPLEMENT_NETWORKCLASS_ALIASED( LaserDot, DT_LaserDot )
+
+BEGIN_NETWORK_TABLE( CLaserDot, DT_LaserDot )
+#ifdef CLIENT_DLL
+ RecvPropBool( RECVINFO( m_bIsOn ) ),
+#else
+ SendPropBool( SENDINFO( m_bIsOn ) ),
+#endif
+END_NETWORK_TABLE()
+
+#ifndef CLIENT_DLL
+// a list of laser dots to search quickly
+CEntityClassList<CLaserDot> g_LaserDotList;
+template <> CLaserDot *CEntityClassList<CLaserDot>::m_pClassList = NULL;
+CLaserDot *GetLaserDotList()
+{
+ return g_LaserDotList.m_pClassList;
+}
+
+#endif
+
+LINK_ENTITY_TO_CLASS( laser_spot, CLaserDot );
+
+BEGIN_DATADESC( CLaserDot )
+ DEFINE_FIELD( m_vecSurfaceNormal, FIELD_VECTOR ),
+ DEFINE_FIELD( m_hTargetEnt, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_bVisibleLaserDot, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_bIsOn, FIELD_BOOLEAN ),
+
+ //DEFINE_FIELD( m_pNext, FIELD_CLASSPTR ), // don't save - regenerated by constructor
+END_DATADESC()
+
+
+//-----------------------------------------------------------------------------
+// Finds missiles in cone
+//-----------------------------------------------------------------------------
+CBaseEntity *CreateLaserDot( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot )
+{
+ return CLaserDot::Create( origin, pOwner, bVisibleDot );
+}
+
+void SetLaserDotTarget( CBaseEntity *pLaserDot, CBaseEntity *pTarget )
+{
+ CLaserDot *pDot = assert_cast< CLaserDot* >(pLaserDot );
+ pDot->SetTargetEntity( pTarget );
+}
+
+void EnableLaserDot( CBaseEntity *pLaserDot, bool bEnable )
+{
+ CLaserDot *pDot = assert_cast< CLaserDot* >(pLaserDot );
+ if ( bEnable )
+ {
+ pDot->TurnOn();
+ }
+ else
+ {
+ pDot->TurnOff();
+ }
+}
+
+CLaserDot::CLaserDot( void )
+{
+ m_hTargetEnt = NULL;
+ m_bIsOn = true;
+#ifndef CLIENT_DLL
+ g_LaserDotList.Insert( this );
+#endif
+}
+
+CLaserDot::~CLaserDot( void )
+{
+#ifndef CLIENT_DLL
+ g_LaserDotList.Remove( this );
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &origin -
+// Output : CLaserDot
+//-----------------------------------------------------------------------------
+CLaserDot *CLaserDot::Create( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot )
+{
+#ifndef CLIENT_DLL
+ CLaserDot *pLaserDot = (CLaserDot *) CBaseEntity::Create( "laser_spot", origin, QAngle(0,0,0) );
+
+ if ( pLaserDot == NULL )
+ return NULL;
+
+ pLaserDot->m_bVisibleLaserDot = bVisibleDot;
+ pLaserDot->SetMoveType( MOVETYPE_NONE );
+ pLaserDot->AddSolidFlags( FSOLID_NOT_SOLID );
+ pLaserDot->AddEffects( EF_NOSHADOW );
+ UTIL_SetSize( pLaserDot, -Vector(6,6,6), Vector(6,6,6) );
+
+ pLaserDot->SetOwnerEntity( pOwner );
+
+ pLaserDot->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
+
+ if ( !bVisibleDot )
+ {
+ pLaserDot->MakeInvisible();
+ }
+
+ return pLaserDot;
+#else
+ return NULL;
+#endif
+}
+
+void CLaserDot::SetLaserPosition( const Vector &origin, const Vector &normal )
+{
+ SetAbsOrigin( origin );
+ m_vecSurfaceNormal = normal;
+}
+
+Vector CLaserDot::GetChasePosition()
+{
+ return GetAbsOrigin() - m_vecSurfaceNormal * 10;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLaserDot::TurnOn( void )
+{
+ m_bIsOn = true;
+ RemoveEffects(EF_NODRAW);
+
+ if ( m_bVisibleLaserDot )
+ {
+ //BaseClass::TurnOn();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLaserDot::TurnOff( void )
+{
+ m_bIsOn = false;
+ AddEffects(EF_NODRAW);
+ if ( m_bVisibleLaserDot )
+ {
+ //BaseClass::TurnOff();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLaserDot::MakeInvisible( void )
+{
+}
+
+#ifdef CLIENT_DLL
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw our sprite
+//-----------------------------------------------------------------------------
+int CLaserDot::DrawModel( int flags )
+{
+ color32 color={255,255,255,255};
+ Vector vecAttachment, vecDir;
+ QAngle angles;
+
+ float scale;
+ Vector endPos;
+
+ C_HL1MP_Player *pOwner = ToHL1MPPlayer( GetOwnerEntity() );
+
+ if ( pOwner != NULL && pOwner->IsDormant() == false )
+ {
+ // Always draw the dot in front of our faces when in first-person
+ if ( pOwner->IsLocalPlayer() )
+ {
+ // Take our view position and orientation
+ vecAttachment = CurrentViewOrigin();
+ vecDir = CurrentViewForward();
+ }
+ else
+ {
+ // Take the eye position and direction
+ vecAttachment = pOwner->EyePosition();
+
+ QAngle angles = pOwner->EyeAngles();
+ AngleVectors( angles, &vecDir );
+ }
+
+ trace_t tr;
+ UTIL_TraceLine( vecAttachment, vecAttachment + ( vecDir * MAX_TRACE_LENGTH ), MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr );
+
+ // Backup off the hit plane
+ endPos = tr.endpos + ( tr.plane.normal * 4.0f );
+ }
+ else
+ {
+ // Just use our position if we can't predict it otherwise
+ endPos = GetAbsOrigin();
+ }
+
+ // Randomly flutter
+ scale = 16.0f + random->RandomFloat( -4.0f, 4.0f );
+
+ // Draw our laser dot in space
+ CMatRenderContextPtr pRenderContext( materials );
+ pRenderContext->Bind( m_hSpriteMaterial, this );
+ DrawSprite( endPos, scale, scale, color );
+
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Setup our sprite reference
+//-----------------------------------------------------------------------------
+void CLaserDot::OnDataChanged( DataUpdateType_t updateType )
+{
+ if ( updateType == DATA_UPDATE_CREATED )
+ {
+ m_hSpriteMaterial.Init( RPG_LASER_SPRITE, TEXTURE_GROUP_CLIENT_EFFECTS );
+ }
+}
+
+#endif //CLIENT_DLL
+
+//=============================================================================
+// RPG Weapon
+//=============================================================================
+
+LINK_ENTITY_TO_CLASS( weapon_rpg, CWeaponRPG );
+
+PRECACHE_WEAPON_REGISTER( weapon_rpg );
+
+//IMPLEMENT_SERVERCLASS_ST( CWeaponRPG, DT_WeaponRPG )
+//END_SEND_TABLE()
+
+IMPLEMENT_NETWORKCLASS_ALIASED( WeaponRPG, DT_WeaponRPG )
+
+BEGIN_DATADESC( CWeaponRPG )
+DEFINE_FIELD( m_bIntialStateUpdate, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_bGuiding, FIELD_BOOLEAN ),
+#ifndef CLIENT_DLL
+ DEFINE_FIELD( m_hLaserDot, FIELD_EHANDLE ),
+#endif
+ DEFINE_FIELD( m_hMissile, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_bLaserDotSuspended, FIELD_BOOLEAN ),
+ DEFINE_FIELD( m_flLaserDotReviveTime, FIELD_TIME ),
+END_DATADESC()
+
+
+BEGIN_NETWORK_TABLE( CWeaponRPG, DT_WeaponRPG )
+#ifdef CLIENT_DLL
+ RecvPropBool( RECVINFO( m_bIntialStateUpdate ) ),
+ RecvPropBool( RECVINFO( m_bGuiding ) ),
+ RecvPropBool( RECVINFO( m_bLaserDotSuspended ) ),
+// RecvPropEHandle( RECVINFO( m_hMissile ), RecvProxy_MissileDied ),
+// RecvPropVector( RECVINFO( m_vecLaserDot ) ),
+#else
+ SendPropBool( SENDINFO( m_bIntialStateUpdate ) ),
+ SendPropBool( SENDINFO( m_bGuiding ) ),
+ SendPropBool( SENDINFO( m_bLaserDotSuspended ) ),
+// SendPropEHandle( SENDINFO( m_hMissile ) ),
+// SendPropVector( SENDINFO( m_vecLaserDot ) ),
+#endif
+END_NETWORK_TABLE()
+
+
+BEGIN_PREDICTION_DATA( CWeaponRPG )
+#ifdef CLIENT_DLL
+ DEFINE_PRED_FIELD( m_bIntialStateUpdate, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bGuiding, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_bLaserDotSuspended, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
+ DEFINE_PRED_FIELD( m_flLaserDotReviveTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
+#endif
+END_PREDICTION_DATA()
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CWeaponRPG::CWeaponRPG( void )
+{
+ m_bReloadsSingly = false;
+ m_bFiresUnderwater = true;
+ m_bGuiding = true;
+ m_bIntialStateUpdate = false;
+ m_bLaserDotSuspended = false;
+}
+
+
+CWeaponRPG::~CWeaponRPG()
+{
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot != NULL )
+ {
+ UTIL_Remove( m_hLaserDot );
+ m_hLaserDot = NULL;
+ }
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponRPG::ItemPostFrame( void )
+{
+ BaseClass::ItemPostFrame();
+
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+
+ if ( pPlayer == NULL )
+ return;
+
+ //If we're pulling the weapon out for the first time, wait to draw the laser
+ if ( m_bIntialStateUpdate )
+ {
+ if ( GetActivity() != ACT_VM_DRAW )
+ {
+ if ( IsGuiding() && !m_bLaserDotSuspended )
+ {
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot != NULL )
+ {
+ m_hLaserDot->TurnOn();
+ }
+#endif
+ }
+
+ m_bIntialStateUpdate = false;
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ //Player has toggled guidance state
+ if ( pPlayer->m_afButtonPressed & IN_ATTACK2 )
+ {
+ if ( IsGuiding() )
+ {
+ StopGuiding();
+ }
+ else
+ {
+ StartGuiding();
+ }
+ }
+
+ //Move the laser
+ UpdateSpot();
+}
+
+
+void CWeaponRPG::Drop( const Vector &vecVelocity )
+{
+ StopGuiding();
+
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot != NULL )
+ {
+ UTIL_Remove( m_hLaserDot );
+ m_hLaserDot = NULL;
+ }
+#endif
+
+ BaseClass::Drop( vecVelocity );
+}
+
+
+int CWeaponRPG::GetDefaultClip1( void ) const
+{
+ if ( g_pGameRules->IsMultiplayer() )
+ {
+ // more default ammo in multiplay.
+ return BaseClass::GetDefaultClip1() * 2;
+ }
+ else
+ {
+ return BaseClass::GetDefaultClip1();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponRPG::Precache( void )
+{
+#ifndef CLIENT_DLL
+ UTIL_PrecacheOther( "laser_spot" );
+ UTIL_PrecacheOther( "rpg_rocket" );
+#endif
+
+// PrecacheModel( RPG_LASER_SPRITE );
+ PrecacheModel( "sprites/redglow_mp1.vmt" );
+
+ BaseClass::Precache();
+}
+
+
+bool CWeaponRPG::Deploy( void )
+{
+ m_bIntialStateUpdate = true;
+ m_bLaserDotSuspended = false;
+ CreateLaserPointer();
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot != NULL )
+ {
+ m_hLaserDot->TurnOff();
+ }
+#endif
+
+ if ( m_iClip1 <= 0 )
+ {
+ return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_RPG_DRAW_UNLOADED, (char*)GetAnimPrefix() );
+ }
+
+ return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_DRAW, (char*)GetAnimPrefix() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWeaponRPG::PrimaryAttack( void )
+{
+ // Can't have an active missile out
+ if ( m_hMissile != NULL )
+ return;
+
+ // Can't be reloading
+ if ( GetActivity() == ACT_VM_RELOAD )
+ return;
+
+ if ( m_iClip1 <= 0 )
+ {
+ if ( !m_bFireOnEmpty )
+ {
+ Reload();
+ }
+ else
+ {
+ WeaponSound( EMPTY );
+ m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
+ }
+ }
+
+ Vector vecOrigin;
+ Vector vecForward;
+
+ CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
+
+ if ( pOwner == NULL )
+ return;
+
+ SendWeaponAnim( ACT_VM_PRIMARYATTACK );
+ WeaponSound( SINGLE );
+#ifndef CLIENT_DLL
+ CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 400, 0.2 );
+#endif
+ pOwner->DoMuzzleFlash();
+
+#ifndef CLIENT_DLL
+ // Register a muzzleflash for the AI
+ pOwner->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 );
+#endif
+
+ Vector vForward, vRight, vUp;
+
+ pOwner->EyeVectors( &vForward, &vRight, &vUp );
+
+ Vector muzzlePoint = pOwner->Weapon_ShootPosition() + vForward * 16.0f + vRight * 8.0f + vUp * -8.0f;
+
+#ifndef CLIENT_DLL
+ QAngle vecAngles;
+ VectorAngles( vForward, vecAngles );
+
+ CRpgRocket * pMissile = CRpgRocket::Create( muzzlePoint, vecAngles, pOwner );
+ pMissile->m_hOwner = this;
+ pMissile->SetAbsVelocity( pMissile->GetAbsVelocity() + vForward * DotProduct( pOwner->GetAbsVelocity(), vForward ) );
+
+ m_hMissile = pMissile;
+#endif
+
+ pOwner->ViewPunch( QAngle( -5, 0, 0 ) );
+
+ m_iClip1--;
+
+ m_flNextPrimaryAttack = gpGlobals->curtime + 1.5;
+ SetWeaponIdleTime( 1.5 );
+
+ UpdateSpot();
+}
+
+
+void CWeaponRPG::WeaponIdle( void )
+{
+ CBaseCombatCharacter *pOwner = GetOwner();
+
+ if ( pOwner == NULL )
+ return;
+
+ if ( !HasWeaponIdleTimeElapsed() )
+ return;
+
+ int iAnim;
+ float flRand = random->RandomFloat( 0, 1 );
+ if ( flRand <= 0.75 || IsGuiding() )
+ {
+ if ( m_iClip1 <= 0 )
+ iAnim = ACT_RPG_IDLE_UNLOADED;
+ else
+ iAnim = ACT_VM_IDLE;
+ }
+ else
+ {
+ if ( m_iClip1 <= 0 )
+ iAnim = ACT_RPG_FIDGET_UNLOADED;
+ else
+ iAnim = ACT_VM_FIDGET;
+ }
+
+ SendWeaponAnim( iAnim );
+}
+
+
+void CWeaponRPG::NotifyRocketDied( void )
+{
+ m_hMissile = NULL;
+
+ // Can't be reloading
+ if ( GetActivity() == ACT_VM_RELOAD )
+ return;
+
+// Reload();
+}
+
+
+bool CWeaponRPG::Reload( void )
+{
+ CBaseCombatCharacter *pOwner = GetOwner();
+
+#if 0
+ if ( pOwner == NULL )
+ return false;
+
+ if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
+ return false;
+
+ WeaponSound( RELOAD );
+
+ SendWeaponAnim( ACT_VM_RELOAD );
+
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot != NULL )
+ {
+ m_hLaserDot->TurnOff();
+ }
+#endif
+
+ m_bLaserDotSuspended = true;
+ m_flLaserDotReviveTime = gpGlobals->curtime + 2.1;
+ m_flNextPrimaryAttack = gpGlobals->curtime + 2.1;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 2.1;
+
+ return true;
+#endif
+
+ // Can't be reloading
+ if ( GetActivity() == ACT_VM_RELOAD )
+ return false;
+
+ if ( pOwner == NULL )
+ return false;
+
+ if ( m_iClip1 > 0 )
+ return false;
+
+ if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
+ return false;
+
+ // because the RPG waits to autoreload when no missiles are active while the LTD is on, the
+ // weapons code is constantly calling into this function, but is often denied because
+ // a) missiles are in flight, but the LTD is on
+ // or
+ // b) player is totally out of ammo and has nothing to switch to, and should be allowed to
+ // shine the designator around
+ //
+ // Set the next attack time into the future so that WeaponIdle will get called more often
+ // than reload, allowing the RPG LTD to be updated
+
+ if ( ( m_hMissile != NULL ) && IsGuiding() )
+ {
+ // no reloading when there are active missiles tracking the designator.
+ // ward off future autoreload attempts by setting next attack time into the future for a bit.
+ return false;
+ }
+
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot != NULL )
+ {
+ m_hLaserDot->TurnOff();
+ }
+#endif
+
+ m_bLaserDotSuspended = true;
+ m_flLaserDotReviveTime = gpGlobals->curtime + 2.1;
+ m_flNextSecondaryAttack = gpGlobals->curtime + 2.1;
+
+ return DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
+}
+
+
+bool CWeaponRPG::Holster( CBaseCombatWeapon *pSwitchingTo )
+{
+ // can't put away while guiding a missile.
+ if ( IsGuiding() && ( m_hMissile != NULL ) )
+ return false;
+
+// StopGuiding();
+
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot != NULL )
+ {
+ m_hLaserDot->TurnOff();
+ UTIL_Remove( m_hLaserDot );
+ m_hLaserDot = NULL;
+ }
+#endif
+
+ m_bLaserDotSuspended = false;
+
+ return BaseClass::Holster( pSwitchingTo );
+}
+
+
+void CWeaponRPG::UpdateSpot( void )
+{
+ CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
+
+ if ( pPlayer == NULL )
+ return;
+
+ CreateLaserPointer();
+
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot == NULL )
+ return;
+#endif
+
+ if ( IsGuiding() && m_bLaserDotSuspended && ( m_flLaserDotReviveTime <= gpGlobals->curtime ) )
+ {
+#ifndef CLIENT_DLL
+ m_hLaserDot->TurnOn();
+#endif
+ m_bLaserDotSuspended = false;
+ }
+
+ //Move the laser dot, if active
+ trace_t tr;
+ Vector muzzlePos = pPlayer->Weapon_ShootPosition();
+
+ Vector forward;
+ AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, &forward );
+
+ Vector endPos = muzzlePos + ( forward * MAX_TRACE_LENGTH );
+
+ // Trace out for the endpoint
+ UTIL_TraceLine( muzzlePos, endPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
+
+ // Move the laser sprite
+ Vector laserPos = tr.endpos + ( tr.plane.normal * 2.0f );
+#ifndef CLIENT_DLL
+ m_hLaserDot->SetLaserPosition( laserPos, tr.plane.normal );
+#endif
+}
+
+
+void CWeaponRPG::CreateLaserPointer( void )
+{
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot != NULL )
+ return;
+
+ m_hLaserDot = CLaserDot::Create( GetAbsOrigin(), GetOwner() );
+ if ( !IsGuiding() )
+ {
+ if ( m_hLaserDot )
+ {
+ m_hLaserDot->TurnOff();
+ }
+ }
+#endif
+}
+
+
+bool CWeaponRPG::IsGuiding( void )
+{
+ return m_bGuiding;
+}
+
+
+void CWeaponRPG::StartGuiding( void )
+{
+ m_bGuiding = true;
+
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot != NULL )
+ {
+ m_hLaserDot->TurnOn();
+ }
+#endif
+
+ UpdateSpot();
+}
+
+void CWeaponRPG::StopGuiding( void )
+{
+ m_bGuiding = false;
+
+#ifndef CLIENT_DLL
+ if ( m_hLaserDot != NULL )
+ {
+ m_hLaserDot->TurnOff();
+ }
+#endif
+}