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.

290 lines
7.8 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "gameweaponmanager.h"
  9. #include "saverestore_utlvector.h"
  10. // memdbgon must be the last include file in a .cpp file!!!
  11. #include "tier0/memdbgon.h"
  12. //=========================================================
  13. //=========================================================
  14. class CGameWeaponManager;
  15. static CUtlVector<CGameWeaponManager *> g_Managers;
  16. //=========================================================
  17. //=========================================================
  18. class CGameWeaponManager : public CBaseEntity
  19. {
  20. DECLARE_CLASS( CGameWeaponManager, CBaseEntity );
  21. DECLARE_DATADESC();
  22. public:
  23. void Spawn();
  24. CGameWeaponManager()
  25. {
  26. m_flAmmoMod = 1.0f;
  27. m_bExpectingWeapon = false;
  28. g_Managers.AddToTail( this );
  29. }
  30. ~CGameWeaponManager()
  31. {
  32. g_Managers.FindAndRemove( this );
  33. }
  34. void Think();
  35. void InputSetMaxPieces( inputdata_t &inputdata );
  36. void InputSetAmmoModifier( inputdata_t &inputdata );
  37. string_t m_iszWeaponName;
  38. int m_iMaxPieces;
  39. float m_flAmmoMod;
  40. bool m_bExpectingWeapon;
  41. CUtlVector<EHANDLE> m_ManagedNonWeapons;
  42. };
  43. BEGIN_DATADESC( CGameWeaponManager )
  44. //fields
  45. DEFINE_KEYFIELD( m_iszWeaponName, FIELD_STRING, "weaponname" ),
  46. DEFINE_KEYFIELD( m_iMaxPieces, FIELD_INTEGER, "maxpieces" ),
  47. DEFINE_KEYFIELD( m_flAmmoMod, FIELD_FLOAT, "ammomod" ),
  48. DEFINE_FIELD( m_bExpectingWeapon, FIELD_BOOLEAN ),
  49. // funcs
  50. DEFINE_FUNCTION( Think ),
  51. // inputs
  52. DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMaxPieces", InputSetMaxPieces ),
  53. DEFINE_INPUTFUNC( FIELD_FLOAT, "SetAmmoModifier", InputSetAmmoModifier ),
  54. DEFINE_UTLVECTOR( m_ManagedNonWeapons, FIELD_EHANDLE ),
  55. END_DATADESC()
  56. LINK_ENTITY_TO_CLASS( game_weapon_manager, CGameWeaponManager );
  57. void CreateWeaponManager( const char *pWeaponName, int iMaxPieces )
  58. {
  59. CGameWeaponManager *pManager = (CGameWeaponManager *)CreateEntityByName( "game_weapon_manager");
  60. if( pManager )
  61. {
  62. pManager->m_iszWeaponName = MAKE_STRING( pWeaponName );
  63. pManager->m_iMaxPieces = iMaxPieces;
  64. DispatchSpawn( pManager );
  65. }
  66. }
  67. void WeaponManager_AmmoMod( CBaseCombatWeapon *pWeapon )
  68. {
  69. for ( int i = 0; i < g_Managers.Count(); i++ )
  70. {
  71. if ( g_Managers[i]->m_iszWeaponName == pWeapon->m_iClassname )
  72. {
  73. int iNewClip = (int)(pWeapon->m_iClip1 * g_Managers[i]->m_flAmmoMod);
  74. int iNewRandomClip = iNewClip + RandomInt( -2, 2 );
  75. if ( iNewRandomClip > pWeapon->GetMaxClip1() )
  76. {
  77. iNewRandomClip = pWeapon->GetMaxClip1();
  78. }
  79. else if ( iNewRandomClip <= 0 )
  80. {
  81. //Drop at least one bullet.
  82. iNewRandomClip = 1;
  83. }
  84. pWeapon->m_iClip1 = iNewRandomClip;
  85. }
  86. }
  87. }
  88. void WeaponManager_AddManaged( CBaseEntity *pWeapon )
  89. {
  90. for ( int i = 0; i < g_Managers.Count(); i++ )
  91. {
  92. if ( g_Managers[i]->m_iszWeaponName == pWeapon->m_iClassname )
  93. {
  94. Assert( g_Managers[i]->m_ManagedNonWeapons.Find( pWeapon ) == g_Managers[i]->m_ManagedNonWeapons.InvalidIndex() );
  95. g_Managers[i]->m_ManagedNonWeapons.AddToTail( pWeapon );
  96. break;
  97. }
  98. }
  99. }
  100. void WeaponManager_RemoveManaged( CBaseEntity *pWeapon )
  101. {
  102. for ( int i = 0; i < g_Managers.Count(); i++ )
  103. {
  104. if ( g_Managers[i]->m_iszWeaponName == pWeapon->m_iClassname )
  105. {
  106. int j = g_Managers[i]->m_ManagedNonWeapons.Find( pWeapon );
  107. if ( j != g_Managers[i]->m_ManagedNonWeapons.InvalidIndex() )
  108. {
  109. g_Managers[i]->m_ManagedNonWeapons.FastRemove( j );
  110. }
  111. }
  112. }
  113. }
  114. //---------------------------------------------------------
  115. //---------------------------------------------------------
  116. void CGameWeaponManager::Spawn()
  117. {
  118. SetThink( &CGameWeaponManager::Think );
  119. SetNextThink( gpGlobals->curtime );
  120. CBaseEntity *pEntity = CreateEntityByName( STRING(m_iszWeaponName) );
  121. if ( !pEntity )
  122. {
  123. DevMsg("%s removed itself!\n", GetDebugName() );
  124. UTIL_Remove(this);
  125. }
  126. else
  127. {
  128. m_bExpectingWeapon = ( dynamic_cast<CBaseCombatWeapon *>(pEntity) != NULL );
  129. UTIL_Remove(pEntity);
  130. }
  131. }
  132. //---------------------------------------------------------
  133. // Count of all the weapons in the world of my type and
  134. // see if we have a surplus. If there is a surplus, try
  135. // to find suitable candidates for removal.
  136. //
  137. // Right now we just remove the first weapons we find that
  138. // are behind the player, or are out of the player's PVS.
  139. // Later, we may want to score the results so that we
  140. // removed the farthest gun that's not in the player's
  141. // viewcone, etc.
  142. //
  143. // Some notes and thoughts:
  144. //
  145. // This code is designed NOT to remove weapons that are
  146. // hand-placed by level designers. It should only clean
  147. // up weapons dropped by dead NPCs, which is useful in
  148. // situations where enemies are spawned in for a sustained
  149. // period of time.
  150. //
  151. // Right now we PREFER to remove weapons that are not in the
  152. // player's PVS, but this could be opposite of what we
  153. // really want. We may only want to conduct the cleanup on
  154. // weapons that are IN the player's PVS.
  155. //---------------------------------------------------------
  156. void CGameWeaponManager::Think()
  157. {
  158. int i;
  159. // Don't have to think all that often.
  160. SetNextThink( gpGlobals->curtime + 2.0 );
  161. const char *pszWeaponName = STRING( m_iszWeaponName );
  162. CUtlVector<CBaseEntity *> candidates( 0, 64 );
  163. if ( m_bExpectingWeapon )
  164. {
  165. CBaseCombatWeapon *pWeapon = NULL;
  166. // Firstly, count the total number of weapons of this type in the world.
  167. // Also count how many of those can potentially be removed.
  168. pWeapon = assert_cast<CBaseCombatWeapon *>(gEntList.FindEntityByClassname( pWeapon, pszWeaponName ));
  169. while( pWeapon )
  170. {
  171. if( !pWeapon->IsEffectActive( EF_NODRAW ) && pWeapon->IsRemoveable() )
  172. {
  173. candidates.AddToTail( pWeapon );
  174. }
  175. pWeapon = assert_cast<CBaseCombatWeapon *>(gEntList.FindEntityByClassname( pWeapon, pszWeaponName ));
  176. }
  177. }
  178. else
  179. {
  180. for ( i = 0; i < m_ManagedNonWeapons.Count(); i++)
  181. {
  182. CBaseEntity *pEntity = m_ManagedNonWeapons[i];
  183. if ( pEntity )
  184. {
  185. Assert( pEntity->m_iClassname == m_iszWeaponName );
  186. if ( !pEntity->IsEffectActive( EF_NODRAW ) )
  187. {
  188. candidates.AddToTail( pEntity );
  189. }
  190. }
  191. else
  192. {
  193. m_ManagedNonWeapons.FastRemove( i-- );
  194. }
  195. }
  196. }
  197. // Calculate the surplus.
  198. int surplus = candidates.Count() - m_iMaxPieces;
  199. // Based on what the player can see, try to clean up the world by removing weapons that
  200. // the player cannot see right at the moment.
  201. CBaseEntity *pCandidate;
  202. for ( i = 0; i < candidates.Count() && surplus > 0; i++ )
  203. {
  204. bool fRemovedOne = false;
  205. pCandidate = candidates[i];
  206. Assert( !pCandidate->IsEffectActive( EF_NODRAW ) );
  207. if ( gpGlobals->maxClients == 1 )
  208. {
  209. CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
  210. // Nodraw serves as a flag that this weapon is already being removed since
  211. // all we're really doing inside this loop is marking them for removal by
  212. // the entity system. We don't want to count the same weapon as removed
  213. // more than once.
  214. if( !UTIL_FindClientInPVS( pCandidate->edict() ) )
  215. {
  216. fRemovedOne = true;
  217. }
  218. else if( !pPlayer->FInViewCone( pCandidate ) )
  219. {
  220. fRemovedOne = true;
  221. }
  222. else if ( UTIL_DistApprox( pPlayer->GetAbsOrigin(), pCandidate->GetAbsOrigin() ) > (30*12) )
  223. {
  224. fRemovedOne = true;
  225. }
  226. }
  227. else
  228. {
  229. fRemovedOne = true;
  230. }
  231. if( fRemovedOne )
  232. {
  233. pCandidate->AddEffects( EF_NODRAW );
  234. UTIL_Remove( pCandidate );
  235. DevMsg( 2, "Surplus %s removed\n", pszWeaponName);
  236. surplus--;
  237. }
  238. }
  239. }
  240. //---------------------------------------------------------
  241. //---------------------------------------------------------
  242. void CGameWeaponManager::InputSetMaxPieces( inputdata_t &inputdata )
  243. {
  244. m_iMaxPieces = inputdata.value.Int();
  245. }
  246. //---------------------------------------------------------
  247. //---------------------------------------------------------
  248. void CGameWeaponManager::InputSetAmmoModifier( inputdata_t &inputdata )
  249. {
  250. m_flAmmoMod = inputdata.value.Float();
  251. }