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.

266 lines
9.7 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Utility functions used by AI code.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "game.h"
  8. #include "vstdlib/random.h"
  9. #include "movevars_shared.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. #define NUM_LATERAL_CHECKS 13 // how many checks are made on each side of a NPC looking for lateral cover
  13. #define NUM_LATERAL_LOS_CHECKS 6 // how many checks are made on each side of a NPC looking for lateral cover
  14. #define TOSS_HEIGHT_MAX 300 // altitude of initial trace done to see how high something can be tossed
  15. //float flRandom = random->RandomFloat(0,1);
  16. bool g_fDrawLines = FALSE;
  17. //=========================================================
  18. // FBoxVisible - a more accurate ( and slower ) version
  19. // of FVisible.
  20. //
  21. // !!!UNDONE - make this CAI_BaseNPC?
  22. //=========================================================
  23. bool FBoxVisible( CBaseEntity *pLooker, CBaseEntity *pTarget, Vector &vecTargetOrigin, float flSize )
  24. {
  25. // don't look through water
  26. if ((pLooker->GetWaterLevel() != 3 && pTarget->GetWaterLevel() == 3)
  27. || (pLooker->GetWaterLevel() == 3 && pTarget->GetWaterLevel() == 0))
  28. return FALSE;
  29. trace_t tr;
  30. Vector vecLookerOrigin = pLooker->EyePosition();//look through the NPC's 'eyes'
  31. for (int i = 0; i < 5; i++)
  32. {
  33. Vector vecTarget = pTarget->GetAbsOrigin();
  34. vecTarget.x += random->RandomFloat( pTarget->WorldAlignMins().x + flSize, pTarget->WorldAlignMaxs().x - flSize);
  35. vecTarget.y += random->RandomFloat( pTarget->WorldAlignMins().y + flSize, pTarget->WorldAlignMaxs().y - flSize);
  36. vecTarget.z += random->RandomFloat( pTarget->WorldAlignMins().z + flSize, pTarget->WorldAlignMaxs().z - flSize);
  37. UTIL_TraceLine(vecLookerOrigin, vecTarget, MASK_BLOCKLOS, pLooker, COLLISION_GROUP_NONE, &tr);
  38. if (tr.fraction == 1.0)
  39. {
  40. vecTargetOrigin = vecTarget;
  41. return TRUE;// line of sight is valid.
  42. }
  43. }
  44. return FALSE;// Line of sight is not established
  45. }
  46. //-----------------------------------------------------------------------------
  47. // Purpose: Returns the correct toss velocity to throw a given object at a point.
  48. // Like the other version of VecCheckToss, but allows you to filter for any
  49. // number of entities to ignore.
  50. // Input : pEntity - The object doing the throwing. Is *NOT* automatically included in the
  51. // filter below.
  52. // pFilter - A trace filter of entities to ignore in the object's collision sweeps.
  53. // It is recommended to include at least the thrower.
  54. // vecSpot1 - The point from which the object is being thrown.
  55. // vecSpot2 - The point TO which the object is being thrown.
  56. // flHeightMaxRatio - A scale factor indicating the maximum ratio of height
  57. // to total throw distance, measured from the higher of the two endpoints to
  58. // the apex. -1 indicates that there is no maximum.
  59. // flGravityAdj - Scale factor for gravity - should match the gravity scale
  60. // that the object will use in midair.
  61. // bRandomize - when true, introduces a little fudge to the throw
  62. // Output : Velocity to throw the object with.
  63. //-----------------------------------------------------------------------------
  64. Vector VecCheckToss( CBaseEntity *pEntity, ITraceFilter *pFilter, Vector vecSpot1, Vector vecSpot2, float flHeightMaxRatio, float flGravityAdj, bool bRandomize, Vector *vecMins, Vector *vecMaxs )
  65. {
  66. trace_t tr;
  67. Vector vecMidPoint;// halfway point between Spot1 and Spot2
  68. Vector vecApex;// highest point
  69. Vector vecScale;
  70. Vector vecTossVel;
  71. Vector vecTemp;
  72. float flGravity = GetCurrentGravity() * flGravityAdj;
  73. if (vecSpot2.z - vecSpot1.z > 500)
  74. {
  75. // to high, fail
  76. return vec3_origin;
  77. }
  78. Vector forward, right;
  79. AngleVectors( pEntity->GetLocalAngles(), &forward, &right, NULL );
  80. if (bRandomize)
  81. {
  82. // toss a little bit to the left or right, not right down on the enemy's bean (head).
  83. vecSpot2 += right * ( random->RandomFloat(-8,8) + random->RandomFloat(-16,16) );
  84. vecSpot2 += forward * ( random->RandomFloat(-8,8) + random->RandomFloat(-16,16) );
  85. }
  86. // calculate the midpoint and apex of the 'triangle'
  87. // UNDONE: normalize any Z position differences between spot1 and spot2 so that triangle is always RIGHT
  88. // get a rough idea of how high it can be thrown
  89. vecMidPoint = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
  90. UTIL_TraceLine(vecMidPoint, vecMidPoint + Vector(0,0,TOSS_HEIGHT_MAX), MASK_SOLID_BRUSHONLY, pFilter, &tr);
  91. vecMidPoint = tr.endpos;
  92. if( tr.fraction != 1.0 )
  93. {
  94. // (subtract 15 so the object doesn't hit the ceiling)
  95. vecMidPoint.z -= 15;
  96. }
  97. if (flHeightMaxRatio != -1)
  98. {
  99. // But don't throw so high that it looks silly. Maximize the height of the
  100. // throw above the highest of the two endpoints to a ratio of the throw length.
  101. float flHeightMax = flHeightMaxRatio * (vecSpot2 - vecSpot1).Length();
  102. float flHighestEndZ = MAX(vecSpot1.z, vecSpot2.z);
  103. if ((vecMidPoint.z - flHighestEndZ) > flHeightMax)
  104. {
  105. vecMidPoint.z = flHighestEndZ + flHeightMax;
  106. }
  107. }
  108. if (vecMidPoint.z < vecSpot1.z || vecMidPoint.z < vecSpot2.z)
  109. {
  110. // Not enough space, fail
  111. return vec3_origin;
  112. }
  113. // How high should the object travel to reach the apex
  114. float distance1 = (vecMidPoint.z - vecSpot1.z);
  115. float distance2 = (vecMidPoint.z - vecSpot2.z);
  116. // How long will it take for the object to travel this distance
  117. float time1 = sqrt( distance1 / (0.5 * flGravity) );
  118. float time2 = sqrt( distance2 / (0.5 * flGravity) );
  119. if (time1 < 0.1)
  120. {
  121. // too close
  122. return vec3_origin;
  123. }
  124. // how hard to throw sideways to get there in time.
  125. vecTossVel = (vecSpot2 - vecSpot1) / (time1 + time2);
  126. // how hard upwards to reach the apex at the right time.
  127. vecTossVel.z = flGravity * time1;
  128. // find the apex
  129. vecApex = vecSpot1 + vecTossVel * time1;
  130. vecApex.z = vecMidPoint.z;
  131. // JAY: Repro behavior from HL1 -- toss check went through gratings
  132. UTIL_TraceLine(vecSpot1, vecApex, (MASK_SOLID&(~CONTENTS_GRATE)), pFilter, &tr);
  133. if (tr.fraction != 1.0)
  134. {
  135. // fail!
  136. return vec3_origin;
  137. }
  138. // UNDONE: either ignore NPCs or change it to not care if we hit our enemy
  139. UTIL_TraceLine(vecSpot2, vecApex, (MASK_SOLID_BRUSHONLY&(~CONTENTS_GRATE)), pFilter, &tr);
  140. if (tr.fraction != 1.0)
  141. {
  142. // fail!
  143. return vec3_origin;
  144. }
  145. if ( vecMins && vecMaxs )
  146. {
  147. // Check to ensure the entity's hull can travel the first half of the grenade throw
  148. UTIL_TraceHull( vecSpot1, vecApex, *vecMins, *vecMaxs, (MASK_SOLID&(~CONTENTS_GRATE)), pFilter, &tr);
  149. if ( tr.fraction < 1.0 )
  150. return vec3_origin;
  151. }
  152. return vecTossVel;
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Purpose: Returns the correct toss velocity to throw a given object at a point.
  156. // Input : pEntity - The entity that is throwing the object.
  157. // vecSpot1 - The point from which the object is being thrown.
  158. // vecSpot2 - The point TO which the object is being thrown.
  159. // flHeightMaxRatio - A scale factor indicating the maximum ratio of height
  160. // to total throw distance, measured from the higher of the two endpoints to
  161. // the apex. -1 indicates that there is no maximum.
  162. // flGravityAdj - Scale factor for gravity - should match the gravity scale
  163. // that the object will use in midair.
  164. // bRandomize - when true, introduces a little fudge to the throw
  165. // Output : Velocity to throw the object with.
  166. //-----------------------------------------------------------------------------
  167. Vector VecCheckToss( CBaseEntity *pEntity, Vector vecSpot1, Vector vecSpot2, float flHeightMaxRatio, float flGravityAdj, bool bRandomize, Vector *vecMins, Vector *vecMaxs )
  168. {
  169. // construct a filter and call through to the other version of this function.
  170. CTraceFilterSimple traceFilter( pEntity, COLLISION_GROUP_NONE );
  171. return VecCheckToss( pEntity, &traceFilter, vecSpot1, vecSpot2,
  172. flHeightMaxRatio, flGravityAdj, bRandomize,
  173. vecMins, vecMaxs );
  174. }
  175. //
  176. // VecCheckThrow - returns the velocity vector at which an object should be thrown from vecspot1 to hit vecspot2.
  177. // returns vec3_origin if throw is not feasible.
  178. //
  179. Vector VecCheckThrow ( CBaseEntity *pEdict, const Vector &vecSpot1, Vector vecSpot2, float flSpeed, float flGravityAdj, Vector *vecMins, Vector *vecMaxs )
  180. {
  181. float flGravity = GetCurrentGravity() * flGravityAdj;
  182. Vector vecGrenadeVel = (vecSpot2 - vecSpot1);
  183. // throw at a constant time
  184. float time = vecGrenadeVel.Length( ) / flSpeed;
  185. vecGrenadeVel = vecGrenadeVel * (1.0 / time);
  186. // adjust upward toss to compensate for gravity loss
  187. vecGrenadeVel.z += flGravity * time * 0.5;
  188. Vector vecApex = vecSpot1 + (vecSpot2 - vecSpot1) * 0.5;
  189. vecApex.z += 0.5 * flGravity * (time * 0.5) * (time * 0.5);
  190. trace_t tr;
  191. UTIL_TraceLine(vecSpot1, vecApex, MASK_SOLID, pEdict, COLLISION_GROUP_NONE, &tr);
  192. if (tr.fraction != 1.0)
  193. {
  194. // fail!
  195. //NDebugOverlay::Line( vecSpot1, vecApex, 255, 0, 0, true, 5.0 );
  196. return vec3_origin;
  197. }
  198. //NDebugOverlay::Line( vecSpot1, vecApex, 0, 255, 0, true, 5.0 );
  199. UTIL_TraceLine(vecSpot2, vecApex, MASK_SOLID_BRUSHONLY, pEdict, COLLISION_GROUP_NONE, &tr);
  200. if (tr.fraction != 1.0)
  201. {
  202. // fail!
  203. //NDebugOverlay::Line( vecApex, vecSpot2, 255, 0, 0, true, 5.0 );
  204. return vec3_origin;
  205. }
  206. //NDebugOverlay::Line( vecApex, vecSpot2, 0, 255, 0, true, 5.0 );
  207. if ( vecMins && vecMaxs )
  208. {
  209. // Check to ensure the entity's hull can travel the first half of the grenade throw
  210. UTIL_TraceHull( vecSpot1, vecApex, *vecMins, *vecMaxs, MASK_SOLID, pEdict, COLLISION_GROUP_NONE, &tr);
  211. if ( tr.fraction < 1.0 )
  212. {
  213. //NDebugOverlay::SweptBox( vecSpot1, tr.endpos, *vecMins, *vecMaxs, vec3_angle, 255, 0, 0, 64, 5.0 );
  214. return vec3_origin;
  215. }
  216. }
  217. //NDebugOverlay::SweptBox( vecSpot1, vecApex, *vecMins, *vecMaxs, vec3_angle, 0, 255, 0, 64, 5.0 );
  218. return vecGrenadeVel;
  219. }