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.

350 lines
11 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: AI Utility classes for building the initial AI Networks
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. //
  8. //-----------------------------------------------------------------------------
  9. // $Log: $
  10. //
  11. // $NoKeywords: $
  12. //=============================================================================//
  13. #include "cbase.h"
  14. #include "ai_node.h"
  15. #include "ai_hull.h"
  16. #include "ai_hint.h"
  17. #include "ai_initutils.h"
  18. #include "ai_networkmanager.h"
  19. // to help eliminate node clutter by level designers, this is used to cap how many other nodes
  20. // any given node is allowed to 'see' in the first stage of graph creation "LinkVisibleNodes()".
  21. #include "ai_network.h"
  22. // memdbgon must be the last include file in a .cpp file!!!
  23. #include "tier0/memdbgon.h"
  24. LINK_ENTITY_TO_CLASS( info_hint, CNodeEnt );
  25. LINK_ENTITY_TO_CLASS( info_node, CNodeEnt );
  26. LINK_ENTITY_TO_CLASS( info_node_hint, CNodeEnt );
  27. LINK_ENTITY_TO_CLASS( info_node_air, CNodeEnt );
  28. LINK_ENTITY_TO_CLASS( info_node_air_hint, CNodeEnt );
  29. LINK_ENTITY_TO_CLASS( info_node_climb, CNodeEnt );
  30. LINK_ENTITY_TO_CLASS( aitesthull, CAI_TestHull );
  31. //-----------------------------------------------------------------------------
  32. // Init static variables
  33. //-----------------------------------------------------------------------------
  34. CAI_TestHull* CAI_TestHull::pTestHull = NULL;
  35. #ifdef CSTRIKE_DLL
  36. #define PLAYER_MODEL "models/player/ct_urban.mdl"
  37. #else
  38. #define PLAYER_MODEL "models/player.mdl"
  39. #endif
  40. //-----------------------------------------------------------------------------
  41. // Purpose: Make sure we have a "player.mdl" hull to test with
  42. //-----------------------------------------------------------------------------
  43. void CAI_TestHull::Precache()
  44. {
  45. BaseClass::Precache();
  46. PrecacheModel( PLAYER_MODEL );
  47. }
  48. //=========================================================
  49. // CAI_TestHull::Spawn
  50. //=========================================================
  51. void CAI_TestHull::Spawn(void)
  52. {
  53. Precache();
  54. SetModel( PLAYER_MODEL );
  55. // Set an initial hull size (this will change later)
  56. SetHullType(HULL_HUMAN);
  57. SetHullSizeNormal();
  58. SetSolid( SOLID_BBOX );
  59. AddSolidFlags( FSOLID_NOT_SOLID );
  60. SetMoveType( MOVETYPE_STEP );
  61. m_iHealth = 50;
  62. bInUse = false;
  63. // Make this invisible
  64. AddEffects( EF_NODRAW );
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose: Get the test hull (create if none)
  68. // Input :
  69. // Output :
  70. //-----------------------------------------------------------------------------
  71. CAI_TestHull* CAI_TestHull::GetTestHull(void)
  72. {
  73. if (!CAI_TestHull::pTestHull)
  74. {
  75. CAI_TestHull::pTestHull = CREATE_ENTITY( CAI_TestHull, "aitesthull" );
  76. CAI_TestHull::pTestHull->Spawn();
  77. CAI_TestHull::pTestHull->AddFlag( FL_NPC );
  78. }
  79. if (CAI_TestHull::pTestHull->bInUse == true)
  80. {
  81. DevMsg("WARNING: TestHull used and never returned!\n");
  82. Assert( 0 );
  83. }
  84. CAI_TestHull::pTestHull->RemoveSolidFlags( FSOLID_NOT_SOLID );
  85. CAI_TestHull::pTestHull->bInUse = true;
  86. return CAI_TestHull::pTestHull;
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Purpose: Get the test hull (create if none)
  90. // Input :
  91. // Output :
  92. //-----------------------------------------------------------------------------
  93. void CAI_TestHull::ReturnTestHull(void)
  94. {
  95. CAI_TestHull::pTestHull->bInUse = false;
  96. CAI_TestHull::pTestHull->AddSolidFlags( FSOLID_NOT_SOLID );
  97. UTIL_SetSize(CAI_TestHull::pTestHull, vec3_origin, vec3_origin);
  98. UTIL_RemoveImmediate( pTestHull );
  99. pTestHull = NULL;
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose:
  103. // Input : &startPos -
  104. // &endPos -
  105. // Output : Returns true on success, false on failure.
  106. //-----------------------------------------------------------------------------
  107. bool CAI_TestHull::IsJumpLegal(const Vector &startPos, const Vector &apex, const Vector &endPos) const
  108. {
  109. const float MAX_JUMP_RISE = 1024.0f;
  110. const float MAX_JUMP_DISTANCE = 1024.0f;
  111. const float MAX_JUMP_DROP = 1024.0f;
  112. return BaseClass::IsJumpLegal( startPos, apex, endPos, MAX_JUMP_RISE, MAX_JUMP_DISTANCE, MAX_JUMP_DROP );
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose:
  116. // Input :
  117. // Output :
  118. //-----------------------------------------------------------------------------
  119. CAI_TestHull::~CAI_TestHull(void)
  120. {
  121. CAI_TestHull::pTestHull = NULL;
  122. }
  123. //###########################################################
  124. // > CNodeEnt
  125. //
  126. // nodes start out as ents in the world. As they are spawned,
  127. // the node info is recorded then the ents are discarded.
  128. //###########################################################
  129. //----------------------------------------------------
  130. // Static vars
  131. //----------------------------------------------------
  132. int CNodeEnt::m_nNodeCount = 0;
  133. // -------------
  134. // Data table
  135. // -------------
  136. BEGIN_SIMPLE_DATADESC( HintNodeData )
  137. DEFINE_FIELD( strEntityName, FIELD_STRING ),
  138. // DEFINE_FIELD( vecPosition, FIELD_VECTOR ), // Don't save
  139. DEFINE_KEYFIELD( nHintType, FIELD_SHORT, "hinttype" ),
  140. DEFINE_KEYFIELD( strGroup, FIELD_STRING, "Group" ),
  141. DEFINE_KEYFIELD( iDisabled, FIELD_INTEGER, "StartHintDisabled" ),
  142. DEFINE_FIELD( nNodeID, FIELD_INTEGER ),
  143. DEFINE_KEYFIELD( iszGenericType, FIELD_STRING, "generictype" ),
  144. DEFINE_KEYFIELD( iszActivityName, FIELD_STRING, "hintactivity" ),
  145. DEFINE_KEYFIELD( nTargetWCNodeID, FIELD_INTEGER, "TargetNode" ),
  146. DEFINE_KEYFIELD( nWCNodeID, FIELD_INTEGER, "nodeid" ),
  147. DEFINE_KEYFIELD( fIgnoreFacing, FIELD_INTEGER, "IgnoreFacing" ),
  148. DEFINE_KEYFIELD( minState, FIELD_INTEGER, "MinimumState" ),
  149. DEFINE_KEYFIELD( maxState, FIELD_INTEGER, "MaximumState" ),
  150. DEFINE_KEYFIELD( nRadius, FIELD_INTEGER, "radius" ),
  151. END_DATADESC()
  152. // -------------
  153. // Data table
  154. // -------------
  155. BEGIN_DATADESC( CNodeEnt )
  156. DEFINE_EMBEDDED( m_NodeData ),
  157. END_DATADESC()
  158. //=========================================================
  159. //=========================================================
  160. void CNodeEnt::Spawn( void )
  161. {
  162. Spawn( NULL );
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose:
  166. // Input : *pMapData -
  167. //-----------------------------------------------------------------------------
  168. int CNodeEnt::Spawn( const char *pMapData )
  169. {
  170. m_NodeData.strEntityName = GetEntityName();
  171. m_NodeData.vecPosition = GetAbsOrigin();
  172. m_NodeData.nNodeID = NO_NODE;
  173. if ( m_NodeData.minState == NPC_STATE_NONE )
  174. m_NodeData.minState = NPC_STATE_IDLE;
  175. if ( m_NodeData.maxState == NPC_STATE_NONE )
  176. m_NodeData.maxState = NPC_STATE_COMBAT;
  177. // ---------------------------------------------------------------------------------
  178. // If just a hint node (not used for navigation) just create a hint and bail
  179. // ---------------------------------------------------------------------------------
  180. if (FClassnameIs( this, "info_hint" ))
  181. {
  182. if (m_NodeData.nHintType)
  183. {
  184. CAI_HintManager::CreateHint( &m_NodeData, pMapData );
  185. }
  186. else
  187. {
  188. Warning("info_hint (HammerID: %d, position (%.2f, %.2f, %.2f)) with no hint type.\n", m_NodeData.nWCNodeID, m_NodeData.vecPosition.x, m_NodeData.vecPosition.y, m_NodeData.vecPosition.z );
  189. }
  190. UTIL_RemoveImmediate( this );
  191. return -1;
  192. }
  193. // ---------------------------------------------------------------------------------
  194. // First check if this node has a hint. If so create a hint entity
  195. // ---------------------------------------------------------------------------------
  196. CAI_Hint *pHint = NULL;
  197. if ( ClassMatches( "info_node_hint" ) || ClassMatches( "info_node_air_hint" ) )
  198. {
  199. if ( m_NodeData.nHintType || m_NodeData.strGroup != NULL_STRING || m_NodeData.strEntityName != NULL_STRING )
  200. {
  201. m_NodeData.nNodeID = m_nNodeCount;
  202. pHint = CAI_HintManager::CreateHint( &m_NodeData, pMapData );
  203. pHint->AddSpawnFlags( GetSpawnFlags() );
  204. }
  205. }
  206. // ---------------------------------------------------------------------------------
  207. // If we loaded from disk, we can discard all these node ents as soon as they spawn
  208. // unless we are in WC edited mode
  209. // ---------------------------------------------------------------------------------
  210. if ( g_pAINetworkManager->NetworksLoaded() && !engine->IsInEditMode())
  211. {
  212. // If hint exists for this node, set it
  213. if (pHint)
  214. {
  215. CAI_Node *pNode = g_pBigAINet->GetNode(m_nNodeCount);
  216. if (pNode)
  217. pNode->SetHint( pHint );
  218. else
  219. {
  220. DevMsg("AI node graph corrupt\n");
  221. }
  222. }
  223. m_nNodeCount++;
  224. UTIL_RemoveImmediate( this );
  225. return -1;
  226. }
  227. else
  228. {
  229. m_nNodeCount++;
  230. }
  231. // ---------------------------------------------------------------------------------
  232. // Add a new node to the network
  233. // ---------------------------------------------------------------------------------
  234. // For now just using one big AI network
  235. CAI_Node *new_node = g_pBigAINet->AddNode( GetAbsOrigin(), GetAbsAngles().y );
  236. new_node->SetHint( pHint );
  237. // -------------------------------------------------------------------------
  238. // Update table of how each WC id relates to each engine ID
  239. // -------------------------------------------------------------------------
  240. if (g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable)
  241. {
  242. g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[new_node->GetId()] = m_NodeData.nWCNodeID;
  243. }
  244. // Keep track of largest index used by WC
  245. if (g_pAINetworkManager->GetEditOps()->m_nNextWCIndex <= m_NodeData.nWCNodeID)
  246. {
  247. g_pAINetworkManager->GetEditOps()->m_nNextWCIndex = m_NodeData.nWCNodeID+1;
  248. }
  249. // -------------------------------------------------------------------------
  250. // If in WC edit mode:
  251. // Remember the original positions of the nodes before
  252. // they drop so we can send the undropped positions to wc.
  253. // -------------------------------------------------------------------------
  254. if (engine->IsInEditMode())
  255. {
  256. if (g_pAINetworkManager->GetEditOps()->m_pWCPosition)
  257. {
  258. g_pAINetworkManager->GetEditOps()->m_pWCPosition[new_node->GetId()] = new_node->GetOrigin();
  259. }
  260. }
  261. if (FClassnameIs( this, "info_node_air" ) || FClassnameIs( this, "info_node_air_hint" ))
  262. {
  263. new_node->SetType( NODE_AIR );
  264. }
  265. else if (FClassnameIs( this, "info_node_climb" ))
  266. {
  267. new_node->SetType( NODE_CLIMB );
  268. }
  269. else
  270. {
  271. new_node->SetType( NODE_GROUND );
  272. }
  273. new_node->m_eNodeInfo = ( m_spawnflags << NODE_ENT_FLAGS_SHIFT );
  274. // Fix up don't drop spawnflag
  275. if ( new_node->m_eNodeInfo & bits_LEGACY_DONT_DROP )
  276. {
  277. new_node->m_eNodeInfo |= bits_DONT_DROP;
  278. }
  279. // If changed as part of WC editing process note that network must be rebuilt
  280. if (m_debugOverlays & OVERLAY_WC_CHANGE_ENTITY)
  281. {
  282. g_pAINetworkManager->GetEditOps()->SetRebuildFlags();
  283. new_node->m_eNodeInfo |= bits_NODE_WC_CHANGED;
  284. // Initialize the new nodes position. The graph may not be rebuild
  285. // right away but the node should at least be positioned correctly
  286. g_AINetworkBuilder.InitNodePosition( g_pBigAINet, new_node );
  287. }
  288. UTIL_RemoveImmediate( this );
  289. return -1;
  290. }
  291. //-----------------------------------------------------------------------------
  292. // Purpose:
  293. // Input :
  294. // Output :
  295. //-----------------------------------------------------------------------------
  296. CNodeEnt::CNodeEnt( void )
  297. {
  298. m_debugOverlays = 0;
  299. }