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.

292 lines
7.9 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include "cbase.h"
  10. #include "ai_basenpc.h"
  11. #include "ai_default.h"
  12. #include "ai_hull.h"
  13. #include "ai_squadslot.h"
  14. #include "ai_squad.h"
  15. #include "bitstring.h"
  16. #include "entitylist.h"
  17. #include "ai_hint.h"
  18. #include "IEffects.h"
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include "tier0/memdbgon.h"
  21. //-----------------------------------------------------------------------------
  22. // Purpose: If requested slot is available return true and take the slot
  23. // Otherwise return false
  24. // Input :
  25. // Output :
  26. //-----------------------------------------------------------------------------
  27. bool CAI_BaseNPC::OccupyStrategySlot( int squadSlotID )
  28. {
  29. return OccupyStrategySlotRange( squadSlotID, squadSlotID );
  30. }
  31. //-----------------------------------------------------------------------------
  32. bool CAI_BaseNPC::OccupyStrategySlotRange( int slotIDStart, int slotIDEnd )
  33. {
  34. // If I'm not in a squad a I don't fill slots
  35. return ( !m_pSquad || m_pSquad->OccupyStrategySlotRange( GetEnemy(), slotIDStart, slotIDEnd, &m_iMySquadSlot ) );
  36. }
  37. //-----------------------------------------------------------------------------
  38. // Returns true if all in the range are full
  39. //-----------------------------------------------------------------------------
  40. bool CAI_BaseNPC::IsStrategySlotRangeOccupied( int slotIDStart, int slotIDEnd )
  41. {
  42. return m_pSquad && m_pSquad->IsStrategySlotRangeOccupied( GetEnemy(), slotIDStart, slotIDEnd );
  43. }
  44. //=========================================================
  45. // HasStrategySlot
  46. //=========================================================
  47. bool CAI_BaseNPC::HasStrategySlot( int squadSlotID )
  48. {
  49. // If I wasn't taking up a squad slot I'm done
  50. return (m_iMySquadSlot == squadSlotID);
  51. }
  52. bool CAI_BaseNPC::HasStrategySlotRange( int slotIDStart, int slotIDEnd )
  53. {
  54. // If I wasn't taking up a squad slot I'm done
  55. if (m_iMySquadSlot < slotIDStart || m_iMySquadSlot > slotIDEnd)
  56. {
  57. return false;
  58. }
  59. return true;
  60. }
  61. //=========================================================
  62. // VacateSlot
  63. //=========================================================
  64. void CAI_BaseNPC::VacateStrategySlot(void)
  65. {
  66. if (m_pSquad)
  67. {
  68. m_pSquad->VacateStrategySlot(GetEnemy(), m_iMySquadSlot);
  69. m_iMySquadSlot = SQUAD_SLOT_NONE;
  70. }
  71. }
  72. //------------------------------------------------------------------------------
  73. // Purpose : Is cover node valid
  74. // Input :
  75. // Output :
  76. //------------------------------------------------------------------------------
  77. bool CAI_BaseNPC::IsValidCover( const Vector &vecCoverLocation, CAI_Hint const *pHint )
  78. {
  79. // firstly, limit choices to hint groups
  80. string_t iszHint = GetHintGroup();
  81. char *pszHint = (char *)STRING(iszHint);
  82. if ((iszHint != NULL_STRING) && (pszHint[0] != '\0'))
  83. {
  84. if (!pHint || pHint->GetGroup() != GetHintGroup())
  85. {
  86. return false;
  87. }
  88. }
  89. /*
  90. // If I'm in a squad don't pick cover node it other squad member
  91. // is already nearby
  92. if (m_pSquad)
  93. {
  94. return m_pSquad->IsValidCover( vecCoverLocation, pHint );
  95. }
  96. */
  97. // UNDONE: Do we really need this test?
  98. // ----------------------------------------------------------------
  99. // Make sure my hull can fit at this node before accepting it.
  100. // Could be another NPC there or it could be blocked
  101. // ----------------------------------------------------------------
  102. // FIXME: shouldn't this see that if I crouch behind it it'll be safe?
  103. Vector startPos = vecCoverLocation;
  104. startPos.z -= GetHullMins().z; // Move hull bottom up to node
  105. Vector endPos = startPos;
  106. endPos.z += 0.01;
  107. trace_t tr;
  108. AI_TraceEntity( this, vecCoverLocation, endPos, GetAITraceMask(), &tr );
  109. if (tr.startsolid)
  110. {
  111. return false;
  112. }
  113. return true;
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose: Is squad member in my way from shooting here
  117. // Input :
  118. // Output :
  119. //-----------------------------------------------------------------------------
  120. bool CAI_BaseNPC::IsValidShootPosition( const Vector &vecShootLocation, CAI_Node *pNode, CAI_Hint const *pHint )
  121. {
  122. // limit choices to hint groups
  123. if (GetHintGroup() != NULL_STRING)
  124. {
  125. if (!pHint || pHint->GetGroup() != GetHintGroup())
  126. {
  127. if ( ( vecShootLocation - GetAbsOrigin() ).Length2DSqr() > 1 )
  128. return false;
  129. }
  130. }
  131. return true;
  132. }
  133. //-----------------------------------------------------------------------------
  134. bool CAI_BaseNPC::IsSquadmateInSpread( const Vector &sourcePos, const Vector &targetPos, float flSpread, float maxDistOffCenter )
  135. {
  136. if( !m_pSquad )
  137. return false;
  138. AISquadIter_t iter;
  139. CAI_BaseNPC *pSquadmate = m_pSquad->GetFirstMember( &iter );
  140. while ( pSquadmate )
  141. {
  142. // Ignore squadmates that can't take damage. This is primarily to ignore npc_enemyfinders.
  143. if ( pSquadmate->m_takedamage != DAMAGE_NO )
  144. {
  145. if ( pSquadmate != this )
  146. {
  147. if ( PointInSpread( pSquadmate, sourcePos, targetPos, pSquadmate->GetAbsOrigin(), flSpread, maxDistOffCenter ) )
  148. return true;
  149. }
  150. }
  151. pSquadmate = m_pSquad->GetNextMember( &iter );
  152. }
  153. return false;
  154. }
  155. //-----------------------------------------------------------------------------
  156. void CAI_BaseNPC::AddToSquad( string_t name )
  157. {
  158. g_AI_SquadManager.FindCreateSquad( this, name );
  159. }
  160. //-----------------------------------------------------------------------------
  161. void CAI_BaseNPC::SetSquad( CAI_Squad *pSquad )
  162. {
  163. if ( m_pSquad == pSquad )
  164. {
  165. return;
  166. }
  167. if ( m_pSquad && m_iMySquadSlot != SQUAD_SLOT_NONE)
  168. {
  169. VacateStrategySlot();
  170. }
  171. m_pSquad = pSquad;
  172. }
  173. //-----------------------------------------------------------------------------
  174. void CAI_BaseNPC::RemoveFromSquad()
  175. {
  176. if ( m_pSquad )
  177. {
  178. m_pSquad->RemoveFromSquad( this, false );
  179. m_pSquad = NULL;
  180. }
  181. }
  182. //-----------------------------------------------------------------------------
  183. void CAI_BaseNPC::CheckSquad()
  184. {
  185. if( !IsInSquad() )
  186. return;
  187. if( !GetSquad()->IsLeader(this) )
  188. return;
  189. if( VPhysicsGetObject() != NULL && (VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD) )
  190. {
  191. // I AM the leader, and I'm currently being held. This will screw up all of my relationship checks
  192. // if I'm a manhack or a rollermine, so just bomb out and try next time.
  193. return;
  194. }
  195. AISquadIter_t iter;
  196. CAI_BaseNPC *pSquadmate = m_pSquad->GetFirstMember( &iter );
  197. while ( pSquadmate )
  198. {
  199. if( IRelationType(pSquadmate) < D_LI )
  200. {
  201. bool bWarn = true;
  202. // Rollermines and manhacks set their Class to NONE when held by the player, which makes all of
  203. // their squadmates complain that an enemy is in the squad. Suppress this.
  204. if( pSquadmate->VPhysicsGetObject() != NULL )
  205. {
  206. if (pSquadmate->VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD)
  207. {
  208. bWarn = false;
  209. }
  210. }
  211. if( bWarn )
  212. {
  213. Warning( "ERROR: Squad '%s' has enemies in it!\n", GetSquad()->GetName() );
  214. Warning( "%s doesn't like %s\n\n", GetDebugName(), pSquadmate->GetDebugName() );
  215. }
  216. }
  217. pSquadmate = m_pSquad->GetNextMember( &iter );
  218. }
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Returns the number of weapons of this type currently owned by squad members.
  222. //-----------------------------------------------------------------------------
  223. int CAI_BaseNPC::NumWeaponsInSquad( const char *pszWeaponClassname )
  224. {
  225. string_t iszWeaponClassname = FindPooledString( pszWeaponClassname );
  226. if( !GetSquad() )
  227. {
  228. if( GetActiveWeapon() && GetActiveWeapon()->m_iClassname == iszWeaponClassname )
  229. {
  230. // I'm alone in my squad, but I do have this weapon.
  231. return 1;
  232. }
  233. return 0;
  234. }
  235. int count = 0;
  236. AISquadIter_t iter;
  237. CAI_BaseNPC *pSquadmate = m_pSquad->GetFirstMember( &iter );
  238. while ( pSquadmate )
  239. {
  240. if( pSquadmate->GetActiveWeapon() && pSquadmate->GetActiveWeapon()->m_iClassname == iszWeaponClassname )
  241. {
  242. count++;
  243. }
  244. pSquadmate = m_pSquad->GetNextMember( &iter );
  245. }
  246. return count;
  247. }