diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/hl1/hl1mp_weapon_rpg.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/shared/hl1/hl1mp_weapon_rpg.cpp')
| -rw-r--r-- | game/shared/hl1/hl1mp_weapon_rpg.cpp | 1080 |
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 +} |