示例#1
0
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_AllyManager::CountAllies( int *pTotal, int *pMedics )
{
	(*pTotal) = (*pMedics) = 0;

/*	if ( !AI_IsSinglePlayer() )
	{
		// @TODO (toml 10-22-04): no MP support right now
		return;
	}
*/
	CAI_BaseNPC **	ppAIs 	= g_AI_Manager.AccessAIs();
	int 			nAIs 	= g_AI_Manager.NumAIs();

	for ( int i = 0; i < nAIs; i++ )
	{
		if ( ppAIs[i]->IsAlive() && ppAIs[i]->IsPlayerAlly() )
		{
			// Vital allies do not count.
			if( ppAIs[i]->Classify() == CLASS_PLAYER_ALLY_VITAL )
				continue;

			// They only count if I can use them.
			if( ppAIs[i]->HasSpawnFlags(SF_CITIZEN_NOT_COMMANDABLE) )
				continue;
			
			// They only count if I can use them.
			if( ppAIs[i]->IRelationType( UTIL_GetNearestPlayer(ppAIs[i]->GetAbsOrigin()) ) != D_LI )
				continue;

			// Skip distant NPCs
			Vector vNearestPlayerPos = UTIL_GetNearestPlayer(ppAIs[i]->GetAbsOrigin())->GetAbsOrigin();
			if ( !ppAIs[i]->IsInPlayerSquad() && 
				!UTIL_FindClientInPVS( ppAIs[i]->edict() ) && 
				( ( ppAIs[i]->GetAbsOrigin() - vNearestPlayerPos ).LengthSqr() > 150*12 ||
				  fabsf( ppAIs[i]->GetAbsOrigin().z - vNearestPlayerPos.z ) > 192 ) )
				continue;

			if( FClassnameIs( ppAIs[i], "npc_citizen" ) ) 
			{  
				CNPC_Citizen *pCitizen = assert_cast<CNPC_Citizen *>(ppAIs[i]);
				if ( !pCitizen->CanJoinPlayerSquad() )
					continue;

				if ( pCitizen->WasInPlayerSquad() && !pCitizen->IsInPlayerSquad() )
					continue;

				if ( ppAIs[i]->HasSpawnFlags( SF_CITIZEN_MEDIC ) )
					(*pMedics)++;
			}

			(*pTotal)++;
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CPropVehicleViewController::InputForcePlayerIn( inputdata_t &inputdata )
{
	CBasePlayer *pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin()); // AI Patch Addition.
	if ( !pPlayer )
		return;

	ResetUseKey( pPlayer );

	// Get the entry animation from the input
	int iEntryAnim = ACTIVITY_NOT_AVAILABLE;
	if ( inputdata.value.StringID() != NULL_STRING )
	{
		iEntryAnim = LookupSequence( inputdata.value.String() );
		if ( iEntryAnim == ACTIVITY_NOT_AVAILABLE )
		{
			Warning("vehicle_viewcontroller %s could not find specified entry animation %s\n", STRING(GetEntityName()), inputdata.value.String() );
			return;
		}
	}

	// Make sure we successfully got in the vehicle
	if ( pPlayer->GetInVehicle( GetServerVehicle(), VEHICLE_ROLE_DRIVER ) == false )
	{
		// The player was unable to enter the vehicle and the output has failed
		Assert( 0 );
		return;
	}

	// Setup the "enter" vehicle sequence
	SetCycle( 0 );
	m_flAnimTime = gpGlobals->curtime;
	ResetSequence( iEntryAnim );
	ResetClientsideFrame();
	m_bEnterAnimOn = true;
}
示例#3
0
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CEnvHudHint::InputHideHudHint( inputdata_t &inputdata )
{
	CBaseEntity *pPlayer = NULL;

	if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
	{
		pPlayer = inputdata.pActivator;
	}
	else
	{
#ifdef HL2SB
		pPlayer = UTIL_GetNearestPlayer( GetAbsOrigin() );
#else
		pPlayer = UTIL_GetLocalPlayer();
#endif
	}

	if ( pPlayer )
	{
		if ( !pPlayer || !pPlayer->IsNetClient() )
			return;

		CSingleUserRecipientFilter user( (CBasePlayer *)pPlayer );
		user.MakeReliable();
		UserMessageBegin( user, "KeyHintText" );
		WRITE_BYTE( 1 );	// one message
		WRITE_STRING( STRING(NULL_STRING) );
		MessageEnd();
	}
}
//-----------------------------------------------------------------------------
// Purpose: Input handler for showing the message and/or playing the sound.
//-----------------------------------------------------------------------------
void CEnvHudHint::InputShowHudHint( inputdata_t &inputdata )
{
	if ( AllPlayers() )
	{
		CReliableBroadcastRecipientFilter user;
		UserMessageBegin( user, "KeyHintText" );
		WRITE_BYTE( 1 );	// one message
		WRITE_STRING( STRING(m_iszMessage) );
		MessageEnd();
	}
	else
	{
		CBaseEntity *pPlayer = NULL;
		if ( inputdata.pActivator && inputdata.pActivator->IsPlayer() )
		{
			pPlayer = inputdata.pActivator;
		}
		else
		{
			pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin());
		}

		if ( !pPlayer || !pPlayer->IsNetClient() )
			return;

		CSingleUserRecipientFilter user( (CBasePlayer *)pPlayer );
		user.MakeReliable();
		UserMessageBegin( user, "KeyHintText" );
			WRITE_BYTE( 1 );	// one message
			WRITE_STRING( STRING(m_iszMessage) );
		MessageEnd();
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &inputdata - 
//-----------------------------------------------------------------------------
void CPropVehiclePrisonerPod::InputEnterVehicleImmediate( inputdata_t &inputdata )
{
	if ( m_bEnterAnimOn )
		return;

	// Try the activator first & use them if they are a player.
	CBaseCombatCharacter *pPassenger = ToBaseCombatCharacter( inputdata.pActivator );
	if ( pPassenger == NULL )
	{
		// Activator was not a player, just grab the nearest player. // AI Patch Addition.
pPassenger = UTIL_GetNearestPlayer(GetAbsOrigin()); // AI Patch Addition.
		if ( pPassenger == NULL )
			return;
	}

	CBasePlayer *pPlayer = ToBasePlayer( pPassenger );
	if ( pPlayer != NULL )
	{
		if ( pPlayer->IsInAVehicle() )
		{
			// Force the player out of whatever vehicle they are in.
			pPlayer->LeaveVehicle();
		}
		
		pPlayer->GetInVehicle( GetServerVehicle(), VEHICLE_ROLE_DRIVER );
	}
	else
	{
		// NPCs are not currently supported - jdw
		Assert( 0 );
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &inputdata - 
//-----------------------------------------------------------------------------
void CEnvZoom::InputZoom( inputdata_t &inputdata )
{
	CBasePlayer *pPlayer;

	if (inputdata.pActivator && inputdata.pActivator->IsPlayer())
		pPlayer = ToBasePlayer(inputdata.pActivator);
	else
		pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin());

	if ( pPlayer )
	{

#ifdef HL2_DLL
		if ( pPlayer == pPlayer->GetFOVOwner() )
		{
			CHL2_Player *pHLPlayer = static_cast<CHL2_Player*>( pPlayer );

			pHLPlayer->StopZooming();
		}
#endif

		// If the player's already holding a fov from another env_zoom, we're allowed to overwrite it
		if ( pPlayer->GetFOVOwner() && FClassnameIs( pPlayer->GetFOVOwner(), "env_zoom" ) )
		{
			pPlayer->ClearZoomOwner();
		}

		//Stuff the values
		pPlayer->SetFOV( this, m_nFOV, m_flSpeed );
	}
}
示例#7
0
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &data - 
//-----------------------------------------------------------------------------
void CItem_DynamicResupply::InputCalculateType( inputdata_t &data )
{
	// spawn gear for the nearest player 
	CBasePlayer *pNearest = UTIL_GetNearestPlayer(GetAbsOrigin()); 
	if ( pNearest != NULL ) 
		SpawnDynamicItem( pNearest );
}
示例#8
0
//-----------------------------------------------------------------------------
// Creates the explosion effect
//-----------------------------------------------------------------------------
void CEnvHeadcrabCanister::Detonate( )
{
	// Send the impact output
	m_OnImpacted.FireOutput( this, this, 0 );

	if ( !HasSpawnFlags( SF_NO_IMPACT_SOUND ) )
	{
		StopSound( "HeadcrabCanister.IncomingSound" );
		EmitSound( "HeadcrabCanister.Explosion" );
	}

	// If we're supposed to be removed, do that now
	if ( HasSpawnFlags( SF_REMOVE_ON_IMPACT ) )
	{
		SetAbsOrigin( m_vecImpactPosition );
		SetModel( ENV_HEADCRABCANISTER_BROKEN_MODEL );
		SetMoveType( MOVETYPE_NONE );
		IncrementInterpolationFrame();
		m_bLanded = true;
		
		// Become invisible so our trail can finish up
		AddEffects( EF_NODRAW );
		SetSolidFlags( FSOLID_NOT_SOLID );

		SetThink( &CEnvHeadcrabCanister::SUB_Remove );
		SetNextThink( gpGlobals->curtime + ENV_HEADCRABCANISTER_TRAIL_TIME );

		return;
	}

	// Test for damaging things
	TestForCollisionsAgainstWorld( m_vecImpactPosition );

	// Shake the screen unless flagged otherwise
	if ( !HasSpawnFlags( SF_NO_SHAKE ) )
	{
		CBasePlayer *pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin());

		// If the player is on foot, then do a more limited shake
		float shakeRadius = ( pPlayer && pPlayer->IsInAVehicle() ) ? sk_env_headcrabcanister_shake_radius_vehicle.GetFloat() : sk_env_headcrabcanister_shake_radius.GetFloat();

		UTIL_ScreenShake( m_vecImpactPosition, sk_env_headcrabcanister_shake_amplitude.GetFloat(), 150.0, 1.0, shakeRadius, SHAKE_START );
	}

	// Do explosion effects
	if ( !HasSpawnFlags( SF_NO_IMPACT_EFFECTS ) )
	{
		// Normal explosion
		ExplosionCreate( m_vecImpactPosition, GetAbsAngles(), this, 50.0f, 500.0f, 
			SF_ENVEXPLOSION_NODLIGHTS | SF_ENVEXPLOSION_NOSPARKS | SF_ENVEXPLOSION_NODAMAGE | SF_ENVEXPLOSION_NOSOUND, 1300.0f );
			
		// Dust explosion
		AR2Explosion *pExplosion = AR2Explosion::CreateAR2Explosion( m_vecImpactPosition );
		
		if( pExplosion )
		{
			pExplosion->SetLifetime(10);
		}
	}
}
示例#9
0
//-----------------------------------------------------------------------------
// Purpose:
// Input  : &inputdata -
//-----------------------------------------------------------------------------
void CPropCrane::InputForcePlayerIn( inputdata_t &inputdata )
{
    CBasePlayer *pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin());
    if ( pPlayer && !m_hPlayer )
    {
        GetServerVehicle()->HandlePassengerEntry( pPlayer, 0 );
    }
}
bool CNPC_Zombine::AllowedToSprint( void )
{
	if ( IsOnFire() )
		return false;
	
	//If you're sprinting then there's no reason to sprint again.
	if ( IsSprinting() )
		return false;

	int iChance = SPRINT_CHANCE_VALUE;

	//Secobmod FixMe ?? also changed to HL2MPRules
	CHL2_Player *pPlayer = dynamic_cast <CHL2_Player*> ( UTIL_GetNearestPlayer(GetAbsOrigin() ));
	//CHL2MP_Player *pPlayer = dynamic_cast<CHL2MP_Player *>( UTIL_GetNearestPlayer(GetAbsOrigin() );

	if ( pPlayer )
	{
#ifdef MFS
		if ( HL2MPRules()->IsAlyxInDarknessMode() && pPlayer->FlashlightIsOn() == false )
#else
		if (IsAlyxInDarknessMode() && pPlayer->FlashlightIsOn() == false)
#endif
		{
			iChance = SPRINT_CHANCE_VALUE_DARKNESS;
		}

		//Bigger chance of this happening if the player is not looking at the zombie
		if ( pPlayer->FInViewCone( this ) == false )
		{
			iChance *= 2;
		}
	}

	if ( HasGrenade() ) 
	{
		iChance *= 4;
	}

	//Below 25% health they'll always sprint
	if ( ( GetHealth() > GetMaxHealth() * 0.5f ) )
	{
		if ( IsStrategySlotRangeOccupied( SQUAD_SLOT_ZOMBINE_SPRINT1, SQUAD_SLOT_ZOMBINE_SPRINT2 ) == true )
			return false;
		
		if ( random->RandomInt( 0, 100 ) > iChance )
			return false;
		
		if ( m_flSprintRestTime > gpGlobals->curtime )
			return false;
	}

	float flLength = ( GetEnemy()->WorldSpaceCenter() - WorldSpaceCenter() ).Length();

	if ( flLength > MAX_SPRINT_DISTANCE )
		return false;

	return true;
}
示例#11
0
void CAI_PlaneSolver::GenerateObstacleNpcs( const AILocalMoveGoal_t &goal, float probeDist )
{
	if ( !ProbeForNpcs() )
	{
		CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs();
		Vector minsSelf, maxsSelf;
		m_pNpc->CollisionProp()->WorldSpaceSurroundingBounds( &minsSelf, &maxsSelf );
		float radiusSelf = (minsSelf.AsVector2D() - maxsSelf.AsVector2D()).Length() * 0.5;

		for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ )
		{
			CAI_BaseNPC *pAI = ppAIs[i];
			if ( pAI != m_pNpc && pAI->IsAlive() && ( !goal.pPath || pAI != goal.pPath->GetTarget() ) )
			{
				Vector mins, maxs;
				
				pAI->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs );
				if ( mins.z < maxsSelf.z + 12.0 && maxs.z > minsSelf.z - 12.0 )
				{
					float radius = (mins.AsVector2D() - maxs.AsVector2D()).Length() * 0.5;
					float distance = ( pAI->GetAbsOrigin().AsVector2D() - m_pNpc->GetAbsOrigin().AsVector2D() ).Length();
					if ( distance - radius < radiusSelf + probeDist )
					{
						AddObstacle( pAI->WorldSpaceCenter(), radius, pAI, AIMST_AVOID_NPC );
					}
				}
			}
		}

		#ifdef SecobMod__Enable_Fixed_Multiplayer_AI
			CBaseEntity *pPlayer = UTIL_GetNearestPlayer(m_pNpc->GetAbsOrigin()); 
		#else
			CBaseEntity *pPlayer = UTIL_PlayerByIndex( 1 );
		#endif //SecobMod__Enable_Fixed_Multiplayer_AI

		if ( pPlayer )
		{
			Vector mins, maxs;
			
			pPlayer->CollisionProp()->WorldSpaceSurroundingBounds( &mins, &maxs );
			if ( mins.z < maxsSelf.z + 12.0 && maxs.z > minsSelf.z - 12.0 )
			{
				float radius = (mins.AsVector2D() - maxs.AsVector2D()).Length();
				float distance = ( pPlayer->GetAbsOrigin().AsVector2D() - m_pNpc->GetAbsOrigin().AsVector2D() ).Length();
				if ( distance - radius < radiusSelf + probeDist )
				{
					AddObstacle( pPlayer->WorldSpaceCenter(), radius, pPlayer, AIMST_AVOID_NPC );
				}
			}
		}

	}
}
//-----------------------------------------------------------------------------
// Purpose: Burn targets around us
//-----------------------------------------------------------------------------
void CEntityDissolve::DissolveThink( void )
{
	CBaseAnimating *pTarget = ( GetMoveParent() ) ? GetMoveParent()->GetBaseAnimating() : NULL;

	if ( GetModelName() == NULL_STRING && pTarget == NULL )
		 return;
	
	if ( pTarget == NULL )
	{
		UTIL_Remove( this );
		return;
	}

	// Turn them into debris
	pTarget->SetCollisionGroup( COLLISION_GROUP_DISSOLVING );

	if ( pTarget && pTarget->GetFlags() & FL_TRANSRAGDOLL )
	{
		SetRenderColorA( 0 );
	}

	float dt = gpGlobals->curtime - m_flStartTime;

	if ( dt < m_flFadeInStart )
	{
		SetNextThink( m_flStartTime + m_flFadeInStart );
		return;
	}

	// If we're done fading, then kill our target entity and us
	if ( dt >= m_flFadeOutStart + m_flFadeOutLength )
	{
		// Necessary to cause it to do the appropriate death cleanup
		// Yeah, the player may have nothing to do with it, but
		// passing NULL to TakeDamage causes bad things to happen
		CBasePlayer *pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin());
		int iNoPhysicsDamage = g_pGameRules->Damage_GetNoPhysicsForce();
		CTakeDamageInfo info( pPlayer, pPlayer, 10000.0, DMG_GENERIC | DMG_REMOVENORAGDOLL | iNoPhysicsDamage );
		pTarget->TakeDamage( info );

		if ( pTarget != pPlayer )
		{
			UTIL_Remove( pTarget );
		}
		
		UTIL_Remove( this );
		
		return;
	}

	SetNextThink( gpGlobals->curtime + TICK_INTERVAL );
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &inputdata - 
//-----------------------------------------------------------------------------
void CEnvZoom::InputUnZoom( inputdata_t &inputdata )
{
	CBasePlayer *pPlayer;
	if (inputdata.pActivator && inputdata.pActivator->IsPlayer())
		pPlayer = ToBasePlayer(inputdata.pActivator);
	else
		pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin());

	if ( pPlayer )
	{
		// Stuff the values
		pPlayer->SetFOV( this, 0 );
	}
}
// player pickup utility routine
void Pickup_ForcePlayerToDropThisObject( CBaseEntity *pTarget )
{
    if ( pTarget == NULL )
        return;

    IPhysicsObject *pPhysics = pTarget->VPhysicsGetObject();

    if ( pPhysics == NULL )
        return;

    if ( pPhysics->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
    {
        CBasePlayer *pPlayer = UTIL_GetNearestPlayer(pTarget->GetAbsOrigin());
        pPlayer->ForceDropOfCarriedPhysObjects( pTarget );
    }
}
CBaseEntity* MoveToRandomSpot( CBaseEntity *pEnt )
{
	if ( pEnt )
	{
#ifdef HL2SB
		CBasePlayer *pLocalPlayer = UTIL_GetNearestPlayer( pEnt->GetAbsOrigin() );
#else
		CBasePlayer *pLocalPlayer = UTIL_GetLocalPlayer();
#endif
		if ( pLocalPlayer )
		{			
			Vector vForward;
			pLocalPlayer->EyeVectors(&vForward );

			UTIL_SetOrigin( pEnt, GetRandomSpot() );
		}
	}

	return pEnt;
}
//-----------------------------------------------------------------------------
// Purpose: Force the player to enter the vehicle.
//-----------------------------------------------------------------------------
void CPropVehiclePrisonerPod::InputEnterVehicle( inputdata_t &inputdata )
{
	if ( m_bEnterAnimOn )
		return;

	// Try the activator first & use them if they are a player.
	CBaseCombatCharacter *pPassenger = ToBaseCombatCharacter( inputdata.pActivator );
	if ( pPassenger == NULL )
	{
		// Activator was not a player, just grab the nearest player. // AI Patch Addition.
pPassenger = UTIL_GetNearestPlayer(GetAbsOrigin()); // AI Patch Addition.
		if ( pPassenger == NULL )
			return;
	}

	// FIXME: I hate code like this. I should really add a parameter to HandlePassengerEntry
	//		  to allow entry into locked vehicles
	bool bWasLocked = m_bLocked;
	m_bLocked = false;
	GetServerVehicle()->HandlePassengerEntry( pPassenger, true );
	m_bLocked = bWasLocked;
}
//------------------------------------------------------------------------------
bool CNPC_EnemyFinder::ShouldAlwaysThink()
{
	if ( BaseClass::ShouldAlwaysThink() )
		return true;
		
	CBasePlayer *pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin());
	if ( pPlayer && IRelationType( pPlayer ) == D_HT )
	{
		float playerDistSqr = GetAbsOrigin().DistToSqr( pPlayer->GetAbsOrigin() );

		if ( !m_flMaxSearchDist || playerDistSqr <= Square(m_flMaxSearchDist) )
		{
			if ( !FBitSet( m_spawnflags, SF_ENEMY_FINDER_CHECK_VIS) )
				return true;
				
			if ( playerDistSqr <= Square( 50 * 12 ) )
				return true;
		}
	}
	
	return false;
}
示例#18
0
//-----------------------------------------
// Think
//-----------------------------------------
void CMessageEntity::Think( void )
{
	SetNextThink( gpGlobals->curtime + 0.1f );

	// check for player distance
	CBasePlayer *pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin());
 

	if ( !pPlayer || ( pPlayer->GetFlags() & FL_NOTARGET ) )
		return;

	Vector worldTargetPosition = pPlayer->EyePosition();

	// bail if player is too far away
	if ( (worldTargetPosition - GetAbsOrigin()).Length() > m_radius )
	{
		m_drawText = false;
		return;
	}

	// turn on text
	m_drawText = true;
}
//------------------------------------------------------------------------------
// Purpose :
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CNPC_EnemyFinder::StartNPC ( void )
{
	AddSpawnFlags(SF_NPC_FALL_TO_GROUND);	// this prevents CAI_BaseNPC from slamming the finder to 
											// the ground just because it's not MOVETYPE_FLY
	BaseClass::StartNPC();

	if ( m_PlayerFreePass.GetParams().duration > 0.1 )
	{
		m_PlayerFreePass.SetPassTarget( UTIL_GetNearestPlayer(GetAbsOrigin()) );

		AI_FreePassParams_t freePassParams = m_PlayerFreePass.GetParams();

		freePassParams.coverDist = 120;
		freePassParams.peekEyeDist = 1.75;
		freePassParams.peekEyeDistZ = 4;

		m_PlayerFreePass.SetParams( freePassParams );
	}

	if (!m_nStartOn)
	{
		SetThink(NULL);
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &data - 
//-----------------------------------------------------------------------------
void CItem_DynamicResupply::InputCalculateType( inputdata_t &data )
{{
	#ifdef SecobMod__Enable_Fixed_Multiplayer_AI
		// spawn gear for the nearest player 
		CBasePlayer *pNearest = UTIL_GetNearestPlayer(GetAbsOrigin()); 
		if ( pNearest != NULL ) 
			SpawnDynamicItem( pNearest ); 
	#else
		CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
		SpawnDynamicItem( pPlayer );
	#endif //SecobMod__Enable_Fixed_Multiplayer_AI
}

//-----------------------------------------------------------------------------
// 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 );
		}
	}
}
CBaseEntity* CHL2MP_Player::EntSelectSpawnPoint( void )
{
	CBaseEntity *pSpot = NULL;
	CBaseEntity *pLastSpawnPoint = g_pLastSpawn;
	edict_t		*player = edict();
	const char *pSpawnpointName = "info_player_deathmatch";

	pSpot = pLastSpawnPoint;
	// Randomize the start spot
	for ( int i = random->RandomInt(1,5); i > 0; i-- )
		pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
	if ( !pSpot )  // skip over the null point
		pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );

	CBaseEntity *pFirstSpot = pSpot;

	do 
	{
		if ( pSpot )
		{
			// check if pSpot is valid
			if ( g_pGameRules->IsSpawnPointValid( pSpot, this ) )
			{
				if ( pSpot->GetLocalOrigin() == vec3_origin )
				{
					pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
					continue;
				}

				// if so, go to pSpot
				goto ReturnSpot;
			}
		}
		// increment pSpot
		pSpot = gEntList.FindEntityByClassname( pSpot, pSpawnpointName );
	} while ( pSpot != pFirstSpot ); // loop if we're not back to the start

	// we haven't found a place to spawn yet,  so kill any guy at the first spawn point and spawn there
	if ( pSpot )
	{
		CBaseEntity *ent = NULL;
		for ( CEntitySphereQuery sphere( pSpot->GetAbsOrigin(), 128 ); (ent = sphere.GetCurrentEntity()) != NULL; sphere.NextEntity() )
		{
			// if ent is a client, kill em (unless they are ourselves)
			if ( ent->IsPlayer() && !(ent->edict() == player) )
				ent->TakeDamage( CTakeDamageInfo( GetContainingEntity(INDEXENT(0)), GetContainingEntity(INDEXENT(0)), 300, DMG_GENERIC ) );
		}
		goto ReturnSpot;
	}

	if ( !pSpot  )
	{
		char szMapName[256];
		Q_strncpy(szMapName, STRING(gpGlobals->mapname), sizeof(szMapName));
		Q_strlower(szMapName);

		//TDT - Information: Although we don't support official maps for gaming, they are useful for testing and these maps for whatever reason spawn you in the wrong location. As such this
		// code is here to force players to spawn at the beginning of the selected maps. Custom maps won't require this as they will have deathmatch/class based player starts.
		if (!Q_strnicmp(szMapName, "d1_canals_01a", 13)
			|| !Q_strnicmp(szMapName, "d1_canals_03", 12)
			|| !Q_strnicmp(szMapName, "d1_canals_13", 12)
			|| !Q_strnicmp(szMapName, "d1_town_01", 10)
			|| !Q_strnicmp(szMapName, "d1_town_01a", 11)
			|| !Q_strnicmp(szMapName, "d1_town_02", 10)
			|| !Q_strnicmp(szMapName, "d1_town_02a", 11)
			|| !Q_strnicmp(szMapName, "d1_town_03", 10)
			|| !Q_strnicmp(szMapName, "d1_town_04", 10)
			|| !Q_strnicmp(szMapName, "d1_town_05", 10)
			|| !Q_strnicmp(szMapName, "d2_coast_03", 11)
			|| !Q_strnicmp(szMapName, "d2_coast_08", 11)
			|| !Q_strnicmp(szMapName, "d2_coast_11", 11)
			|| !Q_strnicmp(szMapName, "d2_prison_01", 12)
			|| !Q_strnicmp(szMapName, "d2_prison_02", 12)
			|| !Q_strnicmp(szMapName, "d2_prison_03", 12)
			|| !Q_strnicmp(szMapName, "d2_prison_04", 12)
			|| !Q_strnicmp(szMapName, "d2_prison_05", 12)
			|| !Q_strnicmp(szMapName, "d2_prison_06", 12)
			|| !Q_strnicmp(szMapName, "d2_prison_07", 12)
			|| !Q_strnicmp(szMapName, "d2_prison_08", 12)
			|| !Q_strnicmp(szMapName, "d3_c17_08", 9)
			|| !Q_strnicmp(szMapName, "d3_citadel_01", 13)
			|| !Q_strnicmp(szMapName, "d3_citadel_02", 13)
			|| !Q_strnicmp(szMapName, "d3_citadel_03", 13)
			|| !Q_strnicmp(szMapName, "d3_citadel_04", 13)
			|| !Q_strnicmp(szMapName, "d3_citadel_05", 13)
			|| !Q_strnicmp(szMapName, "d3_breen_01", 11)
			|| !Q_strnicmp(szMapName, "ep1_c17_00", 10)
			|| !Q_strnicmp(szMapName, "ep1_c17_00a", 11)
			|| !Q_strnicmp(szMapName, "ep1_c17_02b", 11)
			|| !Q_strnicmp(szMapName, "ep1_c17_05", 10)
			|| !Q_strnicmp(szMapName, "ep2_outland_01a", 15)
			|| !Q_strnicmp(szMapName, "ep2_outland_03", 14)
			|| !Q_strnicmp(szMapName, "ep2_outland_08", 14)
			|| !Q_strnicmp(szMapName, "ep2_outland_06", 14)
			)
		{
			CBaseEntity *pEntity = NULL;
			CBasePlayer *pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin());
			Vector vecOrigin = pPlayer->GetAbsOrigin();
			pEntity = gEntList.FindEntityByClassnameNearest("item_suit", vecOrigin, 0);


			if (pEntity != NULL)
			{
				vecOrigin = pEntity->GetAbsOrigin();
				pEntity = gEntList.FindEntityByClassnameNearest("info_player_start", vecOrigin, 0);
				pSpot = pEntity;
				pSpawnpointName = "info_player_start";
				goto ReturnSpot;
			}
			else
			{
				pSpot = gEntList.FindEntityByClassname(pSpot, "info_player_start");
			}
		}
		else if (!Q_strnicmp(szMapName, "d1_trainstation_05", 18))
		{
			CBaseEntity *pEntity = NULL;
			CBasePlayer *pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin());
			Vector vecOrigin = pPlayer->GetAbsOrigin();
			pEntity = gEntList.FindEntityByClassnameNearest("npc_alyx", vecOrigin, 0);
			if (pEntity != NULL)
			{
				vecOrigin = pEntity->GetAbsOrigin();
				pEntity = gEntList.FindEntityByClassnameNearest("info_player_start", vecOrigin, 0);
				pSpot = pEntity;
				pSpawnpointName = "info_player_start";
				goto ReturnSpot;
			}
			else
			{
				pSpot = gEntList.FindEntityByClassname(pSpot, "info_player_start");
			}
		}
		else
		{
			pSpot = gEntList.FindEntityByClassname(pSpot, "info_player_start");
		}

		if ( pSpot )
			goto ReturnSpot;
	}

