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.

382 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Base class for many flying NPCs
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "ai_basenpc_physicsflyer.h"
  9. #include "ai_route.h"
  10. #include "ai_navigator.h"
  11. #include "ai_motor.h"
  12. #include "physics_saverestore.h"
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. BEGIN_DATADESC( CAI_BasePhysicsFlyingBot )
  16. DEFINE_FIELD( m_vCurrentVelocity, FIELD_VECTOR),
  17. DEFINE_FIELD( m_vCurrentBanking, FIELD_VECTOR),
  18. DEFINE_FIELD( m_vNoiseMod, FIELD_VECTOR),
  19. DEFINE_FIELD( m_fHeadYaw, FIELD_FLOAT),
  20. DEFINE_FIELD( m_vLastPatrolDir, FIELD_VECTOR),
  21. DEFINE_PHYSPTR( m_pMotionController ),
  22. END_DATADESC()
  23. //------------------------------------------------------------------------------
  24. // Purpose : Override to return correct velocity
  25. // Input :
  26. // Output :
  27. //------------------------------------------------------------------------------
  28. void CAI_BasePhysicsFlyingBot::GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity)
  29. {
  30. Assert( GetMoveType() == MOVETYPE_VPHYSICS );
  31. if ( VPhysicsGetObject() )
  32. {
  33. VPhysicsGetObject()->GetVelocity( vVelocity, vAngVelocity );
  34. }
  35. else
  36. {
  37. if ( vVelocity )
  38. {
  39. vVelocity->Init();
  40. }
  41. if ( vAngVelocity )
  42. {
  43. vAngVelocity->Init();
  44. }
  45. }
  46. }
  47. //-----------------------------------------------------------------------------
  48. // Purpose: Turn head yaw into facing direction
  49. // Input :
  50. // Output :
  51. //-----------------------------------------------------------------------------
  52. QAngle CAI_BasePhysicsFlyingBot::BodyAngles()
  53. {
  54. return QAngle(0,m_fHeadYaw,0);
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Purpose:
  58. // Input :
  59. // Output :
  60. //-----------------------------------------------------------------------------
  61. void CAI_BasePhysicsFlyingBot::TurnHeadToTarget(float flInterval, const Vector &MoveTarget )
  62. {
  63. float desYaw = UTIL_AngleDiff(VecToYaw(MoveTarget - GetLocalOrigin()), 0 );
  64. m_fHeadYaw = desYaw;
  65. return;
  66. // If I've flipped completely around, reverse angles
  67. float fYawDiff = m_fHeadYaw - desYaw;
  68. if (fYawDiff > 180)
  69. {
  70. m_fHeadYaw -= 360;
  71. }
  72. else if (fYawDiff < -180)
  73. {
  74. m_fHeadYaw += 360;
  75. }
  76. // RIGHT NOW, this affects every flying bot. This rate should be member data that individuals
  77. // can manipulate. THIS change for MANHACKS E3 2003 (sjb)
  78. float iRate = 0.8;
  79. // Make frame rate independent
  80. float timeToUse = flInterval;
  81. while (timeToUse > 0)
  82. {
  83. m_fHeadYaw = (iRate * m_fHeadYaw) + (1-iRate)*desYaw;
  84. timeToUse -= 0.1;
  85. }
  86. while( m_fHeadYaw > 360 )
  87. {
  88. m_fHeadYaw -= 360.0f;
  89. }
  90. while( m_fHeadYaw < 0 )
  91. {
  92. m_fHeadYaw += 360.f;
  93. }
  94. // SetBoneController( 0, m_fHeadYaw );
  95. }
  96. //------------------------------------------------------------------------------
  97. // Purpose :
  98. // Input :
  99. // Output :
  100. //------------------------------------------------------------------------------
  101. float CAI_BasePhysicsFlyingBot::MinGroundDist(void)
  102. {
  103. return 0;
  104. }
  105. //------------------------------------------------------------------------------
  106. // Purpose :
  107. // Input :
  108. // Output :
  109. //------------------------------------------------------------------------------
  110. Vector CAI_BasePhysicsFlyingBot::VelocityToAvoidObstacles(float flInterval)
  111. {
  112. // --------------------------------
  113. // Avoid banging into stuff
  114. // --------------------------------
  115. trace_t tr;
  116. Vector vTravelDir = m_vCurrentVelocity*flInterval;
  117. Vector endPos = GetAbsOrigin() + vTravelDir;
  118. AI_TraceEntity( this, GetAbsOrigin(), endPos, MASK_NPCSOLID|CONTENTS_WATER, &tr);
  119. if (tr.fraction != 1.0)
  120. {
  121. // Bounce off in normal
  122. Vector vBounce = tr.plane.normal * 0.5 * m_vCurrentVelocity.Length();
  123. return (vBounce);
  124. }
  125. // --------------------------------
  126. // Try to remain above the ground.
  127. // --------------------------------
  128. float flMinGroundDist = MinGroundDist();
  129. AI_TraceLine(GetAbsOrigin(), GetAbsOrigin() + Vector(0, 0, -flMinGroundDist),
  130. MASK_NPCSOLID_BRUSHONLY|CONTENTS_WATER, this, COLLISION_GROUP_NONE, &tr);
  131. if (tr.fraction < 1)
  132. {
  133. // Clamp veloctiy
  134. if (tr.fraction < 0.1)
  135. {
  136. tr.fraction = 0.1;
  137. }
  138. return Vector(0, 0, 50/tr.fraction);
  139. }
  140. return vec3_origin;
  141. }
  142. //------------------------------------------------------------------------------
  143. // Purpose :
  144. // Input :
  145. // Output :
  146. //------------------------------------------------------------------------------
  147. void CAI_BasePhysicsFlyingBot::StartTask( const Task_t *pTask )
  148. {
  149. switch (pTask->iTask)
  150. {
  151. // Skip as done via bone controller
  152. case TASK_FACE_ENEMY:
  153. {
  154. TaskComplete();
  155. break;
  156. }
  157. // Activity is just idle (have no run)
  158. case TASK_RUN_PATH:
  159. {
  160. GetNavigator()->SetMovementActivity(ACT_IDLE);
  161. TaskComplete();
  162. break;
  163. }
  164. // Don't check for run/walk activity
  165. case TASK_SCRIPT_RUN_TO_TARGET:
  166. case TASK_SCRIPT_WALK_TO_TARGET:
  167. {
  168. if (GetTarget() == NULL)
  169. {
  170. TaskFail(FAIL_NO_TARGET);
  171. }
  172. else
  173. {
  174. if (!GetNavigator()->SetGoal( GOALTYPE_TARGETENT ) )
  175. {
  176. TaskFail(FAIL_NO_ROUTE);
  177. GetNavigator()->ClearGoal();
  178. }
  179. }
  180. TaskComplete();
  181. break;
  182. }
  183. // Override to get more to get a directional path
  184. case TASK_GET_PATH_TO_RANDOM_NODE:
  185. {
  186. if ( GetNavigator()->SetRandomGoal( pTask->flTaskData, m_vLastPatrolDir ) )
  187. TaskComplete();
  188. else
  189. TaskFail(FAIL_NO_REACHABLE_NODE);
  190. break;
  191. }
  192. default:
  193. {
  194. BaseClass::StartTask(pTask);
  195. }
  196. }
  197. }
  198. //------------------------------------------------------------------------------
  199. void CAI_BasePhysicsFlyingBot::MoveToTarget(float flInterval, const Vector &MoveTarget)
  200. {
  201. Assert(0); // This must be overridden in the leaf classes
  202. }
  203. //------------------------------------------------------------------------------
  204. AI_NavPathProgress_t CAI_BasePhysicsFlyingBot::ProgressFlyPath(
  205. float flInterval,
  206. const CBaseEntity *pNewTarget,
  207. unsigned collisionMask,
  208. bool bNewTrySimplify,
  209. float strictPointTolerance)
  210. {
  211. AI_ProgressFlyPathParams_t params( collisionMask );
  212. params.strictPointTolerance = strictPointTolerance;
  213. params.SetCurrent( pNewTarget, bNewTrySimplify );
  214. AI_NavPathProgress_t progress = GetNavigator()->ProgressFlyPath( params );
  215. switch ( progress )
  216. {
  217. case AINPP_NO_CHANGE:
  218. case AINPP_ADVANCED:
  219. {
  220. MoveToTarget(flInterval, GetNavigator()->GetCurWaypointPos());
  221. break;
  222. }
  223. case AINPP_COMPLETE:
  224. {
  225. TaskMovementComplete();
  226. break;
  227. }
  228. case AINPP_BLOCKED: // function is not supposed to test blocking, just simple path progression
  229. default:
  230. {
  231. AssertMsg( 0, ( "Unexpected result" ) );
  232. break;
  233. }
  234. }
  235. return progress;
  236. }
  237. //------------------------------------------------------------------------------
  238. // Purpose :
  239. // Input :
  240. // Output :
  241. //------------------------------------------------------------------------------
  242. CAI_BasePhysicsFlyingBot::CAI_BasePhysicsFlyingBot()
  243. {
  244. #ifdef _DEBUG
  245. m_vCurrentVelocity.Init();
  246. m_vCurrentBanking.Init();
  247. m_vLastPatrolDir.Init();
  248. #endif
  249. }
  250. //-----------------------------------------------------------------------------
  251. //-----------------------------------------------------------------------------
  252. CAI_BasePhysicsFlyingBot::~CAI_BasePhysicsFlyingBot( void )
  253. {
  254. physenv->DestroyMotionController( m_pMotionController );
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Purpose:
  258. //
  259. //
  260. //-----------------------------------------------------------------------------
  261. bool CAI_BasePhysicsFlyingBot::CreateVPhysics( void )
  262. {
  263. // Create the object in the physics system
  264. IPhysicsObject *pPhysicsObject = VPhysicsInitNormal( SOLID_BBOX, FSOLID_NOT_STANDABLE, false );
  265. m_pMotionController = physenv->CreateMotionController( this );
  266. m_pMotionController->AttachObject( pPhysicsObject, true );
  267. return true;
  268. }
  269. //-----------------------------------------------------------------------------
  270. // Purpose:
  271. // Input : *pTarget -
  272. // &chasePosition -
  273. //-----------------------------------------------------------------------------
  274. void CAI_BasePhysicsFlyingBot::TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition )
  275. {
  276. Assert( pTarget != NULL );
  277. if ( pTarget == NULL )
  278. {
  279. chasePosition = vec3_origin;
  280. return;
  281. }
  282. // Chase their eyes
  283. chasePosition = pTarget->GetAbsOrigin() + pTarget->GetViewOffset();
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Purpose:
  287. // Input : *pController -
  288. // *pObject -
  289. // deltaTime -
  290. // &linear -
  291. // &angular -
  292. // Output : IMotionEvent::simresult_e
  293. //-----------------------------------------------------------------------------
  294. IMotionEvent::simresult_e CAI_BasePhysicsFlyingBot::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular )
  295. {
  296. static int count;
  297. IPhysicsObject *pPhysicsObject = VPhysicsGetObject();
  298. // Assert( pPhysicsObject );
  299. if (!pPhysicsObject)
  300. return SIM_NOTHING;
  301. // move
  302. Vector actualVelocity;
  303. AngularImpulse actualAngularVelocity;
  304. pPhysicsObject->GetVelocity( &actualVelocity, &actualAngularVelocity );
  305. linear = (m_vCurrentVelocity - actualVelocity) * (0.1 / deltaTime) * 10.0;
  306. /*
  307. DevMsg("Sim %d : %5.1f %5.1f %5.1f\n", count++,
  308. m_vCurrentVelocity.x - actualVelocity.x,
  309. m_vCurrentVelocity.y - actualVelocity.y,
  310. m_vCurrentVelocity.z - actualVelocity.z );
  311. */
  312. // do angles.
  313. Vector actualPosition;
  314. QAngle actualAngles;
  315. pPhysicsObject->GetPosition( &actualPosition, &actualAngles );
  316. // FIXME: banking currently disabled, forces simple upright posture
  317. angular.x = (UTIL_AngleDiff( m_vCurrentBanking.z, actualAngles.z ) - actualAngularVelocity.x) * (1 / deltaTime);
  318. angular.y = (UTIL_AngleDiff( m_vCurrentBanking.x, actualAngles.x ) - actualAngularVelocity.y) * (1 / deltaTime);
  319. // turn toward target
  320. angular.z = UTIL_AngleDiff( m_fHeadYaw, actualAngles.y + actualAngularVelocity.z * 0.1 ) * (1 / deltaTime);
  321. // angular = m_vCurrentAngularVelocity - actualAngularVelocity;
  322. // DevMsg("Sim %d : %.1f %.1f %.1f (%.1f)\n", count++, actualAngles.x, actualAngles.y, actualAngles.z, m_fHeadYaw );
  323. // FIXME: remove the stuff from MoveExecute();
  324. // FIXME: check MOVE?
  325. ClampMotorForces( linear, angular );
  326. return SIM_GLOBAL_ACCELERATION; // on my local axis. SIM_GLOBAL_ACCELERATION
  327. }