|
|
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "gameweaponmanager.h"
#include "saverestore_utlvector.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//=========================================================
//=========================================================
class CGameWeaponManager; static CUtlVector<CGameWeaponManager *> g_Managers;
//=========================================================
//=========================================================
class CGameWeaponManager : public CBaseEntity { DECLARE_CLASS( CGameWeaponManager, CBaseEntity ); DECLARE_DATADESC();
public: void Spawn(); CGameWeaponManager() { m_flAmmoMod = 1.0f; m_bExpectingWeapon = false; g_Managers.AddToTail( this ); }
~CGameWeaponManager() { g_Managers.FindAndRemove( this ); }
void Think(); void InputSetMaxPieces( inputdata_t &inputdata ); void InputSetAmmoModifier( inputdata_t &inputdata );
string_t m_iszWeaponName; int m_iMaxPieces; float m_flAmmoMod; bool m_bExpectingWeapon;
CUtlVector<EHANDLE> m_ManagedNonWeapons;
};
BEGIN_DATADESC( CGameWeaponManager )
//fields
DEFINE_KEYFIELD( m_iszWeaponName, FIELD_STRING, "weaponname" ), DEFINE_KEYFIELD( m_iMaxPieces, FIELD_INTEGER, "maxpieces" ), DEFINE_KEYFIELD( m_flAmmoMod, FIELD_FLOAT, "ammomod" ), DEFINE_FIELD( m_bExpectingWeapon, FIELD_BOOLEAN ), // funcs
DEFINE_FUNCTION( Think ), // inputs
DEFINE_INPUTFUNC( FIELD_INTEGER, "SetMaxPieces", InputSetMaxPieces ), DEFINE_INPUTFUNC( FIELD_FLOAT, "SetAmmoModifier", InputSetAmmoModifier ),
DEFINE_UTLVECTOR( m_ManagedNonWeapons, FIELD_EHANDLE ),
END_DATADESC()
LINK_ENTITY_TO_CLASS( game_weapon_manager, CGameWeaponManager );
void CreateWeaponManager( const char *pWeaponName, int iMaxPieces ) { CGameWeaponManager *pManager = (CGameWeaponManager *)CreateEntityByName( "game_weapon_manager");
if( pManager ) { pManager->m_iszWeaponName = MAKE_STRING( pWeaponName ); pManager->m_iMaxPieces = iMaxPieces; DispatchSpawn( pManager ); } }
void WeaponManager_AmmoMod( CBaseCombatWeapon *pWeapon ) { for ( int i = 0; i < g_Managers.Count(); i++ ) { if ( g_Managers[i]->m_iszWeaponName == pWeapon->m_iClassname ) { int iNewClip = (int)(pWeapon->m_iClip1 * g_Managers[i]->m_flAmmoMod); int iNewRandomClip = iNewClip + RandomInt( -2, 2 );
if ( iNewRandomClip > pWeapon->GetMaxClip1() ) { iNewRandomClip = pWeapon->GetMaxClip1(); } else if ( iNewRandomClip <= 0 ) { //Drop at least one bullet.
iNewRandomClip = 1; }
pWeapon->m_iClip1 = iNewRandomClip; } } }
void WeaponManager_AddManaged( CBaseEntity *pWeapon ) { for ( int i = 0; i < g_Managers.Count(); i++ ) { if ( g_Managers[i]->m_iszWeaponName == pWeapon->m_iClassname ) { Assert( g_Managers[i]->m_ManagedNonWeapons.Find( pWeapon ) == g_Managers[i]->m_ManagedNonWeapons.InvalidIndex() ); g_Managers[i]->m_ManagedNonWeapons.AddToTail( pWeapon ); break; } } }
void WeaponManager_RemoveManaged( CBaseEntity *pWeapon ) { for ( int i = 0; i < g_Managers.Count(); i++ ) { if ( g_Managers[i]->m_iszWeaponName == pWeapon->m_iClassname ) { int j = g_Managers[i]->m_ManagedNonWeapons.Find( pWeapon ); if ( j != g_Managers[i]->m_ManagedNonWeapons.InvalidIndex() ) { g_Managers[i]->m_ManagedNonWeapons.FastRemove( j ); } } } }
//---------------------------------------------------------
//---------------------------------------------------------
void CGameWeaponManager::Spawn() { SetThink( &CGameWeaponManager::Think ); SetNextThink( gpGlobals->curtime ); CBaseEntity *pEntity = CreateEntityByName( STRING(m_iszWeaponName) ); if ( !pEntity ) { DevMsg("%s removed itself!\n", GetDebugName() ); UTIL_Remove(this); } else { m_bExpectingWeapon = ( dynamic_cast<CBaseCombatWeapon *>(pEntity) != NULL ); UTIL_Remove(pEntity); } }
//---------------------------------------------------------
// Count of all the weapons in the world of my type and
// see if we have a surplus. If there is a surplus, try
// to find suitable candidates for removal.
//
// Right now we just remove the first weapons we find that
// are behind the player, or are out of the player's PVS.
// Later, we may want to score the results so that we
// removed the farthest gun that's not in the player's
// viewcone, etc.
//
// Some notes and thoughts:
//
// This code is designed NOT to remove weapons that are
// hand-placed by level designers. It should only clean
// up weapons dropped by dead NPCs, which is useful in
// situations where enemies are spawned in for a sustained
// period of time.
//
// Right now we PREFER to remove weapons that are not in the
// player's PVS, but this could be opposite of what we
// really want. We may only want to conduct the cleanup on
// weapons that are IN the player's PVS.
//---------------------------------------------------------
void CGameWeaponManager::Think() { int i;
// Don't have to think all that often.
SetNextThink( gpGlobals->curtime + 2.0 );
const char *pszWeaponName = STRING( m_iszWeaponName );
CUtlVector<CBaseEntity *> candidates( 0, 64 );
if ( m_bExpectingWeapon ) { CBaseCombatWeapon *pWeapon = NULL; // Firstly, count the total number of weapons of this type in the world.
// Also count how many of those can potentially be removed.
pWeapon = assert_cast<CBaseCombatWeapon *>(gEntList.FindEntityByClassname( pWeapon, pszWeaponName ));
while( pWeapon ) { if( !pWeapon->IsEffectActive( EF_NODRAW ) && pWeapon->IsRemoveable() ) { candidates.AddToTail( pWeapon ); }
pWeapon = assert_cast<CBaseCombatWeapon *>(gEntList.FindEntityByClassname( pWeapon, pszWeaponName )); } } else { for ( i = 0; i < m_ManagedNonWeapons.Count(); i++) { CBaseEntity *pEntity = m_ManagedNonWeapons[i]; if ( pEntity ) { Assert( pEntity->m_iClassname == m_iszWeaponName ); if ( !pEntity->IsEffectActive( EF_NODRAW ) ) { candidates.AddToTail( pEntity ); } } else { m_ManagedNonWeapons.FastRemove( i-- ); } } }
// Calculate the surplus.
int surplus = candidates.Count() - m_iMaxPieces;
// Based on what the player can see, try to clean up the world by removing weapons that
// the player cannot see right at the moment.
CBaseEntity *pCandidate; for ( i = 0; i < candidates.Count() && surplus > 0; i++ ) { bool fRemovedOne = false;
pCandidate = candidates[i]; Assert( !pCandidate->IsEffectActive( EF_NODRAW ) );
if ( gpGlobals->maxClients == 1 ) { CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); // Nodraw serves as a flag that this weapon is already being removed since
// all we're really doing inside this loop is marking them for removal by
// the entity system. We don't want to count the same weapon as removed
// more than once.
if( !UTIL_FindClientInPVS( pCandidate->edict() ) ) { fRemovedOne = true; } else if( !pPlayer->FInViewCone( pCandidate ) ) { fRemovedOne = true; } else if ( UTIL_DistApprox( pPlayer->GetAbsOrigin(), pCandidate->GetAbsOrigin() ) > (30*12) ) { fRemovedOne = true; } } else { fRemovedOne = true; }
if( fRemovedOne ) { pCandidate->AddEffects( EF_NODRAW ); UTIL_Remove( pCandidate );
DevMsg( 2, "Surplus %s removed\n", pszWeaponName); surplus--; } } }
//---------------------------------------------------------
//---------------------------------------------------------
void CGameWeaponManager::InputSetMaxPieces( inputdata_t &inputdata ) { m_iMaxPieces = inputdata.value.Int(); }
//---------------------------------------------------------
//---------------------------------------------------------
void CGameWeaponManager::InputSetAmmoModifier( inputdata_t &inputdata ) { m_flAmmoMod = inputdata.value.Float(); }
|