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.

529 lines
16 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Used to fire events based on the orientation of a given entity.
  4. //
  5. // Looks at its target's anglular velocity every frame and fires outputs
  6. // as the angular velocity passes a given threshold value.
  7. //
  8. //=============================================================================//
  9. #include "cbase.h"
  10. #include "entityinput.h"
  11. #include "entityoutput.h"
  12. #include "eventqueue.h"
  13. #include "mathlib/mathlib.h"
  14. // memdbgon must be the last include file in a .cpp file!!!
  15. #include "tier0/memdbgon.h"
  16. enum
  17. {
  18. AVELOCITY_SENSOR_NO_LAST_RESULT = -2
  19. };
  20. ConVar g_debug_angularsensor( "g_debug_angularsensor", "0", FCVAR_CHEAT );
  21. class CPointAngularVelocitySensor : public CPointEntity
  22. {
  23. DECLARE_CLASS( CPointAngularVelocitySensor, CPointEntity );
  24. public:
  25. CPointAngularVelocitySensor();
  26. void Activate(void);
  27. void Spawn(void);
  28. void Think(void);
  29. private:
  30. float SampleAngularVelocity(CBaseEntity *pEntity);
  31. int CompareToThreshold(CBaseEntity *pEntity, float flThreshold, bool bFireVelocityOutput);
  32. void FireCompareOutput(int nCompareResult, CBaseEntity *pActivator);
  33. void DrawDebugLines( void );
  34. // Input handlers
  35. void InputTest( inputdata_t &inputdata );
  36. void InputTestWithInterval( inputdata_t &inputdata );
  37. EHANDLE m_hTargetEntity; // Entity whose angles are being monitored.
  38. float m_flThreshold; // The threshold angular velocity that we are looking for.
  39. int m_nLastCompareResult; // The comparison result from our last measurement, expressed as -1, 0, or 1
  40. int m_nLastFireResult; // The last result for which we fire the output.
  41. float m_flFireTime;
  42. float m_flFireInterval;
  43. float m_flLastAngVelocity;
  44. QAngle m_lastOrientation;
  45. Vector m_vecAxis;
  46. bool m_bUseHelper;
  47. // Outputs
  48. COutputFloat m_AngularVelocity;
  49. // Compare the target's angular velocity to the threshold velocity and fire the appropriate output.
  50. // These outputs are filtered by m_flFireInterval to ignore excessive oscillations.
  51. COutputEvent m_OnLessThan;
  52. COutputEvent m_OnLessThanOrEqualTo;
  53. COutputEvent m_OnGreaterThan;
  54. COutputEvent m_OnGreaterThanOrEqualTo;
  55. COutputEvent m_OnEqualTo;
  56. DECLARE_DATADESC();
  57. };
  58. LINK_ENTITY_TO_CLASS(point_angularvelocitysensor, CPointAngularVelocitySensor);
  59. BEGIN_DATADESC( CPointAngularVelocitySensor )
  60. // Fields
  61. DEFINE_FIELD( m_hTargetEntity, FIELD_EHANDLE ),
  62. DEFINE_KEYFIELD(m_flThreshold, FIELD_FLOAT, "threshold"),
  63. DEFINE_FIELD(m_nLastCompareResult, FIELD_INTEGER),
  64. DEFINE_FIELD( m_nLastFireResult, FIELD_INTEGER ),
  65. DEFINE_FIELD( m_flFireTime, FIELD_TIME ),
  66. DEFINE_KEYFIELD( m_flFireInterval, FIELD_FLOAT, "fireinterval" ),
  67. DEFINE_FIELD( m_flLastAngVelocity, FIELD_FLOAT ),
  68. DEFINE_FIELD( m_lastOrientation, FIELD_VECTOR ),
  69. // Inputs
  70. DEFINE_INPUTFUNC(FIELD_VOID, "Test", InputTest),
  71. DEFINE_INPUTFUNC(FIELD_VOID, "TestWithInterval", InputTestWithInterval),
  72. // Outputs
  73. DEFINE_OUTPUT(m_OnLessThan, "OnLessThan"),
  74. DEFINE_OUTPUT(m_OnLessThanOrEqualTo, "OnLessThanOrEqualTo"),
  75. DEFINE_OUTPUT(m_OnGreaterThan, "OnGreaterThan"),
  76. DEFINE_OUTPUT(m_OnGreaterThanOrEqualTo, "OnGreaterThanOrEqualTo"),
  77. DEFINE_OUTPUT(m_OnEqualTo, "OnEqualTo"),
  78. DEFINE_OUTPUT(m_AngularVelocity, "AngularVelocity"),
  79. DEFINE_KEYFIELD( m_vecAxis, FIELD_VECTOR, "axis" ),
  80. DEFINE_KEYFIELD( m_bUseHelper, FIELD_BOOLEAN, "usehelper" ),
  81. END_DATADESC()
  82. //-----------------------------------------------------------------------------
  83. // Purpose: constructor provides default values
  84. //-----------------------------------------------------------------------------
  85. CPointAngularVelocitySensor::CPointAngularVelocitySensor()
  86. {
  87. m_flFireInterval = 0.2f;
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Purpose: Called when spawning after parsing keyvalues.
  91. //-----------------------------------------------------------------------------
  92. void CPointAngularVelocitySensor::Spawn(void)
  93. {
  94. m_flThreshold = fabs(m_flThreshold);
  95. m_nLastFireResult = AVELOCITY_SENSOR_NO_LAST_RESULT;
  96. m_nLastCompareResult = AVELOCITY_SENSOR_NO_LAST_RESULT;
  97. // m_flFireInterval = 0.2;
  98. m_lastOrientation = vec3_angle;
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose: Called after all entities in the map have spawned.
  102. //-----------------------------------------------------------------------------
  103. void CPointAngularVelocitySensor::Activate(void)
  104. {
  105. BaseClass::Activate();
  106. m_hTargetEntity = gEntList.FindEntityByName( NULL, m_target );
  107. if (m_hTargetEntity)
  108. {
  109. SetNextThink( gpGlobals->curtime );
  110. }
  111. }
  112. //-----------------------------------------------------------------------------
  113. // Purpose: Draws magic lines...
  114. //-----------------------------------------------------------------------------
  115. void CPointAngularVelocitySensor::DrawDebugLines( void )
  116. {
  117. if ( m_hTargetEntity )
  118. {
  119. Vector vForward, vRight, vUp;
  120. AngleVectors( m_hTargetEntity->GetAbsAngles(), &vForward, &vRight, &vUp );
  121. NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vForward * 64, 255, 0, 0, false, 0 );
  122. NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vRight * 64, 0, 255, 0, false, 0 );
  123. NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vUp * 64, 0, 0, 255, false, 0 );
  124. }
  125. if ( m_bUseHelper == true )
  126. {
  127. QAngle Angles;
  128. Vector vAxisForward, vAxisRight, vAxisUp;
  129. Vector vLine = m_vecAxis - GetAbsOrigin();
  130. VectorNormalize( vLine );
  131. VectorAngles( vLine, Angles );
  132. AngleVectors( Angles, &vAxisForward, &vAxisRight, &vAxisUp );
  133. NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vAxisForward * 64, 255, 0, 0, false, 0 );
  134. NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vAxisRight * 64, 0, 255, 0, false, 0 );
  135. NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + vAxisUp * 64, 0, 0, 255, false, 0 );
  136. }
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Purpose: Returns the magnitude of the entity's angular velocity.
  140. //-----------------------------------------------------------------------------
  141. float CPointAngularVelocitySensor::SampleAngularVelocity(CBaseEntity *pEntity)
  142. {
  143. if (pEntity->GetMoveType() == MOVETYPE_VPHYSICS)
  144. {
  145. IPhysicsObject *pPhys = pEntity->VPhysicsGetObject();
  146. if (pPhys != NULL)
  147. {
  148. Vector vecVelocity;
  149. AngularImpulse vecAngVelocity;
  150. pPhys->GetVelocity(&vecVelocity, &vecAngVelocity);
  151. QAngle angles;
  152. pPhys->GetPosition( NULL, &angles );
  153. float dt = gpGlobals->curtime - GetLastThink();
  154. if ( dt == 0 )
  155. dt = 0.1;
  156. // HACKHACK: We don't expect a real 'delta' orientation here, just enough of an error estimate to tell if this thing
  157. // is trying to move, but failing.
  158. QAngle delta = angles - m_lastOrientation;
  159. if ( ( delta.Length() / dt ) < ( vecAngVelocity.Length() * 0.01 ) )
  160. {
  161. return 0.0f;
  162. }
  163. m_lastOrientation = angles;
  164. if ( m_bUseHelper == false )
  165. {
  166. return vecAngVelocity.Length();
  167. }
  168. else
  169. {
  170. Vector vLine = m_vecAxis - GetAbsOrigin();
  171. VectorNormalize( vLine );
  172. Vector vecWorldAngVelocity;
  173. pPhys->LocalToWorldVector( &vecWorldAngVelocity, vecAngVelocity );
  174. float flDot = DotProduct( vecWorldAngVelocity, vLine );
  175. return flDot;
  176. }
  177. }
  178. }
  179. else
  180. {
  181. QAngle vecAngVel = pEntity->GetLocalAngularVelocity();
  182. float flMax = MAX(fabs(vecAngVel[PITCH]), fabs(vecAngVel[YAW]));
  183. return MAX(flMax, fabs(vecAngVel[ROLL]));
  184. }
  185. return 0;
  186. }
  187. //-----------------------------------------------------------------------------
  188. // Purpose: Compares the given entity's angular velocity to the threshold velocity.
  189. // Input : pEntity - Entity whose angular velocity is being measured.
  190. // flThreshold -
  191. // Output : Returns -1 if less than, 0 if equal to, or 1 if greater than the threshold.
  192. //-----------------------------------------------------------------------------
  193. int CPointAngularVelocitySensor::CompareToThreshold(CBaseEntity *pEntity, float flThreshold, bool bFireVelocityOutput)
  194. {
  195. if (pEntity == NULL)
  196. {
  197. return 0;
  198. }
  199. float flAngVelocity = SampleAngularVelocity(pEntity);
  200. if ( g_debug_angularsensor.GetBool() )
  201. {
  202. DrawDebugLines();
  203. }
  204. if (bFireVelocityOutput && (flAngVelocity != m_flLastAngVelocity))
  205. {
  206. m_AngularVelocity.Set(flAngVelocity, pEntity, this);
  207. m_flLastAngVelocity = flAngVelocity;
  208. }
  209. if (flAngVelocity > flThreshold)
  210. {
  211. return 1;
  212. }
  213. if (flAngVelocity == flThreshold)
  214. {
  215. return 0;
  216. }
  217. return -1;
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Called every frame to sense the angular velocity of the target entity.
  221. // Output is filtered by m_flFireInterval to ignore excessive oscillations.
  222. //-----------------------------------------------------------------------------
  223. void CPointAngularVelocitySensor::Think(void)
  224. {
  225. if (m_hTargetEntity != NULL)
  226. {
  227. //
  228. // Check to see if the measure entity's angular velocity has been within
  229. // tolerance of the threshold for the given period of time.
  230. //
  231. int nCompare = CompareToThreshold(m_hTargetEntity, m_flThreshold, true);
  232. if (nCompare != m_nLastCompareResult)
  233. {
  234. // If we've oscillated back to where we last fired the output, don't
  235. // fire the same output again.
  236. if (nCompare == m_nLastFireResult)
  237. {
  238. m_flFireTime = 0;
  239. }
  240. else if (m_nLastCompareResult != AVELOCITY_SENSOR_NO_LAST_RESULT)
  241. {
  242. //
  243. // The value has changed -- reset the timer. We'll fire the output if
  244. // it stays at this value until the interval expires.
  245. //
  246. m_flFireTime = gpGlobals->curtime + m_flFireInterval;
  247. }
  248. m_nLastCompareResult = nCompare;
  249. }
  250. else if ((m_flFireTime != 0) && (gpGlobals->curtime >= m_flFireTime))
  251. {
  252. //
  253. // The compare result has held steady long enough -- time to
  254. // fire the output.
  255. //
  256. FireCompareOutput(nCompare, this);
  257. m_nLastFireResult = nCompare;
  258. m_flFireTime = 0;
  259. }
  260. SetNextThink( gpGlobals->curtime );
  261. }
  262. }
  263. //-----------------------------------------------------------------------------
  264. // Fires the output after the fire interval if the velocity is stable.
  265. //-----------------------------------------------------------------------------
  266. void CPointAngularVelocitySensor::InputTestWithInterval( inputdata_t &inputdata )
  267. {
  268. if (m_hTargetEntity != NULL)
  269. {
  270. m_flFireTime = gpGlobals->curtime + m_flFireInterval;
  271. m_nLastFireResult = AVELOCITY_SENSOR_NO_LAST_RESULT;
  272. m_nLastCompareResult = CompareToThreshold(m_hTargetEntity, m_flThreshold, true);
  273. SetNextThink( gpGlobals->curtime );
  274. }
  275. }
  276. //-----------------------------------------------------------------------------
  277. // Purpose: Input handler for forcing an instantaneous test of the condition.
  278. //-----------------------------------------------------------------------------
  279. void CPointAngularVelocitySensor::InputTest( inputdata_t &inputdata )
  280. {
  281. int nCompareResult = CompareToThreshold(m_hTargetEntity, m_flThreshold, false);
  282. FireCompareOutput(nCompareResult, inputdata.pActivator);
  283. }
  284. //-----------------------------------------------------------------------------
  285. // Purpose: Fires the appropriate output based on the given comparison result.
  286. // Input : nCompareResult -
  287. // pActivator -
  288. //-----------------------------------------------------------------------------
  289. void CPointAngularVelocitySensor::FireCompareOutput( int nCompareResult, CBaseEntity *pActivator )
  290. {
  291. if (nCompareResult == -1)
  292. {
  293. m_OnLessThan.FireOutput(pActivator, this);
  294. m_OnLessThanOrEqualTo.FireOutput(pActivator, this);
  295. }
  296. else if (nCompareResult == 1)
  297. {
  298. m_OnGreaterThan.FireOutput(pActivator, this);
  299. m_OnGreaterThanOrEqualTo.FireOutput(pActivator, this);
  300. }
  301. else
  302. {
  303. m_OnEqualTo.FireOutput(pActivator, this);
  304. m_OnLessThanOrEqualTo.FireOutput(pActivator, this);
  305. m_OnGreaterThanOrEqualTo.FireOutput(pActivator, this);
  306. }
  307. }
  308. // ============================================================================
  309. //
  310. // Simple velocity sensor
  311. //
  312. // ============================================================================
  313. class CPointVelocitySensor : public CPointEntity
  314. {
  315. DECLARE_CLASS( CPointVelocitySensor, CPointEntity );
  316. public:
  317. void Spawn();
  318. void Activate( void );
  319. void Think( void );
  320. private:
  321. void SampleVelocity( void );
  322. EHANDLE m_hTargetEntity; // Entity whose angles are being monitored.
  323. Vector m_vecAxis; // Axis along which to measure the speed.
  324. bool m_bEnabled; // Whether we're measuring or not
  325. // Outputs
  326. float m_fPrevVelocity; // stores velocity from last frame, so we only write the output if it has changed
  327. COutputFloat m_Velocity;
  328. void InputEnable( inputdata_t &inputdata );
  329. void InputDisable( inputdata_t &inputdata );
  330. DECLARE_DATADESC();
  331. };
  332. LINK_ENTITY_TO_CLASS( point_velocitysensor, CPointVelocitySensor );
  333. BEGIN_DATADESC( CPointVelocitySensor )
  334. // Fields
  335. DEFINE_FIELD( m_hTargetEntity, FIELD_EHANDLE ),
  336. DEFINE_KEYFIELD( m_vecAxis, FIELD_VECTOR, "axis" ),
  337. DEFINE_KEYFIELD( m_bEnabled, FIELD_BOOLEAN, "enabled" ),
  338. DEFINE_FIELD( m_fPrevVelocity, FIELD_FLOAT ),
  339. // Outputs
  340. DEFINE_OUTPUT( m_Velocity, "Velocity" ),
  341. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  342. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  343. END_DATADESC()
  344. //-----------------------------------------------------------------------------
  345. //-----------------------------------------------------------------------------
  346. void CPointVelocitySensor::Spawn()
  347. {
  348. Vector vLine = m_vecAxis - GetAbsOrigin();
  349. VectorNormalize( vLine );
  350. m_vecAxis = vLine;
  351. }
  352. //-----------------------------------------------------------------------------
  353. // Purpose:
  354. //-----------------------------------------------------------------------------
  355. void CPointVelocitySensor::Activate( void )
  356. {
  357. BaseClass::Activate();
  358. m_hTargetEntity = gEntList.FindEntityByName( NULL, m_target );
  359. if ( m_bEnabled && m_hTargetEntity )
  360. {
  361. SetNextThink( gpGlobals->curtime );
  362. }
  363. }
  364. //-----------------------------------------------------------------------------
  365. // Purpose:
  366. //-----------------------------------------------------------------------------
  367. void CPointVelocitySensor::InputEnable( inputdata_t &inputdata )
  368. {
  369. // Don't interrupt us if we're already enabled
  370. if ( m_bEnabled )
  371. return;
  372. m_bEnabled = true;
  373. if ( m_hTargetEntity )
  374. {
  375. SetNextThink( gpGlobals->curtime );
  376. }
  377. }
  378. //-----------------------------------------------------------------------------
  379. // Purpose:
  380. //-----------------------------------------------------------------------------
  381. void CPointVelocitySensor::InputDisable( inputdata_t &inputdata )
  382. {
  383. m_bEnabled = false;
  384. }
  385. //-----------------------------------------------------------------------------
  386. // Purpose: Called every frame
  387. //-----------------------------------------------------------------------------
  388. void CPointVelocitySensor::Think( void )
  389. {
  390. if ( m_hTargetEntity != NULL && m_bEnabled )
  391. {
  392. SampleVelocity();
  393. SetNextThink( gpGlobals->curtime );
  394. }
  395. }
  396. //-----------------------------------------------------------------------------
  397. // Purpose: Returns the magnitude of the entity's angular velocity.
  398. //-----------------------------------------------------------------------------
  399. void CPointVelocitySensor::SampleVelocity( void )
  400. {
  401. if ( m_hTargetEntity == NULL )
  402. return;
  403. Vector vecVelocity;
  404. if ( m_hTargetEntity->GetMoveType() == MOVETYPE_VPHYSICS )
  405. {
  406. IPhysicsObject *pPhys = m_hTargetEntity->VPhysicsGetObject();
  407. if ( pPhys != NULL )
  408. {
  409. pPhys->GetVelocity( &vecVelocity, NULL );
  410. }
  411. }
  412. else
  413. {
  414. vecVelocity = m_hTargetEntity->GetAbsVelocity();
  415. }
  416. /*
  417. float flSpeed = VectorNormalize( vecVelocity );
  418. float flDot = ( m_vecAxis != vec3_origin ) ? DotProduct( vecVelocity, m_vecAxis ) : 1.0f;
  419. */
  420. // We want the component of the velocity vector in the direction of the axis, which since the
  421. // axis is normalized is simply their dot product (eg V . A = |V|*|A|*cos(theta) )
  422. m_fPrevVelocity = ( m_vecAxis != vec3_origin ) ? DotProduct( vecVelocity, m_vecAxis ) : 1.0f;
  423. // if it's changed since the last frame, poke the output
  424. if ( m_fPrevVelocity != m_Velocity.Get() )
  425. {
  426. m_Velocity.Set( m_fPrevVelocity, NULL, NULL );
  427. }
  428. }