Counter Strike : Global Offensive Source Code
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.

2932 lines
74 KiB

  1. //========= Copyright © 1996-2005, 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. #ifdef INFESTED_DLL
  27. #include "asw_fire.h"
  28. #else
  29. #include "fire.h"
  30. #endif
  31. #include "te_effect_dispatch.h"
  32. #include "Sprite.h"
  33. #include "precipitation_shared.h"
  34. #include "shot_manipulator.h"
  35. #include "modelentities.h"
  36. #if defined( CSTRIKE15 )
  37. #include "fx_cs_shared.h"
  38. #include "cs_player.h"
  39. #endif
  40. // memdbgon must be the last include file in a .cpp file!!!
  41. #include "tier0/memdbgon.h"
  42. #define SF_FUNNEL_REVERSE 1 // funnel effect repels particles instead of attracting them.
  43. #define SF_GIBSHOOTER_REPEATABLE (1<<0) // allows a gibshooter to be refired
  44. #define SF_SHOOTER_FLAMING (1<<1) // gib is on fire
  45. #define SF_SHOOTER_STRICT_REMOVE (1<<2) // remove this gib even if it is in the player's view
  46. // UNDONE: This should be client-side and not use TempEnts
  47. class CBubbling : public CBaseEntity
  48. {
  49. public:
  50. DECLARE_CLASS( CBubbling, CBaseEntity );
  51. virtual void Spawn( void );
  52. virtual void Precache( void );
  53. void FizzThink( void );
  54. // Input handlers.
  55. void InputActivate( inputdata_t &inputdata );
  56. void InputDeactivate( inputdata_t &inputdata );
  57. void InputToggle( inputdata_t &inputdata );
  58. void InputSetCurrent( inputdata_t &inputdata );
  59. void InputSetDensity( inputdata_t &inputdata );
  60. void InputSetFrequency( inputdata_t &inputdata );
  61. DECLARE_DATADESC();
  62. private:
  63. void TurnOn();
  64. void TurnOff();
  65. void Toggle();
  66. int m_density;
  67. int m_frequency;
  68. int m_bubbleModel;
  69. int m_state;
  70. };
  71. LINK_ENTITY_TO_CLASS( env_bubbles, CBubbling );
  72. BEGIN_DATADESC( CBubbling )
  73. DEFINE_KEYFIELD( m_flSpeed, FIELD_FLOAT, "current" ),
  74. DEFINE_KEYFIELD( m_density, FIELD_INTEGER, "density" ),
  75. DEFINE_KEYFIELD( m_frequency, FIELD_INTEGER, "frequency" ),
  76. DEFINE_FIELD( m_state, FIELD_INTEGER ),
  77. // Let spawn restore this!
  78. // DEFINE_FIELD( m_bubbleModel, FIELD_INTEGER ),
  79. // Function Pointers
  80. DEFINE_FUNCTION( FizzThink ),
  81. DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
  82. DEFINE_INPUTFUNC( FIELD_VOID, "Deactivate", InputDeactivate ),
  83. DEFINE_INPUTFUNC( FIELD_VOID, "Toggle", InputToggle ),
  84. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetCurrent", InputSetCurrent ),
  85. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetDensity", InputSetDensity ),
  86. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetFrequency", InputSetFrequency ),
  87. END_DATADESC()
  88. #define SF_BUBBLES_STARTOFF 0x0001
  89. void CBubbling::Spawn( void )
  90. {
  91. Precache( );
  92. SetModel( STRING( GetModelName() ) ); // Set size
  93. // Make it invisible to client
  94. SetRenderAlpha( 0 );
  95. SetSolid( SOLID_NONE ); // Remove model & collisions
  96. if ( !HasSpawnFlags(SF_BUBBLES_STARTOFF) )
  97. {
  98. SetThink( &CBubbling::FizzThink );
  99. SetNextThink( gpGlobals->curtime + 2.0 );
  100. m_state = 1;
  101. }
  102. else
  103. {
  104. m_state = 0;
  105. }
  106. }
  107. void CBubbling::Precache( void )
  108. {
  109. m_bubbleModel = PrecacheModel("sprites/bubble.vmt"); // Precache bubble sprite
  110. }
  111. void CBubbling::Toggle()
  112. {
  113. if (!m_state)
  114. {
  115. TurnOn();
  116. }
  117. else
  118. {
  119. TurnOff();
  120. }
  121. }
  122. void CBubbling::TurnOn()
  123. {
  124. m_state = 1;
  125. SetThink( &CBubbling::FizzThink );
  126. SetNextThink( gpGlobals->curtime + 0.1f );
  127. }
  128. void CBubbling::TurnOff()
  129. {
  130. m_state = 0;
  131. SetThink( NULL );
  132. SetNextThink( TICK_NEVER_THINK );
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Purpose:
  136. //-----------------------------------------------------------------------------
  137. void CBubbling::InputActivate( inputdata_t &inputdata )
  138. {
  139. TurnOn();
  140. }
  141. //-----------------------------------------------------------------------------
  142. // Purpose:
  143. //-----------------------------------------------------------------------------
  144. void CBubbling::InputDeactivate( inputdata_t &inputdata )
  145. {
  146. TurnOff();
  147. }
  148. //-----------------------------------------------------------------------------
  149. // Purpose:
  150. //-----------------------------------------------------------------------------
  151. void CBubbling::InputToggle( inputdata_t &inputdata )
  152. {
  153. Toggle();
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Purpose:
  157. // Input : &inputdata -
  158. //-----------------------------------------------------------------------------
  159. void CBubbling::InputSetCurrent( inputdata_t &inputdata )
  160. {
  161. m_flSpeed = (float)inputdata.value.Int();
  162. }
  163. //-----------------------------------------------------------------------------
  164. // Purpose:
  165. // Input : &inputdata -
  166. //-----------------------------------------------------------------------------
  167. void CBubbling::InputSetDensity( inputdata_t &inputdata )
  168. {
  169. m_density = inputdata.value.Int();
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Purpose:
  173. // Input : &inputdata -
  174. //-----------------------------------------------------------------------------
  175. void CBubbling::InputSetFrequency( inputdata_t &inputdata )
  176. {
  177. m_frequency = inputdata.value.Int();
  178. // Reset think time
  179. if ( m_state )
  180. {
  181. if ( m_frequency > 19 )
  182. {
  183. SetNextThink( gpGlobals->curtime + 0.5f );
  184. }
  185. else
  186. {
  187. SetNextThink( gpGlobals->curtime + 2.5 - (0.1 * m_frequency) );
  188. }
  189. }
  190. }
  191. void CBubbling::FizzThink( void )
  192. {
  193. Vector center = WorldSpaceCenter();
  194. CPASFilter filter( center );
  195. te->Fizz( filter, 0.0, this, m_bubbleModel, m_density, (int)m_flSpeed );
  196. if ( m_frequency > 19 )
  197. {
  198. SetNextThink( gpGlobals->curtime + 0.5f );
  199. }
  200. else
  201. {
  202. SetNextThink( gpGlobals->curtime + 2.5 - (0.1 * m_frequency) );
  203. }
  204. }
  205. // ENV_TRACER
  206. // Fakes a tracer
  207. class CEnvTracer : public CPointEntity
  208. {
  209. public:
  210. DECLARE_CLASS( CEnvTracer, CPointEntity );
  211. void Spawn( void );
  212. void TracerThink( void );
  213. void Activate( void );
  214. DECLARE_DATADESC();
  215. Vector m_vecEnd;
  216. float m_flDelay;
  217. };
  218. LINK_ENTITY_TO_CLASS( env_tracer, CEnvTracer );
  219. BEGIN_DATADESC( CEnvTracer )
  220. DEFINE_KEYFIELD( m_flDelay, FIELD_FLOAT, "delay" ),
  221. DEFINE_FIELD( m_vecEnd, FIELD_POSITION_VECTOR ),
  222. // Function Pointers
  223. DEFINE_FUNCTION( TracerThink ),
  224. END_DATADESC()
  225. //-----------------------------------------------------------------------------
  226. // Purpose: Called after keyvalues are parsed.
  227. //-----------------------------------------------------------------------------
  228. void CEnvTracer::Spawn( void )
  229. {
  230. SetSolid( SOLID_NONE );
  231. SetMoveType( MOVETYPE_NONE );
  232. if (!m_flDelay)
  233. m_flDelay = 1;
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose: Called after all the entities have been loaded.
  237. //-----------------------------------------------------------------------------
  238. void CEnvTracer::Activate( void )
  239. {
  240. BaseClass::Activate();
  241. CBaseEntity *pEnd = gEntList.FindEntityByName( NULL, m_target );
  242. if (pEnd != NULL)
  243. {
  244. m_vecEnd = pEnd->GetLocalOrigin();
  245. SetThink( &CEnvTracer::TracerThink );
  246. SetNextThink( gpGlobals->curtime + m_flDelay );
  247. }
  248. else
  249. {
  250. Msg( "env_tracer: unknown entity \"%s\"\n", STRING(m_target) );
  251. }
  252. }
  253. // Think
  254. void CEnvTracer::TracerThink( void )
  255. {
  256. UTIL_Tracer( GetAbsOrigin(), m_vecEnd );
  257. SetNextThink( gpGlobals->curtime + m_flDelay );
  258. }
  259. //#################################################################################
  260. // >> CGibShooter
  261. //#################################################################################
  262. enum GibSimulation_t
  263. {
  264. GIB_SIMULATE_POINT,
  265. GIB_SIMULATE_PHYSICS,
  266. GIB_SIMULATE_RAGDOLL,
  267. };
  268. class CGibShooter : public CBaseEntity
  269. {
  270. public:
  271. DECLARE_CLASS( CGibShooter, CBaseEntity );
  272. void Spawn( void );
  273. void Precache( void );
  274. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  275. virtual CGib *CreateGib( void );
  276. protected:
  277. // Purpose:
  278. CBaseEntity *SpawnGib( const Vector &vecShootDir, float flSpeed );
  279. DECLARE_DATADESC();
  280. private:
  281. void InitPointGib( CGib *pGib, const Vector &vecShootDir, float flSpeed );
  282. void ShootThink( void );
  283. protected:
  284. int m_iGibs;
  285. int m_iGibCapacity;
  286. int m_iGibMaterial;
  287. int m_iGibModelIndex;
  288. float m_flGibVelocity;
  289. QAngle m_angGibRotation;
  290. float m_flGibAngVelocity;
  291. float m_flVariance;
  292. float m_flGibLife;
  293. int m_nSimulationType;
  294. int m_nMaxGibModelFrame;
  295. float m_flDelay;
  296. bool m_bNoGibShadows;
  297. bool m_bIsSprite;
  298. string_t m_iszLightingOrigin;
  299. // ----------------
  300. // Inputs
  301. // ----------------
  302. void InputShoot( inputdata_t &inputdata );
  303. };
  304. BEGIN_DATADESC( CGibShooter )
  305. DEFINE_KEYFIELD( m_iGibs, FIELD_INTEGER, "m_iGibs" ),
  306. DEFINE_KEYFIELD( m_flGibVelocity, FIELD_FLOAT, "m_flVelocity" ),
  307. DEFINE_KEYFIELD( m_flVariance, FIELD_FLOAT, "m_flVariance" ),
  308. DEFINE_KEYFIELD( m_flGibLife, FIELD_FLOAT, "m_flGibLife" ),
  309. DEFINE_KEYFIELD( m_nSimulationType, FIELD_INTEGER, "Simulation" ),
  310. DEFINE_KEYFIELD( m_flDelay, FIELD_FLOAT, "delay" ),
  311. DEFINE_KEYFIELD( m_angGibRotation, FIELD_VECTOR, "gibangles" ),
  312. DEFINE_KEYFIELD( m_flGibAngVelocity, FIELD_FLOAT, "gibanglevelocity"),
  313. DEFINE_FIELD( m_bIsSprite, FIELD_BOOLEAN ),
  314. DEFINE_FIELD( m_iGibCapacity, FIELD_INTEGER ),
  315. DEFINE_FIELD( m_iGibMaterial, FIELD_INTEGER ),
  316. DEFINE_FIELD( m_iGibModelIndex, FIELD_INTEGER ),
  317. DEFINE_FIELD( m_nMaxGibModelFrame, FIELD_INTEGER ),
  318. DEFINE_KEYFIELD( m_iszLightingOrigin, FIELD_STRING, "LightingOrigin" ),
  319. DEFINE_KEYFIELD( m_bNoGibShadows, FIELD_BOOLEAN, "nogibshadows" ),
  320. // Inputs
  321. DEFINE_INPUTFUNC( FIELD_VOID, "Shoot", InputShoot ),
  322. // Function Pointers
  323. DEFINE_FUNCTION( ShootThink ),
  324. END_DATADESC()
  325. LINK_ENTITY_TO_CLASS( gibshooter, CGibShooter );
  326. void CGibShooter::Precache ( void )
  327. {
  328. if ( g_Language.GetInt() == LANGUAGE_GERMAN )
  329. {
  330. m_iGibModelIndex = PrecacheModel ("models/germanygibs.mdl");
  331. }
  332. else
  333. {
  334. m_iGibModelIndex = PrecacheModel ("models/gibs/hgibs.mdl");
  335. }
  336. }
  337. void CGibShooter::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  338. {
  339. SetThink( &CGibShooter::ShootThink );
  340. SetNextThink( gpGlobals->curtime );
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Purpose: Input handler for shooting gibs.
  344. //-----------------------------------------------------------------------------
  345. void CGibShooter::InputShoot( inputdata_t &inputdata )
  346. {
  347. SetThink( &CGibShooter::ShootThink );
  348. SetNextThink( gpGlobals->curtime );
  349. }
  350. void CGibShooter::Spawn( void )
  351. {
  352. Precache();
  353. SetSolid( SOLID_NONE );
  354. AddEffects( EF_NODRAW );
  355. if ( m_flDelay < 0 )
  356. {
  357. m_flDelay = 0.0;
  358. }
  359. if ( m_flGibLife == 0 )
  360. {
  361. m_flGibLife = 25;
  362. }
  363. m_iGibCapacity = m_iGibs;
  364. m_nMaxGibModelFrame = modelinfo->GetModelFrameCount( modelinfo->GetModel( m_iGibModelIndex ) );
  365. }
  366. CGib *CGibShooter::CreateGib ( void )
  367. {
  368. ConVarRef violence_hgibs( "violence_hgibs" );
  369. if ( violence_hgibs.IsValid() && !violence_hgibs.GetInt() )
  370. return NULL;
  371. CGib *pGib = CREATE_ENTITY( CGib, "gib" );
  372. pGib->Spawn( "models/gibs/hgibs.mdl" );
  373. pGib->SetBloodColor( BLOOD_COLOR_RED );
  374. if ( m_nMaxGibModelFrame <= 1 )
  375. {
  376. DevWarning( 2, "GibShooter Body is <= 1!\n" );
  377. }
  378. pGib->m_nBody = random->RandomInt ( 1, m_nMaxGibModelFrame - 1 );// avoid throwing random amounts of the 0th gib. (skull).
  379. if ( m_iszLightingOrigin != NULL_STRING )
  380. {
  381. // Make the gibs use the lighting origin
  382. pGib->SetLightingOrigin( m_iszLightingOrigin );
  383. }
  384. return pGib;
  385. }
  386. void CGibShooter::InitPointGib( CGib *pGib, const Vector &vecShootDir, float flSpeed )
  387. {
  388. if ( pGib )
  389. {
  390. pGib->SetLocalOrigin( GetAbsOrigin() );
  391. pGib->SetAbsVelocity( vecShootDir * flSpeed );
  392. QAngle angVel( random->RandomFloat ( 100, 200 ), random->RandomFloat ( 100, 300 ), 0 );
  393. pGib->SetLocalAngularVelocity( angVel );
  394. float thinkTime = ( pGib->GetNextThink() - gpGlobals->curtime );
  395. pGib->m_lifeTime = (m_flGibLife * random->RandomFloat( 0.95, 1.05 )); // +/- 5%
  396. // HL1 gibs always die after a certain time, other games have to opt-in
  397. if( HasSpawnFlags( SF_SHOOTER_STRICT_REMOVE ) )
  398. {
  399. pGib->SetNextThink( gpGlobals->curtime + pGib->m_lifeTime );
  400. pGib->SetThink ( &CGib::DieThink );
  401. }
  402. if ( pGib->m_lifeTime < thinkTime )
  403. {
  404. pGib->SetNextThink( gpGlobals->curtime + pGib->m_lifeTime );
  405. pGib->m_lifeTime = 0;
  406. }
  407. if ( m_bIsSprite == true )
  408. {
  409. pGib->SetSprite( CSprite::SpriteCreate( STRING( GetModelName() ), pGib->GetAbsOrigin(), false ) );
  410. CSprite *pSprite = (CSprite*)pGib->GetSprite();
  411. if ( pSprite )
  412. {
  413. pSprite->SetAttachment( pGib, 0 );
  414. pSprite->SetOwnerEntity( pGib );
  415. pSprite->SetScale( 1 );
  416. pSprite->SetTransparency( m_nRenderMode, m_clrRender->r, m_clrRender->g, m_clrRender->b, m_clrRender->a, m_nRenderFX );
  417. pSprite->AnimateForTime( 5, m_flGibLife + 1 ); //This framerate is totally wrong
  418. }
  419. }
  420. }
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Purpose:
  424. //-----------------------------------------------------------------------------
  425. CBaseEntity *CGibShooter::SpawnGib( const Vector &vecShootDir, float flSpeed )
  426. {
  427. switch (m_nSimulationType)
  428. {
  429. case GIB_SIMULATE_RAGDOLL:
  430. {
  431. // UNDONE: Assume a mass of 200 for now
  432. Vector force = vecShootDir * flSpeed * 200;
  433. return CreateRagGib( STRING( GetModelName() ), GetAbsOrigin(), GetAbsAngles(), force, m_flGibLife );
  434. }
  435. case GIB_SIMULATE_PHYSICS:
  436. {
  437. CGib *pGib = CreateGib();
  438. if ( pGib )
  439. {
  440. pGib->SetAbsOrigin( GetAbsOrigin() );
  441. pGib->SetAbsAngles( m_angGibRotation );
  442. pGib->m_lifeTime = (m_flGibLife * random->RandomFloat( 0.95, 1.05 )); // +/- 5%
  443. pGib->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
  444. IPhysicsObject *pPhysicsObject = pGib->VPhysicsInitNormal( SOLID_VPHYSICS, pGib->GetSolidFlags(), false );
  445. pGib->SetMoveType( MOVETYPE_VPHYSICS );
  446. if ( pPhysicsObject )
  447. {
  448. // Set gib velocity
  449. Vector vVel = vecShootDir * flSpeed;
  450. pPhysicsObject->AddVelocity(&vVel, NULL);
  451. AngularImpulse torque;
  452. torque.x = m_flGibAngVelocity * random->RandomFloat( 0.1f, 1.0f );
  453. torque.y = m_flGibAngVelocity * random->RandomFloat( 0.1f, 1.0f );
  454. torque.z = 0.0f;
  455. torque *= pPhysicsObject->GetMass();
  456. pPhysicsObject->ApplyTorqueCenter( torque );
  457. if( HasSpawnFlags( SF_SHOOTER_STRICT_REMOVE ) )
  458. {
  459. pGib->m_bForceRemove = true;
  460. pGib->SetNextThink( gpGlobals->curtime + pGib->m_lifeTime );
  461. pGib->SetThink ( &CGib::DieThink );
  462. }
  463. }
  464. else
  465. {
  466. InitPointGib( pGib, vecShootDir, flSpeed );
  467. }
  468. }
  469. return pGib;
  470. }
  471. case GIB_SIMULATE_POINT:
  472. {
  473. CGib *pGib = CreateGib();
  474. if ( pGib )
  475. {
  476. pGib->SetAbsAngles( m_angGibRotation );
  477. InitPointGib( pGib, vecShootDir, flSpeed );
  478. return pGib;
  479. }
  480. }
  481. }
  482. return NULL;
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose:
  486. //-----------------------------------------------------------------------------
  487. void CGibShooter::ShootThink ( void )
  488. {
  489. SetNextThink( gpGlobals->curtime + m_flDelay );
  490. Vector vecShootDir, vForward,vRight,vUp;
  491. AngleVectors( GetAbsAngles(), &vForward, &vRight, &vUp );
  492. vecShootDir = vForward;
  493. vecShootDir = vecShootDir + vRight * random->RandomFloat( -1, 1) * m_flVariance;
  494. vecShootDir = vecShootDir + vForward * random->RandomFloat( -1, 1) * m_flVariance;
  495. vecShootDir = vecShootDir + vUp * random->RandomFloat( -1, 1) * m_flVariance;
  496. VectorNormalize( vecShootDir );
  497. SpawnGib( vecShootDir, m_flGibVelocity );
  498. if ( --m_iGibs <= 0 )
  499. {
  500. if ( HasSpawnFlags(SF_GIBSHOOTER_REPEATABLE) )
  501. {
  502. m_iGibs = m_iGibCapacity;
  503. SetThink ( NULL );
  504. SetNextThink( gpGlobals->curtime );
  505. }
  506. else
  507. {
  508. SetThink ( &CGibShooter::SUB_Remove );
  509. SetNextThink( gpGlobals->curtime );
  510. }
  511. }
  512. }
  513. class CEnvShooter : public CGibShooter
  514. {
  515. public:
  516. DECLARE_CLASS( CEnvShooter, CGibShooter );
  517. CEnvShooter() { m_flGibGravityScale = 1.0f; }
  518. void Precache( void );
  519. bool KeyValue( const char *szKeyName, const char *szValue );
  520. CGib *CreateGib( void );
  521. DECLARE_DATADESC();
  522. public:
  523. int m_nSkin;
  524. float m_flGibScale;
  525. float m_flGibGravityScale;
  526. #if HL2_EPISODIC
  527. float m_flMassOverride; // allow designer to force a mass for gibs in some cases
  528. #endif
  529. };
  530. BEGIN_DATADESC( CEnvShooter )
  531. DEFINE_KEYFIELD( m_nSkin, FIELD_INTEGER, "skin" ),
  532. DEFINE_KEYFIELD( m_flGibScale, FIELD_FLOAT ,"scale" ),
  533. DEFINE_KEYFIELD( m_flGibGravityScale, FIELD_FLOAT, "gibgravityscale" ),
  534. #if HL2_EPISODIC
  535. DEFINE_KEYFIELD( m_flMassOverride, FIELD_FLOAT, "massoverride" ),
  536. #endif
  537. END_DATADESC()
  538. LINK_ENTITY_TO_CLASS( env_shooter, CEnvShooter );
  539. bool CEnvShooter::KeyValue( const char *szKeyName, const char *szValue )
  540. {
  541. if (FStrEq(szKeyName, "shootmodel"))
  542. {
  543. m_bIsSprite = false;
  544. SetModelName( AllocPooledString(szValue) );
  545. //Adrian - not pretty...
  546. if ( Q_stristr( szValue, ".vmt" ) )
  547. m_bIsSprite = true;
  548. }
  549. else if (FStrEq(szKeyName, "shootsounds"))
  550. {
  551. int iNoise = atoi(szValue);
  552. switch( iNoise )
  553. {
  554. case 0:
  555. m_iGibMaterial = matGlass;
  556. break;
  557. case 1:
  558. m_iGibMaterial = matWood;
  559. break;
  560. case 2:
  561. m_iGibMaterial = matMetal;
  562. break;
  563. case 3:
  564. m_iGibMaterial = matFlesh;
  565. break;
  566. case 4:
  567. m_iGibMaterial = matRocks;
  568. break;
  569. default:
  570. case -1:
  571. m_iGibMaterial = matNone;
  572. break;
  573. }
  574. }
  575. else
  576. {
  577. return BaseClass::KeyValue( szKeyName, szValue );
  578. }
  579. return true;
  580. }
  581. void CEnvShooter::Precache ( void )
  582. {
  583. m_iGibModelIndex = PrecacheModel( STRING( GetModelName() ) );
  584. }
  585. CGib *CEnvShooter::CreateGib ( void )
  586. {
  587. CGib *pGib = CREATE_ENTITY( CGib, "gib" );
  588. if ( m_bIsSprite == true )
  589. {
  590. //HACK HACK
  591. pGib->Spawn( "" );
  592. }
  593. else
  594. {
  595. pGib->Spawn( STRING( GetModelName() ) );
  596. }
  597. int bodyPart = 0;
  598. if ( m_nMaxGibModelFrame > 1 )
  599. {
  600. bodyPart = random->RandomInt( 0, m_nMaxGibModelFrame-1 );
  601. }
  602. pGib->m_nBody = bodyPart;
  603. pGib->SetBloodColor( DONT_BLEED );
  604. pGib->m_material = m_iGibMaterial;
  605. pGib->m_nRenderMode = m_nRenderMode;
  606. pGib->m_clrRender = m_clrRender;
  607. pGib->m_nRenderFX = m_nRenderFX;
  608. pGib->m_nSkin = m_nSkin;
  609. pGib->m_lifeTime = gpGlobals->curtime + m_flGibLife;
  610. pGib->SetGravity( m_flGibGravityScale );
  611. // Spawn a flaming gib
  612. if ( HasSpawnFlags( SF_SHOOTER_FLAMING ) )
  613. {
  614. // Tag an entity flame along with us
  615. CEntityFlame *pFlame = CEntityFlame::Create( pGib, pGib->m_lifeTime );
  616. if ( pFlame != NULL )
  617. {
  618. pGib->SetFlame( pFlame );
  619. }
  620. }
  621. if ( m_iszLightingOrigin != NULL_STRING )
  622. {
  623. // Make the gibs use the lighting origin
  624. pGib->SetLightingOrigin( m_iszLightingOrigin );
  625. }
  626. if( m_bNoGibShadows )
  627. {
  628. pGib->AddEffects( EF_NOSHADOW );
  629. }
  630. #if HL2_EPISODIC
  631. // if a mass override is set, apply it to the gib
  632. if (m_flMassOverride != 0)
  633. {
  634. IPhysicsObject *pPhys = pGib->VPhysicsGetObject();
  635. if (pPhys)
  636. {
  637. pPhys->SetMass( m_flMassOverride );
  638. }
  639. }
  640. #endif
  641. return pGib;
  642. }
  643. //-----------------------------------------------------------------------------
  644. // An entity that shoots out junk when hit by a rotor wash
  645. //-----------------------------------------------------------------------------
  646. class CRotorWashShooter : public CEnvShooter, public IRotorWashShooter
  647. {
  648. public:
  649. DECLARE_CLASS( CRotorWashShooter, CEnvShooter );
  650. DECLARE_DATADESC();
  651. virtual void Spawn();
  652. public:
  653. // Inherited from IRotorWashShooter
  654. virtual CBaseEntity *DoWashPush( float flTimeSincePushStarted, const Vector &vecForce );
  655. private:
  656. // Amount of time we need to spend under the rotor before we shoot
  657. float m_flTimeUnderRotor;
  658. float m_flTimeUnderRotorVariance;
  659. // Last time we were hit with a wash...
  660. float m_flLastWashStartTime;
  661. float m_flNextGibTime;
  662. };
  663. LINK_ENTITY_TO_CLASS( env_rotorshooter, CRotorWashShooter );
  664. //-----------------------------------------------------------------------------
  665. // Save/load
  666. //-----------------------------------------------------------------------------
  667. BEGIN_DATADESC( CRotorWashShooter )
  668. DEFINE_KEYFIELD( m_flTimeUnderRotor, FIELD_FLOAT ,"rotortime" ),
  669. DEFINE_KEYFIELD( m_flTimeUnderRotorVariance, FIELD_FLOAT ,"rotortimevariance" ),
  670. DEFINE_FIELD( m_flLastWashStartTime, FIELD_TIME ),
  671. DEFINE_FIELD( m_flNextGibTime, FIELD_TIME ),
  672. END_DATADESC()
  673. //-----------------------------------------------------------------------------
  674. // Gets at the interface if the entity supports it
  675. //-----------------------------------------------------------------------------
  676. IRotorWashShooter *GetRotorWashShooter( CBaseEntity *pEntity )
  677. {
  678. CRotorWashShooter *pShooter = dynamic_cast<CRotorWashShooter*>(pEntity);
  679. return pShooter;
  680. }
  681. //-----------------------------------------------------------------------------
  682. // Inherited from IRotorWashShooter
  683. //-----------------------------------------------------------------------------
  684. void CRotorWashShooter::Spawn()
  685. {
  686. BaseClass::Spawn();
  687. m_flLastWashStartTime = -1;
  688. }
  689. //-----------------------------------------------------------------------------
  690. // Inherited from IRotorWashShooter
  691. //-----------------------------------------------------------------------------
  692. CBaseEntity *CRotorWashShooter::DoWashPush( float flWashStartTime, const Vector &vecForce )
  693. {
  694. if ( flWashStartTime == m_flLastWashStartTime )
  695. {
  696. if ( m_flNextGibTime > gpGlobals->curtime )
  697. return NULL;
  698. }
  699. m_flLastWashStartTime = flWashStartTime;
  700. m_flNextGibTime = gpGlobals->curtime + m_flTimeUnderRotor + random->RandomFloat( -1, 1) * m_flTimeUnderRotorVariance;
  701. if ( m_flNextGibTime <= gpGlobals->curtime )
  702. {
  703. m_flNextGibTime = gpGlobals->curtime + 0.01f;
  704. }
  705. // Set the velocity to be what the force would cause it to accelerate to
  706. // after one tick
  707. Vector vecShootDir = vecForce;
  708. VectorNormalize( vecShootDir );
  709. vecShootDir.x += random->RandomFloat( -1, 1 ) * m_flVariance;
  710. vecShootDir.y += random->RandomFloat( -1, 1 ) * m_flVariance;
  711. vecShootDir.z += random->RandomFloat( -1, 1 ) * m_flVariance;
  712. VectorNormalize( vecShootDir );
  713. CBaseEntity *pGib = SpawnGib( vecShootDir, m_flGibVelocity /*flLength*/ );
  714. if ( --m_iGibs <= 0 )
  715. {
  716. if ( HasSpawnFlags(SF_GIBSHOOTER_REPEATABLE) )
  717. {
  718. m_iGibs = m_iGibCapacity;
  719. }
  720. else
  721. {
  722. SetThink ( &CGibShooter::SUB_Remove );
  723. SetNextThink( gpGlobals->curtime );
  724. }
  725. }
  726. return pGib;
  727. }
  728. //-----------------------------------------------------------------------------
  729. // Purpose:
  730. //-----------------------------------------------------------------------------
  731. class CTestEffect : public CBaseEntity
  732. {
  733. public:
  734. DECLARE_CLASS( CTestEffect, CBaseEntity );
  735. void Spawn( void );
  736. void Precache( void );
  737. // bool KeyValue( const char *szKeyName, const char *szValue );
  738. void Think( void );
  739. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  740. int m_iLoop;
  741. int m_iBeam;
  742. CBeam *m_pBeam[24];
  743. float m_flBeamTime[24];
  744. float m_flStartTime;
  745. };
  746. LINK_ENTITY_TO_CLASS( test_effect, CTestEffect );
  747. void CTestEffect::Spawn( void )
  748. {
  749. Precache( );
  750. }
  751. void CTestEffect::Precache( void )
  752. {
  753. PrecacheModel( "sprites/lgtning.vmt" );
  754. }
  755. void CTestEffect::Think( void )
  756. {
  757. int i;
  758. float t = (gpGlobals->curtime - m_flStartTime);
  759. if (m_iBeam < 24)
  760. {
  761. CBeam *pbeam = CBeam::BeamCreate( "sprites/lgtning.vmt", 10 );
  762. trace_t tr;
  763. Vector vecSrc = GetAbsOrigin();
  764. Vector vecDir = Vector( random->RandomFloat( -1.0, 1.0 ), random->RandomFloat( -1.0, 1.0 ),random->RandomFloat( -1.0, 1.0 ) );
  765. VectorNormalize( vecDir );
  766. UTIL_TraceLine( vecSrc, vecSrc + vecDir * 128, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr);
  767. pbeam->PointsInit( vecSrc, tr.endpos );
  768. // pbeam->SetColor( 80, 100, 255 );
  769. pbeam->SetColor( 255, 180, 100 );
  770. pbeam->SetWidth( 10.0 );
  771. pbeam->SetScrollRate( 12 );
  772. m_flBeamTime[m_iBeam] = gpGlobals->curtime;
  773. m_pBeam[m_iBeam] = pbeam;
  774. m_iBeam++;
  775. #if 0
  776. Vector vecMid = (vecSrc + tr.endpos) * 0.5;
  777. CBroadcastRecipientFilter filter;
  778. TE_DynamicLight( filter, 0.0,
  779. vecMid, 255, 180, 100, 3, 2.0, 0.0 );
  780. #endif
  781. }
  782. if (t < 3.0)
  783. {
  784. for (i = 0; i < m_iBeam; i++)
  785. {
  786. t = (gpGlobals->curtime - m_flBeamTime[i]) / ( 3 + m_flStartTime - m_flBeamTime[i]);
  787. m_pBeam[i]->SetBrightness( 255 * t );
  788. // m_pBeam[i]->SetScrollRate( 20 * t );
  789. }
  790. SetNextThink( gpGlobals->curtime + 0.1f );
  791. }
  792. else
  793. {
  794. for (i = 0; i < m_iBeam; i++)
  795. {
  796. UTIL_Remove( m_pBeam[i] );
  797. }
  798. m_flStartTime = gpGlobals->curtime;
  799. m_iBeam = 0;
  800. SetNextThink( TICK_NEVER_THINK );
  801. }
  802. }
  803. void CTestEffect::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  804. {
  805. SetNextThink( gpGlobals->curtime + 0.1f );
  806. m_flStartTime = gpGlobals->curtime;
  807. }
  808. // Blood effects
  809. class CBlood : public CPointEntity
  810. {
  811. public:
  812. DECLARE_CLASS( CBlood, CPointEntity );
  813. void Precache();
  814. void Spawn( void );
  815. bool KeyValue( const char *szKeyName, const char *szValue );
  816. inline int Color( void ) { return m_Color; }
  817. inline float BloodAmount( void ) { return m_flAmount; }
  818. inline void SetColor( int color ) { m_Color = color; }
  819. // Input handlers
  820. void InputEmitBlood( inputdata_t &inputdata );
  821. Vector Direction( void );
  822. Vector BloodPosition( CBaseEntity *pActivator );
  823. DECLARE_DATADESC();
  824. Vector m_vecSprayDir;
  825. float m_flAmount;
  826. int m_Color;
  827. private:
  828. };
  829. LINK_ENTITY_TO_CLASS( env_blood, CBlood );
  830. BEGIN_DATADESC( CBlood )
  831. DEFINE_KEYFIELD( m_vecSprayDir, FIELD_VECTOR, "spraydir" ),
  832. DEFINE_KEYFIELD( m_flAmount, FIELD_FLOAT, "amount" ),
  833. DEFINE_FIELD( m_Color, FIELD_INTEGER ),
  834. DEFINE_INPUTFUNC( FIELD_VOID, "EmitBlood", InputEmitBlood ),
  835. END_DATADESC()
  836. #define SF_BLOOD_RANDOM 0x0001
  837. #define SF_BLOOD_STREAM 0x0002
  838. #define SF_BLOOD_PLAYER 0x0004
  839. #define SF_BLOOD_DECAL 0x0008
  840. #define SF_BLOOD_CLOUD 0x0010
  841. #define SF_BLOOD_DROPS 0x0020
  842. #define SF_BLOOD_GORE 0x0040
  843. //-----------------------------------------------------------------------------
  844. // Precache
  845. //-----------------------------------------------------------------------------
  846. void CBlood::Precache()
  847. {
  848. BaseClass::Precache();
  849. UTIL_BloodSprayPrecache();
  850. }
  851. //-----------------------------------------------------------------------------
  852. // Purpose:
  853. //-----------------------------------------------------------------------------
  854. void CBlood::Spawn( void )
  855. {
  856. Precache();
  857. // Convert spraydir from angles to a vector
  858. QAngle angSprayDir = QAngle( m_vecSprayDir.x, m_vecSprayDir.y, m_vecSprayDir.z );
  859. AngleVectors( angSprayDir, &m_vecSprayDir );
  860. SetSolid( SOLID_NONE );
  861. SetMoveType( MOVETYPE_NONE );
  862. SetColor( BLOOD_COLOR_RED );
  863. }
  864. //-----------------------------------------------------------------------------
  865. // Purpose:
  866. // Input : szKeyName -
  867. // szValue -
  868. // Output : Returns true on success, false on failure.
  869. //-----------------------------------------------------------------------------
  870. bool CBlood::KeyValue( const char *szKeyName, const char *szValue )
  871. {
  872. if (FStrEq(szKeyName, "color"))
  873. {
  874. int color = atoi(szValue);
  875. switch ( color )
  876. {
  877. case 1:
  878. {
  879. SetColor( BLOOD_COLOR_YELLOW );
  880. break;
  881. }
  882. }
  883. }
  884. else
  885. {
  886. return BaseClass::KeyValue( szKeyName, szValue );
  887. }
  888. return true;
  889. }
  890. Vector CBlood::Direction( void )
  891. {
  892. if ( HasSpawnFlags( SF_BLOOD_RANDOM ) )
  893. return UTIL_RandomBloodVector();
  894. return m_vecSprayDir;
  895. }
  896. Vector CBlood::BloodPosition( CBaseEntity *pActivator )
  897. {
  898. if ( HasSpawnFlags( SF_BLOOD_PLAYER ) )
  899. {
  900. CBasePlayer *player;
  901. if ( pActivator && pActivator->IsPlayer() )
  902. {
  903. player = ToBasePlayer( pActivator );
  904. }
  905. else
  906. {
  907. player = UTIL_GetLocalPlayer();
  908. }
  909. if ( player )
  910. {
  911. return (player->EyePosition()) + Vector( random->RandomFloat(-10,10), random->RandomFloat(-10,10), random->RandomFloat(-10,10) );
  912. }
  913. }
  914. return GetLocalOrigin();
  915. }
  916. //-----------------------------------------------------------------------------
  917. // Purpose:
  918. //-----------------------------------------------------------------------------
  919. void UTIL_BloodSprayPrecache()
  920. {
  921. PrecacheEffect( "bloodspray" );
  922. }
  923. void UTIL_BloodSpray( const Vector &pos, const Vector &dir, int color, int amount, int flags )
  924. {
  925. if( color == DONT_BLEED )
  926. return;
  927. CEffectData data;
  928. data.m_vOrigin = pos;
  929. data.m_vNormal = dir;
  930. data.m_flScale = (float)amount;
  931. data.m_fFlags = flags;
  932. data.m_nColor = color;
  933. DispatchEffect( "bloodspray", data );
  934. }
  935. //-----------------------------------------------------------------------------
  936. // Purpose: Input handler for triggering the blood effect.
  937. //-----------------------------------------------------------------------------
  938. void CBlood::InputEmitBlood( inputdata_t &inputdata )
  939. {
  940. if ( HasSpawnFlags( SF_BLOOD_STREAM ) )
  941. {
  942. UTIL_BloodStream( BloodPosition(inputdata.pActivator), Direction(), Color(), BloodAmount() );
  943. }
  944. else
  945. {
  946. UTIL_BloodDrips( BloodPosition(inputdata.pActivator), Direction(), Color(), BloodAmount() );
  947. }
  948. if ( HasSpawnFlags( SF_BLOOD_DECAL ) )
  949. {
  950. Vector forward = Direction();
  951. Vector start = BloodPosition( inputdata.pActivator );
  952. trace_t tr;
  953. UTIL_TraceLine( start, start + forward * BloodAmount() * 2, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &tr );
  954. if ( tr.fraction != 1.0 )
  955. {
  956. UTIL_BloodDecalTrace( &tr, Color() );
  957. }
  958. }
  959. //
  960. // New-fangled blood effects.
  961. //
  962. if ( HasSpawnFlags( SF_BLOOD_CLOUD | SF_BLOOD_DROPS | SF_BLOOD_GORE ) )
  963. {
  964. int nFlags = 0;
  965. if (HasSpawnFlags(SF_BLOOD_CLOUD))
  966. {
  967. nFlags |= FX_BLOODSPRAY_CLOUD;
  968. }
  969. if (HasSpawnFlags(SF_BLOOD_DROPS))
  970. {
  971. nFlags |= FX_BLOODSPRAY_DROPS;
  972. }
  973. if (HasSpawnFlags(SF_BLOOD_GORE))
  974. {
  975. nFlags |= FX_BLOODSPRAY_GORE;
  976. }
  977. UTIL_BloodSpray(GetAbsOrigin(), Direction(), Color(), BloodAmount(), nFlags);
  978. }
  979. }
  980. //-----------------------------------------------------------------------------
  981. //
  982. //-----------------------------------------------------------------------------
  983. class CEnvFunnel : public CBaseEntity
  984. {
  985. DECLARE_DATADESC();
  986. public:
  987. DECLARE_CLASS( CEnvFunnel, CBaseEntity );
  988. void Spawn( void );
  989. void Precache( void );
  990. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  991. int m_iSprite; // Don't save, precache
  992. };
  993. LINK_ENTITY_TO_CLASS( env_funnel, CEnvFunnel );
  994. //---------------------------------------------------------
  995. // Save/Restore
  996. //---------------------------------------------------------
  997. BEGIN_DATADESC( CEnvFunnel )
  998. // DEFINE_FIELD( m_iSprite, FIELD_INTEGER ),
  999. END_DATADESC()
  1000. void CEnvFunnel::Precache ( void )
  1001. {
  1002. m_iSprite = PrecacheModel ( "sprites/flare6.vmt" );
  1003. }
  1004. void CEnvFunnel::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  1005. {
  1006. CBroadcastRecipientFilter filter;
  1007. te->LargeFunnel( filter, 0.0,
  1008. &GetAbsOrigin(), m_iSprite, HasSpawnFlags( SF_FUNNEL_REVERSE ) ? 1 : 0 );
  1009. SetThink( &CEnvFunnel::SUB_Remove );
  1010. SetNextThink( gpGlobals->curtime );
  1011. }
  1012. void CEnvFunnel::Spawn( void )
  1013. {
  1014. Precache();
  1015. SetSolid( SOLID_NONE );
  1016. AddEffects( EF_NODRAW );
  1017. }
  1018. //=========================================================
  1019. // Beverage Dispenser
  1020. // overloaded m_iHealth, is now how many cans remain in the machine.
  1021. //=========================================================
  1022. class CEnvBeverage : public CBaseEntity
  1023. {
  1024. public:
  1025. DECLARE_CLASS( CEnvBeverage, CBaseEntity );
  1026. void Spawn( void );
  1027. void Precache( void );
  1028. void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  1029. bool KeyValue( const char *szKeyName, const char *szValue );
  1030. // Input handlers.
  1031. void InputActivate( inputdata_t &inputdata );
  1032. DECLARE_DATADESC();
  1033. public:
  1034. bool m_CanInDispenser;
  1035. int m_nBeverageType;
  1036. };
  1037. void CEnvBeverage::Precache ( void )
  1038. {
  1039. PrecacheModel( "models/can.mdl" );
  1040. }
  1041. BEGIN_DATADESC( CEnvBeverage )
  1042. DEFINE_FIELD( m_CanInDispenser, FIELD_BOOLEAN ),
  1043. DEFINE_FIELD( m_nBeverageType, FIELD_INTEGER ),
  1044. DEFINE_INPUTFUNC( FIELD_VOID, "Activate", InputActivate ),
  1045. END_DATADESC()
  1046. LINK_ENTITY_TO_CLASS( env_beverage, CEnvBeverage );
  1047. bool CEnvBeverage::KeyValue( const char *szKeyName, const char *szValue )
  1048. {
  1049. if (FStrEq(szKeyName, "beveragetype"))
  1050. {
  1051. m_nBeverageType = atoi(szValue);
  1052. }
  1053. else
  1054. {
  1055. return BaseClass::KeyValue( szKeyName, szValue );
  1056. }
  1057. return true;
  1058. }
  1059. void CEnvBeverage::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  1060. {
  1061. if ( m_CanInDispenser || m_iHealth <= 0 )
  1062. {
  1063. // no more cans while one is waiting in the dispenser, or if I'm out of cans.
  1064. return;
  1065. }
  1066. CBaseAnimating *pCan = (CBaseAnimating *)CBaseEntity::Create( "item_sodacan", GetLocalOrigin(), GetLocalAngles(), this );
  1067. if ( m_nBeverageType == 6 )
  1068. {
  1069. // random
  1070. pCan->m_nSkin = random->RandomInt( 0, 5 );
  1071. }
  1072. else
  1073. {
  1074. pCan->m_nSkin = m_nBeverageType;
  1075. }
  1076. m_CanInDispenser = true;
  1077. m_iHealth -= 1;
  1078. //SetThink (SUB_Remove);
  1079. //SetNextThink( gpGlobals->curtime );
  1080. }
  1081. void CEnvBeverage::InputActivate( inputdata_t &inputdata )
  1082. {
  1083. Use( inputdata.pActivator, inputdata.pCaller, USE_ON, 0 );
  1084. }
  1085. void CEnvBeverage::Spawn( void )
  1086. {
  1087. Precache();
  1088. SetSolid( SOLID_NONE );
  1089. AddEffects( EF_NODRAW );
  1090. m_CanInDispenser = false;
  1091. if ( m_iHealth == 0 )
  1092. {
  1093. m_iHealth = 10;
  1094. }
  1095. }
  1096. //=========================================================
  1097. // Soda can
  1098. //=========================================================
  1099. class CItemSoda : public CBaseAnimating
  1100. {
  1101. public:
  1102. DECLARE_CLASS( CItemSoda, CBaseAnimating );
  1103. void Spawn( void );
  1104. void Precache( void );
  1105. void CanThink ( void );
  1106. void CanTouch ( CBaseEntity *pOther );
  1107. DECLARE_DATADESC();
  1108. };
  1109. BEGIN_DATADESC( CItemSoda )
  1110. // Function Pointers
  1111. DEFINE_FUNCTION( CanThink ),
  1112. DEFINE_FUNCTION( CanTouch ),
  1113. END_DATADESC()
  1114. LINK_ENTITY_TO_CLASS( item_sodacan, CItemSoda );
  1115. void CItemSoda::Precache ( void )
  1116. {
  1117. PrecacheModel( "models/can.mdl" );
  1118. PrecacheScriptSound( "ItemSoda.Bounce" );
  1119. }
  1120. void CItemSoda::Spawn( void )
  1121. {
  1122. Precache();
  1123. SetSolid( SOLID_NONE );
  1124. SetMoveType( MOVETYPE_FLYGRAVITY );
  1125. SetModel ( "models/can.mdl" );
  1126. UTIL_SetSize ( this, Vector ( 0, 0, 0 ), Vector ( 0, 0, 0 ) );
  1127. SetThink (&CItemSoda::CanThink);
  1128. SetNextThink( gpGlobals->curtime + 0.5f );
  1129. }
  1130. void CItemSoda::CanThink ( void )
  1131. {
  1132. EmitSound( "ItemSoda.Bounce" );
  1133. SetSolid( SOLID_BBOX );
  1134. AddSolidFlags( FSOLID_TRIGGER );
  1135. UTIL_SetSize ( this, Vector ( -8, -8, 0 ), Vector ( 8, 8, 8 ) );
  1136. SetThink ( NULL );
  1137. SetTouch ( &CItemSoda::CanTouch );
  1138. }
  1139. void CItemSoda::CanTouch ( CBaseEntity *pOther )
  1140. {
  1141. if ( !pOther->IsPlayer() )
  1142. {
  1143. return;
  1144. }
  1145. // spoit sound here
  1146. pOther->TakeHealth( 1, DMG_GENERIC );// a bit of health.
  1147. if ( GetOwnerEntity() )
  1148. {
  1149. // tell the machine the can was taken
  1150. CEnvBeverage *bev = (CEnvBeverage *)GetOwnerEntity();
  1151. bev->m_CanInDispenser = false;
  1152. }
  1153. AddSolidFlags( FSOLID_NOT_SOLID );
  1154. SetMoveType( MOVETYPE_NONE );
  1155. AddEffects( EF_NODRAW );
  1156. SetTouch ( NULL );
  1157. SetThink ( &CItemSoda::SUB_Remove );
  1158. SetNextThink( gpGlobals->curtime );
  1159. }
  1160. //=========================================================
  1161. // func_precipitation - temporary snow solution for first HL2
  1162. // technology demo
  1163. //=========================================================
  1164. class CPrecipitation : public CBaseEntity
  1165. {
  1166. public:
  1167. DECLARE_CLASS( CPrecipitation, CBaseEntity );
  1168. DECLARE_DATADESC();
  1169. DECLARE_SERVERCLASS();
  1170. CPrecipitation();
  1171. int UpdateTransmitState();
  1172. void Spawn( void );
  1173. CNetworkVar( PrecipitationType_t, m_nPrecipType );
  1174. #ifdef INFESTED_DLL
  1175. CNetworkVar( int, m_nSnowDustAmount );
  1176. #endif
  1177. };
  1178. LINK_ENTITY_TO_CLASS( func_precipitation, CPrecipitation );
  1179. BEGIN_DATADESC( CPrecipitation )
  1180. DEFINE_KEYFIELD( m_nPrecipType, FIELD_INTEGER, "preciptype" ),
  1181. #ifdef INFESTED_DLL
  1182. DEFINE_KEYFIELD( m_nSnowDustAmount, FIELD_INTEGER, "snowDustAmt" ),
  1183. #endif
  1184. END_DATADESC()
  1185. // Just send the normal entity crap
  1186. IMPLEMENT_SERVERCLASS_ST( CPrecipitation, DT_Precipitation)
  1187. SendPropInt( SENDINFO( m_nPrecipType ), Q_log2( NUM_PRECIPITATION_TYPES ) + 1, SPROP_UNSIGNED ),
  1188. #ifdef INFESTED_DLL
  1189. SendPropInt( SENDINFO( m_nSnowDustAmount ) ),
  1190. #endif
  1191. END_SEND_TABLE()
  1192. CPrecipitation::CPrecipitation()
  1193. {
  1194. m_nPrecipType = PRECIPITATION_TYPE_RAIN; // default to rain.
  1195. #ifdef INFESTED_DLL
  1196. m_nSnowDustAmount = 0;
  1197. #endif
  1198. }
  1199. int CPrecipitation::UpdateTransmitState()
  1200. {
  1201. return SetTransmitState( FL_EDICT_ALWAYS );
  1202. }
  1203. void CPrecipitation::Spawn( void )
  1204. {
  1205. //SetTransmitState( FL_EDICT_ALWAYS );
  1206. SetTransmitState( FL_EDICT_PVSCHECK );
  1207. PrecacheMaterial( "effects/fleck_ash1" );
  1208. PrecacheMaterial( "effects/fleck_ash2" );
  1209. PrecacheMaterial( "effects/fleck_ash3" );
  1210. PrecacheMaterial( "effects/ember_swirling001" );
  1211. Precache();
  1212. SetMoveType( MOVETYPE_NONE );
  1213. SetModel( STRING( GetModelName() ) ); // Set size
  1214. if ( m_nPrecipType == PRECIPITATION_TYPE_PARTICLERAIN )
  1215. {
  1216. SetSolid( SOLID_VPHYSICS );
  1217. AddSolidFlags( FSOLID_NOT_SOLID );
  1218. AddSolidFlags( FSOLID_FORCE_WORLD_ALIGNED );
  1219. VPhysicsInitStatic();
  1220. }
  1221. else
  1222. {
  1223. SetSolid( SOLID_NONE ); // Remove model & collisions
  1224. }
  1225. // Default to rain.
  1226. if ( m_nPrecipType < 0 || m_nPrecipType > NUM_PRECIPITATION_TYPES )
  1227. m_nPrecipType = PRECIPITATION_TYPE_RAIN;
  1228. m_nRenderMode = kRenderEnvironmental;
  1229. }
  1230. //=========================================================
  1231. // func_precipitation_blocker - prevents precipitation from happening in this volume
  1232. //=========================================================
  1233. class CPrecipitationBlocker : public CBaseEntity
  1234. {
  1235. public:
  1236. DECLARE_CLASS( CPrecipitationBlocker, CBaseEntity );
  1237. DECLARE_DATADESC();
  1238. DECLARE_SERVERCLASS();
  1239. CPrecipitationBlocker();
  1240. void Spawn( void );
  1241. int UpdateTransmitState( void );
  1242. };
  1243. LINK_ENTITY_TO_CLASS( func_precipitation_blocker, CPrecipitationBlocker );
  1244. BEGIN_DATADESC( CPrecipitationBlocker )
  1245. END_DATADESC()
  1246. // Just send the normal entity crap
  1247. IMPLEMENT_SERVERCLASS_ST( CPrecipitationBlocker, DT_PrecipitationBlocker )
  1248. END_SEND_TABLE()
  1249. CPrecipitationBlocker::CPrecipitationBlocker()
  1250. {
  1251. }
  1252. int CPrecipitationBlocker::UpdateTransmitState()
  1253. {
  1254. return SetTransmitState( FL_EDICT_ALWAYS );
  1255. }
  1256. void CPrecipitationBlocker::Spawn( void )
  1257. {
  1258. SetTransmitState( FL_EDICT_ALWAYS );
  1259. Precache();
  1260. SetSolid( SOLID_NONE ); // Remove model & collisions
  1261. SetMoveType( MOVETYPE_NONE );
  1262. SetModel( STRING( GetModelName() ) ); // Set size
  1263. m_nRenderMode = kRenderEnvironmental;
  1264. }
  1265. //--------------------------------------------------------------------------------------------------------
  1266. class CDetailBlocker : public CServerOnlyEntity
  1267. {
  1268. DECLARE_CLASS( CDetailBlocker, CServerOnlyEntity );
  1269. public:
  1270. CDetailBlocker() : CServerOnlyEntity() {}
  1271. virtual ~CDetailBlocker() {}
  1272. };
  1273. LINK_ENTITY_TO_CLASS( func_detail_blocker, CDetailBlocker );
  1274. //-----------------------------------------------------------------------------
  1275. // EnvWind - global wind info
  1276. //-----------------------------------------------------------------------------
  1277. class CEnvWind : public CBaseEntity
  1278. {
  1279. public:
  1280. DECLARE_CLASS( CEnvWind, CBaseEntity );
  1281. void Spawn( void );
  1282. void Precache( void );
  1283. void WindThink( void );
  1284. int UpdateTransmitState( void );
  1285. DECLARE_DATADESC();
  1286. DECLARE_SERVERCLASS();
  1287. private:
  1288. #ifdef GNUC
  1289. CEnvWindShared m_EnvWindShared; // FIXME - fails to compile as networked var due to operator= problem
  1290. #else
  1291. CNetworkVarEmbedded( CEnvWindShared, m_EnvWindShared );
  1292. #endif
  1293. };
  1294. LINK_ENTITY_TO_CLASS( env_wind, CEnvWind );
  1295. BEGIN_DATADESC( CEnvWind )
  1296. DEFINE_KEYFIELD( m_EnvWindShared.m_iMinWind, FIELD_INTEGER, "minwind" ),
  1297. DEFINE_KEYFIELD( m_EnvWindShared.m_iMaxWind, FIELD_INTEGER, "maxwind" ),
  1298. DEFINE_KEYFIELD( m_EnvWindShared.m_iMinGust, FIELD_INTEGER, "mingust" ),
  1299. DEFINE_KEYFIELD( m_EnvWindShared.m_iMaxGust, FIELD_INTEGER, "maxgust" ),
  1300. DEFINE_KEYFIELD( m_EnvWindShared.m_flMinGustDelay, FIELD_FLOAT, "mingustdelay" ),
  1301. DEFINE_KEYFIELD( m_EnvWindShared.m_flMaxGustDelay, FIELD_FLOAT, "maxgustdelay" ),
  1302. DEFINE_KEYFIELD( m_EnvWindShared.m_iGustDirChange, FIELD_INTEGER, "gustdirchange" ),
  1303. DEFINE_KEYFIELD( m_EnvWindShared.m_flGustDuration, FIELD_FLOAT, "gustduration" ),
  1304. // DEFINE_KEYFIELD( m_EnvWindShared.m_iszGustSound, FIELD_STRING, "gustsound" ),
  1305. // Just here to quiet down classcheck
  1306. // DEFINE_FIELD( m_EnvWindShared, CEnvWindShared ),
  1307. DEFINE_FIELD( m_EnvWindShared.m_iWindDir, FIELD_INTEGER ),
  1308. DEFINE_FIELD( m_EnvWindShared.m_flWindSpeed, FIELD_FLOAT ),
  1309. DEFINE_OUTPUT( m_EnvWindShared.m_OnGustStart, "OnGustStart" ),
  1310. DEFINE_OUTPUT( m_EnvWindShared.m_OnGustEnd, "OnGustEnd" ),
  1311. // Function Pointers
  1312. DEFINE_FUNCTION( WindThink ),
  1313. END_DATADESC()
  1314. BEGIN_SEND_TABLE_NOBASE(CEnvWindShared, DT_EnvWindShared)
  1315. // These are parameters that are used to generate the entire motion
  1316. SendPropInt (SENDINFO(m_iMinWind), 10, SPROP_UNSIGNED ),
  1317. SendPropInt (SENDINFO(m_iMaxWind), 10, SPROP_UNSIGNED ),
  1318. SendPropInt (SENDINFO(m_iMinGust), 10, SPROP_UNSIGNED ),
  1319. SendPropInt (SENDINFO(m_iMaxGust), 10, SPROP_UNSIGNED ),
  1320. SendPropFloat (SENDINFO(m_flMinGustDelay), 0, SPROP_NOSCALE), // NOTE: Have to do this, so it's *exactly* the same on client
  1321. SendPropFloat (SENDINFO(m_flMaxGustDelay), 0, SPROP_NOSCALE),
  1322. SendPropInt (SENDINFO(m_iGustDirChange), 9, SPROP_UNSIGNED ),
  1323. SendPropInt (SENDINFO(m_iWindSeed), 32, SPROP_UNSIGNED ),
  1324. // These are related to initial state
  1325. SendPropInt (SENDINFO(m_iInitialWindDir),9, SPROP_UNSIGNED ),
  1326. SendPropFloat (SENDINFO(m_flInitialWindSpeed),0, SPROP_NOSCALE ),
  1327. SendPropFloat (SENDINFO(m_flStartTime), 0, SPROP_NOSCALE ),
  1328. SendPropFloat (SENDINFO(m_flGustDuration), 0, SPROP_NOSCALE),
  1329. // Sound related
  1330. // SendPropInt (SENDINFO(m_iszGustSound), 10, SPROP_UNSIGNED ),
  1331. END_SEND_TABLE()
  1332. // This table encodes the CBaseEntity data.
  1333. IMPLEMENT_SERVERCLASS_ST_NOBASE(CEnvWind, DT_EnvWind)
  1334. SendPropDataTable(SENDINFO_DT(m_EnvWindShared), &REFERENCE_SEND_TABLE(DT_EnvWindShared)),
  1335. END_SEND_TABLE()
  1336. void CEnvWind::Precache ( void )
  1337. {
  1338. // if (m_iszGustSound)
  1339. // {
  1340. // PrecacheScriptSound( STRING( m_iszGustSound ) );
  1341. // }
  1342. }
  1343. void CEnvWind::Spawn( void )
  1344. {
  1345. Precache();
  1346. SetSolid( SOLID_NONE );
  1347. AddEffects( EF_NODRAW );
  1348. m_EnvWindShared.m_iInitialWindDir = (int)( anglemod( m_EnvWindShared.m_iInitialWindDir ) );
  1349. m_EnvWindShared.Init( entindex(), 0, gpGlobals->curtime, GetLocalAngles().y, 0 );
  1350. SetThink( &CEnvWind::WindThink );
  1351. SetNextThink( gpGlobals->curtime );
  1352. }
  1353. int CEnvWind::UpdateTransmitState()
  1354. {
  1355. return SetTransmitState( FL_EDICT_ALWAYS );
  1356. }
  1357. void CEnvWind::WindThink( void )
  1358. {
  1359. SetNextThink( m_EnvWindShared.WindThink( gpGlobals->curtime ) );
  1360. }
  1361. //==================================================
  1362. // CEmbers
  1363. //==================================================
  1364. #define bitsSF_EMBERS_START_ON 0x00000001
  1365. #define bitsSF_EMBERS_TOGGLE 0x00000002
  1366. // UNDONE: This is a brush effect-in-volume entity, move client side.
  1367. class CEmbers : public CBaseEntity
  1368. {
  1369. public:
  1370. DECLARE_CLASS( CEmbers, CBaseEntity );
  1371. void Spawn( void );
  1372. void Precache( void );
  1373. void EmberUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
  1374. CNetworkVar( int, m_nDensity );
  1375. CNetworkVar( int, m_nLifetime );
  1376. CNetworkVar( int, m_nSpeed );
  1377. CNetworkVar( bool, m_bEmit );
  1378. DECLARE_DATADESC();
  1379. DECLARE_SERVERCLASS();
  1380. };
  1381. LINK_ENTITY_TO_CLASS( env_embers, CEmbers );
  1382. //Data description
  1383. BEGIN_DATADESC( CEmbers )
  1384. DEFINE_KEYFIELD( m_nDensity, FIELD_INTEGER, "density" ),
  1385. DEFINE_KEYFIELD( m_nLifetime, FIELD_INTEGER, "lifetime" ),
  1386. DEFINE_KEYFIELD( m_nSpeed, FIELD_INTEGER, "speed" ),
  1387. DEFINE_FIELD( m_bEmit, FIELD_BOOLEAN ),
  1388. //Function pointers
  1389. DEFINE_FUNCTION( EmberUse ),
  1390. END_DATADESC()
  1391. //Data table
  1392. IMPLEMENT_SERVERCLASS_ST( CEmbers, DT_Embers )
  1393. SendPropInt( SENDINFO( m_nDensity ), 32, SPROP_UNSIGNED ),
  1394. SendPropInt( SENDINFO( m_nLifetime ), 32, SPROP_UNSIGNED ),
  1395. SendPropInt( SENDINFO( m_nSpeed ), 32, SPROP_UNSIGNED ),
  1396. SendPropInt( SENDINFO( m_bEmit ), 2, SPROP_UNSIGNED ),
  1397. END_SEND_TABLE()
  1398. //-----------------------------------------------------------------------------
  1399. // Purpose:
  1400. //-----------------------------------------------------------------------------
  1401. void CEmbers::Spawn( void )
  1402. {
  1403. Precache();
  1404. SetModel( STRING( GetModelName() ) );
  1405. SetSolid( SOLID_NONE );
  1406. SetRenderAlpha( 0 );
  1407. m_nRenderMode = kRenderTransTexture;
  1408. SetUse( &CEmbers::EmberUse );
  1409. //Start off if we're targetted (unless flagged)
  1410. m_bEmit = ( HasSpawnFlags( bitsSF_EMBERS_START_ON ) || ( !GetEntityName() ) );
  1411. }
  1412. //-----------------------------------------------------------------------------
  1413. // Purpose:
  1414. //-----------------------------------------------------------------------------
  1415. void CEmbers::Precache( void )
  1416. {
  1417. }
  1418. //-----------------------------------------------------------------------------
  1419. // Purpose:
  1420. // Input : *pActivator -
  1421. // *pCaller -
  1422. // useType -
  1423. // value -
  1424. //-----------------------------------------------------------------------------
  1425. void CEmbers::EmberUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  1426. {
  1427. //If we're not toggable, only allow one use
  1428. if ( !HasSpawnFlags( bitsSF_EMBERS_TOGGLE ) )
  1429. {
  1430. SetUse( NULL );
  1431. }
  1432. //Handle it
  1433. switch ( useType )
  1434. {
  1435. case USE_OFF:
  1436. m_bEmit = false;
  1437. break;
  1438. case USE_ON:
  1439. m_bEmit = true;
  1440. break;
  1441. case USE_SET:
  1442. m_bEmit = !!(int)value;
  1443. break;
  1444. default:
  1445. case USE_TOGGLE:
  1446. m_bEmit = !m_bEmit;
  1447. break;
  1448. }
  1449. }
  1450. //-----------------------------------------------------------------------------
  1451. // Purpose:
  1452. //-----------------------------------------------------------------------------
  1453. class CPhysicsWire : public CBaseEntity
  1454. {
  1455. public:
  1456. DECLARE_CLASS( CPhysicsWire, CBaseEntity );
  1457. void Spawn( void );
  1458. void Precache( void );
  1459. DECLARE_DATADESC();
  1460. protected:
  1461. bool SetupPhysics( void );
  1462. int m_nDensity;
  1463. };
  1464. LINK_ENTITY_TO_CLASS( env_physwire, CPhysicsWire );
  1465. BEGIN_DATADESC( CPhysicsWire )
  1466. DEFINE_KEYFIELD( m_nDensity, FIELD_INTEGER, "Density" ),
  1467. // DEFINE_KEYFIELD( m_frequency, FIELD_INTEGER, "frequency" ),
  1468. // DEFINE_FIELD( m_flFoo, FIELD_FLOAT ),
  1469. // Function Pointers
  1470. // DEFINE_FUNCTION( WireThink ),
  1471. END_DATADESC()
  1472. //-----------------------------------------------------------------------------
  1473. // Purpose:
  1474. //-----------------------------------------------------------------------------
  1475. void CPhysicsWire::Spawn( void )
  1476. {
  1477. BaseClass::Spawn();
  1478. Precache();
  1479. // if ( SetupPhysics() == false )
  1480. // return;
  1481. }
  1482. //-----------------------------------------------------------------------------
  1483. // Purpose:
  1484. //-----------------------------------------------------------------------------
  1485. void CPhysicsWire::Precache( void )
  1486. {
  1487. BaseClass::Precache();
  1488. }
  1489. class CPhysBallSocket;
  1490. //-----------------------------------------------------------------------------
  1491. // Purpose:
  1492. //-----------------------------------------------------------------------------
  1493. bool CPhysicsWire::SetupPhysics( void )
  1494. {
  1495. /*
  1496. CPointEntity *anchorEnt, *freeEnt;
  1497. CPhysBallSocket *socket;
  1498. char anchorName[256];
  1499. char freeName[256];
  1500. int iAnchorName, iFreeName;
  1501. anchorEnt = (CPointEntity *) CreateEntityByName( "info_target" );
  1502. if ( anchorEnt == NULL )
  1503. return false;
  1504. //Create and connect all segments
  1505. for ( int i = 0; i < m_nDensity; i++ )
  1506. {
  1507. // Create other end of our link
  1508. freeEnt = (CPointEntity *) CreateEntityByName( "info_target" );
  1509. // Create a ballsocket and attach the two
  1510. //socket = (CPhysBallSocket *) CreateEntityByName( "phys_ballsocket" );
  1511. Q_snprintf( anchorName,sizeof(anchorName), "__PWIREANCHOR%d", i );
  1512. Q_snprintf( freeName,sizeof(freeName), "__PWIREFREE%d", i+1 );
  1513. iAnchorName = MAKE_STRING( anchorName );
  1514. iFreeName = MAKE_STRING( freeName );
  1515. //Fake the names
  1516. //socket->m_nameAttach1 = anchorEnt->m_iGlobalname = iAnchorName;
  1517. //socket->m_nameAttach2 = freeEnt->m_iGlobalname = iFreeName
  1518. //socket->Activate();
  1519. //The free ent is now the anchor for the next link
  1520. anchorEnt = freeEnt;
  1521. }
  1522. */
  1523. return true;
  1524. }
  1525. //
  1526. // Muzzle flash
  1527. //
  1528. class CEnvMuzzleFlash : public CPointEntity
  1529. {
  1530. DECLARE_CLASS( CEnvMuzzleFlash, CPointEntity );
  1531. public:
  1532. virtual void Spawn();
  1533. // Input handlers
  1534. void InputFire( inputdata_t &inputdata );
  1535. DECLARE_DATADESC();
  1536. float m_flScale;
  1537. string_t m_iszParentAttachment;
  1538. };
  1539. BEGIN_DATADESC( CEnvMuzzleFlash )
  1540. DEFINE_KEYFIELD( m_flScale, FIELD_FLOAT, "scale" ),
  1541. DEFINE_KEYFIELD( m_iszParentAttachment, FIELD_STRING, "parentattachment" ),
  1542. DEFINE_INPUTFUNC( FIELD_VOID, "Fire", InputFire ),
  1543. END_DATADESC()
  1544. LINK_ENTITY_TO_CLASS( env_muzzleflash, CEnvMuzzleFlash );
  1545. //-----------------------------------------------------------------------------
  1546. // Spawn!
  1547. //-----------------------------------------------------------------------------
  1548. void CEnvMuzzleFlash::Spawn()
  1549. {
  1550. if ( (m_iszParentAttachment != NULL_STRING) && GetParent() && GetParent()->GetBaseAnimating() )
  1551. {
  1552. CBaseAnimating *pAnim = GetParent()->GetBaseAnimating();
  1553. int nParentAttachment = pAnim->LookupAttachment( STRING(m_iszParentAttachment) );
  1554. if ( nParentAttachment != 0 )
  1555. {
  1556. SetParent( GetParent(), nParentAttachment );
  1557. SetLocalOrigin( vec3_origin );
  1558. SetLocalAngles( vec3_angle );
  1559. }
  1560. }
  1561. }
  1562. //-----------------------------------------------------------------------------
  1563. // Purpose:
  1564. // Input : &inputdata -
  1565. //-----------------------------------------------------------------------------
  1566. void CEnvMuzzleFlash::InputFire( inputdata_t &inputdata )
  1567. {
  1568. g_pEffects->MuzzleFlash( GetAbsOrigin(), GetAbsAngles(), m_flScale, MUZZLEFLASH_TYPE_DEFAULT );
  1569. }
  1570. //=========================================================
  1571. // Splash!
  1572. //=========================================================
  1573. #define SF_ENVSPLASH_FINDWATERSURFACE 0x00000001
  1574. #define SF_ENVSPLASH_DIMINISH 0x00000002
  1575. class CEnvSplash : public CPointEntity
  1576. {
  1577. DECLARE_CLASS( CEnvSplash, CPointEntity );
  1578. public:
  1579. virtual void Precache();
  1580. virtual void Spawn();
  1581. // Input handlers
  1582. void InputSplash( inputdata_t &inputdata );
  1583. protected:
  1584. float m_flScale;
  1585. DECLARE_DATADESC();
  1586. };
  1587. BEGIN_DATADESC( CEnvSplash )
  1588. DEFINE_KEYFIELD( m_flScale, FIELD_FLOAT, "scale" ),
  1589. DEFINE_INPUTFUNC( FIELD_VOID, "Splash", InputSplash ),
  1590. END_DATADESC()
  1591. LINK_ENTITY_TO_CLASS( env_splash, CEnvSplash );
  1592. //-----------------------------------------------------------------------------
  1593. // Purpose:
  1594. // Input : &inputdata -
  1595. //-----------------------------------------------------------------------------
  1596. void CEnvSplash::Precache()
  1597. {
  1598. BaseClass::Precache();
  1599. PrecacheEffect( "watersplash" );
  1600. }
  1601. void CEnvSplash::Spawn()
  1602. {
  1603. Precache();
  1604. BaseClass::Spawn();
  1605. }
  1606. #define SPLASH_MAX_DEPTH 120.0f
  1607. void CEnvSplash::InputSplash( inputdata_t &inputdata )
  1608. {
  1609. CEffectData data;
  1610. data.m_fFlags = 0;
  1611. float scale = m_flScale;
  1612. if( HasSpawnFlags( SF_ENVSPLASH_FINDWATERSURFACE ) )
  1613. {
  1614. if( UTIL_PointContents(GetAbsOrigin(), MASK_WATER) & MASK_WATER )
  1615. {
  1616. // No splash if I'm supposed to find the surface of the water, but I'm underwater.
  1617. return;
  1618. }
  1619. // Trace down and find the water's surface. This is designed for making
  1620. // splashes on the surface of water that can change water level.
  1621. trace_t tr;
  1622. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector( 0, 0, 4096 ), (MASK_WATER|MASK_SOLID_BRUSHONLY), this, COLLISION_GROUP_NONE, &tr );
  1623. data.m_vOrigin = tr.endpos;
  1624. if ( tr.contents & CONTENTS_SLIME )
  1625. {
  1626. data.m_fFlags |= FX_WATER_IN_SLIME;
  1627. }
  1628. }
  1629. else
  1630. {
  1631. data.m_vOrigin = GetAbsOrigin();
  1632. }
  1633. if( HasSpawnFlags( SF_ENVSPLASH_DIMINISH ) )
  1634. {
  1635. // Get smaller if I'm in deeper water.
  1636. float depth = 0.0f;
  1637. trace_t tr;
  1638. UTIL_TraceLine( data.m_vOrigin, data.m_vOrigin - Vector( 0, 0, 4096 ), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
  1639. depth = fabs( tr.startpos.z - tr.endpos.z );
  1640. float factor = 1.0f - (depth / SPLASH_MAX_DEPTH);
  1641. if( factor < 0.1 )
  1642. {
  1643. // Don't bother making one this small.
  1644. return;
  1645. }
  1646. scale *= factor;
  1647. }
  1648. data.m_vNormal = Vector( 0, 0, 1 );
  1649. data.m_flScale = scale;
  1650. DispatchEffect( "watersplash", data );
  1651. }
  1652. //-----------------------------------------------------------------------------
  1653. //-----------------------------------------------------------------------------
  1654. class CEnvGunfire : public CPointEntity
  1655. {
  1656. public:
  1657. DECLARE_CLASS( CEnvGunfire, CPointEntity );
  1658. CEnvGunfire()
  1659. {
  1660. // !!!HACKHACK
  1661. // These fields came along kind of late, so they get
  1662. // initialized in the constructor for now. (sjb)
  1663. m_flBias = 1.0f;
  1664. m_bCollide = false;
  1665. }
  1666. void Precache();
  1667. void Spawn();
  1668. void Activate();
  1669. void StartShooting();
  1670. void StopShooting();
  1671. void ShootThink();
  1672. void UpdateTarget();
  1673. void FireBullet(
  1674. Vector vecSrc, // shooting postion
  1675. const QAngle &shootAngles, //shooting angle
  1676. float flDistance, // max distance
  1677. float flPenetration, // the power of the penetration
  1678. int nPenetrationCount,
  1679. int iBulletType, // ammo type
  1680. int iDamage, // base damage
  1681. float flRangeModifier, // damage range modifier
  1682. CBaseEntity *pevAttacker, // shooter
  1683. bool bDoEffects,
  1684. float xSpread, float ySpread,
  1685. const char *pszTracerName
  1686. );
  1687. void InputEnable( inputdata_t &inputdata );
  1688. void InputDisable( inputdata_t &inputdata );
  1689. int m_iMinBurstSize;
  1690. int m_iMaxBurstSize;
  1691. float m_flMinBurstDelay;
  1692. float m_flMaxBurstDelay;
  1693. float m_flRateOfFire;
  1694. string_t m_iszShootSound;
  1695. string_t m_iszTracerType;
  1696. string_t m_iszWeaponName;
  1697. bool m_bDisabled;
  1698. int m_iShotsRemaining;
  1699. int m_iSpread;
  1700. Vector m_vecSpread;
  1701. Vector m_vecTargetPosition;
  1702. float m_flTargetDist;
  1703. float m_flBias;
  1704. bool m_bCollide;
  1705. EHANDLE m_hTarget;
  1706. DECLARE_DATADESC();
  1707. };
  1708. BEGIN_DATADESC( CEnvGunfire )
  1709. DEFINE_KEYFIELD( m_iMinBurstSize, FIELD_INTEGER, "minburstsize" ),
  1710. DEFINE_KEYFIELD( m_iMaxBurstSize, FIELD_INTEGER, "maxburstsize" ),
  1711. DEFINE_KEYFIELD( m_flMinBurstDelay, FIELD_TIME, "minburstdelay" ),
  1712. DEFINE_KEYFIELD( m_flMaxBurstDelay, FIELD_TIME, "maxburstdelay" ),
  1713. DEFINE_KEYFIELD( m_flRateOfFire, FIELD_FLOAT, "rateoffire" ),
  1714. DEFINE_KEYFIELD( m_iszShootSound, FIELD_STRING, "shootsound" ),
  1715. DEFINE_KEYFIELD( m_iszTracerType, FIELD_STRING, "tracertype" ),
  1716. DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "startdisabled" ),
  1717. DEFINE_KEYFIELD( m_iSpread, FIELD_INTEGER, "spread" ),
  1718. DEFINE_KEYFIELD( m_flBias, FIELD_FLOAT, "bias" ),
  1719. DEFINE_KEYFIELD( m_bCollide, FIELD_BOOLEAN, "collisions" ),
  1720. DEFINE_KEYFIELD( m_iszWeaponName, FIELD_STRING, "weaponname" ),
  1721. DEFINE_FIELD( m_iShotsRemaining, FIELD_INTEGER ),
  1722. DEFINE_FIELD( m_vecSpread, FIELD_VECTOR ),
  1723. DEFINE_FIELD( m_vecTargetPosition, FIELD_VECTOR ),
  1724. DEFINE_FIELD( m_flTargetDist, FIELD_FLOAT ),
  1725. DEFINE_FIELD( m_hTarget, FIELD_EHANDLE ),
  1726. DEFINE_THINKFUNC( ShootThink ),
  1727. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  1728. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  1729. END_DATADESC()
  1730. LINK_ENTITY_TO_CLASS( env_gunfire, CEnvGunfire );
  1731. //-----------------------------------------------------------------------------
  1732. //-----------------------------------------------------------------------------
  1733. void CEnvGunfire::Precache()
  1734. {
  1735. PrecacheScriptSound( STRING( m_iszShootSound ) );
  1736. PrecacheEffect( "impact_wallbang_heavy" );
  1737. PrecacheEffect( "impact_wallbang_light" );
  1738. }
  1739. //-----------------------------------------------------------------------------
  1740. //-----------------------------------------------------------------------------
  1741. void CEnvGunfire::Spawn()
  1742. {
  1743. Precache();
  1744. m_iShotsRemaining = 0;
  1745. m_flRateOfFire = 1.0f / m_flRateOfFire;
  1746. switch( m_iSpread )
  1747. {
  1748. case 1:
  1749. m_vecSpread = VECTOR_CONE_1DEGREES;
  1750. break;
  1751. case 5:
  1752. m_vecSpread = VECTOR_CONE_5DEGREES;
  1753. break;
  1754. case 10:
  1755. m_vecSpread = VECTOR_CONE_10DEGREES;
  1756. break;
  1757. case 15:
  1758. m_vecSpread = VECTOR_CONE_15DEGREES;
  1759. break;
  1760. default:
  1761. m_vecSpread = vec3_origin;
  1762. break;
  1763. }
  1764. if( !m_bDisabled )
  1765. {
  1766. StartShooting();
  1767. }
  1768. }
  1769. //-----------------------------------------------------------------------------
  1770. //-----------------------------------------------------------------------------
  1771. void CEnvGunfire::Activate( void )
  1772. {
  1773. // Find my target
  1774. if (m_target != NULL_STRING)
  1775. {
  1776. m_hTarget = gEntList.FindEntityByName( NULL, m_target );
  1777. }
  1778. BaseClass::Activate();
  1779. }
  1780. //-----------------------------------------------------------------------------
  1781. //-----------------------------------------------------------------------------
  1782. void CEnvGunfire::StartShooting()
  1783. {
  1784. m_iShotsRemaining = random->RandomInt( m_iMinBurstSize, m_iMaxBurstSize );
  1785. SetThink( &CEnvGunfire::ShootThink );
  1786. SetNextThink( gpGlobals->curtime );
  1787. }
  1788. //-----------------------------------------------------------------------------
  1789. //-----------------------------------------------------------------------------
  1790. void CEnvGunfire::UpdateTarget()
  1791. {
  1792. if( m_hTarget )
  1793. {
  1794. if( m_hTarget->WorldSpaceCenter() != m_vecTargetPosition )
  1795. {
  1796. // Target has moved.
  1797. // Locate my target and cache the position and distance.
  1798. m_vecTargetPosition = m_hTarget->WorldSpaceCenter();
  1799. m_flTargetDist = (GetAbsOrigin() - m_vecTargetPosition).Length();
  1800. }
  1801. }
  1802. }
  1803. //-----------------------------------------------------------------------------
  1804. //-----------------------------------------------------------------------------
  1805. void CEnvGunfire::StopShooting()
  1806. {
  1807. SetThink( NULL );
  1808. }
  1809. //-----------------------------------------------------------------------------
  1810. //-----------------------------------------------------------------------------
  1811. void CEnvGunfire::ShootThink()
  1812. {
  1813. if( !m_hTarget )
  1814. {
  1815. StopShooting();
  1816. }
  1817. UpdateTarget();
  1818. Vector vecDir = m_vecTargetPosition - GetAbsOrigin();
  1819. VectorNormalize( vecDir );
  1820. CShotManipulator manipulator( vecDir );
  1821. vecDir = manipulator.ApplySpread( m_vecSpread, m_flBias );
  1822. Vector vecEnd;
  1823. #if defined( CSTRIKE15 )
  1824. CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinitionByName( STRING(m_iszWeaponName) );
  1825. if ( pItemDef && pItemDef->GetDefinitionIndex() != 0 )
  1826. {
  1827. CSWeaponID wid = WeaponIdFromString( STRING(m_iszWeaponName) );
  1828. const CCSWeaponInfo* pWeaponInfo = GetWeaponInfo( wid );
  1829. uint16 nItemDefIndex = pItemDef->GetDefinitionIndex();
  1830. QAngle angDir;
  1831. VectorAngles( vecDir, angDir );
  1832. FX_FireBullets(
  1833. entindex(),
  1834. nItemDefIndex,
  1835. GetAbsOrigin(),
  1836. angDir,
  1837. wid,
  1838. 0,
  1839. CBaseEntity::GetPredictionRandomSeed( SERVER_PLATTIME_RNG ) & 255,
  1840. 0,
  1841. 0,
  1842. 0,
  1843. 0,
  1844. SINGLE,
  1845. 0 );
  1846. int nPenetrationCount = 4;
  1847. int iDamage = pWeaponInfo->GetDamage( NULL );
  1848. float flRange = pWeaponInfo->GetRange( NULL );
  1849. float flPenetration = pWeaponInfo->GetPenetration( NULL );
  1850. float flRangeModifier = pWeaponInfo->GetRangeModifier( NULL );
  1851. int iAmmoType = pWeaponInfo->GetPrimaryAmmoType( NULL );
  1852. FireBullet(
  1853. GetAbsOrigin(),
  1854. angDir,
  1855. flRange,
  1856. flPenetration,
  1857. nPenetrationCount,
  1858. iAmmoType,
  1859. iDamage,
  1860. flRangeModifier,
  1861. this,
  1862. true,
  1863. 0, 0,
  1864. pWeaponInfo->GetTracerEffectName() );
  1865. m_iShotsRemaining--;
  1866. float flNextShot = gpGlobals->curtime + pWeaponInfo->GetCycleTime();
  1867. SetNextThink( flNextShot );
  1868. if( m_iShotsRemaining == 0 )
  1869. {
  1870. StartShooting();
  1871. SetNextThink( gpGlobals->curtime + random->RandomFloat( m_flMinBurstDelay, m_flMaxBurstDelay ) );
  1872. }
  1873. }
  1874. #else
  1875. SetNextThink( gpGlobals->curtime + m_flRateOfFire );
  1876. if( m_bCollide )
  1877. {
  1878. trace_t tr;
  1879. UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + vecDir * 8192, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr );
  1880. if( tr.fraction != 1.0 )
  1881. {
  1882. DoImpactEffect( tr, DMG_BULLET );
  1883. }
  1884. vecEnd = tr.endpos;
  1885. }
  1886. else
  1887. {
  1888. vecEnd = GetAbsOrigin() + vecDir * m_flTargetDist;
  1889. }
  1890. if( m_iszTracerType != NULL_STRING )
  1891. {
  1892. UTIL_Tracer( GetAbsOrigin(), vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 5000, true, STRING(m_iszTracerType) );
  1893. }
  1894. else
  1895. {
  1896. UTIL_Tracer( GetAbsOrigin(), vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 5000, true );
  1897. }
  1898. EmitSound( STRING(m_iszShootSound) );
  1899. m_iShotsRemaining--;
  1900. if ( m_iShotsRemaining == 0 )
  1901. {
  1902. StartShooting();
  1903. SetNextThink( gpGlobals->curtime + random->RandomFloat( m_flMinBurstDelay, m_flMaxBurstDelay ) );
  1904. }
  1905. #endif
  1906. }
  1907. static const int kMaxNumPenetrationsSupported = 4;
  1908. struct DelayedDamageInfoData_t
  1909. {
  1910. CTakeDamageInfo m_info;
  1911. trace_t m_tr;
  1912. typedef CUtlVectorFixedGrowable< DelayedDamageInfoData_t, kMaxNumPenetrationsSupported > Array;
  1913. };
  1914. inline void UTIL_TraceLineIgnoreTwoEntities( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask,
  1915. const IHandleEntity *ignore, const IHandleEntity *ignore2, int collisionGroup, trace_t *ptr )
  1916. {
  1917. Ray_t ray;
  1918. ray.Init( vecAbsStart, vecAbsEnd );
  1919. CTraceFilterSkipTwoEntities traceFilter( ignore, ignore2, collisionGroup );
  1920. enginetrace->TraceRay( ray, mask, &traceFilter, ptr );
  1921. if ( r_visualizetraces.GetBool() )
  1922. {
  1923. DebugDrawLine( ptr->startpos, ptr->endpos, 255, 0, 0, true, -1.0f );
  1924. }
  1925. }
  1926. extern ConVar sv_showbullethits;
  1927. extern ConVar sv_penetration_type;
  1928. #define CS_MASK_SHOOT (MASK_SOLID|CONTENTS_DEBRIS)
  1929. void CEnvGunfire::FireBullet(
  1930. Vector vecSrc, // shooting postion
  1931. const QAngle &shootAngles, //shooting angle
  1932. float flDistance, // max distance
  1933. float flPenetration, // the power of the penetration
  1934. int nPenetrationCount,
  1935. int iBulletType, // ammo type
  1936. int iDamage, // base damage
  1937. float flRangeModifier, // damage range modifier
  1938. CBaseEntity *pevAttacker, // shooter
  1939. bool bDoEffects,
  1940. float xSpread, float ySpread,
  1941. const char *pszTracerName
  1942. )
  1943. {
  1944. CCSPlayer *pPlayer = NULL;
  1945. for ( int i = 1; i <= MAX_PLAYERS; i++ )
  1946. {
  1947. pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
  1948. if ( pPlayer )
  1949. break;
  1950. }
  1951. float fCurrentDamage = iDamage; // damage of the bullet at it's current trajectory
  1952. float flCurrentDistance = 0.0; //distance that the bullet has traveled so far
  1953. Vector vecDirShooting, vecRight, vecUp;
  1954. AngleVectors( shootAngles, &vecDirShooting, &vecRight, &vecUp );
  1955. // MIKETODO: put all the ammo parameters into a script file and allow for CS-specific params.
  1956. float flPenetrationPower = 35; // thickness of a wall that this bullet can penetrate
  1957. float flPenetrationDistance = 3000; // distance at which the bullet is capable of penetrating a wall
  1958. float flDamageModifier = 0.5f; // default modification of bullets power after they go through a wall.
  1959. float flPenetrationModifier = 1.0f;
  1960. // we use the max penetrations on this gun to figure out how much penetration it's capable of
  1961. if ( sv_penetration_type.GetInt() == 1 )
  1962. flPenetrationPower = flPenetration;
  1963. if ( !pevAttacker )
  1964. pevAttacker = this; // the default attacker is ourselves
  1965. // add the spray
  1966. Vector vecDir = vecDirShooting + xSpread * vecRight + ySpread * vecUp;
  1967. VectorNormalize( vecDir );
  1968. bool bFirstHit = true;
  1969. const CBaseCombatCharacter *lastPlayerHit = NULL; // this includes players, bots, and hostages
  1970. //#ifdef CLIENT_DLL
  1971. Vector vecWallBangHitStart, vecWallBangHitEnd;
  1972. vecWallBangHitStart.Init();
  1973. vecWallBangHitEnd.Init();
  1974. bool bWallBangStarted = false;
  1975. bool bWallBangEnded = false;
  1976. bool bWallBangHeavyVersion = false;
  1977. //#endif
  1978. bool bBulletHitPlayer = false;
  1979. MDLCACHE_CRITICAL_SECTION();
  1980. //#ifndef CLIENT_DLL
  1981. DelayedDamageInfoData_t::Array arrPendingDamage;
  1982. //#endif
  1983. bool bShotHitTeammate = false;
  1984. float flDist_aim = 0;
  1985. while ( fCurrentDamage > 0 )
  1986. {
  1987. Vector vecEnd = vecSrc + vecDir * ( flDistance - flCurrentDistance );
  1988. trace_t tr; // main enter bullet trace
  1989. UTIL_TraceLineIgnoreTwoEntities( vecSrc, vecEnd, CS_MASK_SHOOT | CONTENTS_HITBOX, this, lastPlayerHit, COLLISION_GROUP_NONE, &tr );
  1990. {
  1991. CTraceFilterSkipTwoEntities filter( this, lastPlayerHit, COLLISION_GROUP_NONE );
  1992. // Check for player hitboxes extending outside their collision bounds
  1993. const float rayExtension = 40.0f;
  1994. UTIL_ClipTraceToPlayers( vecSrc, vecEnd + vecDir * rayExtension, CS_MASK_SHOOT | CONTENTS_HITBOX, &filter, &tr );
  1995. }
  1996. if ( !flDist_aim )
  1997. {
  1998. flDist_aim = ( tr.fraction != 1.0 ) ? ( tr.startpos - tr.endpos ).Length() : 0;
  1999. }
  2000. lastPlayerHit = dynamic_cast< const CBaseCombatCharacter * >( tr.m_pEnt );
  2001. if ( lastPlayerHit )
  2002. {
  2003. if ( lastPlayerHit->GetTeamNumber() == GetTeamNumber() )
  2004. {
  2005. bShotHitTeammate = true;
  2006. }
  2007. bBulletHitPlayer = true;
  2008. }
  2009. if ( tr.fraction == 1.0f )
  2010. break; // we didn't hit anything, stop tracing shoot
  2011. //#ifdef CLIENT_DLL
  2012. if ( !bWallBangStarted && !bBulletHitPlayer )
  2013. {
  2014. vecWallBangHitStart = tr.endpos;
  2015. vecWallBangHitEnd = tr.endpos;
  2016. bWallBangStarted = true;
  2017. if ( fCurrentDamage > 20 )
  2018. bWallBangHeavyVersion = true;
  2019. }
  2020. else if ( !bWallBangEnded )
  2021. {
  2022. vecWallBangHitEnd = tr.endpos;
  2023. if ( bBulletHitPlayer )
  2024. bWallBangEnded = true;
  2025. }
  2026. //#endif
  2027. bFirstHit = false;
  2028. #ifndef CLIENT_DLL
  2029. //
  2030. // Propogate a bullet impact event
  2031. // @todo Add this for shotgun pellets (which dont go thru here)
  2032. //
  2033. // IGameEvent * event = gameeventmanager->CreateEvent( "bullet_impact" );
  2034. // if ( event )
  2035. // {
  2036. // event->SetInt( "userid", GetUserID() );
  2037. // event->SetFloat( "x", tr.endpos.x );
  2038. // event->SetFloat( "y", tr.endpos.y );
  2039. // event->SetFloat( "z", tr.endpos.z );
  2040. // gameeventmanager->FireEvent( event );
  2041. // }
  2042. #endif
  2043. /************* MATERIAL DETECTION ***********/
  2044. surfacedata_t *pSurfaceData = physprops->GetSurfaceData( tr.surface.surfaceProps );
  2045. int iEnterMaterial = pSurfaceData->game.material;
  2046. flPenetrationModifier = pSurfaceData->game.penetrationModifier;
  2047. flDamageModifier = pSurfaceData->game.damageModifier;
  2048. bool hitGrate = ( tr.contents & CONTENTS_GRATE ) != 0;
  2049. //calculate the damage based on the distance the bullet travelled.
  2050. flCurrentDistance += tr.fraction * ( flDistance - flCurrentDistance );
  2051. fCurrentDamage *= pow( flRangeModifier, ( flCurrentDistance / 500 ) );
  2052. #ifndef CLIENT_DLL
  2053. // the value of iPenetration when the round reached its max penetration distance
  2054. int nPenetrationAtMaxDistance = 0;
  2055. #endif
  2056. // check if we reach penetration distance, no more penetrations after that
  2057. // or if our modifyer is super low, just stop the bullet
  2058. if ( ( flCurrentDistance > flPenetrationDistance && flPenetration > 0 ) ||
  2059. flPenetrationModifier < 0.1 )
  2060. {
  2061. #ifndef CLIENT_DLL
  2062. nPenetrationAtMaxDistance = 0;
  2063. #endif
  2064. nPenetrationCount = 0;
  2065. }
  2066. int iDamageType = DMG_BULLET | DMG_NEVERGIB;
  2067. //CWeaponCSBase* pActiveWeapon = NULL;
  2068. if ( bDoEffects )
  2069. {
  2070. // See if the bullet ended up underwater + started out of the water
  2071. if ( enginetrace->GetPointContents( tr.endpos, MASK_WATER ) & ( CONTENTS_WATER | CONTENTS_SLIME ) )
  2072. {
  2073. trace_t waterTrace;
  2074. UTIL_TraceLine( vecSrc, tr.endpos, ( MASK_SHOT | CONTENTS_WATER | CONTENTS_SLIME ), this, COLLISION_GROUP_NONE, &waterTrace );
  2075. if ( waterTrace.allsolid != 1 )
  2076. {
  2077. CEffectData data;
  2078. data.m_vOrigin = waterTrace.endpos;
  2079. data.m_vNormal = waterTrace.plane.normal;
  2080. data.m_flScale = random->RandomFloat( 8, 12 );
  2081. if ( waterTrace.contents & CONTENTS_SLIME )
  2082. {
  2083. data.m_fFlags |= FX_WATER_IN_SLIME;
  2084. }
  2085. DispatchEffect( "gunshotsplash", data );
  2086. }
  2087. }
  2088. else
  2089. {
  2090. //Do Regular hit effects
  2091. // Don't decal nodraw surfaces
  2092. if ( !( tr.surface.flags & ( SURF_SKY | SURF_NODRAW | SURF_HINT | SURF_SKIP ) ) )
  2093. {
  2094. //CBaseEntity *pEntity = tr.m_pEnt;
  2095. UTIL_ImpactTrace( &tr, iDamageType );
  2096. }
  2097. }
  2098. }
  2099. #ifndef CLIENT_DLL
  2100. // decal players on the server to eliminate the disparity between where the client thinks the decal went and where it actually went
  2101. // we want to eliminate the case where a player sees a blood decal on someone, but they are at 100 health
  2102. if ( tr.DidHit() && tr.m_pEnt && tr.m_pEnt->IsPlayer() )
  2103. {
  2104. UTIL_ImpactTrace( &tr, iDamageType );
  2105. }
  2106. #endif
  2107. // #ifdef CLIENT_DLL
  2108. // // create the tracer
  2109. // CreateWeaponTracer( vecSrc, tr.endpos );
  2110. // #endif
  2111. if ( bWallBangStarted == false )
  2112. UTIL_ParticleTracer( pszTracerName, vecSrc, tr.endpos, entindex() );
  2113. // add damage to entity that we hit
  2114. #ifndef CLIENT_DLL
  2115. // CBaseEntity *pEntity = tr.m_pEnt;
  2116. //Shooting dropped grenades detonates them
  2117. //
  2118. // DAMAGE MUST BE DEFERRED TILL LATER IF WE DECIDE TO SHIP IT
  2119. //
  2120. // if ( sv_shoot_dropped_grenades.GetBool() )
  2121. // {
  2122. // CBaseCSGrenade* pWeapon = dynamic_cast<CBaseCSGrenade*>( pEntity );
  2123. // //Only detonate shot grenades if they have been dropped in the world longer than the grace period.
  2124. // //This prevents shooting at players and they miraculously explode - because you shot their grenade the instant they died
  2125. // if ( pWeapon && gpGlobals->curtime > (pWeapon->m_flDroppedAtTime + sv_shoot_dropped_grenades_grace_time.GetFloat()) )
  2126. // {
  2127. // pWeapon->ShotDetonate( this, pWeapon->GetCSWpnData() );
  2128. // pWeapon->AddSolidFlags( FSOLID_NOT_SOLID );
  2129. // pWeapon->AddEffects( EF_NODRAW );
  2130. // UTIL_Remove( pWeapon );
  2131. // }
  2132. // }
  2133. // [pfreese] Check if enemy players were killed by this bullet, and if so,
  2134. // add them to the iPenetrationKills count
  2135. DelayedDamageInfoData_t &delayedDamage = arrPendingDamage.Element( arrPendingDamage.AddToTail() );
  2136. delayedDamage.m_tr = tr;
  2137. int nObjectsPenetrated = kMaxNumPenetrationsSupported - ( nPenetrationCount + nPenetrationAtMaxDistance );
  2138. CTakeDamageInfo &info = delayedDamage.m_info;
  2139. info.Set( pevAttacker, pevAttacker, NULL/*GetActiveWeapon()*/, fCurrentDamage, iDamageType, 0, nObjectsPenetrated );
  2140. // Set the bullet ID so that we can later track all the enemies that are damage by the same bullet
  2141. info.SetAmmoType( iBulletType );
  2142. CalculateBulletDamageForce( &info, iBulletType, vecDir, tr.endpos );
  2143. //bool bWasAlive = pEntity->IsAlive();
  2144. // === Damage applied later ===
  2145. #endif
  2146. // [dkorus] note: values are changed inside of HandleBulletPenetration
  2147. bool bulletStopped = pPlayer->HandleBulletPenetration( flPenetration, iEnterMaterial, hitGrate, tr, vecDir, pSurfaceData, flPenetrationModifier,
  2148. flDamageModifier, bDoEffects, iDamageType, flPenetrationPower, nPenetrationCount, vecSrc, flDistance,
  2149. flCurrentDistance, fCurrentDamage );
  2150. // [dkorus] bulletStopped is true if the bullet can no longer continue penetrating materials
  2151. if ( bulletStopped )
  2152. break;
  2153. }
  2154. #ifndef CLIENT_DLL
  2155. FOR_EACH_VEC( arrPendingDamage, idxDamage )
  2156. {
  2157. ClearMultiDamage();
  2158. CTakeDamageInfo &info = arrPendingDamage[idxDamage].m_info;
  2159. trace_t &tr = arrPendingDamage[idxDamage].m_tr;
  2160. CBaseEntity *pEntity = tr.m_pEnt;
  2161. //bool bWasAlive = pEntity->IsAlive();
  2162. pEntity->DispatchTraceAttack( info, vecDir, &tr );
  2163. TraceAttackToTriggers( info, tr.startpos, tr.endpos, vecDir );
  2164. ApplyMultiDamage();
  2165. // if ( bWasAlive && !pEntity->IsAlive() && pEntity->IsPlayer() && IsOtherEnemy( pEntity->entindex() ) )
  2166. // {
  2167. // ++iPenetrationKills;
  2168. // }
  2169. }
  2170. #endif
  2171. //#ifdef CLIENT_DLL
  2172. if ( bWallBangStarted )
  2173. {
  2174. float flWallBangLength = ( vecWallBangHitEnd - vecWallBangHitStart ).Length();
  2175. if ( flWallBangLength > 0 && flWallBangLength < 800 )
  2176. {
  2177. QAngle temp;
  2178. VectorAngles( vecWallBangHitEnd - vecWallBangHitStart, temp );
  2179. // CEffectData data;
  2180. // data.m_vOrigin = vecWallBangHitStart;
  2181. // data.m_vStart = vecWallBangHitEnd;
  2182. // data.m_vAngles = temp;
  2183. // //data.m_vNormal = vecWallBangHitStart - vecWallBangHitEnd;
  2184. // data.m_flScale = 1.0f;
  2185. //why is particle system index stored on m_nHitBox?
  2186. if ( bWallBangHeavyVersion )
  2187. {
  2188. //data.m_nHitBox = GetParticleSystemIndex( "impact_wallbang_heavy" );
  2189. //UTIL_Tracer( vecWallBangHitStart, vecWallBangHitEnd, 0, TRACER_DONT_USE_ATTACHMENT, 0, true, "impact_wallbang_heavy"/*, data.m_nHitBox */);
  2190. UTIL_ParticleTracer( "impact_wallbang_heavy", vecWallBangHitStart, vecWallBangHitEnd, entindex() );
  2191. }
  2192. else
  2193. {
  2194. //data.m_nHitBox = GetParticleSystemIndex( "impact_wallbang_light" );
  2195. //UTIL_Tracer( vecWallBangHitStart, vecWallBangHitEnd, 0, TRACER_DONT_USE_ATTACHMENT, 0, true, "impact_wallbang_light"/*, data.m_nHitBox*/ );
  2196. UTIL_ParticleTracer( "impact_wallbang_light", vecWallBangHitStart, vecWallBangHitEnd, entindex() );
  2197. }
  2198. //StartParticleEffect( data );
  2199. //debugoverlay->AddLineOverlay( vecWallBangHitStart, vecWallBangHitEnd, 0, 255, 0, false, 3 );
  2200. }
  2201. }
  2202. //#endif
  2203. }
  2204. //-----------------------------------------------------------------------------
  2205. //-----------------------------------------------------------------------------
  2206. void CEnvGunfire::InputEnable( inputdata_t &inputdata )
  2207. {
  2208. m_bDisabled = false;
  2209. StartShooting();
  2210. }
  2211. //-----------------------------------------------------------------------------
  2212. //-----------------------------------------------------------------------------
  2213. void CEnvGunfire::InputDisable( inputdata_t &inputdata )
  2214. {
  2215. m_bDisabled = true;
  2216. SetThink( NULL );
  2217. }
  2218. //-----------------------------------------------------------------------------
  2219. // Quadratic spline beam effect
  2220. //-----------------------------------------------------------------------------
  2221. BEGIN_DATADESC( CEnvQuadraticBeam )
  2222. DEFINE_FIELD( m_targetPosition, FIELD_POSITION_VECTOR ),
  2223. DEFINE_FIELD( m_controlPosition, FIELD_POSITION_VECTOR ),
  2224. DEFINE_FIELD( m_scrollRate, FIELD_FLOAT ),
  2225. DEFINE_FIELD( m_flWidth, FIELD_FLOAT ),
  2226. END_DATADESC()
  2227. LINK_ENTITY_TO_CLASS( env_quadraticbeam, CEnvQuadraticBeam );
  2228. IMPLEMENT_SERVERCLASS_ST( CEnvQuadraticBeam, DT_QuadraticBeam )
  2229. SendPropVector(SENDINFO(m_targetPosition), -1, SPROP_COORD),
  2230. SendPropVector(SENDINFO(m_controlPosition), -1, SPROP_COORD),
  2231. SendPropFloat(SENDINFO(m_scrollRate), 8, 0, -4, 4),
  2232. SendPropFloat(SENDINFO(m_flWidth), -1, SPROP_NOSCALE),
  2233. END_SEND_TABLE()
  2234. void CEnvQuadraticBeam::Spawn()
  2235. {
  2236. BaseClass::Spawn();
  2237. m_nRenderMode = kRenderTransAdd;
  2238. SetRenderColor( 255, 255, 255 );
  2239. }
  2240. CEnvQuadraticBeam *CreateQuadraticBeam( const char *pSpriteName, const Vector &start, const Vector &control, const Vector &end, float width, CBaseEntity *pOwner )
  2241. {
  2242. CEnvQuadraticBeam *pBeam = (CEnvQuadraticBeam *)CBaseEntity::Create( "env_quadraticbeam", start, vec3_angle, pOwner );
  2243. UTIL_SetModel( pBeam, pSpriteName );
  2244. pBeam->SetSpline( control, end );
  2245. pBeam->SetScrollRate( 0.0 );
  2246. pBeam->SetWidth(width);
  2247. return pBeam;
  2248. }
  2249. PRECACHE_REGISTER_BEGIN( GLOBAL, EffectsPrecache )
  2250. #ifndef DOTA_DLL
  2251. PRECACHE( GAMESOUND, "Underwater.BulletImpact" )
  2252. PRECACHE( GAMESOUND, "FX_RicochetSound.Ricochet" )
  2253. PRECACHE(GAMESOUND, "FX_RicochetSound.Ricochet_Legacy")
  2254. PRECACHE( GAMESOUND, "Physics.WaterSplash" )
  2255. PRECACHE( GAMESOUND, "BaseExplosionEffect.Sound" )
  2256. PRECACHE( GAMESOUND, "Splash.SplashSound" )
  2257. #ifndef _WIN64 // TODO64: PRECACHE_CONDITIONAL is not supported on 64bit , hopefully it's not an issue for the server to not precache a sound
  2258. PRECACHE_CONDITIONAL( GAMESOUND, "HudChat.Message", gpGlobals->maxClients > 1 )
  2259. #endif
  2260. #endif
  2261. PRECACHE_REGISTER_END()
  2262. class CEnvViewPunch : public CPointEntity
  2263. {
  2264. public:
  2265. DECLARE_CLASS( CEnvViewPunch, CPointEntity );
  2266. virtual void Spawn();
  2267. // Input handlers
  2268. void InputViewPunch( inputdata_t &inputdata );
  2269. private:
  2270. float m_flRadius;
  2271. QAngle m_angViewPunch;
  2272. void DoViewPunch();
  2273. DECLARE_DATADESC();
  2274. };
  2275. LINK_ENTITY_TO_CLASS( env_viewpunch, CEnvViewPunch );
  2276. BEGIN_DATADESC( CEnvViewPunch )
  2277. DEFINE_KEYFIELD( m_angViewPunch, FIELD_VECTOR, "punchangle" ),
  2278. DEFINE_KEYFIELD( m_flRadius, FIELD_FLOAT, "radius" ),
  2279. DEFINE_INPUTFUNC( FIELD_VOID, "ViewPunch", InputViewPunch ),
  2280. END_DATADESC()
  2281. #define SF_PUNCH_EVERYONE 0x0001 // Don't check radius
  2282. #define SF_PUNCH_IN_AIR 0x0002 // Punch players in air
  2283. //-----------------------------------------------------------------------------
  2284. //-----------------------------------------------------------------------------
  2285. void CEnvViewPunch::Spawn( void )
  2286. {
  2287. SetSolid( SOLID_NONE );
  2288. SetMoveType( MOVETYPE_NONE );
  2289. if ( GetSpawnFlags() & SF_PUNCH_EVERYONE )
  2290. {
  2291. m_flRadius = 0;
  2292. }
  2293. }
  2294. //-----------------------------------------------------------------------------
  2295. //-----------------------------------------------------------------------------
  2296. void CEnvViewPunch::DoViewPunch()
  2297. {
  2298. bool bAir = (GetSpawnFlags() & SF_PUNCH_IN_AIR) ? true : false;
  2299. UTIL_ViewPunch( GetAbsOrigin(), m_angViewPunch, m_flRadius, bAir );
  2300. }
  2301. //-----------------------------------------------------------------------------
  2302. //-----------------------------------------------------------------------------
  2303. void CEnvViewPunch::InputViewPunch( inputdata_t &inputdata )
  2304. {
  2305. DoViewPunch();
  2306. }