Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1080 lines
24 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: RPG
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "npcevent.h"
  9. #include "in_buttons.h"
  10. #include "hl1mp_basecombatweapon_shared.h"
  11. #include "hl1mp_weapon_rpg.h"
  12. #ifdef CLIENT_DLL
  13. #include "hl1/c_hl1mp_player.h"
  14. #include "model_types.h"
  15. #include "beamdraw.h"
  16. #include "fx_line.h"
  17. #include "view.h"
  18. #else
  19. #include "basecombatcharacter.h"
  20. #include "movie_explosion.h"
  21. #include "hl1mp_player.h"
  22. #include "rope.h"
  23. #include "soundent.h"
  24. #include "vstdlib/random.h"
  25. #include "engine/IEngineSound.h"
  26. #include "explode.h"
  27. #include "util.h"
  28. #include "te_effect_dispatch.h"
  29. #include "shake.h"
  30. #endif
  31. // memdbgon must be the last include file in a .cpp file!!!
  32. #include "tier0/memdbgon.h"
  33. extern ConVar sk_plr_dmg_rpg;
  34. void TE_BeamFollow( IRecipientFilter& filter, float delay,
  35. int iEntIndex, int modelIndex, int haloIndex, float life, float width, float endWidth,
  36. float fadeLength,float r, float g, float b, float a );
  37. #define RPG_LASER_SPRITE "sprites/redglow_mp1"
  38. class CLaserDot : public CBaseEntity
  39. {
  40. DECLARE_CLASS( CLaserDot, CBaseEntity );
  41. public:
  42. CLaserDot( void );
  43. ~CLaserDot( void );
  44. static CLaserDot *Create( const Vector &origin, CBaseEntity *pOwner = NULL, bool bVisibleDot = true );
  45. void SetTargetEntity( CBaseEntity *pTarget ) { m_hTargetEnt = pTarget; }
  46. CBaseEntity *GetTargetEntity( void ) { return m_hTargetEnt; }
  47. void SetLaserPosition( const Vector &origin, const Vector &normal );
  48. Vector GetChasePosition();
  49. void TurnOn( void );
  50. void TurnOff( void );
  51. bool IsOn() const { return m_bIsOn; }
  52. void Toggle( void );
  53. int ObjectCaps() { return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION) | FCAP_DONT_SAVE; }
  54. void MakeInvisible( void );
  55. #ifdef CLIENT_DLL
  56. virtual bool IsTransparent( void ) { return true; }
  57. virtual RenderGroup_t GetRenderGroup( void ) { return RENDER_GROUP_TRANSLUCENT_ENTITY; }
  58. virtual int DrawModel( int flags );
  59. virtual void OnDataChanged( DataUpdateType_t updateType );
  60. virtual bool ShouldDraw( void ) { return (IsEffectActive(EF_NODRAW)==false); }
  61. CMaterialReference m_hSpriteMaterial;
  62. #endif
  63. protected:
  64. Vector m_vecSurfaceNormal;
  65. EHANDLE m_hTargetEnt;
  66. bool m_bVisibleLaserDot;
  67. // bool m_bIsOn;
  68. CNetworkVar( bool, m_bIsOn );
  69. DECLARE_NETWORKCLASS();
  70. DECLARE_DATADESC();
  71. public:
  72. CLaserDot *m_pNext;
  73. };
  74. #ifndef CLIENT_DLL
  75. //=============================================================================
  76. // RPG Rocket
  77. //=============================================================================
  78. BEGIN_DATADESC( CRpgRocket )
  79. DEFINE_FIELD( m_hOwner, FIELD_EHANDLE ),
  80. DEFINE_FIELD( m_vecAbsVelocity, FIELD_VECTOR ),
  81. DEFINE_FIELD( m_flIgniteTime, FIELD_TIME ),
  82. //DEFINE_FIELD( m_iTrail, FIELD_INTEGER ),
  83. // Function Pointers
  84. DEFINE_ENTITYFUNC( RocketTouch ),
  85. DEFINE_THINKFUNC( IgniteThink ),
  86. DEFINE_THINKFUNC( SeekThink ),
  87. END_DATADESC()
  88. LINK_ENTITY_TO_CLASS( rpg_rocket, CRpgRocket );
  89. IMPLEMENT_SERVERCLASS_ST(CRpgRocket, DT_RpgRocket)
  90. END_SEND_TABLE()
  91. CRpgRocket::CRpgRocket()
  92. {
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose:
  96. //
  97. //
  98. //-----------------------------------------------------------------------------
  99. void CRpgRocket::Precache( void )
  100. {
  101. PrecacheModel( "models/rpgrocket.mdl" );
  102. PrecacheModel( "sprites/animglow01.vmt" );
  103. PrecacheScriptSound( "Weapon_RPG.RocketIgnite" );
  104. m_iTrail = PrecacheModel("sprites/smoke.vmt");
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose:
  108. //
  109. //
  110. //-----------------------------------------------------------------------------
  111. void CRpgRocket::Spawn( void )
  112. {
  113. Precache();
  114. SetSolid( SOLID_BBOX );
  115. SetModel("models/rpgrocket.mdl");
  116. UTIL_SetSize( this, -Vector(0,0,0), Vector(0,0,0) );
  117. SetTouch( &CRpgRocket::RocketTouch );
  118. SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
  119. SetThink( &CRpgRocket::IgniteThink );
  120. SetNextThink( gpGlobals->curtime + 0.4f );
  121. QAngle angAngs;
  122. Vector vecFwd;
  123. angAngs = GetAbsAngles();
  124. angAngs.x -= 30;
  125. AngleVectors( angAngs, &vecFwd );
  126. SetAbsVelocity( vecFwd * 250 );
  127. SetGravity( UTIL_ScaleForGravity( 400 ) ); // use a lower gravity for rockets
  128. m_flDamage = sk_plr_dmg_rpg.GetFloat();
  129. m_DmgRadius = m_flDamage * 2.5;
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose:
  133. // Input : *pOther -
  134. //-----------------------------------------------------------------------------
  135. void CRpgRocket::RocketTouch( CBaseEntity *pOther )
  136. {
  137. if ( !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) )
  138. return;
  139. if ( m_hOwner != NULL )
  140. {
  141. m_hOwner->NotifyRocketDied();
  142. }
  143. StopSound( "Weapon_RPG.RocketIgnite" );
  144. ExplodeTouch( pOther );
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Purpose:
  148. //-----------------------------------------------------------------------------
  149. void CRpgRocket::IgniteThink( void )
  150. {
  151. SetMoveType( MOVETYPE_FLY );
  152. AddEffects( EF_DIMLIGHT );
  153. EmitSound( "Weapon_RPG.RocketIgnite" );
  154. SetThink( &CRpgRocket::SeekThink );
  155. SetNextThink( gpGlobals->curtime + 0.1f );
  156. CBroadcastRecipientFilter filter;
  157. TE_BeamFollow( filter, 0.0,
  158. entindex(),
  159. m_iTrail,
  160. 0,
  161. 4,
  162. 5,
  163. 5,
  164. 0,
  165. 224,
  166. 224,
  167. 255,
  168. 255 );
  169. m_flIgniteTime = gpGlobals->curtime;
  170. }
  171. #define RPG_HOMING_SPEED 0.125f
  172. //-----------------------------------------------------------------------------
  173. // Purpose:
  174. //-----------------------------------------------------------------------------
  175. void CRpgRocket::SeekThink( void )
  176. {
  177. CBaseEntity *pOther = NULL;
  178. Vector vecTarget;
  179. Vector vecFwd;
  180. Vector vecDir;
  181. float flDist, flMax, flDot;
  182. trace_t tr;
  183. AngleVectors( GetAbsAngles(), &vecFwd );
  184. vecTarget = vecFwd;
  185. flMax = 4096;
  186. // Examine all entities within a reasonable radius
  187. while ( (pOther = gEntList.FindEntityByClassname( pOther, "laser_spot" ) ) != NULL)
  188. {
  189. CLaserDot *pDot = dynamic_cast<CLaserDot*>(pOther);
  190. // if ( pDot->IsActive() )
  191. if ( pDot->IsOn() )
  192. {
  193. UTIL_TraceLine( GetAbsOrigin(), pDot->GetAbsOrigin(), MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  194. if ( tr.fraction >= 0.90 )
  195. {
  196. vecDir = pDot->GetAbsOrigin() - GetAbsOrigin();
  197. flDist = VectorLength( vecDir );
  198. VectorNormalize( vecDir );
  199. flDot = DotProduct( vecFwd, vecDir );
  200. if ( (flDot > 0) && (flDist * (1 - flDot) < flMax) )
  201. {
  202. flMax = flDist * (1 - flDot);
  203. vecTarget = vecDir;
  204. }
  205. }
  206. }
  207. }
  208. QAngle vecAng;
  209. VectorAngles( vecTarget, vecAng );
  210. SetAbsAngles( vecAng );
  211. // this acceleration and turning math is totally wrong, but it seems to respond well so don't change it.
  212. float flSpeed = GetAbsVelocity().Length();
  213. if ( gpGlobals->curtime - m_flIgniteTime < 1.0 )
  214. {
  215. SetAbsVelocity( GetAbsVelocity() * 0.2 + vecTarget * (flSpeed * 0.8 + 400) );
  216. if ( GetWaterLevel() == 3 )
  217. {
  218. // go slow underwater
  219. if ( GetAbsVelocity().Length() > 300 )
  220. {
  221. Vector vecVel = GetAbsVelocity();
  222. VectorNormalize( vecVel );
  223. SetAbsVelocity( vecVel * 300 );
  224. }
  225. UTIL_BubbleTrail( GetAbsOrigin() - GetAbsVelocity() * 0.1, GetAbsOrigin(), 4 );
  226. }
  227. else
  228. {
  229. if ( GetAbsVelocity().Length() > 2000 )
  230. {
  231. Vector vecVel = GetAbsVelocity();
  232. VectorNormalize( vecVel );
  233. SetAbsVelocity( vecVel * 2000 );
  234. }
  235. }
  236. }
  237. else
  238. {
  239. if ( IsEffectActive( EF_DIMLIGHT ) )
  240. {
  241. ClearEffects();
  242. }
  243. SetAbsVelocity( GetAbsVelocity() * 0.2 + vecTarget * flSpeed * 0.798 );
  244. if ( GetWaterLevel() == 0 && GetAbsVelocity().Length() < 1500 )
  245. {
  246. Detonate();
  247. }
  248. }
  249. SetNextThink( gpGlobals->curtime + 0.1f );
  250. }
  251. void CRpgRocket::Detonate( void )
  252. {
  253. StopSound( "Weapon_RPG.RocketIgnite" );
  254. BaseClass::Detonate();
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Purpose:
  258. //
  259. // Input : &vecOrigin -
  260. // &vecAngles -
  261. // NULL -
  262. //
  263. // Output : CRpgRocket
  264. //-----------------------------------------------------------------------------
  265. CRpgRocket *CRpgRocket::Create( const Vector &vecOrigin, const QAngle &angAngles, CBasePlayer *pentOwner )
  266. {
  267. CRpgRocket *pRocket = (CRpgRocket *)CreateEntityByName( "rpg_rocket" );
  268. UTIL_SetOrigin( pRocket, vecOrigin );
  269. pRocket->SetAbsAngles( angAngles );
  270. pRocket->Spawn();
  271. pRocket->SetOwnerEntity( pentOwner );
  272. return pRocket;
  273. }
  274. #endif // endif #ifndef CLIENT_DLL
  275. //=============================================================================
  276. // Laser Dot
  277. //=============================================================================
  278. IMPLEMENT_NETWORKCLASS_ALIASED( LaserDot, DT_LaserDot )
  279. BEGIN_NETWORK_TABLE( CLaserDot, DT_LaserDot )
  280. #ifdef CLIENT_DLL
  281. RecvPropBool( RECVINFO( m_bIsOn ) ),
  282. #else
  283. SendPropBool( SENDINFO( m_bIsOn ) ),
  284. #endif
  285. END_NETWORK_TABLE()
  286. #ifndef CLIENT_DLL
  287. // a list of laser dots to search quickly
  288. CEntityClassList<CLaserDot> g_LaserDotList;
  289. template <> CLaserDot *CEntityClassList<CLaserDot>::m_pClassList = NULL;
  290. CLaserDot *GetLaserDotList()
  291. {
  292. return g_LaserDotList.m_pClassList;
  293. }
  294. #endif
  295. LINK_ENTITY_TO_CLASS( laser_spot, CLaserDot );
  296. BEGIN_DATADESC( CLaserDot )
  297. DEFINE_FIELD( m_vecSurfaceNormal, FIELD_VECTOR ),
  298. DEFINE_FIELD( m_hTargetEnt, FIELD_EHANDLE ),
  299. DEFINE_FIELD( m_bVisibleLaserDot, FIELD_BOOLEAN ),
  300. DEFINE_FIELD( m_bIsOn, FIELD_BOOLEAN ),
  301. //DEFINE_FIELD( m_pNext, FIELD_CLASSPTR ), // don't save - regenerated by constructor
  302. END_DATADESC()
  303. //-----------------------------------------------------------------------------
  304. // Finds missiles in cone
  305. //-----------------------------------------------------------------------------
  306. CBaseEntity *CreateLaserDot( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot )
  307. {
  308. return CLaserDot::Create( origin, pOwner, bVisibleDot );
  309. }
  310. void SetLaserDotTarget( CBaseEntity *pLaserDot, CBaseEntity *pTarget )
  311. {
  312. CLaserDot *pDot = assert_cast< CLaserDot* >(pLaserDot );
  313. pDot->SetTargetEntity( pTarget );
  314. }
  315. void EnableLaserDot( CBaseEntity *pLaserDot, bool bEnable )
  316. {
  317. CLaserDot *pDot = assert_cast< CLaserDot* >(pLaserDot );
  318. if ( bEnable )
  319. {
  320. pDot->TurnOn();
  321. }
  322. else
  323. {
  324. pDot->TurnOff();
  325. }
  326. }
  327. CLaserDot::CLaserDot( void )
  328. {
  329. m_hTargetEnt = NULL;
  330. m_bIsOn = true;
  331. #ifndef CLIENT_DLL
  332. g_LaserDotList.Insert( this );
  333. #endif
  334. }
  335. CLaserDot::~CLaserDot( void )
  336. {
  337. #ifndef CLIENT_DLL
  338. g_LaserDotList.Remove( this );
  339. #endif
  340. }
  341. //-----------------------------------------------------------------------------
  342. // Purpose:
  343. // Input : &origin -
  344. // Output : CLaserDot
  345. //-----------------------------------------------------------------------------
  346. CLaserDot *CLaserDot::Create( const Vector &origin, CBaseEntity *pOwner, bool bVisibleDot )
  347. {
  348. #ifndef CLIENT_DLL
  349. CLaserDot *pLaserDot = (CLaserDot *) CBaseEntity::Create( "laser_spot", origin, QAngle(0,0,0) );
  350. if ( pLaserDot == NULL )
  351. return NULL;
  352. pLaserDot->m_bVisibleLaserDot = bVisibleDot;
  353. pLaserDot->SetMoveType( MOVETYPE_NONE );
  354. pLaserDot->AddSolidFlags( FSOLID_NOT_SOLID );
  355. pLaserDot->AddEffects( EF_NOSHADOW );
  356. UTIL_SetSize( pLaserDot, -Vector(6,6,6), Vector(6,6,6) );
  357. pLaserDot->SetOwnerEntity( pOwner );
  358. pLaserDot->AddEFlags( EFL_FORCE_CHECK_TRANSMIT );
  359. if ( !bVisibleDot )
  360. {
  361. pLaserDot->MakeInvisible();
  362. }
  363. return pLaserDot;
  364. #else
  365. return NULL;
  366. #endif
  367. }
  368. void CLaserDot::SetLaserPosition( const Vector &origin, const Vector &normal )
  369. {
  370. SetAbsOrigin( origin );
  371. m_vecSurfaceNormal = normal;
  372. }
  373. Vector CLaserDot::GetChasePosition()
  374. {
  375. return GetAbsOrigin() - m_vecSurfaceNormal * 10;
  376. }
  377. //-----------------------------------------------------------------------------
  378. // Purpose:
  379. //-----------------------------------------------------------------------------
  380. void CLaserDot::TurnOn( void )
  381. {
  382. m_bIsOn = true;
  383. RemoveEffects(EF_NODRAW);
  384. if ( m_bVisibleLaserDot )
  385. {
  386. //BaseClass::TurnOn();
  387. }
  388. }
  389. //-----------------------------------------------------------------------------
  390. // Purpose:
  391. //-----------------------------------------------------------------------------
  392. void CLaserDot::TurnOff( void )
  393. {
  394. m_bIsOn = false;
  395. AddEffects(EF_NODRAW);
  396. if ( m_bVisibleLaserDot )
  397. {
  398. //BaseClass::TurnOff();
  399. }
  400. }
  401. //-----------------------------------------------------------------------------
  402. // Purpose:
  403. //-----------------------------------------------------------------------------
  404. void CLaserDot::MakeInvisible( void )
  405. {
  406. }
  407. #ifdef CLIENT_DLL
  408. //-----------------------------------------------------------------------------
  409. // Purpose: Draw our sprite
  410. //-----------------------------------------------------------------------------
  411. int CLaserDot::DrawModel( int flags )
  412. {
  413. color32 color={255,255,255,255};
  414. Vector vecAttachment, vecDir;
  415. QAngle angles;
  416. float scale;
  417. Vector endPos;
  418. C_HL1MP_Player *pOwner = ToHL1MPPlayer( GetOwnerEntity() );
  419. if ( pOwner != NULL && pOwner->IsDormant() == false )
  420. {
  421. // Always draw the dot in front of our faces when in first-person
  422. if ( pOwner->IsLocalPlayer() )
  423. {
  424. // Take our view position and orientation
  425. vecAttachment = CurrentViewOrigin();
  426. vecDir = CurrentViewForward();
  427. }
  428. else
  429. {
  430. // Take the eye position and direction
  431. vecAttachment = pOwner->EyePosition();
  432. QAngle angles = pOwner->EyeAngles();
  433. AngleVectors( angles, &vecDir );
  434. }
  435. trace_t tr;
  436. UTIL_TraceLine( vecAttachment, vecAttachment + ( vecDir * MAX_TRACE_LENGTH ), MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr );
  437. // Backup off the hit plane
  438. endPos = tr.endpos + ( tr.plane.normal * 4.0f );
  439. }
  440. else
  441. {
  442. // Just use our position if we can't predict it otherwise
  443. endPos = GetAbsOrigin();
  444. }
  445. // Randomly flutter
  446. scale = 16.0f + random->RandomFloat( -4.0f, 4.0f );
  447. // Draw our laser dot in space
  448. CMatRenderContextPtr pRenderContext( materials );
  449. pRenderContext->Bind( m_hSpriteMaterial, this );
  450. DrawSprite( endPos, scale, scale, color );
  451. return 1;
  452. }
  453. //-----------------------------------------------------------------------------
  454. // Purpose: Setup our sprite reference
  455. //-----------------------------------------------------------------------------
  456. void CLaserDot::OnDataChanged( DataUpdateType_t updateType )
  457. {
  458. if ( updateType == DATA_UPDATE_CREATED )
  459. {
  460. m_hSpriteMaterial.Init( RPG_LASER_SPRITE, TEXTURE_GROUP_CLIENT_EFFECTS );
  461. }
  462. }
  463. #endif //CLIENT_DLL
  464. //=============================================================================
  465. // RPG Weapon
  466. //=============================================================================
  467. LINK_ENTITY_TO_CLASS( weapon_rpg, CWeaponRPG );
  468. PRECACHE_WEAPON_REGISTER( weapon_rpg );
  469. //IMPLEMENT_SERVERCLASS_ST( CWeaponRPG, DT_WeaponRPG )
  470. //END_SEND_TABLE()
  471. IMPLEMENT_NETWORKCLASS_ALIASED( WeaponRPG, DT_WeaponRPG )
  472. BEGIN_DATADESC( CWeaponRPG )
  473. DEFINE_FIELD( m_bIntialStateUpdate, FIELD_BOOLEAN ),
  474. DEFINE_FIELD( m_bGuiding, FIELD_BOOLEAN ),
  475. #ifndef CLIENT_DLL
  476. DEFINE_FIELD( m_hLaserDot, FIELD_EHANDLE ),
  477. #endif
  478. DEFINE_FIELD( m_hMissile, FIELD_EHANDLE ),
  479. DEFINE_FIELD( m_bLaserDotSuspended, FIELD_BOOLEAN ),
  480. DEFINE_FIELD( m_flLaserDotReviveTime, FIELD_TIME ),
  481. END_DATADESC()
  482. BEGIN_NETWORK_TABLE( CWeaponRPG, DT_WeaponRPG )
  483. #ifdef CLIENT_DLL
  484. RecvPropBool( RECVINFO( m_bIntialStateUpdate ) ),
  485. RecvPropBool( RECVINFO( m_bGuiding ) ),
  486. RecvPropBool( RECVINFO( m_bLaserDotSuspended ) ),
  487. // RecvPropEHandle( RECVINFO( m_hMissile ), RecvProxy_MissileDied ),
  488. // RecvPropVector( RECVINFO( m_vecLaserDot ) ),
  489. #else
  490. SendPropBool( SENDINFO( m_bIntialStateUpdate ) ),
  491. SendPropBool( SENDINFO( m_bGuiding ) ),
  492. SendPropBool( SENDINFO( m_bLaserDotSuspended ) ),
  493. // SendPropEHandle( SENDINFO( m_hMissile ) ),
  494. // SendPropVector( SENDINFO( m_vecLaserDot ) ),
  495. #endif
  496. END_NETWORK_TABLE()
  497. BEGIN_PREDICTION_DATA( CWeaponRPG )
  498. #ifdef CLIENT_DLL
  499. DEFINE_PRED_FIELD( m_bIntialStateUpdate, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  500. DEFINE_PRED_FIELD( m_bGuiding, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  501. DEFINE_PRED_FIELD( m_bLaserDotSuspended, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ),
  502. DEFINE_PRED_FIELD( m_flLaserDotReviveTime, FIELD_FLOAT, FTYPEDESC_INSENDTABLE ),
  503. #endif
  504. END_PREDICTION_DATA()
  505. //-----------------------------------------------------------------------------
  506. // Purpose: Constructor
  507. //-----------------------------------------------------------------------------
  508. CWeaponRPG::CWeaponRPG( void )
  509. {
  510. m_bReloadsSingly = false;
  511. m_bFiresUnderwater = true;
  512. m_bGuiding = true;
  513. m_bIntialStateUpdate = false;
  514. m_bLaserDotSuspended = false;
  515. }
  516. CWeaponRPG::~CWeaponRPG()
  517. {
  518. #ifndef CLIENT_DLL
  519. if ( m_hLaserDot != NULL )
  520. {
  521. UTIL_Remove( m_hLaserDot );
  522. m_hLaserDot = NULL;
  523. }
  524. #endif
  525. }
  526. //-----------------------------------------------------------------------------
  527. // Purpose:
  528. //-----------------------------------------------------------------------------
  529. void CWeaponRPG::ItemPostFrame( void )
  530. {
  531. BaseClass::ItemPostFrame();
  532. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  533. if ( pPlayer == NULL )
  534. return;
  535. //If we're pulling the weapon out for the first time, wait to draw the laser
  536. if ( m_bIntialStateUpdate )
  537. {
  538. if ( GetActivity() != ACT_VM_DRAW )
  539. {
  540. if ( IsGuiding() && !m_bLaserDotSuspended )
  541. {
  542. #ifndef CLIENT_DLL
  543. if ( m_hLaserDot != NULL )
  544. {
  545. m_hLaserDot->TurnOn();
  546. }
  547. #endif
  548. }
  549. m_bIntialStateUpdate = false;
  550. }
  551. else
  552. {
  553. return;
  554. }
  555. }
  556. //Player has toggled guidance state
  557. if ( pPlayer->m_afButtonPressed & IN_ATTACK2 )
  558. {
  559. if ( IsGuiding() )
  560. {
  561. StopGuiding();
  562. }
  563. else
  564. {
  565. StartGuiding();
  566. }
  567. }
  568. //Move the laser
  569. UpdateSpot();
  570. }
  571. void CWeaponRPG::Drop( const Vector &vecVelocity )
  572. {
  573. StopGuiding();
  574. #ifndef CLIENT_DLL
  575. if ( m_hLaserDot != NULL )
  576. {
  577. UTIL_Remove( m_hLaserDot );
  578. m_hLaserDot = NULL;
  579. }
  580. #endif
  581. BaseClass::Drop( vecVelocity );
  582. }
  583. int CWeaponRPG::GetDefaultClip1( void ) const
  584. {
  585. if ( g_pGameRules->IsMultiplayer() )
  586. {
  587. // more default ammo in multiplay.
  588. return BaseClass::GetDefaultClip1() * 2;
  589. }
  590. else
  591. {
  592. return BaseClass::GetDefaultClip1();
  593. }
  594. }
  595. //-----------------------------------------------------------------------------
  596. // Purpose:
  597. //-----------------------------------------------------------------------------
  598. void CWeaponRPG::Precache( void )
  599. {
  600. #ifndef CLIENT_DLL
  601. UTIL_PrecacheOther( "laser_spot" );
  602. UTIL_PrecacheOther( "rpg_rocket" );
  603. #endif
  604. // PrecacheModel( RPG_LASER_SPRITE );
  605. PrecacheModel( "sprites/redglow_mp1.vmt" );
  606. BaseClass::Precache();
  607. }
  608. bool CWeaponRPG::Deploy( void )
  609. {
  610. m_bIntialStateUpdate = true;
  611. m_bLaserDotSuspended = false;
  612. CreateLaserPointer();
  613. #ifndef CLIENT_DLL
  614. if ( m_hLaserDot != NULL )
  615. {
  616. m_hLaserDot->TurnOff();
  617. }
  618. #endif
  619. if ( m_iClip1 <= 0 )
  620. {
  621. return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_RPG_DRAW_UNLOADED, (char*)GetAnimPrefix() );
  622. }
  623. return DefaultDeploy( (char*)GetViewModel(), (char*)GetWorldModel(), ACT_VM_DRAW, (char*)GetAnimPrefix() );
  624. }
  625. //-----------------------------------------------------------------------------
  626. // Purpose:
  627. //-----------------------------------------------------------------------------
  628. void CWeaponRPG::PrimaryAttack( void )
  629. {
  630. // Can't have an active missile out
  631. if ( m_hMissile != NULL )
  632. return;
  633. // Can't be reloading
  634. if ( GetActivity() == ACT_VM_RELOAD )
  635. return;
  636. if ( m_iClip1 <= 0 )
  637. {
  638. if ( !m_bFireOnEmpty )
  639. {
  640. Reload();
  641. }
  642. else
  643. {
  644. WeaponSound( EMPTY );
  645. m_flNextPrimaryAttack = gpGlobals->curtime + 0.2;
  646. }
  647. }
  648. Vector vecOrigin;
  649. Vector vecForward;
  650. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  651. if ( pOwner == NULL )
  652. return;
  653. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  654. WeaponSound( SINGLE );
  655. #ifndef CLIENT_DLL
  656. CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 400, 0.2 );
  657. #endif
  658. pOwner->DoMuzzleFlash();
  659. #ifndef CLIENT_DLL
  660. // Register a muzzleflash for the AI
  661. pOwner->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 );
  662. #endif
  663. Vector vForward, vRight, vUp;
  664. pOwner->EyeVectors( &vForward, &vRight, &vUp );
  665. Vector muzzlePoint = pOwner->Weapon_ShootPosition() + vForward * 16.0f + vRight * 8.0f + vUp * -8.0f;
  666. #ifndef CLIENT_DLL
  667. QAngle vecAngles;
  668. VectorAngles( vForward, vecAngles );
  669. CRpgRocket * pMissile = CRpgRocket::Create( muzzlePoint, vecAngles, pOwner );
  670. pMissile->m_hOwner = this;
  671. pMissile->SetAbsVelocity( pMissile->GetAbsVelocity() + vForward * DotProduct( pOwner->GetAbsVelocity(), vForward ) );
  672. m_hMissile = pMissile;
  673. #endif
  674. pOwner->ViewPunch( QAngle( -5, 0, 0 ) );
  675. m_iClip1--;
  676. m_flNextPrimaryAttack = gpGlobals->curtime + 1.5;
  677. SetWeaponIdleTime( 1.5 );
  678. UpdateSpot();
  679. }
  680. void CWeaponRPG::WeaponIdle( void )
  681. {
  682. CBaseCombatCharacter *pOwner = GetOwner();
  683. if ( pOwner == NULL )
  684. return;
  685. if ( !HasWeaponIdleTimeElapsed() )
  686. return;
  687. int iAnim;
  688. float flRand = random->RandomFloat( 0, 1 );
  689. if ( flRand <= 0.75 || IsGuiding() )
  690. {
  691. if ( m_iClip1 <= 0 )
  692. iAnim = ACT_RPG_IDLE_UNLOADED;
  693. else
  694. iAnim = ACT_VM_IDLE;
  695. }
  696. else
  697. {
  698. if ( m_iClip1 <= 0 )
  699. iAnim = ACT_RPG_FIDGET_UNLOADED;
  700. else
  701. iAnim = ACT_VM_FIDGET;
  702. }
  703. SendWeaponAnim( iAnim );
  704. }
  705. void CWeaponRPG::NotifyRocketDied( void )
  706. {
  707. m_hMissile = NULL;
  708. // Can't be reloading
  709. if ( GetActivity() == ACT_VM_RELOAD )
  710. return;
  711. // Reload();
  712. }
  713. bool CWeaponRPG::Reload( void )
  714. {
  715. CBaseCombatCharacter *pOwner = GetOwner();
  716. #if 0
  717. if ( pOwner == NULL )
  718. return false;
  719. if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
  720. return false;
  721. WeaponSound( RELOAD );
  722. SendWeaponAnim( ACT_VM_RELOAD );
  723. #ifndef CLIENT_DLL
  724. if ( m_hLaserDot != NULL )
  725. {
  726. m_hLaserDot->TurnOff();
  727. }
  728. #endif
  729. m_bLaserDotSuspended = true;
  730. m_flLaserDotReviveTime = gpGlobals->curtime + 2.1;
  731. m_flNextPrimaryAttack = gpGlobals->curtime + 2.1;
  732. m_flNextSecondaryAttack = gpGlobals->curtime + 2.1;
  733. return true;
  734. #endif
  735. // Can't be reloading
  736. if ( GetActivity() == ACT_VM_RELOAD )
  737. return false;
  738. if ( pOwner == NULL )
  739. return false;
  740. if ( m_iClip1 > 0 )
  741. return false;
  742. if ( pOwner->GetAmmoCount(m_iPrimaryAmmoType) <= 0 )
  743. return false;
  744. // because the RPG waits to autoreload when no missiles are active while the LTD is on, the
  745. // weapons code is constantly calling into this function, but is often denied because
  746. // a) missiles are in flight, but the LTD is on
  747. // or
  748. // b) player is totally out of ammo and has nothing to switch to, and should be allowed to
  749. // shine the designator around
  750. //
  751. // Set the next attack time into the future so that WeaponIdle will get called more often
  752. // than reload, allowing the RPG LTD to be updated
  753. if ( ( m_hMissile != NULL ) && IsGuiding() )
  754. {
  755. // no reloading when there are active missiles tracking the designator.
  756. // ward off future autoreload attempts by setting next attack time into the future for a bit.
  757. return false;
  758. }
  759. #ifndef CLIENT_DLL
  760. if ( m_hLaserDot != NULL )
  761. {
  762. m_hLaserDot->TurnOff();
  763. }
  764. #endif
  765. m_bLaserDotSuspended = true;
  766. m_flLaserDotReviveTime = gpGlobals->curtime + 2.1;
  767. m_flNextSecondaryAttack = gpGlobals->curtime + 2.1;
  768. return DefaultReload( GetMaxClip1(), GetMaxClip2(), ACT_VM_RELOAD );
  769. }
  770. bool CWeaponRPG::Holster( CBaseCombatWeapon *pSwitchingTo )
  771. {
  772. // can't put away while guiding a missile.
  773. if ( IsGuiding() && ( m_hMissile != NULL ) )
  774. return false;
  775. // StopGuiding();
  776. #ifndef CLIENT_DLL
  777. if ( m_hLaserDot != NULL )
  778. {
  779. m_hLaserDot->TurnOff();
  780. UTIL_Remove( m_hLaserDot );
  781. m_hLaserDot = NULL;
  782. }
  783. #endif
  784. m_bLaserDotSuspended = false;
  785. return BaseClass::Holster( pSwitchingTo );
  786. }
  787. void CWeaponRPG::UpdateSpot( void )
  788. {
  789. CBasePlayer *pPlayer = ToBasePlayer( GetOwner() );
  790. if ( pPlayer == NULL )
  791. return;
  792. CreateLaserPointer();
  793. #ifndef CLIENT_DLL
  794. if ( m_hLaserDot == NULL )
  795. return;
  796. #endif
  797. if ( IsGuiding() && m_bLaserDotSuspended && ( m_flLaserDotReviveTime <= gpGlobals->curtime ) )
  798. {
  799. #ifndef CLIENT_DLL
  800. m_hLaserDot->TurnOn();
  801. #endif
  802. m_bLaserDotSuspended = false;
  803. }
  804. //Move the laser dot, if active
  805. trace_t tr;
  806. Vector muzzlePos = pPlayer->Weapon_ShootPosition();
  807. Vector forward;
  808. AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, &forward );
  809. Vector endPos = muzzlePos + ( forward * MAX_TRACE_LENGTH );
  810. // Trace out for the endpoint
  811. UTIL_TraceLine( muzzlePos, endPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  812. // Move the laser sprite
  813. Vector laserPos = tr.endpos + ( tr.plane.normal * 2.0f );
  814. #ifndef CLIENT_DLL
  815. m_hLaserDot->SetLaserPosition( laserPos, tr.plane.normal );
  816. #endif
  817. }
  818. void CWeaponRPG::CreateLaserPointer( void )
  819. {
  820. #ifndef CLIENT_DLL
  821. if ( m_hLaserDot != NULL )
  822. return;
  823. m_hLaserDot = CLaserDot::Create( GetAbsOrigin(), GetOwner() );
  824. if ( !IsGuiding() )
  825. {
  826. if ( m_hLaserDot )
  827. {
  828. m_hLaserDot->TurnOff();
  829. }
  830. }
  831. #endif
  832. }
  833. bool CWeaponRPG::IsGuiding( void )
  834. {
  835. return m_bGuiding;
  836. }
  837. void CWeaponRPG::StartGuiding( void )
  838. {
  839. m_bGuiding = true;
  840. #ifndef CLIENT_DLL
  841. if ( m_hLaserDot != NULL )
  842. {
  843. m_hLaserDot->TurnOn();
  844. }
  845. #endif
  846. UpdateSpot();
  847. }
  848. void CWeaponRPG::StopGuiding( void )
  849. {
  850. m_bGuiding = false;
  851. #ifndef CLIENT_DLL
  852. if ( m_hLaserDot != NULL )
  853. {
  854. m_hLaserDot->TurnOff();
  855. }
  856. #endif
  857. }