ReturnSpot:

	g_pLastSpawn = pSpot;

	m_flSlamProtectTime = gpGlobals->curtime + 0.5;

	return pSpot;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
float CalculatePhysicsImpactDamage( int index, gamevcollisionevent_t *pEvent, const impactdamagetable_t &table, float energyScale, bool allowStaticDamage, int &damageType, bool bDamageFromHeldObjects )
{
	damageType = DMG_CRUSH;
	int otherIndex = !index;

	// UNDONE: Expose a flag for self-inflicted damage?  Can't think of a valid case so far.
	if ( pEvent->pEntities[0] == pEvent->pEntities[1] )
		return 0;

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_NO_NPC_IMPACT_DMG )
	{
		if( pEvent->pEntities[index]->IsNPC() || pEvent->pEntities[index]->IsPlayer() )
		{
			return 0;
		}
	}

	// use implicit velocities on ragdolls since they may have high constraint velocities that aren't actually executed, just pushed through contacts
	if (( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PART_OF_RAGDOLL) && pEvent->pEntities[index]->IsPlayer() )
	{
		pEvent->pObjects[otherIndex]->GetImplicitVelocity( &pEvent->preVelocity[otherIndex], &pEvent->preAngularVelocity[otherIndex] );
	}

	// Dissolving impact damage results in death always.
	if ( ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_DISSOLVE ) && 
			!pEvent->pEntities[index]->IsEFlagSet(EFL_NO_DISSOLVE) )
	{
		damageType |= DMG_DISSOLVE;
		return 1000;
	}

	if ( energyScale <= 0.0f )
		return 0;

	const int gameFlagsNoDamage = FVPHYSICS_CONSTRAINT_STATIC | FVPHYSICS_NO_IMPACT_DMG;

	// NOTE: Crushing damage is handled by stress calcs in vphysics update functions, this is ONLY impact damage
	// this is a non-moving object due to a constraint - no damage
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & gameFlagsNoDamage )
		return 0;

	// If it doesn't take damage from held objects and the object is being held - no damage
	if ( !bDamageFromHeldObjects && ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD ) )
	{
		// If it doesn't take damage from held objects - no damage
		if ( !bDamageFromHeldObjects )
			return 0;
	}

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY )
	{
		// UNDONE: Add up mass here for car wheels and prop_ragdoll pieces?
		IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
		int count = pEvent->pEntities[otherIndex]->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
		for ( int i = 0; i < count; i++ )
		{
			if ( pList[i]->GetGameFlags() & gameFlagsNoDamage )
				return 0;
		}
	}

	if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		// players can't damage held objects
		if ( pEvent->pEntities[otherIndex]->IsPlayer() )
			return 0;

		allowStaticDamage = false;
	}

