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.

261 lines
7.2 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // TF Entity Spawner
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "tf_entity_spawner.h"
  8. // memdbgon must be the last include file in a .cpp file!!!
  9. #include "tier0/memdbgon.h"
  10. //-----------------------------------------------------------------------------
  11. // CEntitySpawnManager
  12. //-----------------------------------------------------------------------------
  13. BEGIN_DATADESC( CEntitySpawnManager )
  14. // Fields
  15. DEFINE_KEYFIELD( m_iszEntityName, FIELD_STRING, "entity_name" ),
  16. DEFINE_KEYFIELD( m_iEntityCount, FIELD_INTEGER, "entity_count" ),
  17. DEFINE_KEYFIELD( m_iRespawnTime, FIELD_INTEGER, "respawn_time" ),
  18. DEFINE_KEYFIELD( m_bDropToGround, FIELD_BOOLEAN, "drop_to_ground" ),
  19. DEFINE_KEYFIELD( m_bRandomRotation, FIELD_BOOLEAN, "random_rotation" ),
  20. // Outputs
  21. // ON RESPAWN ?
  22. END_DATADESC()
  23. LINK_ENTITY_TO_CLASS( entity_spawn_manager, CEntitySpawnManager );
  24. //-----------------------------------------------------------------------------
  25. //
  26. //-----------------------------------------------------------------------------
  27. void CEntitySpawnManager::Spawn( void )
  28. {
  29. BaseClass::Spawn();
  30. SetNextThink( TICK_NEVER_THINK );
  31. SetThink( NULL );
  32. }
  33. //-----------------------------------------------------------------------------
  34. // Stores related spawn points.
  35. //-----------------------------------------------------------------------------
  36. void CEntitySpawnManager::RegisterSpawnPoint( CEntitySpawnPoint* pNewPoint )
  37. {
  38. m_SpawnPoints.AddToHead( pNewPoint );
  39. }
  40. //-----------------------------------------------------------------------------
  41. //
  42. //-----------------------------------------------------------------------------
  43. void CEntitySpawnManager::Activate( void )
  44. {
  45. BaseClass::Activate();
  46. // AssertMsg1( 0, ("entity_spawn_manager active with %i points!"), m_SpawnPoints.Count() );
  47. // Don't spawn more objects than we have points.
  48. m_iMaxSpawnedEntities = MIN( m_SpawnPoints.Count(), m_iEntityCount );
  49. if ( !m_iszEntityName || (m_iMaxSpawnedEntities == 0) )
  50. {
  51. AssertMsg1( 0, ("entity_spawn_manager %s active with nothing to spawn!"), GetEntityName().ToCStr() );
  52. return;
  53. }
  54. // Perform initial spawn.
  55. SpawnAllEntities();
  56. }
  57. //-----------------------------------------------------------------------------
  58. // Populates a random set of spawn points with objects, up to our max.
  59. //-----------------------------------------------------------------------------
  60. void CEntitySpawnManager::SpawnAllEntities()
  61. {
  62. int iNumUsed = 0;
  63. for ( int i=0; i<m_SpawnPoints.Count(); ++i )
  64. {
  65. if ( m_SpawnPoints[i]->IsUsed() )
  66. {
  67. iNumUsed++;
  68. }
  69. }
  70. int iNumToSpawn = m_iMaxSpawnedEntities - iNumUsed;
  71. if ( iNumToSpawn <= 0 )
  72. return;
  73. while ( iNumToSpawn )
  74. {
  75. SpawnEntity();
  76. iNumToSpawn--;
  77. }
  78. }
  79. //-----------------------------------------------------------------------------
  80. // Spawns a single entity at a random location.
  81. //-----------------------------------------------------------------------------
  82. bool CEntitySpawnManager::SpawnEntity()
  83. {
  84. return SpawnEntityAt( GetRandomUnusedIndex() );
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Returns a random unused point.
  88. //-----------------------------------------------------------------------------
  89. int CEntitySpawnManager::GetRandomUnusedIndex()
  90. {
  91. int iStartIndex = rand() % m_SpawnPoints.Count();
  92. for ( int i=0; i<m_SpawnPoints.Count(); ++i )
  93. {
  94. int index = i+iStartIndex;
  95. if ( index >= m_SpawnPoints.Count() )
  96. index -= m_SpawnPoints.Count();
  97. CEntitySpawnPoint *pPoint = m_SpawnPoints[index];
  98. if ( !pPoint || pPoint->IsUsed() )
  99. continue;
  100. else
  101. return index;
  102. }
  103. return -1;
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Creates the entity.
  107. //-----------------------------------------------------------------------------
  108. bool CEntitySpawnManager::SpawnEntityAt( int iIndex )
  109. {
  110. if ( iIndex == -1 )
  111. return false;
  112. CEntitySpawnPoint *pPoint = m_SpawnPoints[iIndex];
  113. if ( !pPoint )
  114. return false;
  115. CBaseEntity *pEnt = CreateEntityByName( m_iszEntityName.ToCStr() );
  116. if ( !pEnt )
  117. return false;
  118. Vector origin = pPoint->GetAbsOrigin();
  119. Vector mins, maxs, mins_o, maxs_o;
  120. pEnt->CollisionProp()->WorldSpaceAABB( &mins, &maxs );
  121. mins_o = origin + mins;
  122. maxs_o = origin + mins;
  123. if ( !UTIL_IsSpaceEmpty( pEnt, mins_o, maxs_o ) )
  124. {
  125. UTIL_Remove( pEnt );
  126. return false;
  127. }
  128. if ( m_bDropToGround )
  129. {
  130. trace_t trace;
  131. UTIL_TraceHull( origin, origin + Vector( 0, 0, -500 ), mins, maxs, MASK_SOLID, pEnt, COLLISION_GROUP_NONE, &trace );
  132. origin = trace.endpos;
  133. }
  134. pEnt->SetAbsOrigin( origin );
  135. DispatchSpawn( pEnt );
  136. if ( m_bRandomRotation )
  137. {
  138. pEnt->SetAbsAngles( QAngle( 0, random->RandomFloat( 0, 360 ), 0 ) );
  139. }
  140. else
  141. {
  142. pEnt->SetAbsAngles( pPoint->GetAbsAngles() );
  143. }
  144. pPoint->SetEntity( pEnt );
  145. return true;
  146. }
  147. //-----------------------------------------------------------------------------
  148. // CEntitySpawnPoint
  149. //-----------------------------------------------------------------------------
  150. BEGIN_DATADESC( CEntitySpawnPoint )
  151. // Fields
  152. DEFINE_KEYFIELD( m_iszSpawnManagerName, FIELD_STRING, "spawn_manager_name" ),
  153. END_DATADESC()
  154. LINK_ENTITY_TO_CLASS( entity_spawn_point, CEntitySpawnPoint );
  155. //-----------------------------------------------------------------------------
  156. // Initializes the spawn point and registers it with its manager.
  157. //-----------------------------------------------------------------------------
  158. void CEntitySpawnPoint::Spawn( void )
  159. {
  160. BaseClass::Spawn();
  161. SetNextThink( TICK_NEVER_THINK );
  162. SetThink( NULL );
  163. if ( !m_iszSpawnManagerName )
  164. {
  165. AssertMsg( 0, ("entity_spawn_point with no spawn_manager_name!") );
  166. return;
  167. }
  168. m_hSpawnManager = dynamic_cast<CEntitySpawnManager*>( gEntList.FindEntityByName( NULL, m_iszSpawnManagerName ) );
  169. if ( !m_hSpawnManager )
  170. {
  171. AssertMsg2( 0, ("entity_spawn_point %s unable to find spawn_manager_name %s!"), GetEntityName().ToCStr(), m_iszSpawnManagerName.ToCStr() );
  172. return;
  173. }
  174. m_hSpawnManager->RegisterSpawnPoint( this );
  175. gEntList.AddListenerEntity( this );
  176. }
  177. //-----------------------------------------------------------------------------
  178. //
  179. //-----------------------------------------------------------------------------
  180. void CEntitySpawnPoint::UpdateOnRemove(void)
  181. {
  182. gEntList.RemoveListenerEntity( this );
  183. BaseClass::UpdateOnRemove();
  184. }
  185. //-----------------------------------------------------------------------------
  186. // When our entity is deleted, we become responsible for indicating when a new one should spawn.
  187. //-----------------------------------------------------------------------------
  188. void CEntitySpawnPoint::OnEntityDeleted( CBaseEntity *pEntity )
  189. {
  190. if ( !m_hSpawnManager )
  191. return;
  192. if ( pEntity == m_hMyEntity )
  193. {
  194. m_flNodeFree = gpGlobals->curtime + 10.f;
  195. m_hMyEntity = NULL;
  196. SetNextThink( gpGlobals->curtime + m_hSpawnManager->GetRespawnTime() );
  197. SetThink( &CEntitySpawnPoint::RespawnNotifyThink );
  198. }
  199. }
  200. void CEntitySpawnPoint::RespawnNotifyThink( void )
  201. {
  202. if ( (gpGlobals->curtime > m_flNodeFree) && m_hSpawnManager->SpawnEntity() )
  203. {
  204. SetThink( NULL );
  205. SetNextThink( TICK_NEVER_THINK );
  206. }
  207. else
  208. {
  209. SetNextThink( gpGlobals->curtime + 5.f );
  210. SetThink( &CEntitySpawnPoint::RespawnNotifyThink );
  211. }
  212. }