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

222 lines
6.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "game.h"
  9. #include "CRagdollMagnet.h"
  10. #include "cplane.h"
  11. ConVar ai_debug_ragdoll_magnets( "ai_debug_ragdoll_magnets", "0");
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. LINK_ENTITY_TO_CLASS( phys_ragdollmagnet, CRagdollMagnet );
  15. BEGIN_DATADESC( CRagdollMagnet )
  16. DEFINE_KEYFIELD( m_radius, FIELD_FLOAT, "radius" ),
  17. DEFINE_KEYFIELD( m_force, FIELD_FLOAT, "force" ),
  18. DEFINE_KEYFIELD( m_axis, FIELD_VECTOR, "axis" ),
  19. DEFINE_KEYFIELD( m_bDisabled, FIELD_BOOLEAN, "StartDisabled" ),
  20. DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  21. DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  22. END_DATADESC()
  23. //-----------------------------------------------------------------------------
  24. // Purpose:
  25. // Input : &inputdata -
  26. //-----------------------------------------------------------------------------
  27. void CRagdollMagnet::InputEnable( inputdata_t &inputdata )
  28. {
  29. Enable( true );
  30. }
  31. //-----------------------------------------------------------------------------
  32. // Purpose:
  33. // Input : &inputdata -
  34. //-----------------------------------------------------------------------------
  35. void CRagdollMagnet::InputDisable( inputdata_t &inputdata )
  36. {
  37. Enable( false );
  38. }
  39. //-----------------------------------------------------------------------------
  40. // Purpose: Find the ragdoll magnet entity that should pull this entity's ragdoll
  41. // Input : *pNPC - the npc that's dying
  42. // Output : CRagdollMagnet - the magnet that's best to use.
  43. //
  44. // NOTES:
  45. //
  46. // The nearest ragdoll magnet pulls me in IF:
  47. // - Present
  48. // - I'm within the magnet's RADIUS
  49. // - LATER: There is clear line of sight from my center to the magnet
  50. // - LATER: I'm not flagged to ignore ragdoll magnets
  51. // - LATER: The magnet is not turned OFF
  52. //-----------------------------------------------------------------------------
  53. CRagdollMagnet *CRagdollMagnet::FindBestMagnet( CBaseEntity *pNPC )
  54. {
  55. CRagdollMagnet *pMagnet = NULL;
  56. CRagdollMagnet *pBestMagnet;
  57. float flClosestDist;
  58. // Assume we won't find one.
  59. pBestMagnet = NULL;
  60. flClosestDist = FLT_MAX;
  61. do
  62. {
  63. pMagnet = (CRagdollMagnet *)gEntList.FindEntityByClassname( pMagnet, "phys_ragdollmagnet" );
  64. if( pMagnet && pMagnet->IsEnabled() )
  65. {
  66. if( pMagnet->m_target != NULL_STRING )
  67. {
  68. // if this magnet has a target, only affect that target!
  69. if( pNPC->GetEntityName() == pMagnet->m_target )
  70. {
  71. return pMagnet;
  72. }
  73. else
  74. {
  75. continue;
  76. }
  77. }
  78. float flDist;
  79. flDist = pMagnet->DistToPoint( pNPC->WorldSpaceCenter() );
  80. if( flDist < flClosestDist && flDist <= pMagnet->GetRadius() )
  81. {
  82. // This is the closest magnet that can pull this npc.
  83. flClosestDist = flDist;
  84. pBestMagnet = pMagnet;
  85. }
  86. }
  87. } while( pMagnet );
  88. return pBestMagnet;
  89. }
  90. //-----------------------------------------------------------------------------
  91. // Purpose: Get the force that we should add to this NPC's ragdoll.
  92. // Input : *pNPC -
  93. // Output : Vector
  94. //
  95. // NOTE: This function assumes pNPC is within this magnet's radius.
  96. //-----------------------------------------------------------------------------
  97. Vector CRagdollMagnet::GetForceVector( CBaseEntity *pNPC )
  98. {
  99. Vector vecForceToApply;
  100. if( IsBarMagnet() )
  101. {
  102. CPlane axis;
  103. Vector vecForceDir;
  104. Vector vecClosest;
  105. CalcClosestPointOnLineSegment( pNPC->WorldSpaceCenter(), GetAbsOrigin(), m_axis, vecClosest, NULL );
  106. vecForceDir = (vecClosest - pNPC->WorldSpaceCenter() );
  107. VectorNormalize( vecForceDir );
  108. vecForceToApply = vecForceDir * m_force;
  109. }
  110. else
  111. {
  112. Vector vecForce;
  113. vecForce = GetAbsOrigin() - pNPC->WorldSpaceCenter();
  114. VectorNormalize( vecForce );
  115. vecForceToApply = vecForce * m_force;
  116. }
  117. if( ai_debug_ragdoll_magnets.GetBool() )
  118. {
  119. IPhysicsObject *pPhysObject;
  120. pPhysObject = pNPC->VPhysicsGetObject();
  121. if( pPhysObject )
  122. {
  123. Msg("Ragdoll magnet adding %f inches/sec to %s\n", m_force/pPhysObject->GetMass(), pNPC->GetClassname() );
  124. }
  125. }
  126. return vecForceToApply;
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose: How far away is this point? This is different for point and bar magnets
  130. // Input : &vecPoint - the point
  131. // Output : float - the dist
  132. //-----------------------------------------------------------------------------
  133. float CRagdollMagnet::DistToPoint( const Vector &vecPoint )
  134. {
  135. if( IsBarMagnet() )
  136. {
  137. // I'm a bar magnet, so the point's distance is really the plane constant.
  138. // A bar magnet is a cylinder who's length is AbsOrigin() to m_axis, and whose
  139. // diameter is m_radius.
  140. // first we build two planes. The TOP and BOTTOM planes.
  141. // the idea is that vecPoint must be on the right side of both
  142. // planes to be affected by this particular magnet.
  143. // TOP and BOTTOM planes can be visualized as the 'caps' of the cylinder
  144. // that describes the bar magnet, and they point towards each other.
  145. // We're making sure vecPoint is between the caps.
  146. Vector vecAxis;
  147. vecAxis = GetAxisVector();
  148. VectorNormalize( vecAxis );
  149. CPlane top, bottom;
  150. bottom.InitializePlane( -vecAxis, m_axis );
  151. top.InitializePlane( vecAxis, GetAbsOrigin() );
  152. if( top.PointInFront( vecPoint ) && bottom.PointInFront( vecPoint ) )
  153. {
  154. // This point is between the two caps, so calculate the distance
  155. // of vecPoint from the axis of the bar magnet
  156. CPlane axis;
  157. Vector vecUp;
  158. Vector vecRight;
  159. // Horizontal and Vertical distances.
  160. float hDist, vDist;
  161. // Need to get a vector that's right-hand to m_axis
  162. VectorVectors( vecAxis, vecRight, vecUp );
  163. //CrossProduct( vecAxis, vecUp, vecRight );
  164. //VectorNormalize( vecRight );
  165. //VectorNormalize( vecUp );
  166. // Set up the plane to measure horizontal dist.
  167. axis.InitializePlane( vecRight, GetAbsOrigin() );
  168. hDist = fabs( axis.PointDist( vecPoint ) );
  169. axis.InitializePlane( vecUp, GetAbsOrigin() );
  170. vDist = fabs( axis.PointDist( vecPoint ) );
  171. return MAX( hDist, vDist );
  172. }
  173. else
  174. {
  175. return FLT_MAX;
  176. }
  177. }
  178. else
  179. {
  180. // I'm a point magnet. Just return dist
  181. return ( GetAbsOrigin() - vecPoint ).Length();
  182. }
  183. }