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.

755 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Flare gun (fffsssssssssss!!)
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "player.h"
  9. #include "gamerules.h"
  10. #include "basehlcombatweapon.h"
  11. #include "decals.h"
  12. #include "soundenvelope.h"
  13. #include "IEffects.h"
  14. #include "engine/IEngineSound.h"
  15. #include "weapon_flaregun.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. /********************************************************************
  19. NOTE: if you are looking at this file becase you would like flares
  20. to be considered as fires (and thereby trigger gas traps), be aware
  21. that the env_flare class is actually found in weapon_flaregun.cpp
  22. and is really a repurposed piece of ammunition. (env_flare isn't the
  23. rod-like safety flare prop, but rather the bit of flame on the end.)
  24. You will have some difficulty making it work here, because CFlare
  25. does not inherit from CFire and will thus not be enumerated by
  26. CFireSphere::EnumElement(). In order to have flares be detected and
  27. used by this system, you will need to promote certain member functions
  28. of CFire into an interface class from which both CFire and CFlare
  29. inherit. You will also need to modify CFireSphere::EnumElement so that
  30. it properly disambiguates between fires and flares.
  31. For some partial work towards this end, see changelist 192474.
  32. ********************************************************************/
  33. #define FLARE_LAUNCH_SPEED 1500
  34. LINK_ENTITY_TO_CLASS( env_flare, CFlare );
  35. BEGIN_DATADESC( CFlare )
  36. DEFINE_FIELD( m_pOwner, FIELD_CLASSPTR ),
  37. DEFINE_FIELD( m_nBounces, FIELD_INTEGER ),
  38. DEFINE_FIELD( m_flTimeBurnOut, FIELD_TIME ),
  39. DEFINE_KEYFIELD( m_flScale, FIELD_FLOAT, "scale" ),
  40. DEFINE_KEYFIELD( m_flDuration, FIELD_FLOAT, "duration" ),
  41. DEFINE_FIELD( m_flNextDamage, FIELD_TIME ),
  42. DEFINE_SOUNDPATCH( m_pBurnSound ),
  43. DEFINE_FIELD( m_bFading, FIELD_BOOLEAN ),
  44. DEFINE_FIELD( m_bLight, FIELD_BOOLEAN ),
  45. DEFINE_FIELD( m_bSmoke, FIELD_BOOLEAN ),
  46. DEFINE_FIELD( m_bPropFlare, FIELD_BOOLEAN ),
  47. DEFINE_FIELD( m_bInActiveList, FIELD_BOOLEAN ),
  48. DEFINE_FIELD( m_pNextFlare, FIELD_CLASSPTR ),
  49. //Input functions
  50. DEFINE_INPUTFUNC( FIELD_FLOAT, "Start", InputStart ),
  51. DEFINE_INPUTFUNC( FIELD_FLOAT, "Die", InputDie ),
  52. DEFINE_INPUTFUNC( FIELD_FLOAT, "Launch", InputLaunch),
  53. // Function Pointers
  54. DEFINE_FUNCTION( FlareTouch ),
  55. DEFINE_FUNCTION( FlareBurnTouch ),
  56. DEFINE_FUNCTION( FlareThink ),
  57. END_DATADESC()
  58. //Data-tables
  59. IMPLEMENT_SERVERCLASS_ST( CFlare, DT_Flare )
  60. SendPropFloat( SENDINFO( m_flTimeBurnOut ), 0, SPROP_NOSCALE ),
  61. SendPropFloat( SENDINFO( m_flScale ), 0, SPROP_NOSCALE ),
  62. SendPropInt( SENDINFO( m_bLight ), 1, SPROP_UNSIGNED ),
  63. SendPropInt( SENDINFO( m_bSmoke ), 1, SPROP_UNSIGNED ),
  64. SendPropInt( SENDINFO( m_bPropFlare ), 1, SPROP_UNSIGNED ),
  65. END_SEND_TABLE()
  66. CFlare *CFlare::activeFlares = NULL;
  67. CFlare *CFlare::GetActiveFlares( void )
  68. {
  69. return CFlare::activeFlares;
  70. }
  71. Class_T CFlare::Classify( void )
  72. {
  73. return CLASS_FLARE;
  74. }
  75. CBaseEntity *CreateFlare( Vector vOrigin, QAngle Angles, CBaseEntity *pOwner, float flDuration )
  76. {
  77. CFlare *pFlare = CFlare::Create( vOrigin, Angles, pOwner, flDuration );
  78. if ( pFlare )
  79. {
  80. pFlare->m_bPropFlare = true;
  81. }
  82. return pFlare;
  83. }
  84. void KillFlare( CBaseEntity *pOwnerEntity, CBaseEntity *pEntity, float flKillTime )
  85. {
  86. CFlare *pFlare = dynamic_cast< CFlare *>( pEntity );
  87. if ( pFlare )
  88. {
  89. float flDieTime = (pFlare->m_flTimeBurnOut - gpGlobals->curtime) - flKillTime;
  90. if ( flDieTime > 1.0f )
  91. {
  92. pFlare->Die( flDieTime );
  93. pOwnerEntity->SetNextThink( gpGlobals->curtime + flDieTime + 3.0f );
  94. }
  95. }
  96. }
  97. //-----------------------------------------------------------------------------
  98. // Purpose:
  99. //-----------------------------------------------------------------------------
  100. CFlare::CFlare( void )
  101. {
  102. m_flScale = 1.0f;
  103. m_nBounces = 0;
  104. m_bFading = false;
  105. m_bLight = true;
  106. m_bSmoke = true;
  107. m_flNextDamage = gpGlobals->curtime;
  108. m_lifeState = LIFE_ALIVE;
  109. m_iHealth = 100;
  110. m_bPropFlare = false;
  111. m_bInActiveList = false;
  112. m_pNextFlare = NULL;
  113. }
  114. CFlare::~CFlare()
  115. {
  116. CSoundEnvelopeController::GetController().SoundDestroy( m_pBurnSound );
  117. m_pBurnSound = NULL;
  118. RemoveFromActiveFlares();
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Purpose:
  122. //-----------------------------------------------------------------------------
  123. void CFlare::Precache( void )
  124. {
  125. PrecacheModel("models/weapons/flare.mdl" );
  126. PrecacheScriptSound( "Weapon_FlareGun.Burn" );
  127. // FIXME: needed to precache the fire model. Shouldn't have to do this.
  128. UTIL_PrecacheOther( "_firesmoke" );
  129. }
  130. //-----------------------------------------------------------------------------
  131. // Purpose:
  132. // Input : &restore -
  133. // Output : int
  134. //-----------------------------------------------------------------------------
  135. int CFlare::Restore( IRestore &restore )
  136. {
  137. int result = BaseClass::Restore( restore );
  138. if ( m_spawnflags & SF_FLARE_NO_DLIGHT )
  139. {
  140. m_bLight = false;
  141. }
  142. if ( m_spawnflags & SF_FLARE_NO_SMOKE )
  143. {
  144. m_bSmoke = false;
  145. }
  146. return result;
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Purpose:
  150. //-----------------------------------------------------------------------------
  151. void CFlare::Spawn( void )
  152. {
  153. Precache();
  154. SetModel( "models/weapons/flare.mdl" );
  155. UTIL_SetSize( this, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ) );
  156. SetSolid( SOLID_BBOX );
  157. AddSolidFlags( FSOLID_NOT_SOLID );
  158. SetMoveType( MOVETYPE_NONE );
  159. SetFriction( 0.6f );
  160. SetGravity( UTIL_ScaleForGravity( 400 ) );
  161. m_flTimeBurnOut = gpGlobals->curtime + 30;
  162. AddEffects( EF_NOSHADOW|EF_NORECEIVESHADOW );
  163. if ( m_spawnflags & SF_FLARE_NO_DLIGHT )
  164. {
  165. m_bLight = false;
  166. }
  167. if ( m_spawnflags & SF_FLARE_NO_SMOKE )
  168. {
  169. m_bSmoke = false;
  170. }
  171. if ( m_spawnflags & SF_FLARE_INFINITE )
  172. {
  173. m_flTimeBurnOut = -1.0f;
  174. }
  175. if ( m_spawnflags & SF_FLARE_START_OFF )
  176. {
  177. AddEffects( EF_NODRAW );
  178. }
  179. AddFlag( FL_OBJECT );
  180. }
  181. //-----------------------------------------------------------------------------
  182. // Purpose:
  183. //-----------------------------------------------------------------------------
  184. void CFlare::Activate( void )
  185. {
  186. BaseClass::Activate();
  187. // Start the burning sound if we're already on
  188. if ( ( m_spawnflags & SF_FLARE_START_OFF ) == false )
  189. {
  190. StartBurnSound();
  191. }
  192. }
  193. //-----------------------------------------------------------------------------
  194. // Purpose:
  195. //-----------------------------------------------------------------------------
  196. void CFlare::StartBurnSound( void )
  197. {
  198. if ( m_pBurnSound == NULL )
  199. {
  200. CPASAttenuationFilter filter( this );
  201. m_pBurnSound = CSoundEnvelopeController::GetController().SoundCreate(
  202. filter, entindex(), CHAN_WEAPON, "Weapon_FlareGun.Burn", 3.0f );
  203. }
  204. }
  205. //-----------------------------------------------------------------------------
  206. // Purpose:
  207. // Input : vecOrigin -
  208. // vecAngles -
  209. // *pOwner -
  210. // Output : CFlare
  211. //-----------------------------------------------------------------------------
  212. CFlare *CFlare::Create( Vector vecOrigin, QAngle vecAngles, CBaseEntity *pOwner, float lifetime )
  213. {
  214. CFlare *pFlare = (CFlare *) CreateEntityByName( "env_flare" );
  215. if ( pFlare == NULL )
  216. return NULL;
  217. UTIL_SetOrigin( pFlare, vecOrigin );
  218. pFlare->SetLocalAngles( vecAngles );
  219. pFlare->Spawn();
  220. pFlare->SetTouch( &CFlare::FlareTouch );
  221. pFlare->SetThink( &CFlare::FlareThink );
  222. //Start up the flare
  223. pFlare->Start( lifetime );
  224. //Don't start sparking immediately
  225. pFlare->SetNextThink( gpGlobals->curtime + 0.5f );
  226. //Burn out time
  227. pFlare->m_flTimeBurnOut = gpGlobals->curtime + lifetime;
  228. pFlare->RemoveSolidFlags( FSOLID_NOT_SOLID );
  229. pFlare->AddSolidFlags( FSOLID_NOT_STANDABLE );
  230. pFlare->SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
  231. pFlare->SetOwnerEntity( pOwner );
  232. pFlare->m_pOwner = pOwner;
  233. return pFlare;
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose:
  237. //-----------------------------------------------------------------------------
  238. unsigned int CFlare::PhysicsSolidMaskForEntity( void ) const
  239. {
  240. return MASK_NPCSOLID;
  241. }
  242. //-----------------------------------------------------------------------------
  243. // Purpose:
  244. //-----------------------------------------------------------------------------
  245. void CFlare::FlareThink( void )
  246. {
  247. float deltaTime = ( m_flTimeBurnOut - gpGlobals->curtime );
  248. if ( !m_bInActiveList && ( ( deltaTime > FLARE_BLIND_TIME ) || ( m_flTimeBurnOut == -1.0f ) ) )
  249. {
  250. AddToActiveFlares();
  251. }
  252. if ( m_flTimeBurnOut != -1.0f )
  253. {
  254. //Fading away
  255. if ( ( deltaTime <= FLARE_DECAY_TIME ) && ( m_bFading == false ) )
  256. {
  257. m_bFading = true;
  258. CSoundEnvelopeController::GetController().SoundChangePitch( m_pBurnSound, 60, deltaTime );
  259. CSoundEnvelopeController::GetController().SoundFadeOut( m_pBurnSound, deltaTime );
  260. }
  261. // if flare is no longer bright, remove it from active flare list
  262. if ( m_bInActiveList && ( deltaTime <= FLARE_BLIND_TIME ) )
  263. {
  264. RemoveFromActiveFlares();
  265. }
  266. //Burned out
  267. if ( m_flTimeBurnOut < gpGlobals->curtime )
  268. {
  269. UTIL_Remove( this );
  270. return;
  271. }
  272. }
  273. //Act differently underwater
  274. if ( GetWaterLevel() > 1 )
  275. {
  276. UTIL_Bubbles( GetAbsOrigin() + Vector( -2, -2, -2 ), GetAbsOrigin() + Vector( 2, 2, 2 ), 1 );
  277. m_bSmoke = false;
  278. }
  279. else
  280. {
  281. //Shoot sparks
  282. if ( random->RandomInt( 0, 8 ) == 1 )
  283. {
  284. g_pEffects->Sparks( GetAbsOrigin() );
  285. }
  286. }
  287. //Next update
  288. SetNextThink( gpGlobals->curtime + 0.1f );
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Purpose:
  292. // Input : *pOther -
  293. //-----------------------------------------------------------------------------
  294. void CFlare::FlareBurnTouch( CBaseEntity *pOther )
  295. {
  296. if ( pOther && pOther->m_takedamage && ( m_flNextDamage < gpGlobals->curtime ) )
  297. {
  298. pOther->TakeDamage( CTakeDamageInfo( this, m_pOwner, 1, (DMG_BULLET|DMG_BURN) ) );
  299. m_flNextDamage = gpGlobals->curtime + 1.0f;
  300. }
  301. }
  302. //-----------------------------------------------------------------------------
  303. // Purpose:
  304. // Input : *pOther -
  305. //-----------------------------------------------------------------------------
  306. void CFlare::FlareTouch( CBaseEntity *pOther )
  307. {
  308. Assert( pOther );
  309. if ( !pOther->IsSolid() )
  310. return;
  311. if ( ( m_nBounces < 10 ) && ( GetWaterLevel() < 1 ) )
  312. {
  313. // Throw some real chunks here
  314. g_pEffects->Sparks( GetAbsOrigin() );
  315. }
  316. //If the flare hit a person or NPC, do damage here.
  317. if ( pOther && pOther->m_takedamage )
  318. {
  319. /*
  320. The Flare is the iRifle round right now. No damage, just ignite. (sjb)
  321. //Damage is a function of how fast the flare is flying.
  322. int iDamage = GetAbsVelocity().Length() / 50.0f;
  323. if ( iDamage < 5 )
  324. {
  325. //Clamp minimum damage
  326. iDamage = 5;
  327. }
  328. //Use m_pOwner, not GetOwnerEntity()
  329. pOther->TakeDamage( CTakeDamageInfo( this, m_pOwner, iDamage, (DMG_BULLET|DMG_BURN) ) );
  330. m_flNextDamage = gpGlobals->curtime + 1.0f;
  331. */
  332. CBaseAnimating *pAnim;
  333. pAnim = dynamic_cast<CBaseAnimating*>(pOther);
  334. if( pAnim )
  335. {
  336. pAnim->Ignite( 30.0f );
  337. }
  338. Vector vecNewVelocity = GetAbsVelocity();
  339. vecNewVelocity *= 0.1f;
  340. SetAbsVelocity( vecNewVelocity );
  341. SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
  342. SetGravity(1.0f);
  343. Die( 0.5 );
  344. return;
  345. }
  346. else
  347. {
  348. // hit the world, check the material type here, see if the flare should stick.
  349. trace_t tr;
  350. tr = CBaseEntity::GetTouchTrace();
  351. //Only do this on the first bounce
  352. if ( m_nBounces == 0 )
  353. {
  354. const surfacedata_t *pdata = physprops->GetSurfaceData( tr.surface.surfaceProps );
  355. if ( pdata != NULL )
  356. {
  357. //Only embed into concrete and wood (jdw: too obscure for players?)
  358. //if ( ( pdata->gameMaterial == 'C' ) || ( pdata->gameMaterial == 'W' ) )
  359. {
  360. Vector impactDir = ( tr.endpos - tr.startpos );
  361. VectorNormalize( impactDir );
  362. float surfDot = tr.plane.normal.Dot( impactDir );
  363. //Do not stick to ceilings or on shallow impacts
  364. if ( ( tr.plane.normal.z > -0.5f ) && ( surfDot < -0.9f ) )
  365. {
  366. RemoveSolidFlags( FSOLID_NOT_SOLID );
  367. AddSolidFlags( FSOLID_TRIGGER );
  368. UTIL_SetOrigin( this, tr.endpos + ( tr.plane.normal * 2.0f ) );
  369. SetAbsVelocity( vec3_origin );
  370. SetMoveType( MOVETYPE_NONE );
  371. SetTouch( &CFlare::FlareBurnTouch );
  372. int index = decalsystem->GetDecalIndexForName( "SmallScorch" );
  373. if ( index >= 0 )
  374. {
  375. CBroadcastRecipientFilter filter;
  376. te->Decal( filter, 0.0, &tr.endpos, &tr.startpos, ENTINDEX( tr.m_pEnt ), tr.hitbox, index );
  377. }
  378. CPASAttenuationFilter filter2( this, "Flare.Touch" );
  379. EmitSound( filter2, entindex(), "Flare.Touch" );
  380. return;
  381. }
  382. }
  383. }
  384. }
  385. //Scorch decal
  386. if ( GetAbsVelocity().LengthSqr() > (250*250) )
  387. {
  388. int index = decalsystem->GetDecalIndexForName( "FadingScorch" );
  389. if ( index >= 0 )
  390. {
  391. CBroadcastRecipientFilter filter;
  392. te->Decal( filter, 0.0, &tr.endpos, &tr.startpos, ENTINDEX( tr.m_pEnt ), tr.hitbox, index );
  393. }
  394. }
  395. // Change our flight characteristics
  396. SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
  397. SetGravity( UTIL_ScaleForGravity( 640 ) );
  398. m_nBounces++;
  399. //After the first bounce, smacking into whoever fired the flare is fair game
  400. SetOwnerEntity( this );
  401. // Slow down
  402. Vector vecNewVelocity = GetAbsVelocity();
  403. vecNewVelocity.x *= 0.8f;
  404. vecNewVelocity.y *= 0.8f;
  405. SetAbsVelocity( vecNewVelocity );
  406. //Stopped?
  407. if ( GetAbsVelocity().Length() < 64.0f )
  408. {
  409. SetAbsVelocity( vec3_origin );
  410. SetMoveType( MOVETYPE_NONE );
  411. RemoveSolidFlags( FSOLID_NOT_SOLID );
  412. AddSolidFlags( FSOLID_TRIGGER );
  413. SetTouch( &CFlare::FlareBurnTouch );
  414. }
  415. }
  416. }
  417. //-----------------------------------------------------------------------------
  418. // Purpose:
  419. //-----------------------------------------------------------------------------
  420. void CFlare::Start( float lifeTime )
  421. {
  422. StartBurnSound();
  423. if ( m_pBurnSound != NULL )
  424. {
  425. CSoundEnvelopeController::GetController().Play( m_pBurnSound, 0.0f, 60 );
  426. CSoundEnvelopeController::GetController().SoundChangeVolume( m_pBurnSound, 0.8f, 2.0f );
  427. CSoundEnvelopeController::GetController().SoundChangePitch( m_pBurnSound, 100, 2.0f );
  428. }
  429. if ( lifeTime > 0 )
  430. {
  431. m_flTimeBurnOut = gpGlobals->curtime + lifeTime;
  432. }
  433. else
  434. {
  435. m_flTimeBurnOut = -1.0f;
  436. }
  437. RemoveEffects( EF_NODRAW );
  438. SetThink( &CFlare::FlareThink );
  439. SetNextThink( gpGlobals->curtime + 0.1f );
  440. }
  441. //-----------------------------------------------------------------------------
  442. // Purpose:
  443. //-----------------------------------------------------------------------------
  444. void CFlare::Die( float fadeTime )
  445. {
  446. m_flTimeBurnOut = gpGlobals->curtime + fadeTime;
  447. SetThink( &CFlare::FlareThink );
  448. SetNextThink( gpGlobals->curtime + 0.1f );
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Purpose:
  452. //-----------------------------------------------------------------------------
  453. void CFlare::Launch( const Vector &direction, float speed )
  454. {
  455. // Make sure we're visible
  456. if ( m_spawnflags & SF_FLARE_INFINITE )
  457. {
  458. Start( -1 );
  459. }
  460. else
  461. {
  462. Start( 8.0f );
  463. }
  464. SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
  465. // Punch our velocity towards our facing
  466. SetAbsVelocity( direction * speed );
  467. SetGravity( 1.0f );
  468. }
  469. //-----------------------------------------------------------------------------
  470. // Purpose:
  471. // Input : &inputdata -
  472. //-----------------------------------------------------------------------------
  473. void CFlare::InputStart( inputdata_t &inputdata )
  474. {
  475. Start( inputdata.value.Float() );
  476. }
  477. //-----------------------------------------------------------------------------
  478. // Purpose:
  479. // Input : &inputdata -
  480. //-----------------------------------------------------------------------------
  481. void CFlare::InputDie( inputdata_t &inputdata )
  482. {
  483. Die( inputdata.value.Float() );
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Purpose:
  487. // Input : &inputdata -
  488. //-----------------------------------------------------------------------------
  489. void CFlare::InputLaunch( inputdata_t &inputdata )
  490. {
  491. Vector direction;
  492. AngleVectors( GetAbsAngles(), &direction );
  493. float speed = inputdata.value.Float();
  494. if ( speed == 0 )
  495. {
  496. speed = FLARE_LAUNCH_SPEED;
  497. }
  498. Launch( direction, speed );
  499. }
  500. //-----------------------------------------------------------------------------
  501. // Purpose: Removes flare from active flare list
  502. //-----------------------------------------------------------------------------
  503. void CFlare::RemoveFromActiveFlares( void )
  504. {
  505. CFlare *pFlare;
  506. CFlare *pPrevFlare;
  507. if ( !m_bInActiveList )
  508. return;
  509. pPrevFlare = NULL;
  510. for( pFlare = CFlare::activeFlares; pFlare != NULL; pFlare = pFlare->m_pNextFlare )
  511. {
  512. if ( pFlare == this )
  513. {
  514. if ( pPrevFlare )
  515. {
  516. pPrevFlare->m_pNextFlare = m_pNextFlare;
  517. }
  518. else
  519. {
  520. activeFlares = m_pNextFlare;
  521. }
  522. break;
  523. }
  524. pPrevFlare = pFlare;
  525. }
  526. m_pNextFlare = NULL;
  527. m_bInActiveList = false;
  528. }
  529. //-----------------------------------------------------------------------------
  530. // Purpose: Adds flare to active flare list
  531. //-----------------------------------------------------------------------------
  532. void CFlare::AddToActiveFlares( void )
  533. {
  534. if ( !m_bInActiveList )
  535. {
  536. m_pNextFlare = CFlare::activeFlares;
  537. CFlare::activeFlares = this;
  538. m_bInActiveList = true;
  539. }
  540. }
  541. #if 0
  542. IMPLEMENT_SERVERCLASS_ST(CFlaregun, DT_Flaregun)
  543. END_SEND_TABLE()
  544. LINK_ENTITY_TO_CLASS( weapon_flaregun, CFlaregun );
  545. PRECACHE_WEAPON_REGISTER( weapon_flaregun );
  546. //-----------------------------------------------------------------------------
  547. // Purpose: Precache
  548. //-----------------------------------------------------------------------------
  549. void CFlaregun::Precache( void )
  550. {
  551. BaseClass::Precache();
  552. PrecacheScriptSound( "Flare.Touch" );
  553. PrecacheScriptSound( "Weapon_FlareGun.Burn" );
  554. UTIL_PrecacheOther( "env_flare" );
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Purpose: Main attack
  558. //-----------------------------------------------------------------------------
  559. void CFlaregun::PrimaryAttack( void )
  560. {
  561. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  562. if ( pOwner == NULL )
  563. return;
  564. if ( m_iClip1 <= 0 )
  565. {
  566. SendWeaponAnim( ACT_VM_DRYFIRE );
  567. pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration();
  568. return;
  569. }
  570. m_iClip1 = m_iClip1 - 1;
  571. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  572. pOwner->m_flNextAttack = gpGlobals->curtime + 1;
  573. CFlare *pFlare = CFlare::Create( pOwner->Weapon_ShootPosition(), pOwner->EyeAngles(), pOwner, FLARE_DURATION );
  574. if ( pFlare == NULL )
  575. return;
  576. Vector forward;
  577. pOwner->EyeVectors( &forward );
  578. pFlare->SetAbsVelocity( forward * 1500 );
  579. WeaponSound( SINGLE );
  580. }
  581. //-----------------------------------------------------------------------------
  582. // Purpose:
  583. //-----------------------------------------------------------------------------
  584. void CFlaregun::SecondaryAttack( void )
  585. {
  586. CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
  587. if ( pOwner == NULL )
  588. return;
  589. if ( m_iClip1 <= 0 )
  590. {
  591. SendWeaponAnim( ACT_VM_DRYFIRE );
  592. pOwner->m_flNextAttack = gpGlobals->curtime + SequenceDuration();
  593. return;
  594. }
  595. m_iClip1 = m_iClip1 - 1;
  596. SendWeaponAnim( ACT_VM_PRIMARYATTACK );
  597. pOwner->m_flNextAttack = gpGlobals->curtime + 1;
  598. CFlare *pFlare = CFlare::Create( pOwner->Weapon_ShootPosition(), pOwner->EyeAngles(), pOwner, FLARE_DURATION );
  599. if ( pFlare == NULL )
  600. return;
  601. Vector forward;
  602. pOwner->EyeVectors( &forward );
  603. pFlare->SetAbsVelocity( forward * 500 );
  604. pFlare->SetGravity(1.0f);
  605. pFlare->SetFriction( 0.85f );
  606. pFlare->SetMoveType( MOVETYPE_FLYGRAVITY, MOVECOLLIDE_FLY_BOUNCE );
  607. WeaponSound( SINGLE );
  608. }
  609. #endif