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.

2379 lines
58 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Implements a grab bag of visual effects entities.
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "effects.h"
  9. #include "gib.h"
  10. #include "beam_shared.h"
  11. #include "decals.h"
  12. #include "func_break.h"
  13. #include "EntityFlame.h"
  14. #include "entitylist.h"
  15. #include "basecombatweapon.h"
  16. #include "model_types.h"
  17. #include "player.h"
  18. #include "physics.h"
  19. #include "baseparticleentity.h"
  20. #include "ndebugoverlay.h"
  21. #include "IEffects.h"
  22. #include "vstdlib/random.h"
  23. #include "env_wind_shared.h"
  24. #include "filesystem.h"
  25. #include "engine/IEngineSound.h"
  26. #include "fire.h"
  27. #include "te_effect_dispatch.h"
  28. #include "Sprite.h"
  29. #include "precipitation_shared.h"
  30. #include "shot_manipulator.h"
  31. // memdbgon must be the last include file in a .cpp file!!!
  32. #include "tier0/memdbgon.h"
  33. #define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them.
  34. #define SF_GIBSHOOTER_REPEATABLE (1<<0) // allows a gibshooter to be refired
  35. #define SF_SHOOTER_FLAMING (1<<1) // gib is on fire
  36. #define SF_SHOOTER_STRICT_REMOVE (1<<2) // remove this gib even if it is in the player's view
  37. // UNDONE: This should be client-side and not use TempEnts
  38. class CBubbling : public CBaseEntity
  39. {
  40. public:
  41. DECLARE_CLASS( CBubbling, CBaseEntity );
  42. virtual void Spawn( void );
  43. virtual void Precache( void );
  44. void FizzThink( void );
  45. // Input handlers.
  46. void InputActivate( inputdata_t &inputdata );
  47. void InputDeactivate( inputdata_t &inputdata );
  48. void InputToggle( inputdata_t &inputdata );
  49. void InputSetCurrent( inputdata_t &inputdata );
  50. void InputSetDensity( inputdata_t &inputdata );
  51. void InputSetFrequency( inputdata_t &inputdata );
  52. DECLARE_DATADESC();
  53. private:
  54. void TurnOn();
  55. void TurnOff();
  56. void Toggle();
  57. int m_density;
  58. int m_frequency;
  59. int m_bubbleModel;
  60. int m_state;
  61. };
  62. LINK_ENTITY_TO_CLASS( env_bubbles, CBubbling );
  63. BEGIN_DATADESC( CBubbling )
  64. DEFINE_KEYFIELD( m_flSpeed, FIELD_FLOAT, "current" ),
  65. DEFINE_KEYFIELD( m_density, FIELD_INTEGER, "density" ),
  66. DEFINE_KEYFIELD( m_frequency, FIELD_INTEGER, "frequency" ),
  67. DEFINE_FIELD( m_state, FIELD_INTEGER ),
  68. // Let spawn restore this!
  69. // DEFINE_FIELD( m_bubbleModel, FIELD_INTEGER ),
  70. // Function Pointers
  71. DEFINE_FUNCTION( FizzThink ),
  72. DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
  73. DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ),
  74. DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
  75. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetCurrent", InputSetCurrent ),
  76. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetDensity", InputSetDensity ),
  77. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetFrequency", InputSetFrequency ),
  78. END_DATADESC()
  79. #define SF_BUBBLES_STARTOFF 0x0001
  80. void CBubbling::Spawn( void )
  81. {
  82. Precache( );
  83. SetModel( STRING( GetModelName() ) ); // Set size
  84. // Make it invisible to client
  85. SetRenderColorA( 0 );
  86. SetSolid( SOLID_NONE ); // Remove model & collisions
  87. if ( !HasSpawnFlags(SF_BUBBLES_STARTOFF) )
  88. {
  89. SetThink( &CBubbling::FizzThink );
  90. SetNextThink( gpGlobals->curtime + 2.0 );
  91. m_state = 1;
  92. }
  93. else
  94. {
  95. m_state = 0;
  96. }
  97. }
  98. void CBubbling::Precache( void )
  99. {
  100. m_bubbleModel = PrecacheModel("sprites/bubble.vmt"); // Precache bubble sprite
  101. }
  102. void CBubbling::Toggle()
  103. {
  104. if (!m_state)
  105. {
  106. TurnOn();
  107. }
  108. else
  109. {
  110. TurnOff();
  111. }
  112. }
  113. void CBubbling::TurnOn()
  114. {
  115. m_state = 1;
  116. SetThink( &CBubbling::FizzThink );
  117. SetNextThink( gpGlobals->curtime + 0.1f );
  118. }
  119. void CBubbling::TurnOff()
  120. {
  121. m_state = 0;
  122. SetThink( NULL );
  123. SetNextThink( TICK_NEVER_THINK );
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose:
  127. //-----------------------------------------------------------------------------
  128. void CBubbling::InputActivate( inputdata_t &inputdata )
  129. {
  130. TurnOn();
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose:
  134. //-----------------------------------------------------------------------------
  135. void CBubbling::InputDeactivate( inputdata_t &inputdata )
  136. {
  137. TurnOff();
  138. }
  139. //-----------------------------------------------------------------------------
  140. // Purpose:
  141. //-----------------------------------------------------------------------------
  142. void CBubbling::InputToggle( inputdata_t &inputdata )
  143. {
  144. Toggle();
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Purpose:
  148. // Input : &inputdata -
  149. //-----------------------------------------------------------------------------
  150. void CBubbling::InputSetCurrent( inputdata_t &inputdata )
  151. {
  152. m_flSpeed = (float)inputdata.value.Int();
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose:
  156. // Input : &inputdata -
  157. //-----------------------------------------------------------------------------
  158. void CBubbling::InputSetDensity( inputdata_t &inputdata )
  159. {
  160. m_density = inputdata.value.Int();
  161. }
  162. //-----------------------------------------------------------------------------
  163. // Purpose:
  164. // Input : &inputdata -
  165. //-----------------------------------------------------------------------------
  166. void CBubbling::InputSetFrequency( inputdata_t &inputdata )
  167. {
  168. m_frequency = inputdata.value.Int();
  169. // Reset think time
  170. if ( m_state )
  171. {
  172. if ( m_frequency > 19 )
  173. {
  174. SetNextThink( gpGlobals->curtime + 0.5f );
  175. }
  176. else
  177. {
  178. SetNextThink( gpGlobals->curtime + 2.5 - (0.1 * m_frequency) );
  179. }
  180. }
  181. }
  182. void CBubbling::FizzThink( void )
  183. {
  184. Vector center = WorldSpaceCenter();
  185. CPASFilter filter( center );
  186. te->Fizz( filter, 0.0, this, m_bubbleModel, m_density, (int)m_flSpeed );
  187. if ( m_frequency > 19 )
  188. {
  189. SetNextThink( gpGlobals->curtime + 0.5f );
  190. }
  191. else
  192. {
  193. SetNextThink( gpGlobals->curtime + 2.5 - (0.1 * m_frequency) );
  194. }
  195. }
  196. // ENV_TRACER
  197. // Fakes a tracer
  198. class CEnvTracer : public CPointEntity
  199. {
  200. public:
  201. DECLARE_CLASS( CEnvTracer, CPointEntity );
  202. void Spawn( void );
  203. void TracerThink( void );
  204. void Activate( void );
  205. DECLARE_DATADESC();
  206. Vector m_vecEnd;
  207. float m_flDelay;
  208. };
  209. LINK_ENTITY_TO_CLASS( env_tracer, CEnvTracer );
  210. BEGIN_DATADESC( CEnvTracer )
  211. DEFINE_KEYFIELD( m_flDelay, FIELD_FLOAT, "delay" ),
  212. DEFINE_FIELD( m_vecEnd, FIELD_POSITION_VECTOR ),
  213. // Function Pointers
  214. DEFINE_FUNCTION( TracerThink ),
  215. END_DATADESC()
  216. //-----------------------------------------------------------------------------
  217. // Purpose: Called after keyvalues are parsed.
  218. //-----------------------------------------------------------------------------
  219. void CEnvTracer::Spawn( void )
  220. {
  221. SetSolid( SOLID_NONE );
  222. SetMoveType( MOVETYPE_NONE );
  223. if (!m_flDelay)
  224. m_flDelay = 1;
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose: Called after all the entities have been loaded.
  228. //-----------------------------------------------------------------------------
  229. void CEnvTracer::Activate( void )
  230. {
  231. BaseClass::Activate();
  232. CBaseEntity *pEnd = gEntList.FindEntityByName( NULL, m_target );
  233. if (pEnd != NULL)
  234. {
  235. m_vecEnd = pEnd->GetLocalOrigin();
  236. SetThink( &CEnvTracer::TracerThink );
  237. SetNextThink( gpGlobals->curtime + m_flDelay );
  238. }
  239. else
  240. {
  241. Msg( "env_tracer: unknown entity \"%s\"\n", STRING(m_target) );
  242. }
  243. }
  244. // Think
  245. void CEnvTracer::TracerThink( void )
  246. {
  247. UTIL_Tracer( GetAbsOrigin(), m_vecEnd );
  248. SetNextThink( gpGlobals->curtime + m_flDelay );
  249. }
  250. //#################################################################################
  251. // >> CGibShooter
  252. //#################################################################################
  253. enum GibSimulation_t
  254. {
  255. GIB_SIMULATE_POINT,
  256. GIB_SIMULATE_PHYSICS,
  257. GIB_SIMULATE_RAGDOLL,
  258. };
  259. class CGibShooter : public CBaseEntity
  260. {
  261. public:
  262. DECLARE_CLASS( CGibShooter, CBaseEntity );
  263. void Spawn( void );
  264. void Precache( void );
  265. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  266. virtual CGib *CreateGib( void );
  267. protected:
  268. // Purpose:
  269. CBaseEntity *SpawnGib( const Vector &vecShootDir, float flSpeed );
  270. DECLARE_DATADESC();
  271. private:
  272. void InitPointGib( CGib *pGib, const Vector &vecShootDir, float flSpeed );
  273. void ShootThink( void );
  274. protected:
  275. int m_iGibs;
  276. int m_iGibCapacity;
  277. int m_iGibMaterial;
  278. int m_iGibModelIndex;
  279. float m_flGibVelocity;
  280. QAngle m_angGibRotation;
  281. float m_flGibAngVelocity;
  282. float m_flVariance;
  283. float m_flGibLife;
  284. int m_nSimulationType;
  285. int m_nMaxGibModelFrame;
  286. float m_flDelay;
  287. bool m_bNoGibShadows;
  288. bool m_bIsSprite;
  289. string_t m_iszLightingOrigin;
  290. // ----------------
  291. // Inputs
  292. // ----------------
  293. void InputShoot( inputdata_t &inputdata );
  294. };
  295. BEGIN_DATADESC( CGibShooter )
  296. DEFINE_KEYFIELD( m_iGibs, FIELD_INTEGER, "m_iGibs" ),
  297. DEFINE_KEYFIELD( m_flGibVelocity, FIELD_FLOAT, "m_flVelocity" ),
  298. DEFINE_KEYFIELD( m_flVariance, FIELD_FLOAT, "m_flVariance" ),
  299. DEFINE_KEYFIELD( m_flGibLife, FIELD_FLOAT, "m_flGibLife" ),
  300. DEFINE_KEYFIELD( m_nSimulationType, FIELD_INTEGER, "Simulation" ),
  301. DEFINE_KEYFIELD( m_flDelay, FIELD_FLOAT, "delay" ),
  302. DEFINE_KEYFIELD( m_angGibRotation, FIELD_VECTOR, "gibangles" ),
  303. DEFINE_KEYFIELD( m_flGibAngVelocity, FIELD_FLOAT, "gibanglevelocity"),
  304. DEFINE_FIELD( m_bIsSprite, FIELD_BOOLEAN ),
  305. DEFINE_FIELD( m_iGibCapacity, FIELD_INTEGER ),
  306. DEFINE_FIELD( m_iGibMaterial, FIELD_INTEGER ),
  307. DEFINE_FIELD( m_iGibModelIndex, FIELD_INTEGER ),
  308. DEFINE_FIELD( m_nMaxGibModelFrame, FIELD_INTEGER ),
  309. DEFINE_KEYFIELD( m_iszLightingOrigin, FIELD_STRING, "LightingOrigin" ),
  310. DEFINE_KEYFIELD( m_bNoGibShadows, FIELD_BOOLEAN, "nogibshadows" ),
  311. // Inputs
  312. DEFINE_INPUTFUNC( FIELD_VOID, "Shoot", InputShoot ),
  313. // Function Pointers
  314. DEFINE_FUNCTION( ShootThink ),
  315. END_DATADESC()
  316. LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter );
  317. void CGibShooter::Precache ( void )
  318. {
  319. if ( g_Language.GetInt() == LANGUAGE_GERMAN )
  320. {
  321. m_iGibModelIndex = PrecacheModel ("models/germanygibs.mdl");
  322. }
  323. else
  324. {
  325. m_iGibModelIndex = PrecacheModel ("models/gibs/hgibs.mdl");
  326. }
  327. }
  328. void CGibShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  329. {
  330. SetThink( &CGibShooter::ShootThink );
  331. SetNextThink( gpGlobals->curtime );
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose: Input handler for shooting gibs.
  335. //-----------------------------------------------------------------------------
  336. void CGibShooter::InputShoot( inputdata_t &inputdata )
  337. {
  338. SetThink( &CGibShooter::ShootThink );
  339. SetNextThink( gpGlobals->curtime );
  340. }
  341. void CGibShooter::Spawn( void )
  342. {
  343. Precache();
  344. SetSolid( SOLID_NONE );
  345. AddEffects( EF_NODRAW );
  346. if ( m_flDelay < 0 )
  347. {
  348. m_flDelay = 0.0;
  349. }
  350. if ( m_flGibLife == 0 )
  351. {
  352. m_flGibLife = 25;
  353. }
  354. m_iGibCapacity = m_iGibs;
  355. m_nMaxGibModelFrame = modelinfo->GetModelFrameCount( modelinfo->GetModel( m_iGibModelIndex ) );
  356. }
  357. CGib *CGibShooter::CreateGib ( void )
  358. {
  359. ConVarRef violence_hgibs( "violence_hgibs" );
  360. if ( violence_hgibs.IsValid() && !violence_hgibs.GetInt() )
  361. return NULL;
  362. CGib *pGib = CREATE_ENTITY( CGib, "gib" );
  363. pGib->Spawn( "models/gibs/hgibs.mdl" );
  364. pGib->SetBloodColor( BLOOD_COLOR_RED );
  365. if ( m_nMaxGibModelFrame <= 1 )
  366. {
  367. DevWarning( 2, "GibShooter Body is <= 1!\n" );
  368. }
  369. pGib->m_nBody = random->RandomInt ( 1, m_nMaxGibModelFrame - 1 );// avoid throwing random amounts of the 0th gib. (skull).
  370. if ( m_iszLightingOrigin != NULL_STRING )
  371. {
  372. // Make the gibs use the lighting origin
  373. pGib->SetLightingOrigin( m_iszLightingOrigin );
  374. }
  375. return pGib;
  376. }
  377. void CGibShooter::InitPointGib( CGib *pGib, const Vector &vecShootDir, float flSpeed )
  378. {
  379. if ( pGib )
  380. {
  381. pGib->SetLocalOrigin( GetAbsOrigin() );
  382. pGib->SetAbsVelocity( vecShootDir * flSpeed );
  383. QAngle angVel( random->RandomFloat ( 100, 200 ), random->RandomFloat ( 100, 300 ), 0 );
  384. pGib->SetLocalAngularVelocity( angVel );
  385. float thinkTime = ( pGib->GetNextThink() - gpGlobals->curtime );
  386. pGib->m_lifeTime = (m_flGibLife * random->RandomFloat( 0.95, 1.05 )); // +/- 5%
  387. // HL1 gibs always die after a certain time, other games have to opt-in
  388. #ifndef HL1_DLL
  389. if( HasSpawnFlags( SF_SHOOTER_STRICT_REMOVE ) )
  390. #endif
  391. {
  392. pGib->SetNextThink( gpGlobals->curtime + pGib->m_lifeTime );
  393. pGib->SetThink ( &CGib::DieThink );
  394. }
  395. if ( pGib->m_lifeTime < thinkTime )
  396. {
  397. pGib->SetNextThink( gpGlobals->curtime + pGib->m_lifeTime );
  398. pGib->m_lifeTime = 0;
  399. }
  400. if ( m_bIsSprite == true )
  401. {
  402. pGib->SetSprite( CSprite::SpriteCreate( STRING( GetModelName() ), pGib->GetAbsOrigin(), false ) );
  403. CSprite *pSprite = (CSprite*)pGib->GetSprite();
  404. if ( pSprite )
  405. {
  406. pSprite->SetAttachment( pGib, 0 );
  407. pSprite->SetOwnerEntity( pGib );
  408. pSprite->SetScale( 1 );
  409. pSprite->SetTransparency( m_nRenderMode, m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a, m_nRenderFX );
  410. pSprite->AnimateForTime( 5, m_flGibLife + 1 ); //This framerate is totally wrong
  411. }
  412. }
  413. }
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Purpose:
  417. //-----------------------------------------------------------------------------
  418. CBaseEntity *CGibShooter::SpawnGib( const Vector &vecShootDir, float flSpeed )
  419. {
  420. switch (m_nSimulationType)
  421. {
  422. case GIB_SIMULATE_RAGDOLL:
  423. {
  424. // UNDONE: Assume a mass of 200 for now
  425. Vector force = vecShootDir * flSpeed * 200;
  426. return CreateRagGib( STRING( GetModelName() ), GetAbsOrigin(), GetAbsAngles(), force, m_flGibLife );
  427. }
  428. case GIB_SIMULATE_PHYSICS:
  429. {
  430. CGib *pGib = CreateGib();
  431. if ( pGib )
  432. {
  433. pGib->SetAbsOrigin( GetAbsOrigin() );
  434. pGib->SetAbsAngles( m_angGibRotation );
  435. pGib->m_lifeTime = (m_flGibLife * random->RandomFloat( 0.95, 1.05 )); // +/- 5%
  436. pGib->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
  437. IPhysicsObject *pPhysicsObject = pGib->VPhysicsInitNormal( SOLID_VPHYSICS, pGib->GetSolidFlags(), false );
  438. pGib->SetMoveType( MOVETYPE_VPHYSICS );
  439. if ( pPhysicsObject )
  440. {
  441. // Set gib velocity
  442. Vector vVel = vecShootDir * flSpeed;
  443. pPhysicsObject->AddVelocity(&vVel, NULL);
  444. AngularImpulse torque;
  445. torque.x = m_flGibAngVelocity * random->RandomFloat( 0.1f, 1.0f );
  446. torque.y = m_flGibAngVelocity * random->RandomFloat( 0.1f, 1.0f );
  447. torque.z = 0.0f;
  448. torque *= pPhysicsObject->GetMass();
  449. pPhysicsObject->ApplyTorqueCenter( torque );
  450. #ifndef HL1_DLL
  451. if( HasSpawnFlags( SF_SHOOTER_STRICT_REMOVE ) )
  452. #endif
  453. {
  454. pGib->m_bForceRemove = true;
  455. pGib->SetNextThink( gpGlobals->curtime + pGib->m_lifeTime );
  456. pGib->SetThink ( &CGib::DieThink );
  457. }
  458. }
  459. else
  460. {
  461. InitPointGib( pGib, vecShootDir, flSpeed );
  462. }
  463. }
  464. return pGib;
  465. }
  466. case GIB_SIMULATE_POINT:
  467. {
  468. CGib *pGib = CreateGib();
  469. if ( pGib )
  470. {
  471. pGib->SetAbsAngles( m_angGibRotation );
  472. InitPointGib( pGib, vecShootDir, flSpeed );
  473. return pGib;
  474. }
  475. }
  476. }
  477. return NULL;
  478. }
  479. //-----------------------------------------------------------------------------
  480. // Purpose:
  481. //-----------------------------------------------------------------------------
  482. void CGibShooter::ShootThink ( void )
  483. {
  484. SetNextThink( gpGlobals->curtime + m_flDelay );
  485. Vector vecShootDir, vForward,vRight,vUp;
  486. AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp );
  487. vecShootDir = vForward;
  488. vecShootDir = vecShootDir + vRight * random->RandomFloat( -1, 1) * m_flVariance;
  489. vecShootDir = vecShootDir + vForward * random->RandomFloat( -1, 1) * m_flVariance;
  490. vecShootDir = vecShootDir + vUp * random->RandomFloat( -1, 1) * m_flVariance;
  491. VectorNormalize( vecShootDir );
  492. SpawnGib( vecShootDir, m_flGibVelocity );
  493. if ( --m_iGibs <= 0 )
  494. {
  495. if ( HasSpawnFlags(SF_GIBSHOOTER_REPEATABLE) )
  496. {
  497. m_iGibs = m_iGibCapacity;
  498. SetThink ( NULL );
  499. SetNextThink( gpGlobals->curtime );
  500. }
  501. else
  502. {
  503. SetThink ( &CGibShooter::SUB_Remove );
  504. SetNextThink( gpGlobals->curtime );
  505. }
  506. }
  507. }
  508. class CEnvShooter : public CGibShooter
  509. {
  510. public:
  511. DECLARE_CLASS( CEnvShooter, CGibShooter );
  512. CEnvShooter() { m_flGibGravityScale = 1.0f; }
  513. void Precache( void );
  514. bool KeyValue( const char *szKeyName, const char *szValue );
  515. CGib *CreateGib( void );
  516. DECLARE_DATADESC();
  517. public:
  518. int m_nSkin;
  519. float m_flGibScale;
  520. float m_flGibGravityScale;
  521. #if HL2_EPISODIC
  522. float m_flMassOverride; // allow designer to force a mass for gibs in some cases
  523. #endif
  524. };
  525. BEGIN_DATADESC( CEnvShooter )
  526. DEFINE_KEYFIELD( m_nSkin, FIELD_INTEGER, "skin" ),
  527. DEFINE_KEYFIELD( m_flGibScale, FIELD_FLOAT ,"scale" ),
  528. DEFINE_KEYFIELD( m_flGibGravityScale, FIELD_FLOAT, "gibgravityscale" ),
  529. #if HL2_EPISODIC
  530. DEFINE_KEYFIELD( m_flMassOverride, FIELD_FLOAT, "massoverride" ),
  531. #endif
  532. END_DATADESC()
  533. LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter );
  534. bool CEnvShooter::KeyValue( const char *szKeyName, const char *szValue )
  535. {
  536. if (FStrEq(szKeyName, "shootmodel"))
  537. {
  538. m_bIsSprite = false;
  539. SetModelName( AllocPooledString(szValue) );
  540. //Adrian - not pretty...
  541. if ( Q_stristr( szValue, ".vmt" ) )
  542. m_bIsSprite = true;
  543. }
  544. else if (FStrEq(szKeyName, "shootsounds"))
  545. {
  546. int iNoise = atoi(szValue);
  547. switch( iNoise )
  548. {
  549. case 0:
  550. m_iGibMaterial = matGlass;
  551. break;
  552. case 1:
  553. m_iGibMaterial = matWood;
  554. break;
  555. case 2:
  556. m_iGibMaterial = matMetal;
  557. break;
  558. case 3:
  559. m_iGibMaterial = matFlesh;
  560. break;
  561. case 4:
  562. m_iGibMaterial = matRocks;
  563. break;
  564. default:
  565. case -1:
  566. m_iGibMaterial = matNone;
  567. break;
  568. }
  569. }
  570. else
  571. {
  572. return BaseClass::KeyValue( szKeyName, szValue );
  573. }
  574. return true;
  575. }
  576. void CEnvShooter::Precache ( void )
  577. {
  578. m_iGibModelIndex = PrecacheModel( STRING( GetModelName() ) );
  579. }
  580. CGib *CEnvShooter::CreateGib ( void )
  581. {
  582. CGib *pGib = CREATE_ENTITY( CGib, "gib" );
  583. if ( m_bIsSprite == true )
  584. {
  585. //HACK HACK
  586. pGib->Spawn( "" );
  587. }
  588. else
  589. {
  590. pGib->Spawn( STRING( GetModelName() ) );
  591. }
  592. int bodyPart = 0;
  593. if ( m_nMaxGibModelFrame > 1 )
  594. {
  595. bodyPart = random->RandomInt( 0, m_nMaxGibModelFrame-1 );
  596. }
  597. pGib->m_nBody = bodyPart;
  598. pGib->SetBloodColor( DONT_BLEED );
  599. pGib->m_material = m_iGibMaterial;
  600. pGib->m_nRenderMode = m_nRenderMode;
  601. pGib->m_clrRender = m_clrRender;
  602. pGib->m_nRenderFX = m_nRenderFX;
  603. pGib->m_nSkin = m_nSkin;
  604. pGib->m_lifeTime = gpGlobals->curtime + m_flGibLife;
  605. pGib->SetGravity( m_flGibGravityScale );
  606. // Spawn a flaming gib
  607. if ( HasSpawnFlags( SF_SHOOTER_FLAMING ) )
  608. {
  609. // Tag an entity flame along with us
  610. CEntityFlame *pFlame = CEntityFlame::Create( pGib, false );
  611. if ( pFlame != NULL )
  612. {
  613. pFlame->SetLifetime( pGib->m_lifeTime );
  614. pGib->SetFlame( pFlame );
  615. }
  616. }
  617. if ( m_iszLightingOrigin != NULL_STRING )
  618. {
  619. // Make the gibs use the lighting origin
  620. pGib->SetLightingOrigin( m_iszLightingOrigin );
  621. }
  622. if( m_bNoGibShadows )
  623. {
  624. pGib->AddEffects( EF_NOSHADOW );
  625. }
  626. #if HL2_EPISODIC
  627. // if a mass override is set, apply it to the gib
  628. if (m_flMassOverride != 0)
  629. {
  630. IPhysicsObject *pPhys = pGib->VPhysicsGetObject();
  631. if (pPhys)
  632. {
  633. pPhys->SetMass( m_flMassOverride );
  634. }
  635. }
  636. #endif
  637. return pGib;
  638. }
  639. //-----------------------------------------------------------------------------
  640. // An entity that shoots out junk when hit by a rotor wash
  641. //-----------------------------------------------------------------------------
  642. class CRotorWashShooter : public CEnvShooter, public IRotorWashShooter
  643. {
  644. public:
  645. DECLARE_CLASS( CRotorWashShooter, CEnvShooter );
  646. DECLARE_DATADESC();
  647. virtual void Spawn();
  648. public:
  649. // Inherited from IRotorWashShooter
  650. virtual CBaseEntity *DoWashPush( float flTimeSincePushStarted, const Vector &vecForce );
  651. private:
  652. // Amount of time we need to spend under the rotor before we shoot
  653. float m_flTimeUnderRotor;
  654. float m_flTimeUnderRotorVariance;
  655. // Last time we were hit with a wash...
  656. float m_flLastWashStartTime;
  657. float m_flNextGibTime;
  658. };
  659. LINK_ENTITY_TO_CLASS( env_rotorshooter, CRotorWashShooter );
  660. //-----------------------------------------------------------------------------
  661. // Save/load
  662. //-----------------------------------------------------------------------------
  663. BEGIN_DATADESC( CRotorWashShooter )
  664. DEFINE_KEYFIELD( m_flTimeUnderRotor, FIELD_FLOAT ,"rotortime" ),
  665. DEFINE_KEYFIELD( m_flTimeUnderRotorVariance, FIELD_FLOAT ,"rotortimevariance" ),
  666. DEFINE_FIELD( m_flLastWashStartTime, FIELD_TIME ),
  667. DEFINE_FIELD( m_flNextGibTime, FIELD_TIME ),
  668. END_DATADESC()
  669. //-----------------------------------------------------------------------------
  670. // Gets at the interface if the entity supports it
  671. //-----------------------------------------------------------------------------
  672. IRotorWashShooter *GetRotorWashShooter( CBaseEntity *pEntity )
  673. {
  674. CRotorWashShooter *pShooter = dynamic_cast<CRotorWashShooter*>(pEntity);
  675. return pShooter;
  676. }
  677. //-----------------------------------------------------------------------------
  678. // Inherited from IRotorWashShooter
  679. //-----------------------------------------------------------------------------
  680. void CRotorWashShooter::Spawn()
  681. {
  682. BaseClass::Spawn();
  683. m_flLastWashStartTime = -1;
  684. }
  685. //-----------------------------------------------------------------------------
  686. // Inherited from IRotorWashShooter
  687. //-----------------------------------------------------------------------------
  688. CBaseEntity *CRotorWashShooter::DoWashPush( float flWashStartTime, const Vector &vecForce )
  689. {
  690. if ( flWashStartTime == m_flLastWashStartTime )
  691. {
  692. if ( m_flNextGibTime > gpGlobals->curtime )
  693. return NULL;
  694. }
  695. m_flLastWashStartTime = flWashStartTime;
  696. m_flNextGibTime = gpGlobals->curtime + m_flTimeUnderRotor + random->RandomFloat( -1, 1) * m_flTimeUnderRotorVariance;
  697. if ( m_flNextGibTime <= gpGlobals->curtime )
  698. {
  699. m_flNextGibTime = gpGlobals->curtime + 0.01f;
  700. }
  701. // Set the velocity to be what the force would cause it to accelerate to
  702. // after one tick
  703. Vector vecShootDir = vecForce;
  704. VectorNormalize( vecShootDir );
  705. vecShootDir.x += random->RandomFloat( -1, 1 ) * m_flVariance;
  706. vecShootDir.y += random->RandomFloat( -1, 1 ) * m_flVariance;
  707. vecShootDir.z += random->RandomFloat( -1, 1 ) * m_flVariance;
  708. VectorNormalize( vecShootDir );
  709. CBaseEntity *pGib = SpawnGib( vecShootDir, m_flGibVelocity /*flLength*/ );
  710. if ( --m_iGibs <= 0 )
  711. {
  712. if ( HasSpawnFlags(SF_GIBSHOOTER_REPEATABLE) )
  713. {
  714. m_iGibs = m_iGibCapacity;
  715. }
  716. else
  717. {
  718. SetThink ( &CGibShooter::SUB_Remove );
  719. SetNextThink( gpGlobals->curtime );
  720. }
  721. }
  722. return pGib;
  723. }
  724. //-----------------------------------------------------------------------------
  725. // Purpose:
  726. //-----------------------------------------------------------------------------
  727. class CTestEffect : public CBaseEntity
  728. {
  729. public:
  730. DECLARE_CLASS( CTestEffect, CBaseEntity );
  731. void Spawn( void );
  732. void Precache( void );
  733. // bool KeyValue( const char *szKeyName, const char *szValue );
  734. void Think( void );
  735. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  736. int m_iLoop;
  737. int m_iBeam;
  738. CBeam *m_pBeam[24];
  739. float m_flBeamTime[24];
  740. float m_flStartTime;
  741. };
  742. LINK_ENTITY_TO_CLASS( test_effect, CTestEffect );
  743. void CTestEffect::Spawn( void )
  744. {
  745. Precache( );
  746. }
  747. void CTestEffect::Precache( void )
  748. {
  749. PrecacheModel( "sprites/lgtning.vmt" );
  750. }
  751. void CTestEffect::Think( void )
  752. {
  753. int i;
  754. float t = (gpGlobals->curtime - m_flStartTime);
  755. if (m_iBeam < 24)
  756. {
  757. CBeam *pbeam = CBeam::BeamCreate( "sprites/lgtning.vmt", 10 );
  758. trace_t tr;
  759. Vector vecSrc = GetAbsOrigin();
  760. Vector vecDir = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) );
  761. VectorNormalize( vecDir );
  762. UTIL_TraceLine( vecSrc, vecSrc + vecDir * 128, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
  763. pbeam->PointsInit( vecSrc, tr.endpos );
  764. // pbeam->SetColor( 80, 100, 255 );
  765. pbeam->SetColor( 255, 180, 100 );
  766. pbeam->SetWidth( 10.0 );
  767. pbeam->SetScrollRate( 12 );
  768. m_flBeamTime[m_iBeam] = gpGlobals->curtime;
  769. m_pBeam[m_iBeam] = pbeam;
  770. m_iBeam++;
  771. #if 0
  772. Vector vecMid = (vecSrc + tr.endpos) * 0.5;
  773. CBroadcastRecipientFilter filter;
  774. TE_DynamicLight( filter, 0.0,
  775. vecMid, 255, 180, 100, 3, 2.0, 0.0 );
  776. #endif
  777. }
  778. if (t < 3.0)
  779. {
  780. for (i = 0; i < m_iBeam; i++)
  781. {
  782. t = (gpGlobals->curtime - m_flBeamTime[i]) / ( 3 + m_flStartTime - m_flBeamTime[i]);
  783. m_pBeam[i]->SetBrightness( 255 * t );
  784. // m_pBeam[i]->SetScrollRate( 20 * t );
  785. }
  786. SetNextThink( gpGlobals->curtime + 0.1f );
  787. }
  788. else
  789. {
  790. for (i = 0; i < m_iBeam; i++)
  791. {
  792. UTIL_Remove( m_pBeam[i] );
  793. }
  794. m_flStartTime = gpGlobals->curtime;
  795. m_iBeam = 0;
  796. SetNextThink( TICK_NEVER_THINK );
  797. }
  798. }
  799. void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  800. {
  801. SetNextThink( gpGlobals->curtime + 0.1f );
  802. m_flStartTime = gpGlobals->curtime;
  803. }
  804. // Blood effects
  805. class CBlood : public CPointEntity
  806. {
  807. public:
  808. DECLARE_CLASS( CBlood, CPointEntity );
  809. void Spawn( void );
  810. bool KeyValue( const char *szKeyName, const char *szValue );
  811. inline int Color( void ) { return m_Color; }
  812. inline float BloodAmount( void ) { return m_flAmount; }
  813. inline void SetColor( int color ) { m_Color = color; }
  814. // Input handlers
  815. void InputEmitBlood( inputdata_t &inputdata );
  816. Vector Direction( void );
  817. Vector BloodPosition( CBaseEntity *pActivator );
  818. DECLARE_DATADESC();
  819. Vector m_vecSprayDir;
  820. float m_flAmount;
  821. int m_Color;
  822. private:
  823. };
  824. LINK_ENTITY_TO_CLASS( env_blood, CBlood );
  825. BEGIN_DATADESC( CBlood )
  826. DEFINE_KEYFIELD( m_vecSprayDir, FIELD_VECTOR, "spraydir" ),
  827. DEFINE_KEYFIELD( m_flAmount, FIELD_FLOAT, "amount" ),
  828. DEFINE_FIELD( m_Color, FIELD_INTEGER ),
  829. DEFINE_INPUTFUNC( FIELD_VOID, "EmitBlood", InputEmitBlood ),
  830. END_DATADESC()
  831. #define SF_BLOOD_RANDOM 0x0001
  832. #define SF_BLOOD_STREAM 0x0002
  833. #define SF_BLOOD_PLAYER 0x0004
  834. #define SF_BLOOD_DECAL 0x0008
  835. #define SF_BLOOD_CLOUD 0x0010
  836. #define SF_BLOOD_DROPS 0x0020
  837. #define SF_BLOOD_GORE 0x0040
  838. //-----------------------------------------------------------------------------
  839. // Purpose:
  840. //-----------------------------------------------------------------------------
  841. void CBlood::Spawn( void )
  842. {
  843. // Convert spraydir from angles to a vector
  844. QAngle angSprayDir = QAngle( m_vecSprayDir.x, m_vecSprayDir.y, m_vecSprayDir.z );
  845. AngleVectors( angSprayDir, &m_vecSprayDir );
  846. SetSolid( SOLID_NONE );
  847. SetMoveType( MOVETYPE_NONE );
  848. SetColor( BLOOD_COLOR_RED );
  849. }
  850. //-----------------------------------------------------------------------------
  851. // Purpose:
  852. // Input : szKeyName -
  853. // szValue -
  854. // Output : Returns true on success, false on failure.
  855. //-----------------------------------------------------------------------------
  856. bool CBlood::KeyValue( const char *szKeyName, const char *szValue )
  857. {
  858. if (FStrEq(szKeyName, "color"))
  859. {
  860. int color = atoi(szValue);
  861. switch ( color )
  862. {
  863. case 1:
  864. {
  865. SetColor( BLOOD_COLOR_YELLOW );
  866. break;
  867. }
  868. }
  869. }
  870. else
  871. {
  872. return BaseClass::KeyValue( szKeyName, szValue );
  873. }
  874. return true;
  875. }
  876. Vector CBlood::Direction( void )
  877. {
  878. if ( HasSpawnFlags( SF_BLOOD_RANDOM ) )
  879. return UTIL_RandomBloodVector();
  880. return m_vecSprayDir;
  881. }
  882. Vector CBlood::BloodPosition( CBaseEntity *pActivator )
  883. {
  884. if ( HasSpawnFlags( SF_BLOOD_PLAYER ) )
  885. {
  886. CBasePlayer *player;
  887. if ( pActivator && pActivator->IsPlayer() )
  888. {
  889. player = ToBasePlayer( pActivator );
  890. }
  891. else
  892. {
  893. player = UTIL_GetLocalPlayer();
  894. }
  895. if ( player )
  896. {
  897. return (player->EyePosition()) + Vector( random->RandomFloat(-10,10), random->RandomFloat(-10,10), random->RandomFloat(-10,10) );
  898. }
  899. }
  900. return GetLocalOrigin();
  901. }
  902. //-----------------------------------------------------------------------------
  903. // Purpose:
  904. //-----------------------------------------------------------------------------
  905. void UTIL_BloodSpray( const Vector &pos, const Vector &dir, int color, int amount, int flags )
  906. {
  907. if( color == DONT_BLEED )
  908. return;
  909. CEffectData data;
  910. data.m_vOrigin = pos;
  911. data.m_vNormal = dir;
  912. data.m_flScale = (float)amount;
  913. data.m_fFlags = flags;
  914. data.m_nColor = color;
  915. DispatchEffect( "bloodspray", data );
  916. }
  917. //-----------------------------------------------------------------------------
  918. // Purpose: Input handler for triggering the blood effect.
  919. //-----------------------------------------------------------------------------
  920. void CBlood::InputEmitBlood( inputdata_t &inputdata )
  921. {
  922. if ( HasSpawnFlags( SF_BLOOD_STREAM ) )
  923. {
  924. UTIL_BloodStream( BloodPosition(inputdata.pActivator), Direction(), Color(), BloodAmount() );
  925. }
  926. else
  927. {
  928. UTIL_BloodDrips( BloodPosition(inputdata.pActivator), Direction(), Color(), BloodAmount() );
  929. }
  930. if ( HasSpawnFlags( SF_BLOOD_DECAL ) )
  931. {
  932. Vector forward = Direction();
  933. Vector start = BloodPosition( inputdata.pActivator );
  934. trace_t tr;
  935. UTIL_TraceLine( start, start + forward * BloodAmount() * 2, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
  936. if ( tr.fraction != 1.0 )
  937. {
  938. UTIL_BloodDecalTrace( &tr, Color() );
  939. }
  940. }
  941. //
  942. // New-fangled blood effects.
  943. //
  944. if ( HasSpawnFlags( SF_BLOOD_CLOUD | SF_BLOOD_DROPS | SF_BLOOD_GORE ) )
  945. {
  946. int nFlags = 0;
  947. if (HasSpawnFlags(SF_BLOOD_CLOUD))
  948. {
  949. nFlags |= FX_BLOODSPRAY_CLOUD;
  950. }
  951. if (HasSpawnFlags(SF_BLOOD_DROPS))
  952. {
  953. nFlags |= FX_BLOODSPRAY_DROPS;
  954. }
  955. if (HasSpawnFlags(SF_BLOOD_GORE))
  956. {
  957. nFlags |= FX_BLOODSPRAY_GORE;
  958. }
  959. UTIL_BloodSpray(GetAbsOrigin(), Direction(), Color(), BloodAmount(), nFlags);
  960. }
  961. }
  962. //-----------------------------------------------------------------------------
  963. // Purpose: Console command for emitting the blood spray effect from an NPC.
  964. //-----------------------------------------------------------------------------
  965. void CC_BloodSpray( const CCommand &args )
  966. {
  967. CBaseEntity *pEnt = NULL;
  968. while ( ( pEnt = gEntList.FindEntityGeneric( pEnt, args[1] ) ) != NULL )
  969. {
  970. Vector forward;
  971. pEnt->GetVectors(&forward, NULL, NULL);
  972. UTIL_BloodSpray( (forward * 4 ) + ( pEnt->EyePosition() + pEnt->WorldSpaceCenter() ) * 0.5f, forward, BLOOD_COLOR_RED, 4, FX_BLOODSPRAY_ALL );
  973. }
  974. }
  975. static ConCommand bloodspray( "bloodspray", CC_BloodSpray, "blood", FCVAR_CHEAT );
  976. //-----------------------------------------------------------------------------
  977. //
  978. //-----------------------------------------------------------------------------
  979. class CEnvFunnel : public CBaseEntity
  980. {
  981. DECLARE_DATADESC();
  982. public:
  983. DECLARE_CLASS( CEnvFunnel, CBaseEntity );
  984. void Spawn( void );
  985. void Precache( void );
  986. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  987. int m_iSprite; // Don't save, precache
  988. };
  989. LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel );
  990. //---------------------------------------------------------
  991. // Save/Restore
  992. //---------------------------------------------------------
  993. BEGIN_DATADESC( CEnvFunnel )
  994. // DEFINE_FIELD( m_iSprite, FIELD_INTEGER ),
  995. END_DATADESC()
  996. void CEnvFunnel::Precache ( void )
  997. {
  998. m_iSprite = PrecacheModel ( "sprites/flare6.vmt" );
  999. }
  1000. void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  1001. {
  1002. CBroadcastRecipientFilter filter;
  1003. te->LargeFunnel( filter, 0.0,
  1004. &GetAbsOrigin(), m_iSprite, HasSpawnFlags( SF_FUNNEL_REVERSE ) ? 1 : 0 );
  1005. SetThink( &CEnvFunnel::SUB_Remove );
  1006. SetNextThink( gpGlobals->curtime );
  1007. }
  1008. void CEnvFunnel::Spawn( void )
  1009. {
  1010. Precache();
  1011. SetSolid( SOLID_NONE );
  1012. AddEffects( EF_NODRAW );
  1013. }
  1014. //=========================================================
  1015. // Beverage Dispenser
  1016. // overloaded m_iHealth, is now how many cans remain in the machine.
  1017. //=========================================================
  1018. class CEnvBeverage : public CBaseEntity
  1019. {
  1020. public:
  1021. DECLARE_CLASS( CEnvBeverage, CBaseEntity );
  1022. void Spawn( void );
  1023. void Precache( void );
  1024. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  1025. bool KeyValue( const char *szKeyName, const char *szValue );
  1026. // Input handlers.
  1027. void InputActivate( inputdata_t &inputdata );
  1028. DECLARE_DATADESC();
  1029. public:
  1030. bool m_CanInDispenser;
  1031. int m_nBeverageType;
  1032. };
  1033. void CEnvBeverage::Precache ( void )
  1034. {
  1035. PrecacheModel( "models/can.mdl" );
  1036. }
  1037. BEGIN_DATADESC( CEnvBeverage )
  1038. DEFINE_FIELD( m_CanInDispenser, FIELD_BOOLEAN ),
  1039. DEFINE_FIELD( m_nBeverageType, FIELD_INTEGER ),
  1040. DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
  1041. END_DATADESC()
  1042. LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage );
  1043. bool CEnvBeverage::KeyValue( const char *szKeyName, const char *szValue )
  1044. {
  1045. if (FStrEq(szKeyName, "beveragetype"))
  1046. {
  1047. m_nBeverageType = atoi(szValue);
  1048. }
  1049. else
  1050. {
  1051. return BaseClass::KeyValue( szKeyName, szValue );
  1052. }
  1053. return true;
  1054. }
  1055. void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  1056. {
  1057. if ( m_CanInDispenser || m_iHealth <= 0 )
  1058. {
  1059. // no more cans while one is waiting in the dispenser, or if I'm out of cans.
  1060. return;
  1061. }
  1062. CBaseAnimating *pCan = (CBaseAnimating *)CBaseEntity::Create( "item_sodacan", GetLocalOrigin(), GetLocalAngles(), this );
  1063. if ( m_nBeverageType == 6 )
  1064. {
  1065. // random
  1066. pCan->m_nSkin = random->RandomInt( 0, 5 );
  1067. }
  1068. else
  1069. {
  1070. pCan->m_nSkin = m_nBeverageType;
  1071. }
  1072. m_CanInDispenser = true;
  1073. m_iHealth -= 1;
  1074. //SetThink (SUB_Remove);
  1075. //SetNextThink( gpGlobals->curtime );
  1076. }
  1077. void CEnvBeverage::InputActivate( inputdata_t &inputdata )
  1078. {
  1079. Use( inputdata.pActivator, inputdata.pCaller, USE_ON, 0 );
  1080. }
  1081. void CEnvBeverage::Spawn( void )
  1082. {
  1083. Precache();
  1084. SetSolid( SOLID_NONE );
  1085. AddEffects( EF_NODRAW );
  1086. m_CanInDispenser = false;
  1087. if ( m_iHealth == 0 )
  1088. {
  1089. m_iHealth = 10;
  1090. }
  1091. }
  1092. //=========================================================
  1093. // Soda can
  1094. //=========================================================
  1095. class CItemSoda : public CBaseAnimating
  1096. {
  1097. public:
  1098. DECLARE_CLASS( CItemSoda, CBaseAnimating );
  1099. void Spawn( void );
  1100. void Precache( void );
  1101. void CanThink ( void );
  1102. void CanTouch ( CBaseEntity *pOther );
  1103. DECLARE_DATADESC();
  1104. };
  1105. BEGIN_DATADESC( CItemSoda )
  1106. // Function Pointers
  1107. DEFINE_FUNCTION( CanThink ),
  1108. DEFINE_FUNCTION( CanTouch ),
  1109. END_DATADESC()
  1110. LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda );
  1111. void CItemSoda::Precache ( void )
  1112. {
  1113. PrecacheModel( "models/can.mdl" );
  1114. PrecacheScriptSound( "ItemSoda.Bounce" );
  1115. }
  1116. void CItemSoda::Spawn( void )
  1117. {
  1118. Precache();
  1119. SetSolid( SOLID_NONE );
  1120. SetMoveType( MOVETYPE_FLYGRAVITY );
  1121. SetModel ( "models/can.mdl" );
  1122. UTIL_SetSize ( this, Vector ( 0, 0, 0 ), Vector ( 0, 0, 0 ) );
  1123. SetThink (&CItemSoda::CanThink);
  1124. SetNextThink( gpGlobals->curtime + 0.5f );
  1125. }
  1126. void CItemSoda::CanThink ( void )
  1127. {
  1128. EmitSound( "ItemSoda.Bounce" );
  1129. SetSolid( SOLID_BBOX );
  1130. AddSolidFlags( FSOLID_TRIGGER );
  1131. UTIL_SetSize ( this, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) );
  1132. SetThink ( NULL );
  1133. SetTouch ( &CItemSoda::CanTouch );
  1134. }
  1135. void CItemSoda::CanTouch ( CBaseEntity *pOther )
  1136. {
  1137. if ( !pOther->IsPlayer() )
  1138. {
  1139. return;
  1140. }
  1141. // spoit sound here
  1142. pOther->TakeHealth( 1, DMG_GENERIC );// a bit of health.
  1143. if ( GetOwnerEntity() )
  1144. {
  1145. // tell the machine the can was taken
  1146. CEnvBeverage *bev = (CEnvBeverage *)GetOwnerEntity();
  1147. bev->m_CanInDispenser = false;
  1148. }
  1149. AddSolidFlags( FSOLID_NOT_SOLID );
  1150. SetMoveType( MOVETYPE_NONE );
  1151. AddEffects( EF_NODRAW );
  1152. SetTouch ( NULL );
  1153. SetThink ( &CItemSoda::SUB_Remove );
  1154. SetNextThink( gpGlobals->curtime );
  1155. }
  1156. #ifndef _XBOX
  1157. //=========================================================
  1158. // func_precipitation - temporary snow solution for first HL2
  1159. // technology demo
  1160. //=========================================================
  1161. class CPrecipitation : public CBaseEntity
  1162. {
  1163. public:
  1164. DECLARE_CLASS( CPrecipitation, CBaseEntity );
  1165. DECLARE_DATADESC();
  1166. DECLARE_SERVERCLASS();
  1167. CPrecipitation();
  1168. void Spawn( void );
  1169. CNetworkVar( PrecipitationType_t, m_nPrecipType );
  1170. };
  1171. LINK_ENTITY_TO_CLASS( func_precipitation, CPrecipitation );
  1172. BEGIN_DATADESC( CPrecipitation )
  1173. DEFINE_KEYFIELD( m_nPrecipType, FIELD_INTEGER, "preciptype" ),
  1174. END_DATADESC()
  1175. // Just send the normal entity crap
  1176. IMPLEMENT_SERVERCLASS_ST( CPrecipitation, DT_Precipitation)
  1177. SendPropInt( SENDINFO( m_nPrecipType ), Q_log2( NUM_PRECIPITATION_TYPES ) + 1, SPROP_UNSIGNED )
  1178. END_SEND_TABLE()
  1179. CPrecipitation::CPrecipitation()
  1180. {
  1181. m_nPrecipType = PRECIPITATION_TYPE_RAIN; // default to rain.
  1182. }
  1183. void CPrecipitation::Spawn( void )
  1184. {
  1185. PrecacheMaterial( "effects/fleck_ash1" );
  1186. PrecacheMaterial( "effects/fleck_ash2" );
  1187. PrecacheMaterial( "effects/fleck_ash3" );
  1188. PrecacheMaterial( "effects/ember_swirling001" );
  1189. Precache();
  1190. SetSolid( SOLID_NONE ); // Remove model & collisions
  1191. SetMoveType( MOVETYPE_NONE );
  1192. SetModel( STRING( GetModelName() ) ); // Set size
  1193. // Default to rain.
  1194. if ( m_nPrecipType < 0 || m_nPrecipType > NUM_PRECIPITATION_TYPES )
  1195. m_nPrecipType = PRECIPITATION_TYPE_RAIN;
  1196. m_nRenderMode = kRenderEnvironmental;
  1197. }
  1198. #endif
  1199. //-----------------------------------------------------------------------------
  1200. // EnvWind - global wind info
  1201. //-----------------------------------------------------------------------------
  1202. class CEnvWind : public CBaseEntity
  1203. {
  1204. public:
  1205. DECLARE_CLASS( CEnvWind, CBaseEntity );
  1206. void Spawn( void );
  1207. void Precache( void );
  1208. void WindThink( void );
  1209. int UpdateTransmitState( void );
  1210. DECLARE_DATADESC();
  1211. DECLARE_SERVERCLASS();
  1212. private:
  1213. #ifdef POSIX
  1214. CEnvWindShared m_EnvWindShared; // FIXME - fails to compile as networked var due to operator= problem
  1215. #else
  1216. CNetworkVarEmbedded( CEnvWindShared, m_EnvWindShared );
  1217. #endif
  1218. };
  1219. LINK_ENTITY_TO_CLASS( env_wind, CEnvWind );
  1220. BEGIN_DATADESC( CEnvWind )
  1221. DEFINE_KEYFIELD( m_EnvWindShared.m_iMinWind, FIELD_INTEGER, "minwind" ),
  1222. DEFINE_KEYFIELD( m_EnvWindShared.m_iMaxWind, FIELD_INTEGER, "maxwind" ),
  1223. DEFINE_KEYFIELD( m_EnvWindShared.m_iMinGust, FIELD_INTEGER, "mingust" ),
  1224. DEFINE_KEYFIELD( m_EnvWindShared.m_iMaxGust, FIELD_INTEGER, "maxgust" ),
  1225. DEFINE_KEYFIELD( m_EnvWindShared.m_flMinGustDelay, FIELD_FLOAT, "mingustdelay" ),
  1226. DEFINE_KEYFIELD( m_EnvWindShared.m_flMaxGustDelay, FIELD_FLOAT, "maxgustdelay" ),
  1227. DEFINE_KEYFIELD( m_EnvWindShared.m_iGustDirChange, FIELD_INTEGER, "gustdirchange" ),
  1228. DEFINE_KEYFIELD( m_EnvWindShared.m_flGustDuration, FIELD_FLOAT, "gustduration" ),
  1229. // DEFINE_KEYFIELD( m_EnvWindShared.m_iszGustSound, FIELD_STRING, "gustsound" ),
  1230. // Just here to quiet down classcheck
  1231. // DEFINE_FIELD( m_EnvWindShared, CEnvWindShared ),
  1232. DEFINE_FIELD( m_EnvWindShared.m_iWindDir, FIELD_INTEGER ),
  1233. DEFINE_FIELD( m_EnvWindShared.m_flWindSpeed, FIELD_FLOAT ),
  1234. DEFINE_OUTPUT( m_EnvWindShared.m_OnGustStart, "OnGustStart" ),
  1235. DEFINE_OUTPUT( m_EnvWindShared.m_OnGustEnd, "OnGustEnd" ),
  1236. // Function Pointers
  1237. DEFINE_FUNCTION( WindThink ),
  1238. END_DATADESC()
  1239. BEGIN_SEND_TABLE_NOBASE(CEnvWindShared, DT_EnvWindShared)
  1240. // These are parameters that are used to generate the entire motion
  1241. SendPropInt (SENDINFO(m_iMinWind), 10, SPROP_UNSIGNED ),
  1242. SendPropInt (SENDINFO(m_iMaxWind), 10, SPROP_UNSIGNED ),
  1243. SendPropInt (SENDINFO(m_iMinGust), 10, SPROP_UNSIGNED ),
  1244. SendPropInt (SENDINFO(m_iMaxGust), 10, SPROP_UNSIGNED ),
  1245. SendPropFloat (SENDINFO(m_flMinGustDelay), 0, SPROP_NOSCALE), // NOTE: Have to do this, so it's *exactly* the same on client
  1246. SendPropFloat (SENDINFO(m_flMaxGustDelay), 0, SPROP_NOSCALE),
  1247. SendPropInt (SENDINFO(m_iGustDirChange), 9, SPROP_UNSIGNED ),
  1248. SendPropInt (SENDINFO(m_iWindSeed), 32, SPROP_UNSIGNED ),
  1249. // These are related to initial state
  1250. SendPropInt (SENDINFO(m_iInitialWindDir),9, SPROP_UNSIGNED ),
  1251. SendPropFloat (SENDINFO(m_flInitialWindSpeed),0, SPROP_NOSCALE ),
  1252. SendPropFloat (SENDINFO(m_flStartTime), 0, SPROP_NOSCALE ),
  1253. SendPropFloat (SENDINFO(m_flGustDuration), 0, SPROP_NOSCALE),
  1254. // Sound related
  1255. // SendPropInt (SENDINFO(m_iszGustSound), 10, SPROP_UNSIGNED ),
  1256. END_SEND_TABLE()
  1257. // This table encodes the CBaseEntity data.
  1258. IMPLEMENT_SERVERCLASS_ST_NOBASE(CEnvWind, DT_EnvWind)
  1259. SendPropDataTable(SENDINFO_DT(m_EnvWindShared), &REFERENCE_SEND_TABLE(DT_EnvWindShared)),
  1260. END_SEND_TABLE()
  1261. void CEnvWind::Precache ( void )
  1262. {
  1263. // if (m_iszGustSound)
  1264. // {
  1265. // PrecacheScriptSound( STRING( m_iszGustSound ) );
  1266. // }
  1267. }
  1268. void CEnvWind::Spawn( void )
  1269. {
  1270. Precache();
  1271. SetSolid( SOLID_NONE );
  1272. AddEffects( EF_NODRAW );
  1273. m_EnvWindShared.Init( entindex(), 0, gpGlobals->frametime, GetLocalAngles().y, 0 );
  1274. SetThink( &CEnvWind::WindThink );
  1275. SetNextThink( gpGlobals->curtime );
  1276. }
  1277. int CEnvWind::UpdateTransmitState()
  1278. {
  1279. return SetTransmitState( FL_EDICT_ALWAYS );
  1280. }
  1281. void CEnvWind::WindThink( void )
  1282. {
  1283. SetNextThink( m_EnvWindShared.WindThink( gpGlobals->curtime ) );
  1284. }
  1285. //==================================================
  1286. // CEmbers
  1287. //==================================================
  1288. #define bitsSF_EMBERS_START_ON 0x00000001
  1289. #define bitsSF_EMBERS_TOGGLE 0x00000002
  1290. // UNDONE: This is a brush effect-in-volume entity, move client side.
  1291. class CEmbers : public CBaseEntity
  1292. {
  1293. public:
  1294. DECLARE_CLASS( CEmbers, CBaseEntity );
  1295. void Spawn( void );
  1296. void Precache( void );
  1297. void EmberUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  1298. CNetworkVar( int, m_nDensity );
  1299. CNetworkVar( int, m_nLifetime );
  1300. CNetworkVar( int, m_nSpeed );
  1301. CNetworkVar( bool, m_bEmit );
  1302. DECLARE_DATADESC();
  1303. DECLARE_SERVERCLASS();
  1304. };
  1305. LINK_ENTITY_TO_CLASS( env_embers, CEmbers );
  1306. //Data description
  1307. BEGIN_DATADESC( CEmbers )
  1308. DEFINE_KEYFIELD( m_nDensity, FIELD_INTEGER, "density" ),
  1309. DEFINE_KEYFIELD( m_nLifetime, FIELD_INTEGER, "lifetime" ),
  1310. DEFINE_KEYFIELD( m_nSpeed, FIELD_INTEGER, "speed" ),
  1311. DEFINE_FIELD( m_bEmit, FIELD_BOOLEAN ),
  1312. //Function pointers
  1313. DEFINE_FUNCTION( EmberUse ),
  1314. END_DATADESC()
  1315. //Data table
  1316. IMPLEMENT_SERVERCLASS_ST( CEmbers, DT_Embers )
  1317. SendPropInt( SENDINFO( m_nDensity ), 32, SPROP_UNSIGNED ),
  1318. SendPropInt( SENDINFO( m_nLifetime ), 32, SPROP_UNSIGNED ),
  1319. SendPropInt( SENDINFO( m_nSpeed ), 32, SPROP_UNSIGNED ),
  1320. SendPropInt( SENDINFO( m_bEmit ), 2, SPROP_UNSIGNED ),
  1321. END_SEND_TABLE()
  1322. //-----------------------------------------------------------------------------
  1323. // Purpose:
  1324. //-----------------------------------------------------------------------------
  1325. void CEmbers::Spawn( void )
  1326. {
  1327. Precache();
  1328. SetModel( STRING( GetModelName() ) );
  1329. SetSolid( SOLID_NONE );
  1330. SetRenderColorA( 0 );
  1331. m_nRenderMode = kRenderTransTexture;
  1332. SetUse( &CEmbers::EmberUse );
  1333. //Start off if we're targetted (unless flagged)
  1334. m_bEmit = ( HasSpawnFlags( bitsSF_EMBERS_START_ON ) || ( !GetEntityName() ) );
  1335. }
  1336. //-----------------------------------------------------------------------------
  1337. // Purpose:
  1338. //-----------------------------------------------------------------------------
  1339. void CEmbers::Precache( void )
  1340. {
  1341. }
  1342. //-----------------------------------------------------------------------------
  1343. // Purpose:
  1344. // Input : *pActivator -
  1345. // *pCaller -
  1346. // useType -
  1347. // value -
  1348. //-----------------------------------------------------------------------------
  1349. void CEmbers::EmberUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  1350. {
  1351. //If we're not toggable, only allow one use
  1352. if ( !HasSpawnFlags( bitsSF_EMBERS_TOGGLE ) )
  1353. {
  1354. SetUse( NULL );
  1355. }
  1356. //Handle it
  1357. switch ( useType )
  1358. {
  1359. case USE_OFF:
  1360. m_bEmit = false;
  1361. break;
  1362. case USE_ON:
  1363. m_bEmit = true;
  1364. break;
  1365. case USE_SET:
  1366. m_bEmit = !!(int)value;
  1367. break;
  1368. default:
  1369. case USE_TOGGLE:
  1370. m_bEmit = !m_bEmit;
  1371. break;
  1372. }
  1373. }
  1374. //-----------------------------------------------------------------------------
  1375. // Purpose:
  1376. //-----------------------------------------------------------------------------
  1377. class CPhysicsWire : public CBaseEntity
  1378. {
  1379. public:
  1380. DECLARE_CLASS( CPhysicsWire, CBaseEntity );
  1381. void Spawn( void );
  1382. void Precache( void );
  1383. DECLARE_DATADESC();
  1384. protected:
  1385. bool SetupPhysics( void );
  1386. int m_nDensity;
  1387. };
  1388. LINK_ENTITY_TO_CLASS( env_physwire, CPhysicsWire );
  1389. BEGIN_DATADESC( CPhysicsWire )
  1390. DEFINE_KEYFIELD( m_nDensity, FIELD_INTEGER, "Density" ),
  1391. // DEFINE_KEYFIELD( m_frequency, FIELD_INTEGER, "frequency" ),
  1392. // DEFINE_FIELD( m_flFoo, FIELD_FLOAT ),
  1393. // Function Pointers
  1394. // DEFINE_FUNCTION( WireThink ),
  1395. END_DATADESC()
  1396. //-----------------------------------------------------------------------------
  1397. // Purpose:
  1398. //-----------------------------------------------------------------------------
  1399. void CPhysicsWire::Spawn( void )
  1400. {
  1401. BaseClass::Spawn();
  1402. Precache();
  1403. // if ( SetupPhysics() == false )
  1404. // return;
  1405. }
  1406. //-----------------------------------------------------------------------------
  1407. // Purpose:
  1408. //-----------------------------------------------------------------------------
  1409. void CPhysicsWire::Precache( void )
  1410. {
  1411. BaseClass::Precache();
  1412. }
  1413. class CPhysBallSocket;
  1414. //-----------------------------------------------------------------------------
  1415. // Purpose:
  1416. //-----------------------------------------------------------------------------
  1417. bool CPhysicsWire::SetupPhysics( void )
  1418. {
  1419. /*
  1420. CPointEntity *anchorEnt, *freeEnt;
  1421. CPhysBallSocket *socket;
  1422. char anchorName[256];
  1423. char freeName[256];
  1424. int iAnchorName, iFreeName;
  1425. anchorEnt = (CPointEntity *) CreateEntityByName( "info_target" );
  1426. if ( anchorEnt == NULL )
  1427. return false;
  1428. //Create and connect all segments
  1429. for ( int i = 0; i < m_nDensity; i++ )
  1430. {
  1431. // Create other end of our link
  1432. freeEnt = (CPointEntity *) CreateEntityByName( "info_target" );
  1433. // Create a ballsocket and attach the two
  1434. //socket = (CPhysBallSocket *) CreateEntityByName( "phys_ballsocket" );
  1435. Q_snprintf( anchorName,sizeof(anchorName), "__PWIREANCHOR%d", i );
  1436. Q_snprintf( freeName,sizeof(freeName), "__PWIREFREE%d", i+1 );
  1437. iAnchorName = MAKE_STRING( anchorName );
  1438. iFreeName = MAKE_STRING( freeName );
  1439. //Fake the names
  1440. //socket->m_nameAttach1 = anchorEnt->m_iGlobalname = iAnchorName;
  1441. //socket->m_nameAttach2 = freeEnt->m_iGlobalname = iFreeName
  1442. //socket->Activate();
  1443. //The free ent is now the anchor for the next link
  1444. anchorEnt = freeEnt;
  1445. }
  1446. */
  1447. return true;
  1448. }
  1449. //
  1450. // Muzzle flash
  1451. //
  1452. class CEnvMuzzleFlash : public CPointEntity
  1453. {
  1454. DECLARE_CLASS( CEnvMuzzleFlash, CPointEntity );
  1455. public:
  1456. virtual void Spawn();
  1457. // Input handlers
  1458. void InputFire( inputdata_t &inputdata );
  1459. DECLARE_DATADESC();
  1460. float m_flScale;
  1461. string_t m_iszParentAttachment;
  1462. };
  1463. BEGIN_DATADESC( CEnvMuzzleFlash )
  1464. DEFINE_KEYFIELD( m_flScale, FIELD_FLOAT, "scale" ),
  1465. DEFINE_KEYFIELD( m_iszParentAttachment, FIELD_STRING, "parentattachment" ),
  1466. DEFINE_INPUTFUNC( FIELD_VOID, "Fire", InputFire ),
  1467. END_DATADESC()
  1468. LINK_ENTITY_TO_CLASS( env_muzzleflash, CEnvMuzzleFlash );
  1469. //-----------------------------------------------------------------------------
  1470. // Spawn!
  1471. //-----------------------------------------------------------------------------
  1472. void CEnvMuzzleFlash::Spawn()
  1473. {
  1474. if ( (m_iszParentAttachment != NULL_STRING) && GetParent() && GetParent()->GetBaseAnimating() )
  1475. {
  1476. CBaseAnimating *pAnim = GetParent()->GetBaseAnimating();
  1477. int nParentAttachment = pAnim->LookupAttachment( STRING(m_iszParentAttachment) );
  1478. if ( nParentAttachment > 0 )
  1479. {
  1480. SetParent( GetParent(), nParentAttachment );
  1481. SetLocalOrigin( vec3_origin );
  1482. SetLocalAngles( vec3_angle );
  1483. }
  1484. }
  1485. }
  1486. //-----------------------------------------------------------------------------
  1487. // Purpose:
  1488. // Input : &inputdata -
  1489. //-----------------------------------------------------------------------------
  1490. void CEnvMuzzleFlash::InputFire( inputdata_t &inputdata )
  1491. {
  1492. g_pEffects->MuzzleFlash( GetAbsOrigin(), GetAbsAngles(), m_flScale, MUZZLEFLASH_TYPE_DEFAULT );
  1493. }
  1494. //=========================================================
  1495. // Splash!
  1496. //=========================================================
  1497. #define SF_ENVSPLASH_FINDWATERSURFACE 0x00000001
  1498. #define SF_ENVSPLASH_DIMINISH 0x00000002
  1499. class CEnvSplash : public CPointEntity
  1500. {
  1501. DECLARE_CLASS( CEnvSplash, CPointEntity );
  1502. public:
  1503. // Input handlers
  1504. void InputSplash( inputdata_t &inputdata );
  1505. protected:
  1506. float m_flScale;
  1507. DECLARE_DATADESC();
  1508. };
  1509. BEGIN_DATADESC( CEnvSplash )
  1510. DEFINE_KEYFIELD( m_flScale, FIELD_FLOAT, "scale" ),
  1511. DEFINE_INPUTFUNC( FIELD_VOID, "Splash", InputSplash ),
  1512. END_DATADESC()
  1513. LINK_ENTITY_TO_CLASS( env_splash, CEnvSplash );
  1514. //-----------------------------------------------------------------------------
  1515. // Purpose:
  1516. // Input : &inputdata -
  1517. //-----------------------------------------------------------------------------
  1518. #define SPLASH_MAX_DEPTH 120.0f
  1519. void CEnvSplash::InputSplash( inputdata_t &inputdata )
  1520. {
  1521. CEffectData data;
  1522. data.m_fFlags = 0;
  1523. float scale = m_flScale;
  1524. if( HasSpawnFlags( SF_ENVSPLASH_FINDWATERSURFACE ) )
  1525. {
  1526. if( UTIL_PointContents(GetAbsOrigin()) & MASK_WATER )
  1527. {
  1528. // No splash if I'm supposed to find the surface of the water, but I'm underwater.
  1529. return;
  1530. }
  1531. // Trace down and find the water's surface. This is designed for making
  1532. // splashes on the surface of water that can change water level.
  1533. trace_t tr;
  1534. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector( 0, 0, 4096 ), (MASK_WATER|MASK_SOLID_BRUSHONLY), this, COLLISION_GROUP_NONE, &tr );
  1535. data.m_vOrigin = tr.endpos;
  1536. if ( tr.contents & CONTENTS_SLIME )
  1537. {
  1538. data.m_fFlags |= FX_WATER_IN_SLIME;
  1539. }
  1540. }
  1541. else
  1542. {
  1543. data.m_vOrigin = GetAbsOrigin();
  1544. }
  1545. if( HasSpawnFlags( SF_ENVSPLASH_DIMINISH ) )
  1546. {
  1547. // Get smaller if I'm in deeper water.
  1548. float depth = 0.0f;
  1549. trace_t tr;
  1550. UTIL_TraceLine( data.m_vOrigin, data.m_vOrigin - Vector( 0, 0, 4096 ), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
  1551. depth = fabs( tr.startpos.z - tr.endpos.z );
  1552. float factor = 1.0f - (depth / SPLASH_MAX_DEPTH);
  1553. if( factor < 0.1 )
  1554. {
  1555. // Don't bother making one this small.
  1556. return;
  1557. }
  1558. scale *= factor;
  1559. }
  1560. data.m_vNormal = Vector( 0, 0, 1 );
  1561. data.m_flScale = scale;
  1562. DispatchEffect( "watersplash", data );
  1563. }
  1564. //-----------------------------------------------------------------------------
  1565. //-----------------------------------------------------------------------------
  1566. class CEnvGunfire : public CPointEntity
  1567. {
  1568. public:
  1569. DECLARE_CLASS( CEnvGunfire, CPointEntity );
  1570. CEnvGunfire()
  1571. {
  1572. // !!!HACKHACK
  1573. // These fields came along kind of late, so they get
  1574. // initialized in the constructor for now. (sjb)
  1575. m_flBias = 1.0f;
  1576. m_bCollide = false;
  1577. }
  1578. void Precache();
  1579. void Spawn();
  1580. void Activate();
  1581. void StartShooting();
  1582. void StopShooting();
  1583. void ShootThink();
  1584. void UpdateTarget();
  1585. void InputEnable( inputdata_t &inputdata );
  1586. void InputDisable( inputdata_t &inputdata );
  1587. int m_iMinBurstSize;
  1588. int m_iMaxBurstSize;
  1589. float m_flMinBurstDelay;
  1590. float m_flMaxBurstDelay;
  1591. float m_flRateOfFire;
  1592. string_t m_iszShootSound;
  1593. string_t m_iszTracerType;
  1594. bool m_bDisabled;
  1595. int m_iShotsRemaining;
  1596. int m_iSpread;
  1597. Vector m_vecSpread;
  1598. Vector m_vecTargetPosition;
  1599. float m_flTargetDist;
  1600. float m_flBias;
  1601. bool m_bCollide;
  1602. EHANDLE m_hTarget;
  1603. DECLARE_DATADESC();
  1604. };
  1605. BEGIN_DATADESC( CEnvGunfire )
  1606. DEFINE_KEYFIELD( m_iMinBurstSize, FIELD_INTEGER, "minburstsize" ),
  1607. DEFINE_KEYFIELD( m_iMaxBurstSize, FIELD_INTEGER, "maxburstsize" ),
  1608. DEFINE_KEYFIELD( m_flMinBurstDelay, FIELD_TIME, "minburstdelay" ),
  1609. DEFINE_KEYFIELD( m_flMaxBurstDelay, FIELD_TIME, "maxburstdelay" ),
  1610. DEFINE_KEYFIELD( m_flRateOfFire, FIELD_FLOAT, "rateoffire" ),
  1611. DEFINE_KEYFIELD( m_iszShootSound, FIELD_STRING, "shootsound" ),
  1612. DEFINE_KEYFIELD( m_iszTracerType, FIELD_STRING, "tracertype" ),
  1613. DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "startdisabled" ),
  1614. DEFINE_KEYFIELD( m_iSpread, FIELD_INTEGER, "spread" ),
  1615. DEFINE_KEYFIELD( m_flBias, FIELD_FLOAT, "bias" ),
  1616. DEFINE_KEYFIELD( m_bCollide, FIELD_BOOLEAN, "collisions" ),
  1617. DEFINE_FIELD( m_iShotsRemaining, FIELD_INTEGER ),
  1618. DEFINE_FIELD( m_vecSpread, FIELD_VECTOR ),
  1619. DEFINE_FIELD( m_vecTargetPosition, FIELD_VECTOR ),
  1620. DEFINE_FIELD( m_flTargetDist, FIELD_FLOAT ),
  1621. DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ),
  1622. DEFINE_THINKFUNC( ShootThink ),
  1623. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  1624. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  1625. END_DATADESC()
  1626. LINK_ENTITY_TO_CLASS( env_gunfire, CEnvGunfire );
  1627. //-----------------------------------------------------------------------------
  1628. //-----------------------------------------------------------------------------
  1629. void CEnvGunfire::Precache()
  1630. {
  1631. PrecacheScriptSound( STRING( m_iszShootSound ) );
  1632. }
  1633. //-----------------------------------------------------------------------------
  1634. //-----------------------------------------------------------------------------
  1635. void CEnvGunfire::Spawn()
  1636. {
  1637. Precache();
  1638. m_iShotsRemaining = 0;
  1639. m_flRateOfFire = 1.0f / m_flRateOfFire;
  1640. switch( m_iSpread )
  1641. {
  1642. case 1:
  1643. m_vecSpread = VECTOR_CONE_1DEGREES;
  1644. break;
  1645. case 5:
  1646. m_vecSpread = VECTOR_CONE_5DEGREES;
  1647. break;
  1648. case 10:
  1649. m_vecSpread = VECTOR_CONE_10DEGREES;
  1650. break;
  1651. case 15:
  1652. m_vecSpread = VECTOR_CONE_15DEGREES;
  1653. break;
  1654. default:
  1655. m_vecSpread = vec3_origin;
  1656. break;
  1657. }
  1658. if( !m_bDisabled )
  1659. {
  1660. StartShooting();
  1661. }
  1662. }
  1663. //-----------------------------------------------------------------------------
  1664. //-----------------------------------------------------------------------------
  1665. void CEnvGunfire::Activate( void )
  1666. {
  1667. // Find my target
  1668. if (m_target != NULL_STRING)
  1669. {
  1670. m_hTarget = gEntList.FindEntityByName( NULL, m_target );
  1671. }
  1672. BaseClass::Activate();
  1673. }
  1674. //-----------------------------------------------------------------------------
  1675. //-----------------------------------------------------------------------------
  1676. void CEnvGunfire::StartShooting()
  1677. {
  1678. m_iShotsRemaining = random->RandomInt( m_iMinBurstSize, m_iMaxBurstSize );
  1679. SetThink( &CEnvGunfire::ShootThink );
  1680. SetNextThink( gpGlobals->curtime );
  1681. }
  1682. //-----------------------------------------------------------------------------
  1683. //-----------------------------------------------------------------------------
  1684. void CEnvGunfire::UpdateTarget()
  1685. {
  1686. if( m_hTarget )
  1687. {
  1688. if( m_hTarget->WorldSpaceCenter() != m_vecTargetPosition )
  1689. {
  1690. // Target has moved.
  1691. // Locate my target and cache the position and distance.
  1692. m_vecTargetPosition = m_hTarget->WorldSpaceCenter();
  1693. m_flTargetDist = (GetAbsOrigin() - m_vecTargetPosition).Length();
  1694. }
  1695. }
  1696. }
  1697. //-----------------------------------------------------------------------------
  1698. //-----------------------------------------------------------------------------
  1699. void CEnvGunfire::StopShooting()
  1700. {
  1701. SetThink( NULL );
  1702. }
  1703. //-----------------------------------------------------------------------------
  1704. //-----------------------------------------------------------------------------
  1705. void CEnvGunfire::ShootThink()
  1706. {
  1707. if( !m_hTarget )
  1708. {
  1709. StopShooting();
  1710. }
  1711. SetNextThink( gpGlobals->curtime + m_flRateOfFire );
  1712. UpdateTarget();
  1713. Vector vecDir = m_vecTargetPosition - GetAbsOrigin();
  1714. VectorNormalize( vecDir );
  1715. CShotManipulator manipulator( vecDir );
  1716. vecDir = manipulator.ApplySpread( m_vecSpread, m_flBias );
  1717. Vector vecEnd;
  1718. if( m_bCollide )
  1719. {
  1720. trace_t tr;
  1721. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vecDir * 8192, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  1722. if( tr.fraction != 1.0 )
  1723. {
  1724. DoImpactEffect( tr, DMG_BULLET );
  1725. }
  1726. vecEnd = tr.endpos;
  1727. }
  1728. else
  1729. {
  1730. vecEnd = GetAbsOrigin() + vecDir * m_flTargetDist;
  1731. }
  1732. if( m_iszTracerType != NULL_STRING )
  1733. {
  1734. UTIL_Tracer( GetAbsOrigin(), vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 5000, true, STRING(m_iszTracerType) );
  1735. }
  1736. else
  1737. {
  1738. UTIL_Tracer( GetAbsOrigin(), vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 5000, true );
  1739. }
  1740. EmitSound( STRING(m_iszShootSound) );
  1741. m_iShotsRemaining--;
  1742. if( m_iShotsRemaining == 0 )
  1743. {
  1744. StartShooting();
  1745. SetNextThink( gpGlobals->curtime + random->RandomFloat( m_flMinBurstDelay, m_flMaxBurstDelay ) );
  1746. }
  1747. }
  1748. //-----------------------------------------------------------------------------
  1749. //-----------------------------------------------------------------------------
  1750. void CEnvGunfire::InputEnable( inputdata_t &inputdata )
  1751. {
  1752. m_bDisabled = false;
  1753. StartShooting();
  1754. }
  1755. //-----------------------------------------------------------------------------
  1756. //-----------------------------------------------------------------------------
  1757. void CEnvGunfire::InputDisable( inputdata_t &inputdata )
  1758. {
  1759. m_bDisabled = true;
  1760. SetThink( NULL );
  1761. }
  1762. //-----------------------------------------------------------------------------
  1763. // Quadratic spline beam effect
  1764. //-----------------------------------------------------------------------------
  1765. BEGIN_DATADESC( CEnvQuadraticBeam )
  1766. DEFINE_FIELD( m_targetPosition, FIELD_POSITION_VECTOR ),
  1767. DEFINE_FIELD( m_controlPosition, FIELD_POSITION_VECTOR ),
  1768. DEFINE_FIELD( m_scrollRate, FIELD_FLOAT ),
  1769. DEFINE_FIELD( m_flWidth, FIELD_FLOAT ),
  1770. END_DATADESC()
  1771. LINK_ENTITY_TO_CLASS( env_quadraticbeam, CEnvQuadraticBeam );
  1772. IMPLEMENT_SERVERCLASS_ST( CEnvQuadraticBeam, DT_QuadraticBeam )
  1773. SendPropVector(SENDINFO(m_targetPosition), -1, SPROP_COORD),
  1774. SendPropVector(SENDINFO(m_controlPosition), -1, SPROP_COORD),
  1775. SendPropFloat(SENDINFO(m_scrollRate), 8, 0, -4, 4),
  1776. SendPropFloat(SENDINFO(m_flWidth), -1, SPROP_NOSCALE),
  1777. END_SEND_TABLE()
  1778. void CEnvQuadraticBeam::Spawn()
  1779. {
  1780. BaseClass::Spawn();
  1781. m_nRenderMode = kRenderTransAdd;
  1782. SetRenderColor( 255, 255, 255 );
  1783. }
  1784. CEnvQuadraticBeam *CreateQuadraticBeam( const char *pSpriteName, const Vector &start, const Vector &control, const Vector &end, float width, CBaseEntity *pOwner )
  1785. {
  1786. CEnvQuadraticBeam *pBeam = (CEnvQuadraticBeam *)CBaseEntity::Create( "env_quadraticbeam", start, vec3_angle, pOwner );
  1787. UTIL_SetModel( pBeam, pSpriteName );
  1788. pBeam->SetSpline( control, end );
  1789. pBeam->SetScrollRate( 0.0 );
  1790. pBeam->SetWidth(width);
  1791. return pBeam;
  1792. }
  1793. void EffectsPrecache( void *pUser )
  1794. {
  1795. CBaseEntity::PrecacheScriptSound( "Underwater.BulletImpact" );
  1796. CBaseEntity::PrecacheScriptSound( "FX_RicochetSound.Ricochet" );
  1797. CBaseEntity::PrecacheScriptSound( "Physics.WaterSplash" );
  1798. CBaseEntity::PrecacheScriptSound( "BaseExplosionEffect.Sound" );
  1799. CBaseEntity::PrecacheScriptSound( "Splash.SplashSound" );
  1800. if ( gpGlobals->maxClients > 1 )
  1801. {
  1802. CBaseEntity::PrecacheScriptSound( "HudChat.Message" );
  1803. }
  1804. }
  1805. PRECACHE_REGISTER_FN( EffectsPrecache );
  1806. class CEnvViewPunch : public CPointEntity
  1807. {
  1808. public:
  1809. DECLARE_CLASS( CEnvViewPunch, CPointEntity );
  1810. virtual void Spawn();
  1811. // Input handlers
  1812. void InputViewPunch( inputdata_t &inputdata );
  1813. private:
  1814. float m_flRadius;
  1815. QAngle m_angViewPunch;
  1816. void DoViewPunch();
  1817. DECLARE_DATADESC();
  1818. };
  1819. LINK_ENTITY_TO_CLASS( env_viewpunch, CEnvViewPunch );
  1820. BEGIN_DATADESC( CEnvViewPunch )
  1821. DEFINE_KEYFIELD( m_angViewPunch, FIELD_VECTOR, "punchangle" ),
  1822. DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),
  1823. DEFINE_INPUTFUNC( FIELD_VOID, "ViewPunch", InputViewPunch ),
  1824. END_DATADESC()
  1825. #define SF_PUNCH_EVERYONE 0x0001 // Don't check radius
  1826. #define SF_PUNCH_IN_AIR 0x0002 // Punch players in air
  1827. //-----------------------------------------------------------------------------
  1828. //-----------------------------------------------------------------------------
  1829. void CEnvViewPunch::Spawn( void )
  1830. {
  1831. SetSolid( SOLID_NONE );
  1832. SetMoveType( MOVETYPE_NONE );
  1833. if ( GetSpawnFlags() & SF_PUNCH_EVERYONE )
  1834. {
  1835. m_flRadius = 0;
  1836. }
  1837. }
  1838. //-----------------------------------------------------------------------------
  1839. //-----------------------------------------------------------------------------
  1840. void CEnvViewPunch::DoViewPunch()
  1841. {
  1842. bool bAir = (GetSpawnFlags() & SF_PUNCH_IN_AIR) ? true : false;
  1843. UTIL_ViewPunch( GetAbsOrigin(), m_angViewPunch, m_flRadius, bAir );
  1844. }
  1845. //-----------------------------------------------------------------------------
  1846. //-----------------------------------------------------------------------------
  1847. void CEnvViewPunch::InputViewPunch( inputdata_t &inputdata )
  1848. {
  1849. DoViewPunch();
  1850. }