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.

263 lines
7.1 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "entitylist.h"
  8. #include "ai_basenpc.h"
  9. #include "npc_citizen17.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. #define MAX_ALLIES 10
  13. class CAI_AllyManager : public CBaseEntity
  14. {
  15. DECLARE_CLASS( CAI_AllyManager, CBaseEntity );
  16. public:
  17. void Spawn();
  18. void CountAllies( int *pTotal, int *pMedics );
  19. private:
  20. int m_iMaxAllies;
  21. int m_iMaxMedics;
  22. int m_iAlliesLast;
  23. int m_iMedicsLast;
  24. public:
  25. void WatchCounts();
  26. // Input functions
  27. void InputSetMaxAllies( inputdata_t &inputdata );
  28. void InputSetMaxMedics( inputdata_t &inputdata );
  29. void InputReplenish( inputdata_t &inputdata );
  30. // Outputs
  31. COutputEvent m_SpawnAlly[ MAX_ALLIES ];
  32. COutputEvent m_SpawnMedicAlly;
  33. COutputEvent m_OnZeroAllies;
  34. COutputEvent m_OnZeroMedicAllies;
  35. DECLARE_DATADESC();
  36. };
  37. ConVar ai_ally_manager_debug("ai_ally_manager_debug", "0" );
  38. LINK_ENTITY_TO_CLASS( ai_ally_manager, CAI_AllyManager );
  39. BEGIN_DATADESC( CAI_AllyManager )
  40. DEFINE_KEYFIELD( m_iMaxAllies, FIELD_INTEGER, "maxallies" ),
  41. DEFINE_KEYFIELD( m_iMaxMedics, FIELD_INTEGER, "maxmedics" ),
  42. DEFINE_FIELD( m_iAlliesLast, FIELD_INTEGER ),
  43. DEFINE_FIELD( m_iMedicsLast, FIELD_INTEGER ),
  44. DEFINE_THINKFUNC( WatchCounts ),
  45. // Inputs
  46. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMaxAllies", InputSetMaxAllies ),
  47. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMaxMedics", InputSetMaxMedics ),
  48. DEFINE_INPUTFUNC( FIELD_VOID, "Replenish", InputReplenish ),
  49. // Outputs
  50. DEFINE_OUTPUT( m_SpawnAlly[ 0 ], "SpawnAlly0" ),
  51. DEFINE_OUTPUT( m_SpawnAlly[ 1 ], "SpawnAlly1" ),
  52. DEFINE_OUTPUT( m_SpawnAlly[ 2 ], "SpawnAlly2" ),
  53. DEFINE_OUTPUT( m_SpawnAlly[ 3 ], "SpawnAlly3" ),
  54. DEFINE_OUTPUT( m_SpawnAlly[ 4 ], "SpawnAlly4" ),
  55. DEFINE_OUTPUT( m_SpawnAlly[ 5 ], "SpawnAlly5" ),
  56. DEFINE_OUTPUT( m_SpawnAlly[ 6 ], "SpawnAlly6" ),
  57. DEFINE_OUTPUT( m_SpawnAlly[ 7 ], "SpawnAlly7" ),
  58. DEFINE_OUTPUT( m_SpawnAlly[ 8 ], "SpawnAlly8" ),
  59. DEFINE_OUTPUT( m_SpawnAlly[ 9 ], "SpawnAlly9" ),
  60. DEFINE_OUTPUT( m_SpawnMedicAlly, "SpawnMedicAlly" ),
  61. DEFINE_OUTPUT( m_OnZeroAllies, "OnZeroAllies" ),
  62. DEFINE_OUTPUT( m_OnZeroMedicAllies, "OnZeroMedicAllies" ),
  63. END_DATADESC()
  64. //-----------------------------------------------------------------------------
  65. // Purpose:
  66. //-----------------------------------------------------------------------------
  67. void CAI_AllyManager::Spawn()
  68. {
  69. SetThink( &CAI_AllyManager::WatchCounts );
  70. SetNextThink( gpGlobals->curtime + 1.0 );
  71. }
  72. //-----------------------------------------------------------------------------
  73. //-----------------------------------------------------------------------------
  74. void CAI_AllyManager::WatchCounts()
  75. {
  76. // Count the number of allies with the player right now.
  77. int iCurrentAllies;
  78. int iCurrentMedics;
  79. CountAllies( &iCurrentAllies, &iCurrentMedics );
  80. if ( !iCurrentAllies && m_iAlliesLast )
  81. m_OnZeroAllies.FireOutput( this, this, 0 );
  82. if ( !iCurrentMedics && m_iMedicsLast )
  83. m_OnZeroMedicAllies.FireOutput( this, this, 0 );
  84. m_iAlliesLast = iCurrentAllies;
  85. m_iMedicsLast = iCurrentMedics;
  86. SetNextThink( gpGlobals->curtime + 1.0 );
  87. if ( ai_ally_manager_debug.GetBool() )
  88. DevMsg( "Ally manager counts %d allies, %d of which are medics\n", iCurrentAllies, iCurrentMedics );
  89. }
  90. //-----------------------------------------------------------------------------
  91. //-----------------------------------------------------------------------------
  92. void CAI_AllyManager::CountAllies( int *pTotal, int *pMedics )
  93. {
  94. (*pTotal) = (*pMedics) = 0;
  95. if ( !AI_IsSinglePlayer() )
  96. {
  97. // @TODO (toml 10-22-04): no MP support right now
  98. return;
  99. }
  100. const Vector & vPlayerPos = UTIL_GetLocalPlayer()->GetAbsOrigin();
  101. CAI_BaseNPC ** ppAIs = g_AI_Manager.AccessAIs();
  102. int nAIs = g_AI_Manager.NumAIs();
  103. for ( int i = 0; i < nAIs; i++ )
  104. {
  105. if ( ppAIs[i]->IsAlive() && ppAIs[i]->IsPlayerAlly() )
  106. {
  107. // Vital allies do not count.
  108. if( ppAIs[i]->Classify() == CLASS_PLAYER_ALLY_VITAL )
  109. continue;
  110. // They only count if I can use them.
  111. if( ppAIs[i]->HasSpawnFlags(SF_CITIZEN_NOT_COMMANDABLE) )
  112. continue;
  113. // They only count if I can use them.
  114. if( ppAIs[i]->IRelationType( UTIL_GetLocalPlayer() ) != D_LI )
  115. continue;
  116. // Skip distant NPCs
  117. if ( !ppAIs[i]->IsInPlayerSquad() &&
  118. !UTIL_FindClientInPVS( ppAIs[i]->edict() ) &&
  119. ( ( ppAIs[i]->GetAbsOrigin() - vPlayerPos ).LengthSqr() > 150*12 ||
  120. fabsf( ppAIs[i]->GetAbsOrigin().z - vPlayerPos.z ) > 192 ) )
  121. continue;
  122. if( FClassnameIs( ppAIs[i], "npc_citizen" ) )
  123. {
  124. CNPC_Citizen *pCitizen = assert_cast<CNPC_Citizen *>(ppAIs[i]);
  125. if ( !pCitizen->CanJoinPlayerSquad() )
  126. continue;
  127. if ( pCitizen->WasInPlayerSquad() && !pCitizen->IsInPlayerSquad() )
  128. continue;
  129. if ( ppAIs[i]->HasSpawnFlags( SF_CITIZEN_MEDIC ) )
  130. (*pMedics)++;
  131. }
  132. (*pTotal)++;
  133. }
  134. }
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose:
  138. // Input : &inputdata -
  139. //-----------------------------------------------------------------------------
  140. void CAI_AllyManager::InputSetMaxAllies( inputdata_t &inputdata )
  141. {
  142. m_iMaxAllies = inputdata.value.Int();
  143. }
  144. //-----------------------------------------------------------------------------
  145. //-----------------------------------------------------------------------------
  146. void CAI_AllyManager::InputSetMaxMedics( inputdata_t &inputdata )
  147. {
  148. m_iMaxMedics = inputdata.value.Int();
  149. }
  150. //-----------------------------------------------------------------------------
  151. // Purpose:
  152. // Input : &inputdata -
  153. //-----------------------------------------------------------------------------
  154. void CAI_AllyManager::InputReplenish( inputdata_t &inputdata )
  155. {
  156. // Count the number of allies with the player right now.
  157. int iCurrentAllies;
  158. int iCurrentMedics;
  159. CountAllies( &iCurrentAllies, &iCurrentMedics );
  160. // TOTAL number of allies to be replaced.
  161. int iReplaceAllies = m_iMaxAllies - iCurrentAllies;
  162. // The number of total allies that should be medics.
  163. int iReplaceMedics = m_iMaxMedics - iCurrentMedics;
  164. if( iReplaceMedics > iReplaceAllies )
  165. {
  166. // Clamp medics.
  167. iReplaceMedics = iReplaceAllies;
  168. }
  169. // Medics.
  170. if( m_iMaxMedics > 0 )
  171. {
  172. if( iReplaceMedics > MAX_ALLIES )
  173. {
  174. // This error is fatal now. (sjb)
  175. Msg("**ERROR! ai_allymanager - ReplaceMedics > MAX_ALLIES\n" );
  176. return;
  177. }
  178. if ( ai_ally_manager_debug.GetBool() )
  179. DevMsg( "Ally manager spawning %d medics\n", iReplaceMedics );
  180. int i;
  181. for( i = 0 ; i < iReplaceMedics ; i++ )
  182. {
  183. m_SpawnMedicAlly.FireOutput( this, this, 0 );
  184. // Don't forget to count this guy against the number of
  185. // allies to be replenished.
  186. iReplaceAllies--;
  187. }
  188. }
  189. // Allies
  190. if( iReplaceAllies < 1 )
  191. {
  192. return;
  193. }
  194. if( iReplaceAllies > MAX_ALLIES )
  195. {
  196. Msg("**ERROR! ai_allymanager - ReplaceAllies > MAX_ALLIES\n" );
  197. iReplaceAllies = MAX_ALLIES;
  198. }
  199. if ( ai_ally_manager_debug.GetBool() )
  200. DevMsg( "Ally manager spawning %d regulars\n", iReplaceAllies );
  201. int i;
  202. for( i = 0 ; i < iReplaceAllies ; i++ )
  203. {
  204. m_SpawnAlly[ i ].FireOutput( this, this, 0 );
  205. }
  206. }