2013-12-02 19:31:46 -08:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
# include "cbase.h"
# include "item_dynamic_resupply.h"
# include "props.h"
# include "items.h"
# include "ammodef.h"
// memdbgon must be the last include file in a .cpp file!!!
# include "tier0/memdbgon.h"
ConVar sk_dynamic_resupply_modifier ( " sk_dynamic_resupply_modifier " , " 1.0 " ) ;
extern ConVar sk_battery ;
extern ConVar sk_healthkit ;
ConVar g_debug_dynamicresupplies ( " g_debug_dynamicresupplies " , " 0 " , FCVAR_NONE , " Debug item_dynamic_resupply spawning. Set to 1 to see text printouts of the spawning. Set to 2 to see lines drawn to other items factored into the spawning. " ) ;
struct DynamicResupplyItems_t
{
const char * sEntityName ;
const char * sAmmoDef ;
int iAmmoCount ;
float flFullProbability ; // Probability of spawning if the player meeds all goals
} ;
struct SpawnInfo_t
{
float m_flDesiredRatio ;
float m_flCurrentRatio ;
float m_flDelta ;
int m_iPotentialItems ;
} ;
// Health types
static DynamicResupplyItems_t g_DynamicResupplyHealthItems [ ] =
{
{ " item_healthkit " , " Health " , 0 , 0.0f , } ,
{ " item_battery " , " Armor " , 0 , 0.0f } ,
} ;
// Ammo types
static DynamicResupplyItems_t g_DynamicResupplyAmmoItems [ ] =
{
{ " item_ammo_pistol " , " Pistol " , SIZE_AMMO_PISTOL , 0.5f } ,
{ " item_ammo_smg1 " , " SMG1 " , SIZE_AMMO_SMG1 , 0.4f } ,
{ " item_ammo_smg1_grenade " , " SMG1_Grenade " , SIZE_AMMO_SMG1_GRENADE , 0.0f } ,
{ " item_ammo_ar2 " , " AR2 " , SIZE_AMMO_AR2 , 0.0f } ,
{ " item_box_buckshot " , " Buckshot " , SIZE_AMMO_BUCKSHOT , 0.0f } ,
{ " item_rpg_round " , " RPG_Round " , SIZE_AMMO_RPG_ROUND , 0.0f } ,
{ " weapon_frag " , " Grenade " , 1 , 0.1f } ,
{ " item_ammo_357 " , " 357 " , SIZE_AMMO_357 , 0.0f } ,
{ " item_ammo_crossbow " , " XBowBolt " , SIZE_AMMO_CROSSBOW , 0.0f } ,
{ " item_ammo_ar2_altfire " , " AR2AltFire " , SIZE_AMMO_AR2_ALTFIRE , 0.0f } ,
} ;
# define DS_HEALTH_INDEX 0
# define DS_ARMOR_INDEX 1
# define DS_GRENADE_INDEX 6
# define NUM_HEALTH_ITEMS (ARRAYSIZE(g_DynamicResupplyHealthItems))
# define NUM_AMMO_ITEMS (ARRAYSIZE(g_DynamicResupplyAmmoItems))
# define DYNAMIC_ITEM_THINK 1.0
# define POTENTIAL_ITEM_RADIUS 1024
//-----------------------------------------------------------------------------
// Purpose: An item that dynamically decides what the player needs most and spawns that.
//-----------------------------------------------------------------------------
class CItem_DynamicResupply : public CPointEntity
{
DECLARE_CLASS ( CItem_DynamicResupply , CPointEntity ) ;
public :
DECLARE_DATADESC ( ) ;
CItem_DynamicResupply ( ) ;
void Spawn ( void ) ;
void Precache ( void ) ;
void Activate ( void ) ;
void CheckPVSThink ( void ) ;
// Inputs
void InputKill ( inputdata_t & data ) ;
void InputCalculateType ( inputdata_t & data ) ;
void InputBecomeMaster ( inputdata_t & data ) ;
float GetDesiredHealthPercentage ( void ) const { return m_flDesiredHealth [ 0 ] ; }
private :
friend void DynamicResupply_InitFromAlternateMaster ( CBaseEntity * pTargetEnt , string_t iszMaster ) ;
void FindPotentialItems ( int nCount , DynamicResupplyItems_t * pItems , int iDebug , SpawnInfo_t * pSpawnInfo ) ;
void ComputeHealthRatios ( CItem_DynamicResupply * pMaster , CBasePlayer * pPlayer , int iDebug , SpawnInfo_t * pSpawnInfo ) ;
void ComputeAmmoRatios ( CItem_DynamicResupply * pMaster , CBasePlayer * pPlayer , int iDebug , SpawnInfo_t * pSpawnInfo ) ;
bool SpawnItemFromRatio ( int nCount , DynamicResupplyItems_t * pItems , int iDebug , SpawnInfo_t * pSpawnInfo , Vector * pVecSpawnOrigin ) ;
// Spawns an item when the player is full
void SpawnFullItem ( CItem_DynamicResupply * pMaster , CBasePlayer * pPlayer , int iDebug ) ;
void SpawnDynamicItem ( CBasePlayer * pPlayer ) ;
enum Versions
{
VERSION_0 ,
VERSION_1_PERSISTENT_MASTER ,
VERSION_CURRENT = VERSION_1_PERSISTENT_MASTER ,
} ;
int m_version ;
float m_flDesiredHealth [ NUM_HEALTH_ITEMS ] ;
float m_flDesiredAmmo [ NUM_AMMO_ITEMS ] ;
bool m_bIsMaster ;
} ;
LINK_ENTITY_TO_CLASS ( item_dynamic_resupply , CItem_DynamicResupply ) ;
// Master
typedef CHandle < CItem_DynamicResupply > DynamicResupplyHandle_t ;
static DynamicResupplyHandle_t g_MasterResupply ;
//-----------------------------------------------------------------------------
// Save/load:
//-----------------------------------------------------------------------------
BEGIN_DATADESC ( CItem_DynamicResupply )
DEFINE_THINKFUNC ( CheckPVSThink ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " Kill " , InputKill ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " CalculateType " , InputCalculateType ) ,
DEFINE_INPUTFUNC ( FIELD_VOID , " BecomeMaster " , InputBecomeMaster ) ,
DEFINE_KEYFIELD ( m_flDesiredHealth [ 0 ] , FIELD_FLOAT , " DesiredHealth " ) ,
DEFINE_KEYFIELD ( m_flDesiredHealth [ 1 ] , FIELD_FLOAT , " DesiredArmor " ) ,
DEFINE_KEYFIELD ( m_flDesiredAmmo [ 0 ] , FIELD_FLOAT , " DesiredAmmoPistol " ) ,
DEFINE_KEYFIELD ( m_flDesiredAmmo [ 1 ] , FIELD_FLOAT , " DesiredAmmoSMG1 " ) ,
DEFINE_KEYFIELD ( m_flDesiredAmmo [ 2 ] , FIELD_FLOAT , " DesiredAmmoSMG1_Grenade " ) ,
DEFINE_KEYFIELD ( m_flDesiredAmmo [ 3 ] , FIELD_FLOAT , " DesiredAmmoAR2 " ) ,
DEFINE_KEYFIELD ( m_flDesiredAmmo [ 4 ] , FIELD_FLOAT , " DesiredAmmoBuckshot " ) ,
DEFINE_KEYFIELD ( m_flDesiredAmmo [ 5 ] , FIELD_FLOAT , " DesiredAmmoRPG_Round " ) ,
DEFINE_KEYFIELD ( m_flDesiredAmmo [ 6 ] , FIELD_FLOAT , " DesiredAmmoGrenade " ) ,
DEFINE_KEYFIELD ( m_flDesiredAmmo [ 7 ] , FIELD_FLOAT , " DesiredAmmo357 " ) ,
DEFINE_KEYFIELD ( m_flDesiredAmmo [ 8 ] , FIELD_FLOAT , " DesiredAmmoCrossbow " ) ,
DEFINE_KEYFIELD ( m_flDesiredAmmo [ 9 ] , FIELD_FLOAT , " DesiredAmmoAR2_AltFire " ) ,
DEFINE_FIELD ( m_version , FIELD_INTEGER ) ,
DEFINE_FIELD ( m_bIsMaster , FIELD_BOOLEAN ) ,
// Silence, Classcheck!
// DEFINE_ARRAY( m_flDesiredHealth, FIELD_FLOAT, NUM_HEALTH_ITEMS ),
// DEFINE_ARRAY( m_flDesiredAmmo, FIELD_FLOAT, NUM_AMMO_ITEMS ),
END_DATADESC ( )
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CItem_DynamicResupply : : CItem_DynamicResupply ( void )
{
AddSpawnFlags ( SF_DYNAMICRESUPPLY_USE_MASTER ) ;
m_version = VERSION_CURRENT ;
// Setup default values
m_flDesiredHealth [ 0 ] = 1.0 ; // Health
m_flDesiredHealth [ 1 ] = 0.3 ; // Armor
m_flDesiredAmmo [ 0 ] = 0.5 ; // Pistol
m_flDesiredAmmo [ 1 ] = 0.5 ; // SMG1
m_flDesiredAmmo [ 2 ] = 0.1 ; // SMG1 Grenade
m_flDesiredAmmo [ 3 ] = 0.4 ; // AR2
m_flDesiredAmmo [ 4 ] = 0.5 ; // Shotgun
m_flDesiredAmmo [ 5 ] = 0.0 ; // RPG Round
m_flDesiredAmmo [ 6 ] = 0.1 ; // Grenade
m_flDesiredAmmo [ 7 ] = 0 ; // 357
m_flDesiredAmmo [ 8 ] = 0 ; // Crossbow
m_flDesiredAmmo [ 9 ] = 0 ; // AR2 alt-fire
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : Spawn ( void )
{
if ( g_pGameRules - > IsAllowedToSpawn ( this ) = = false )
{
UTIL_Remove ( this ) ;
return ;
}
// Don't callback to spawn
Precache ( ) ;
m_bIsMaster = HasSpawnFlags ( SF_DYNAMICRESUPPLY_IS_MASTER ) ;
// Am I the master?
if ( ! HasSpawnFlags ( SF_DYNAMICRESUPPLY_IS_MASTER | SF_DYNAMICRESUPPLY_ALTERNATE_MASTER ) )
{
// Stagger the thinks a bit so they don't all think at the same time
SetNextThink ( gpGlobals - > curtime + RandomFloat ( 0.2f , 0.4f ) ) ;
SetThink ( & CItem_DynamicResupply : : CheckPVSThink ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : Activate ( void )
{
BaseClass : : Activate ( ) ;
if ( HasSpawnFlags ( SF_DYNAMICRESUPPLY_IS_MASTER ) )
{
if ( ! g_MasterResupply & & ( m_bIsMaster | | m_version < VERSION_1_PERSISTENT_MASTER ) )
{
g_MasterResupply = this ;
}
else
{
m_bIsMaster = false ;
}
}
if ( ! HasSpawnFlags ( SF_DYNAMICRESUPPLY_ALTERNATE_MASTER ) & & HasSpawnFlags ( SF_DYNAMICRESUPPLY_USE_MASTER ) & & gpGlobals - > curtime < 1.0 )
{
if ( ! g_MasterResupply )
{
Warning ( " item_dynamic_resupply set to 'Use Master', but no item_dynamic_resupply master exists. \n " ) ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : Precache ( void )
{
// Precache all the items potentially spawned
int i ;
for ( i = 0 ; i < NUM_HEALTH_ITEMS ; i + + )
{
UTIL_PrecacheOther ( g_DynamicResupplyHealthItems [ i ] . sEntityName ) ;
}
for ( i = 0 ; i < NUM_AMMO_ITEMS ; i + + )
{
UTIL_PrecacheOther ( g_DynamicResupplyAmmoItems [ i ] . sEntityName ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : CheckPVSThink ( void )
{
edict_t * pentPlayer = UTIL_FindClientInPVS ( edict ( ) ) ;
if ( pentPlayer )
{
CBasePlayer * pPlayer = ( CBasePlayer * ) CBaseEntity : : Instance ( pentPlayer ) ;
if ( pPlayer )
{
SpawnDynamicItem ( pPlayer ) ;
return ;
}
}
SetNextThink ( gpGlobals - > curtime + DYNAMIC_ITEM_THINK ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &data -
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : InputKill ( inputdata_t & data )
{
UTIL_Remove ( this ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &data -
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : InputCalculateType ( inputdata_t & data )
{
CBasePlayer * pPlayer = UTIL_GetLocalPlayer ( ) ;
SpawnDynamicItem ( pPlayer ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &data -
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : InputBecomeMaster ( inputdata_t & data )
{
if ( g_MasterResupply )
g_MasterResupply - > m_bIsMaster = false ;
g_MasterResupply = this ;
m_bIsMaster = true ;
// Stop thinking now that I am the master.
SetThink ( NULL ) ;
}
//-----------------------------------------------------------------------------
// Chooses an item when the player is full
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : SpawnFullItem ( CItem_DynamicResupply * pMaster , CBasePlayer * pPlayer , int iDebug )
{
// Can we not actually spawn the item?
if ( ! HasSpawnFlags ( SF_DYNAMICRESUPPLY_ALWAYS_SPAWN ) )
return ;
float flRatio [ NUM_AMMO_ITEMS ] ;
int i ;
float flTotalProb = 0.0f ;
for ( i = 0 ; i < NUM_AMMO_ITEMS ; + + i )
{
int iAmmoType = GetAmmoDef ( ) - > Index ( g_DynamicResupplyAmmoItems [ i ] . sAmmoDef ) ;
bool bCanSpawn = pPlayer - > Weapon_GetWpnForAmmo ( iAmmoType ) ! = NULL ;
if ( bCanSpawn & & ( g_DynamicResupplyAmmoItems [ i ] . flFullProbability ! = 0 ) & & ( pMaster - > m_flDesiredAmmo [ i ] ! = 0.0f ) )
{
flTotalProb + = g_DynamicResupplyAmmoItems [ i ] . flFullProbability ;
flRatio [ i ] = flTotalProb ;
}
else
{
flRatio [ i ] = - 1.0f ;
}
}
if ( flTotalProb = = 0.0f )
{
// If we're supposed to fallback to just a health vial, do that and finish.
if ( pMaster - > HasSpawnFlags ( SF_DYNAMICRESUPPLY_FALLBACK_TO_VIAL ) )
{
CBaseEntity : : Create ( " item_healthvial " , GetAbsOrigin ( ) , GetAbsAngles ( ) , this ) ;
if ( iDebug )
{
Msg ( " Player is full, spawning item_healthvial due to spawnflag. \n " ) ;
}
return ;
}
// Otherwise, spawn the first ammo item in the list
flRatio [ 0 ] = 1.0f ;
flTotalProb = 1.0f ;
}
float flChoice = random - > RandomFloat ( 0.0f , flTotalProb ) ;
for ( i = 0 ; i < NUM_AMMO_ITEMS ; + + i )
{
if ( flChoice < = flRatio [ i ] )
{
CBaseEntity : : Create ( g_DynamicResupplyAmmoItems [ i ] . sEntityName , GetAbsOrigin ( ) , GetAbsAngles ( ) , this ) ;
if ( iDebug )
{
Msg ( " Player is full, spawning %s \n " , g_DynamicResupplyAmmoItems [ i ] . sEntityName ) ;
}
return ;
}
}
if ( iDebug )
{
Msg ( " Player is full on all health + ammo, is not spawning. \n " ) ;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : FindPotentialItems ( int nCount , DynamicResupplyItems_t * pItems , int iDebug , SpawnInfo_t * pSpawnInfo )
{
int i ;
for ( i = 0 ; i < nCount ; + + i )
{
pSpawnInfo [ i ] . m_iPotentialItems = 0 ;
}
// Count the potential addition of items in the PVS
CBaseEntity * pEntity = NULL ;
while ( ( pEntity = UTIL_EntitiesInPVS ( this , pEntity ) ) ! = NULL )
{
if ( pEntity - > WorldSpaceCenter ( ) . DistToSqr ( WorldSpaceCenter ( ) ) > ( POTENTIAL_ITEM_RADIUS * POTENTIAL_ITEM_RADIUS ) )
continue ;
for ( i = 0 ; i < nCount ; + + i )
{
if ( ! FClassnameIs ( pEntity , pItems [ i ] . sEntityName ) )
continue ;
if ( iDebug = = 2 )
{
NDebugOverlay : : Line ( WorldSpaceCenter ( ) , pEntity - > WorldSpaceCenter ( ) , 0 , 255 , 0 , true , 20.0 ) ;
}
+ + pSpawnInfo [ i ] . m_iPotentialItems ;
break ;
}
}
if ( iDebug )
{
Msg ( " Searching the PVS: \n " ) ;
for ( int i = 0 ; i < nCount ; i + + )
{
Msg ( " Found %d '%s' in the PVS. \n " , pSpawnInfo [ i ] . m_iPotentialItems , pItems [ i ] . sEntityName ) ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : ComputeHealthRatios ( CItem_DynamicResupply * pMaster , CBasePlayer * pPlayer , int iDebug , SpawnInfo_t * pSpawnInfo )
{
for ( int i = 0 ; i < NUM_HEALTH_ITEMS ; i + + )
{
// Figure out the current level of this resupply type
float flMax ;
if ( i = = DS_HEALTH_INDEX )
{
// Health
flMax = pPlayer - > GetMaxHealth ( ) ;
float flCurrentHealth = pPlayer - > GetHealth ( ) + ( pSpawnInfo [ i ] . m_iPotentialItems * sk_healthkit . GetFloat ( ) ) ;
pSpawnInfo [ i ] . m_flCurrentRatio = ( flCurrentHealth / flMax ) ;
}
else if ( i = = DS_ARMOR_INDEX )
{
// Armor
// Ignore armor if we don't have the suit
if ( ! pPlayer - > IsSuitEquipped ( ) )
{
pSpawnInfo [ i ] . m_flCurrentRatio = 1.0 ;
}
else
{
flMax = MAX_NORMAL_BATTERY ;
float flCurrentArmor = pPlayer - > ArmorValue ( ) + ( pSpawnInfo [ i ] . m_iPotentialItems * sk_battery . GetFloat ( ) ) ;
pSpawnInfo [ i ] . m_flCurrentRatio = ( flCurrentArmor / flMax ) ;
}
}
pSpawnInfo [ i ] . m_flDesiredRatio = pMaster - > m_flDesiredHealth [ i ] * sk_dynamic_resupply_modifier . GetFloat ( ) ;
pSpawnInfo [ i ] . m_flDelta = pSpawnInfo [ i ] . m_flDesiredRatio - pSpawnInfo [ i ] . m_flCurrentRatio ;
pSpawnInfo [ i ] . m_flDelta = clamp ( pSpawnInfo [ i ] . m_flDelta , 0 , 1 ) ;
}
if ( iDebug )
{
Msg ( " Calculating desired health ratios & deltas: \n " ) ;
for ( int i = 0 ; i < NUM_HEALTH_ITEMS ; i + + )
{
Msg ( " %s Desired Ratio: %.2f, Current Ratio: %.2f = Delta of %.2f \n " ,
g_DynamicResupplyHealthItems [ i ] . sEntityName , pSpawnInfo [ i ] . m_flDesiredRatio , pSpawnInfo [ i ] . m_flCurrentRatio , pSpawnInfo [ i ] . m_flDelta ) ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : ComputeAmmoRatios ( CItem_DynamicResupply * pMaster , CBasePlayer * pPlayer , int iDebug , SpawnInfo_t * pSpawnInfo )
{
for ( int i = 0 ; i < NUM_AMMO_ITEMS ; i + + )
{
// Get the ammodef's
int iAmmoType = GetAmmoDef ( ) - > Index ( g_DynamicResupplyAmmoItems [ i ] . sAmmoDef ) ;
Assert ( iAmmoType ! = - 1 ) ;
// Ignore ammo types if we don't have a weapon that uses it (except for the grenade)
if ( ( i ! = DS_GRENADE_INDEX ) & & ! pPlayer - > Weapon_GetWpnForAmmo ( iAmmoType ) )
{
pSpawnInfo [ i ] . m_flCurrentRatio = 1.0 ;
}
else
{
float flMax = GetAmmoDef ( ) - > MaxCarry ( iAmmoType ) ;
float flCurrentAmmo = pPlayer - > GetAmmoCount ( iAmmoType ) ;
flCurrentAmmo + = ( pSpawnInfo [ i ] . m_iPotentialItems * g_DynamicResupplyAmmoItems [ i ] . iAmmoCount ) ;
pSpawnInfo [ i ] . m_flCurrentRatio = ( flCurrentAmmo / flMax ) ;
}
// Use the master if we're supposed to
pSpawnInfo [ i ] . m_flDesiredRatio = pMaster - > m_flDesiredAmmo [ i ] * sk_dynamic_resupply_modifier . GetFloat ( ) ;
pSpawnInfo [ i ] . m_flDelta = pSpawnInfo [ i ] . m_flDesiredRatio - pSpawnInfo [ i ] . m_flCurrentRatio ;
pSpawnInfo [ i ] . m_flDelta = clamp ( pSpawnInfo [ i ] . m_flDelta , 0 , 1 ) ;
}
if ( iDebug )
{
Msg ( " Calculating desired ammo ratios & deltas: \n " ) ;
for ( int i = 0 ; i < NUM_AMMO_ITEMS ; i + + )
{
Msg ( " %s Desired Ratio: %.2f, Current Ratio: %.2f = Delta of %.2f \n " ,
g_DynamicResupplyAmmoItems [ i ] . sEntityName , pSpawnInfo [ i ] . m_flDesiredRatio , pSpawnInfo [ i ] . m_flCurrentRatio , pSpawnInfo [ i ] . m_flDelta ) ;
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CItem_DynamicResupply : : SpawnItemFromRatio ( int nCount , DynamicResupplyItems_t * pItems , int iDebug , SpawnInfo_t * pSpawnInfo , Vector * pVecSpawnOrigin )
{
// Now find the one we're farthest from
float flFarthest = 0 ;
int iSelectedIndex = - 1 ;
for ( int i = 0 ; i < nCount ; + + i )
{
if ( pSpawnInfo [ i ] . m_flDelta > flFarthest )
{
flFarthest = pSpawnInfo [ i ] . m_flDelta ;
iSelectedIndex = i ;
}
}
if ( iSelectedIndex < 0 )
return false ;
if ( iDebug )
{
Msg ( " Chosen item: %s (had farthest delta, %.2f) \n " , pItems [ iSelectedIndex ] . sEntityName , pSpawnInfo [ iSelectedIndex ] . m_flDelta ) ;
}
CBaseEntity * pEnt = CBaseEntity : : Create ( pItems [ iSelectedIndex ] . sEntityName , * pVecSpawnOrigin , GetAbsAngles ( ) , this ) ;
pEnt - > SetAbsVelocity ( GetAbsVelocity ( ) ) ;
pEnt - > SetLocalAngularVelocity ( GetLocalAngularVelocity ( ) ) ;
// Move the entity up so that it doesn't go below the spawn origin
Vector vecWorldMins , vecWorldMaxs ;
pEnt - > CollisionProp ( ) - > WorldSpaceAABB ( & vecWorldMins , & vecWorldMaxs ) ;
if ( vecWorldMins . z < pVecSpawnOrigin - > z )
{
float dz = pVecSpawnOrigin - > z - vecWorldMins . z ;
pVecSpawnOrigin - > z + = dz ;
vecWorldMaxs . z + = dz ;
pEnt - > SetAbsOrigin ( * pVecSpawnOrigin ) ;
}
// Update the spawn position to spawn them on top of each other
pVecSpawnOrigin - > z = vecWorldMaxs . z + 6.0f ;
pVecSpawnOrigin - > x + = random - > RandomFloat ( - 6 , 6 ) ;
pVecSpawnOrigin - > y + = random - > RandomFloat ( - 6 , 6 ) ;
return true ;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItem_DynamicResupply : : SpawnDynamicItem ( CBasePlayer * pPlayer )
{
Assert ( pPlayer ) ;
// If we're the master, we never want to spawn
if ( g_MasterResupply = = this )
return ;
int iDebug = g_debug_dynamicresupplies . GetInt ( ) ;
if ( iDebug )
{
Msg ( " Spawning item_dynamic_resupply: \n " ) ;
}
SpawnInfo_t pAmmoInfo [ NUM_AMMO_ITEMS ] ;
SpawnInfo_t pHealthInfo [ NUM_HEALTH_ITEMS ] ;
// Count the potential addition of items in the PVS
FindPotentialItems ( NUM_HEALTH_ITEMS , g_DynamicResupplyHealthItems , iDebug , pHealthInfo ) ;
FindPotentialItems ( NUM_AMMO_ITEMS , g_DynamicResupplyAmmoItems , iDebug , pAmmoInfo ) ;
// Use the master if we're supposed to
CItem_DynamicResupply * pMaster = this ;
if ( HasSpawnFlags ( SF_DYNAMICRESUPPLY_USE_MASTER ) & & g_MasterResupply )
{
pMaster = g_MasterResupply ;
}
// Compute desired ratios for health and ammo
ComputeHealthRatios ( pMaster , pPlayer , iDebug , pHealthInfo ) ;
ComputeAmmoRatios ( pMaster , pPlayer , iDebug , pAmmoInfo ) ;
Vector vecSpawnOrigin = GetAbsOrigin ( ) ;
bool bHealthSpawned = SpawnItemFromRatio ( NUM_HEALTH_ITEMS , g_DynamicResupplyHealthItems , iDebug , pHealthInfo , & vecSpawnOrigin ) ;
bool bAmmoSpawned = SpawnItemFromRatio ( NUM_AMMO_ITEMS , g_DynamicResupplyAmmoItems , iDebug , pAmmoInfo , & vecSpawnOrigin ) ;
if ( ! bHealthSpawned & & ! bAmmoSpawned )
{
SpawnFullItem ( pMaster , pPlayer , iDebug ) ;
}
SetThink ( NULL ) ;
UTIL_Remove ( this ) ;
}
//-----------------------------------------------------------------------------
// Purpose:
// Output : float
//-----------------------------------------------------------------------------
float DynamicResupply_GetDesiredHealthPercentage ( void )
{
// Return what the master supply dictates
if ( g_MasterResupply ! = NULL )
return g_MasterResupply - > GetDesiredHealthPercentage ( ) ;
// Full health if they haven't specified otherwise
return 1.0f ;
}
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
void DynamicResupply_InitFromAlternateMaster ( CBaseEntity * pTargetEnt , string_t iszMaster )
{
if ( iszMaster = = NULL_STRING )
{
return ;
}
CItem_DynamicResupply * pTargetResupply = assert_cast < CItem_DynamicResupply * > ( pTargetEnt ) ;
CBaseEntity * pMasterEnt = gEntList . FindEntityByName ( NULL , iszMaster ) ;
if ( ! pMasterEnt | | ! pMasterEnt - > ClassMatches ( pTargetResupply - > GetClassname ( ) ) )
{
DevWarning ( " Invalid item_dynamic_resupply name %s \n " , STRING ( iszMaster ) ) ;
return ;
}
CItem_DynamicResupply * pMasterResupply = assert_cast < CItem_DynamicResupply * > ( pMasterEnt ) ;
pTargetResupply - > RemoveSpawnFlags ( SF_DYNAMICRESUPPLY_USE_MASTER ) ;
memcpy ( pTargetResupply - > m_flDesiredHealth , pMasterResupply - > m_flDesiredHealth , sizeof ( pMasterResupply - > m_flDesiredHealth ) ) ;
memcpy ( pTargetResupply - > m_flDesiredAmmo , pMasterResupply - > m_flDesiredAmmo , sizeof ( pMasterResupply - > m_flDesiredAmmo ) ) ;
2013-06-26 15:22:04 -07:00
}