#if 0
	{
		PhysGetDamageInflictorVelocityStartOfFrame( pEvent->pObjects[otherIndex], pEvent->preVelocity[otherIndex], pEvent->preAngularVelocity[otherIndex] );
	}
#endif

	float otherSpeedSqr = pEvent->preVelocity[otherIndex].LengthSqr();
	float otherAngSqr = 0;
	
	// factor in angular for sharp objects
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_DMG_SLICE )
	{
		otherAngSqr = pEvent->preAngularVelocity[otherIndex].LengthSqr();
	}

	float otherMass = pEvent->pObjects[otherIndex]->GetMass();

	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		// if the player is holding the object, use it's real mass (player holding reduced the mass)
		Vector origin;
		pEvent->pObjects[otherIndex]->GetPosition(&origin,NULL);
		CBasePlayer *pPlayer = UTIL_GetNearestPlayer(origin);
		if ( pPlayer )
		{
			otherMass = pPlayer->GetHeldObjectMass( pEvent->pObjects[otherIndex] );
		}
	}

	// NOTE: sum the mass of each object in this system for the purpose of damage
	if ( pEvent->pEntities[otherIndex] && (pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY) )
	{
		otherMass = PhysGetEntityMass( pEvent->pEntities[otherIndex] );
	}
	
	if ( pEvent->pObjects[otherIndex]->GetGameFlags() & FVPHYSICS_HEAVY_OBJECT )
	{
		otherMass = table.largeMassMin;
		if ( energyScale < 2.0f )
		{
			energyScale = 2.0f;
		}
	}

	// UNDONE: allowStaticDamage is a hack - work out some method for 
	// breakable props to impact the world and break!!
	if ( !allowStaticDamage )
	{
		if ( otherMass < table.minMass )
			return 0;
		// check to see if the object is small
		if ( otherMass < table.smallMassMax && otherSpeedSqr < table.smallMassMinSpeedSqr )
			return 0;
		
		if ( otherSpeedSqr < table.minSpeedSqr && otherAngSqr < table.minRotSpeedSqr )
			return 0;
	}

	// Add extra oomph for floating objects
	if ( pEvent->pEntities[index]->IsFloating() && !pEvent->pEntities[otherIndex]->IsWorld() )
	{
		if ( energyScale < 3.0f )
		{
			energyScale = 3.0f;
		}
	}

	float damage = 0;
	bool bDebug = false;//(&table == &gDefaultPlayerImpactDamageTable);

	// don't ever take spin damage from slowly spinning objects
	if ( otherAngSqr > table.minRotSpeedSqr )
	{
		Vector otherInertia = pEvent->pObjects[otherIndex]->GetInertia();
		float angularMom = DotProductAbs( otherInertia, pEvent->preAngularVelocity[otherIndex] );
		damage = ReadDamageTable( table.angularTable, table.angularCount, angularMom * energyScale, bDebug );
		if ( damage > 0 )
		{
//			Msg("Spin : %.1f, Damage %.0f\n", FastSqrt(angularMom), damage );
			damageType |= DMG_SLASH;
		}
	}
	
	float deltaV = pEvent->preVelocity[index].Length() - pEvent->postVelocity[index].Length();
	float mass = pEvent->pObjects[index]->GetMass();

	// If I lost speed, and I lost less than min velocity, then filter out this energy
	if ( deltaV > 0 && deltaV < table.myMinVelocity )
	{
		deltaV = 0;
	}
	float eliminatedEnergy = deltaV * deltaV * mass;

	deltaV = pEvent->preVelocity[otherIndex].Length() - pEvent->postVelocity[otherIndex].Length();
	float otherEliminatedEnergy = deltaV * deltaV * otherMass;
	
	// exaggerate the effects of really large objects
	if ( otherMass >= table.largeMassMin )
	{
		otherEliminatedEnergy *= table.largeMassScale;
		float dz = pEvent->preVelocity[otherIndex].z - pEvent->postVelocity[otherIndex].z;

		if ( deltaV > 0 && dz < 0 && pEvent->preVelocity[otherIndex].z < 0 )
		{
			float factor = fabs(dz / deltaV);
			otherEliminatedEnergy *= (1 + factor * (table.largeMassFallingScale - 1.0f));
		}
	}

	eliminatedEnergy += otherEliminatedEnergy;

	// now in units of this character's speed squared
	float invMass = pEvent->pObjects[index]->GetInvMass();
	if ( !pEvent->pObjects[index]->IsMoveable() )
	{
		// inv mass is zero, but impact damage is enabled on this
		// prop, so recompute:
		invMass = 1.0f / pEvent->pObjects[index]->GetMass();
	}
	else if ( pEvent->pObjects[index]->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
	{
		// if the player is holding the object, use it's real mass (player holding reduced the mass)
		Vector origin;
		pEvent->pObjects[otherIndex]->GetPosition(&origin,NULL);
		CBasePlayer *pPlayer = UTIL_GetNearestPlayer(origin);
		if ( pPlayer )
		{
			float mass = pPlayer->GetHeldObjectMass( pEvent->pObjects[index] );
			if ( mass > 0 )
			{
				invMass = 1.0f / mass;
			}
		}
	}

	eliminatedEnergy *= invMass * energyScale;
	
	damage += ReadDamageTable( table.linearTable, table.linearCount, eliminatedEnergy, bDebug );

	if ( !pEvent->pObjects[otherIndex]->IsStatic() && otherMass < table.smallMassMax && table.smallMassCap > 0 )
	{
		damage = clamp( damage, 0.f, table.smallMassCap );
	}

	return damage;
}
CNPCSpawnDestination *CTemplateNPCMaker::FindSpawnDestination()
{
	CNPCSpawnDestination *pDestinations[ MAX_DESTINATION_ENTS ];
	CBaseEntity *pEnt = NULL;
	CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
	int	count = 0;

	if( !pPlayer )
	{
		return NULL;
	}

	// Collect all the qualifiying destination ents
	pEnt = gEntList.FindEntityByName( NULL, m_iszDestinationGroup );

	if( !pEnt )
	{
		DevWarning("Template NPC Spawner (%s) doesn't have any spawn destinations!\n", GetDebugName() );
		return NULL;
	}
	
	while( pEnt )
	{
		CNPCSpawnDestination *pDestination;

		pDestination = dynamic_cast <CNPCSpawnDestination*>(pEnt);

		if( pDestination && pDestination->IsAvailable() )
		{
			bool fValid = true;
			Vector vecTest = pDestination->GetAbsOrigin();
			pPlayer = UTIL_GetNearestPlayer(vecTest);

			if( m_CriterionVisibility != TS_YN_DONT_CARE )
			{
				// Right now View Cone check is omitted intentionally.
				Vector vecTopOfHull = NAI_Hull::Maxs( HULL_HUMAN );
				vecTopOfHull.x = 0;
				vecTopOfHull.y = 0;
				bool fVisible = (pPlayer->FVisible( vecTest ) || pPlayer->FVisible( vecTest + vecTopOfHull ) );

				if( m_CriterionVisibility == TS_YN_YES )
				{
					if( !fVisible )
						fValid = false;
				}
				else
				{
					if( fVisible )
					{
						if ( !(pPlayer->GetFlags() & FL_NOTARGET) )
							fValid = false;
						else
							DevMsg( 2, "Spawner %s spawning even though seen due to notarget\n", STRING( GetEntityName() ) );
					}
				}
			}

			if( fValid )
			{
				pDestinations[ count ] = pDestination;
				count++;
			}
		}

		pEnt = gEntList.FindEntityByName( pEnt, m_iszDestinationGroup );
	}

	if( count < 1 )
		return NULL;

	// Now find the nearest/farthest based on distance criterion
	if( m_CriterionDistance == TS_DIST_DONT_CARE )
	{
		// Pretty lame way to pick randomly. Try a few times to find a random
		// location where a hull can fit. Don't try too many times due to performance
		// concerns.
		for( int i = 0 ; i < 5 ; i++ )
		{
			CNPCSpawnDestination *pRandomDest = pDestinations[ rand() % count ];

			if( HumanHullFits( pRandomDest->GetAbsOrigin() ) )
			{
				return pRandomDest;
			}
		}

		return NULL;
	}
	else
	{
		if( m_CriterionDistance == TS_DIST_NEAREST )
		{
			float flNearest = FLT_MAX;
			CNPCSpawnDestination *pNearest = NULL;

			for( int i = 0 ; i < count ; i++ )
			{
				Vector vecTest = pDestinations[ i ]->GetAbsOrigin();
				pPlayer = UTIL_GetNearestPlayer(vecTest);
				float flDist = ( vecTest - pPlayer->GetAbsOrigin() ).Length();

				if ( m_iMinSpawnDistance != 0 && m_iMinSpawnDistance > flDist )
					continue;

				if( flDist < flNearest && HumanHullFits( vecTest ) )
				{
					flNearest = flDist;
					pNearest = pDestinations[ i ];
				}
			}

			return pNearest;
		}
		else
		{
			float flFarthest = 0;
			CNPCSpawnDestination *pFarthest = NULL;

			for( int i = 0 ; i < count ; i++ )
			{
				Vector vecTest = pDestinations[ i ]->GetAbsOrigin();
				float flDist = ( vecTest - pPlayer->GetAbsOrigin() ).Length();

				if ( m_iMinSpawnDistance != 0 && m_iMinSpawnDistance > flDist )
					continue;

				if( flDist > flFarthest && HumanHullFits( vecTest ) )
				{
					flFarthest = flDist;
					pFarthest = pDestinations[ i ];
				}
			}

			return pFarthest;
		}
	}

	return NULL;
}
void CNPC_Dog::SetPlayerAvoidState( void )
{
	bool bIntersectingBoneFollowers = false;
	bool bIntersectingNPCBox = false;

	Vector vNothing;

	GetSequenceLinearMotion( GetSequence(), &vNothing );
	bool bIsMoving = ( IsMoving() || ( vNothing != vec3_origin ) );

	//If we are coming out of a script, check if we are stuck inside the player.
	if ( m_bPerformAvoidance || ( ShouldPlayerAvoid() && bIsMoving ) )
	{
		trace_t trace;
		Vector vMins, vMaxs;
		Vector vWorldMins, vWorldMaxs;
		Vector vPlayerMins, vPlayerMaxs;
		physfollower_t *pBone;
		int i;
		
		#ifdef SecobMod__Enable_Fixed_Multiplayer_AI
			CBasePlayer *pLocalPlayer = UTIL_GetNearestPlayer(GetAbsOrigin()); 
		#else
			CBasePlayer *pLocalPlayer = AI_GetSinglePlayer();
		#endif //SecobMod__Enable_Fixed_Multiplayer_AI

		if ( pLocalPlayer )
		{
			vWorldMins = WorldAlignMins();
			vWorldMaxs = WorldAlignMaxs();

			vPlayerMins = pLocalPlayer->GetAbsOrigin() + pLocalPlayer->WorldAlignMins();
			vPlayerMaxs = pLocalPlayer->GetAbsOrigin() + pLocalPlayer->WorldAlignMaxs();

			// check if the player intersects the bounds of any of the bone followers
			for ( i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
			{
				pBone = m_BoneFollowerManager.GetBoneFollower( i );
				if ( pBone && pBone->hFollower )
				{
					pBone->hFollower->CollisionProp()->WorldSpaceSurroundingBounds( &vMins, &vMaxs );
					if ( IsBoxIntersectingBox( vMins, vMaxs, vPlayerMins, vPlayerMaxs ) )
					{
						bIntersectingBoneFollowers = true;
						break;
					}
				}
			}

			bIntersectingNPCBox = IsBoxIntersectingBox( GetAbsOrigin() + vWorldMins, GetAbsOrigin() + vWorldMaxs, vPlayerMins, vPlayerMaxs );

			if ( ai_debug_avoidancebounds.GetBool() )
			{
				int iRed = ( bIntersectingNPCBox == true ) ? 255 : 0;

				NDebugOverlay::Box( GetAbsOrigin(), vWorldMins, vWorldMaxs, iRed, 0, 255, 64, 0.1 );

				// draw the bounds of the bone followers
				for ( i = 0; i < m_BoneFollowerManager.GetNumBoneFollowers(); i++ )
				{
					pBone = m_BoneFollowerManager.GetBoneFollower( i );
					if ( pBone && pBone->hFollower )
					{
						pBone->hFollower->CollisionProp()->WorldSpaceSurroundingBounds( &vMins, &vMaxs );
						iRed = ( IsBoxIntersectingBox( vMins, vMaxs, vPlayerMins, vPlayerMaxs ) ) ? 255 : 0;

						NDebugOverlay::Box( vec3_origin, vMins, vMaxs, iRed, 0, 255, 64, 0.1 );
					}
				}
			}
		}
	}

	m_bPlayerAvoidState = ShouldPlayerAvoid();
	m_bPerformAvoidance = bIntersectingNPCBox || bIntersectingBoneFollowers;

	if ( GetCollisionGroup() == COLLISION_GROUP_NPC || GetCollisionGroup() == COLLISION_GROUP_NPC_ACTOR )
	{
		if ( bIntersectingNPCBox == true )
		{
			SetCollisionGroup( COLLISION_GROUP_NPC_ACTOR );
		}
		else
		{
			SetCollisionGroup( COLLISION_GROUP_NPC );
		}

		if ( bIntersectingBoneFollowers == true )
		{
			MantainBoneFollowerCollisionGroups( COLLISION_GROUP_NPC_ACTOR );
		}
		else
		{
			MantainBoneFollowerCollisionGroups( COLLISION_GROUP_NPC );
		}
	}
}
void CNPC_Zombine::GatherGrenadeConditions( void )
{
	if ( m_iGrenadeCount <= 0 )
		return;

	if ( g_flZombineGrenadeTimes > gpGlobals->curtime )
		return;

	if ( m_flGrenadePullTime > gpGlobals->curtime )
		return;

	if ( m_flSuperFastAttackTime >= gpGlobals->curtime )
		return;
	
	if ( HasGrenade() )
		return;

	if ( GetEnemy() == NULL )
		return;

	if ( FVisible( GetEnemy() ) == false )
		return;

	if ( IsSprinting() )
		return;

	if ( IsOnFire() )
		return;
	
	if ( IsRunningDynamicInteraction() == true )
		return;

	if ( m_ActBusyBehavior.IsActive() )
		return;

	//Secobmod FixMe
	//CBasePlayer *pPlayer = AI_GetSinglePlayer();
	CBasePlayer *pPlayer = UTIL_GetNearestPlayer(GetAbsOrigin()); 

	if ( pPlayer && pPlayer->FVisible( this ) )
	{
		float flLengthToPlayer = (pPlayer->GetAbsOrigin() - GetAbsOrigin()).Length();
		float flLengthToEnemy = flLengthToPlayer;

		if ( pPlayer != GetEnemy() )
		{
			flLengthToEnemy = ( GetEnemy()->GetAbsOrigin() - GetAbsOrigin()).Length();
		}

		if ( flLengthToPlayer <= GRENADE_PULL_MAX_DISTANCE && flLengthToEnemy <= GRENADE_PULL_MAX_DISTANCE )
		{
			float flPullChance = 1.0f - ( flLengthToEnemy / GRENADE_PULL_MAX_DISTANCE );
			m_flGrenadePullTime = gpGlobals->curtime + 0.5f;

			if ( flPullChance >= random->RandomFloat( 0.0f, 1.0f ) )
			{
				g_flZombineGrenadeTimes = gpGlobals->curtime + 10.0f;
				SetCondition( COND_ZOMBINE_GRENADE );
			}
		}
	}
}