//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CHL1_Player::FindMissTargets( void )
{
	if ( m_flTargetFindTime > gpGlobals->curtime )
		return;

	m_flTargetFindTime	= gpGlobals->curtime + 1.0f;
	m_nNumMissPositions = 0;

	CBaseEntity *pEnts[256];
	Vector		radius( 80, 80, 80);

	int numEnts = UTIL_EntitiesInBox( pEnts, 256, GetAbsOrigin()-radius, GetAbsOrigin()+radius, 0 );

	for ( int i = 0; i < numEnts; i++ )
	{
		if ( pEnts[i] == NULL )
			continue;

		if ( m_nNumMissPositions >= 16 )
			return;

		//See if it's a good target candidate
		if ( FClassnameIs( pEnts[i], "prop_dynamic" ) || 
			 FClassnameIs( pEnts[i], "dynamic_prop" ) || 
			 FClassnameIs( pEnts[i], "prop_physics" ) || 
			 FClassnameIs( pEnts[i], "physics_prop" ) )
		{
			//NDebugOverlay::Cross3D( pEnts[i]->WorldSpaceCenter(), -Vector(4,4,4), Vector(4,4,4), 0, 255, 0, true, 1.0f );

			m_vecMissPositions[m_nNumMissPositions++] = pEnts[i]->WorldSpaceCenter();
			continue;
		}
	}
}
CBaseEntity *CBarnacle :: TongueTouchEnt ( float *pflLength )
{
	TraceResult	tr;
	float		length;

	// trace once to hit architecture and see if the tongue needs to change position.
	UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0 , 0 , 2048 ), ignore_monsters, ENT(pev), &tr );
	length = fabs( pev->origin.z - tr.vecEndPos.z );
	if ( pflLength )
	{
		*pflLength = length;
	}

	Vector delta = Vector( BARNACLE_CHECK_SPACING, BARNACLE_CHECK_SPACING, 0 );
	Vector mins = pev->origin - delta;
	Vector maxs = pev->origin + delta;
	maxs.z = pev->origin.z;
	mins.z -= length;

	CBaseEntity *pList[10];
	int count = UTIL_EntitiesInBox( pList, 10, mins, maxs, (FL_CLIENT|FL_MONSTER) );
	if ( count )
	{
		for ( int i = 0; i < count; i++ )
		{
			// only clients and monsters
			if ( pList[i] != this && IRelationship( pList[i] ) > R_NO && pList[ i ]->pev->deadflag == DEAD_NO )	// this ent is one of our enemies. Barnacle tries to eat it.
			{
				return pList[i];
			}
		}
	}

	return NULL;
}
Exemple #3
0
bool AvHHive::SetSolid(bool inForce)
{
	// Check to make sure there aren't any players in the destination area
	CBaseEntity* pList[128];
	
	// Crank up the area just to be safe
	Vector theMinArea = this->pev->origin + kHiveMinSize;
	Vector theMaxArea = this->pev->origin + kHiveMaxSize;
	
	// TODO: If players are blocking this area for too long, spawn hive and kill them
	int theNumBlockingEntities = UTIL_EntitiesInBox(pList, 128, theMinArea, theMaxArea, FL_CLIENT);
	if((theNumBlockingEntities == 0) || inForce)
	{
		this->pev->solid = SOLID_BBOX;
		this->pev->movetype = MOVETYPE_NONE;
			
		UTIL_SetSize(this->pev, kHiveMinSize, kHiveMaxSize);
			
		//		pev->frame = 0;
		//		pev->body = 3;
		//		pev->sequence = 0;
		//		// ResetSequenceInfo( );
		//		pev->framerate = 0;
		//		
		//		UTIL_SetOrigin(pev, pev->origin);
		//		UTIL_SetSize(pev, Vector(-20, -20, 0), Vector(20, 20, 28) ); 
			
		SetTouch(&AvHHive::HiveTouch);

		this->mSolid = true;
	}

	return this->mSolid;
}
Exemple #4
0
// This function takes a lot of CPU, so make sure it's not called often!  Don't call this function directly, use UpdateEnemy instead whenever possible.
CBaseEntity* AvHTurret::FindBestEnemy()
{
    PROFILE_START()
	CBaseEntity* theEntityList[100];
	
	int theMaxRange = this->GetXYRange();
	
	Vector delta = Vector(theMaxRange, theMaxRange, theMaxRange);
	CBaseEntity* theCurrentEntity = NULL;
	CBaseEntity* theBestPlayer = NULL;
	CBaseEntity* theBestStructure = NULL;

	float theCurrentEntityRange = 100000;
	
	// Find only monsters/clients in box, NOT limited to PVS
	int theCount = UTIL_EntitiesInBox(theEntityList, 100, this->pev->origin - delta, this->pev->origin + delta, FL_CLIENT | FL_MONSTER);
	for(int i = 0; i < theCount; i++ )
	{
		theCurrentEntity = theEntityList[i];
		if((theCurrentEntity != this) && theCurrentEntity->IsAlive())
		{
			// the looker will want to consider this entity
			// don't check anything else about an entity that can't be seen, or an entity that you don't care about.
			if(this->IRelationship(theCurrentEntity ) != R_NO && FInViewCone(theCurrentEntity) && !FBitSet(theCurrentEntity->pev->flags, FL_NOTARGET))
			{
				AvHPlayer* thePlayer = dynamic_cast<AvHPlayer*>(theCurrentEntity);
				if(!thePlayer || thePlayer->GetCanBeAffectedByEnemies())
				{
					if(this->GetIsValidTarget(theCurrentEntity))
					{
						// Find nearest enemy
						float theRangeToTarget = VectorDistance2D(this->pev->origin, theCurrentEntity->pev->origin);
						if(theRangeToTarget < theCurrentEntityRange)
						{
                            // FVisible is expensive, so defer until necessary
                            if(!this->GetRequiresLOS() || FVisible(theCurrentEntity))
                            {
                                theCurrentEntityRange = theRangeToTarget;
								if ( thePlayer ) 
								{
									theBestPlayer = theCurrentEntity;
								}
								else
								{
									theBestStructure = theCurrentEntity;
								}
                            }
						}
					}
				}
			}
		}
	}
    PROFILE_END(kAvHTurretFindBestEnemy);

	return (theBestPlayer != NULL ) ? theBestPlayer : theBestStructure;
}
//=========================================================
// TryMakeMonster-  check that it's ok to drop a monster.
//=========================================================
void CMonsterMaker::TryMakeMonster( void )
{
	if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren )
	{// not allowed to make a new one yet. Too many live ones out right now.
		return;
	}

	if ( !m_flGround )
	{
		// set altitude. Now that I'm activated, any breakables, etc should be out from under me. 
		TraceResult tr;

		UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr );
		m_flGround = tr.vecEndPos.z;
	}

	Vector mins = pev->origin - Vector( 34, 34, 0 );
	Vector maxs = pev->origin + Vector( 34, 34, 0 );
	maxs.z = pev->origin.z;
	mins.z = m_flGround;

	CBaseEntity *pList[2];
	int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER );
	if ( count )
	{
		// don't build a stack of monsters!
		return;
	}

	if (m_fSpawnDelay)
	{
		// If I have a target, fire. (no locus)
		if ( !FStringNull ( pev->target ) )
		{
			// delay already overloaded for this entity, so can't call SUB_UseTargets()
			FireTargets( STRING(pev->target), this, this, USE_TOGGLE, 0 );
		}

//		ALERT(at_console,"Making Monster in %f seconds\n",m_fSpawnDelay);
		SetThink(&CMonsterMaker:: MakeMonsterThink );
		SetNextThink( m_fSpawnDelay );
	}
	else
	{
//		ALERT(at_console,"No delay. Making monster.\n",m_fSpawnDelay);
		CBaseMonster* pMonst = MakeMonster();

		// If I have a target, fire! (the new monster is the locus)
		if ( !FStringNull ( pev->target ) )
		{
			FireTargets( STRING(pev->target), pMonst, this, USE_TOGGLE, 0 );
		}
	}
}
Exemple #6
0
boost::python::object UTIL_PyEntitiesInBox( int listMax, const Vector &mins, const Vector &maxs, int flagMask )
{
	int i, n;
	CBaseEntity **pList;
	boost::python::list pylist = boost::python::list();

	pList = (CBaseEntity **)malloc(listMax*sizeof(CBaseEntity *));
	n = UTIL_EntitiesInBox(pList, listMax, mins, maxs, flagMask);
	for( i=0; i < n; i++)
		pylist.append(*pList[i]);
	free(pList);
	return pylist;
}
Exemple #7
0
void CBaseMonster::Look(int iDistance)
{
    int iSighted = 0;
    ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT);
    m_pLink = NULL;

    CBaseEntity *pSightEnt = NULL;
    CBaseEntity *pList[100];
    Vector delta = Vector(iDistance, iDistance, iDistance);
    int count = UTIL_EntitiesInBox(pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT | FL_MONSTER);

    for (int i = 0; i < count; i++)
    {
        pSightEnt = pList[i];

        if (pSightEnt != this && pSightEnt->pev->health > 0)
        {
            if (IRelationship(pSightEnt) != R_NO && FInViewCone(pSightEnt) && !FBitSet(pSightEnt->pev->flags, FL_NOTARGET) && FVisible(pSightEnt))
            {
                if (pSightEnt->IsPlayer())
                    iSighted |= bits_COND_SEE_CLIENT;

                pSightEnt->m_pLink = m_pLink;
                m_pLink = pSightEnt;

                if (pSightEnt == m_hEnemy)
                    iSighted |= bits_COND_SEE_ENEMY;

                switch (IRelationship(pSightEnt))
                {
                case R_NM:
                    iSighted |= bits_COND_SEE_NEMESIS;
                    break;
                case R_HT:
                    iSighted |= bits_COND_SEE_HATE;
                    break;
                case R_DL:
                    iSighted |= bits_COND_SEE_DISLIKE;
                    break;
                case R_FR:
                    iSighted |= bits_COND_SEE_FEAR;
                    break;
                case R_AL:
                    break;
                }
            }
        }
    }

    SetConditions(iSighted);
}
Exemple #8
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CGrenadeHopwire::KillStriders( void )
{
	CBaseEntity *pEnts[128];
	Vector	mins, maxs;

	ClearBounds( mins, maxs );
	AddPointToBounds( -Vector( MAX_STRIDER_STUN_DISTANCE_HORZ, MAX_STRIDER_STUN_DISTANCE_HORZ, MAX_STRIDER_STUN_DISTANCE_HORZ ), mins, maxs );
	AddPointToBounds(  Vector( MAX_STRIDER_STUN_DISTANCE_HORZ, MAX_STRIDER_STUN_DISTANCE_HORZ, MAX_STRIDER_STUN_DISTANCE_HORZ ), mins, maxs );
	AddPointToBounds( -Vector( MAX_STRIDER_STUN_DISTANCE_VERT, MAX_STRIDER_STUN_DISTANCE_VERT, MAX_STRIDER_STUN_DISTANCE_VERT ), mins, maxs );
	AddPointToBounds(  Vector( MAX_STRIDER_STUN_DISTANCE_VERT, MAX_STRIDER_STUN_DISTANCE_VERT, MAX_STRIDER_STUN_DISTANCE_VERT ), mins, maxs );

	// FIXME: It's probably much faster to simply iterate over the striders in the map, rather than any entity in the radius - jdw

	// Find any striders in range of us
	int numTargets = UTIL_EntitiesInBox( pEnts, ARRAYSIZE( pEnts ), GetAbsOrigin()+mins, GetAbsOrigin()+maxs, FL_NPC );
	float targetDistHorz, targetDistVert;

	for ( int i = 0; i < numTargets; i++ )
	{
		// Only affect striders
		if ( FClassnameIs( pEnts[i], "npc_strider" ) == false )
			continue;

		// We categorize our spatial relation to the strider in horizontal and vertical terms, so that we can specify both parameters separately
		targetDistHorz = UTIL_DistApprox2D( pEnts[i]->GetAbsOrigin(), GetAbsOrigin() );
		targetDistVert = fabs( pEnts[i]->GetAbsOrigin()[2] - GetAbsOrigin()[2] );

		if ( targetDistHorz < MAX_STRIDER_KILL_DISTANCE_HORZ && targetDistHorz < MAX_STRIDER_KILL_DISTANCE_VERT )
		{
			// Kill the strider
			float fracDamage = ( pEnts[i]->GetMaxHealth() / hopwire_strider_hits.GetFloat() ) + 1.0f;
			CTakeDamageInfo killInfo( this, this, fracDamage, DMG_GENERIC );
			Vector	killDir = pEnts[i]->GetAbsOrigin() - GetAbsOrigin();
			VectorNormalize( killDir );

			killInfo.SetDamageForce( killDir * -1000.0f );
			killInfo.SetDamagePosition( GetAbsOrigin() );

			pEnts[i]->TakeDamage( killInfo );
		}
		else if ( targetDistHorz < MAX_STRIDER_STUN_DISTANCE_HORZ && targetDistHorz < MAX_STRIDER_STUN_DISTANCE_VERT )
		{
			// Stun the strider
			CTakeDamageInfo killInfo( this, this, 200.0f, DMG_GENERIC );
			pEnts[i]->TakeDamage( killInfo );
		}
	}
}
//LRC
void CBreakable::RespawnThink( void )
{
//	ALERT(at_debug,"RespawnThink: ");
	CBaseEntity *pList[2];
	int count = UTIL_EntitiesInBox( pList, 2, pev->mins, pev->maxs, FL_MONSTER | FL_CLIENT );
	if ( count )
	{
		// Can't respawn right now, a monster or player is in the way. Wait a bit.
//		ALERT(at_debug,"Respawn failed, count is %d\n",count);
		SetThink(&CBreakable:: RespawnThink );
		SetNextThink( 2 ); // CONSIDER: change this number?
	}
	else
	{
		// fade in, don't just appear(?)
		if (pev->spawnflags & SF_BREAK_FADE_RESPAWN)
		{
			SetThink(&CBreakable:: RespawnFadeThink );
			SetNextThink( 0.1 );
			pev->renderamt = 0;
			if (m_iInitialRenderMode == kRenderNormal)
			{
				pev->rendermode = kRenderTransTexture;
				m_iInitialRenderAmt = 255;
			}
		}
//		ALERT(at_debug,"Respawn OK\n");
	/*	if (FStrEq("func_pushable",STRING(pev->classname))){	//AJH Fix for respawnable breakable pushables
			pev->solid = SOLID_BBOX;							//For some reason this code must be executed outside of 
			pev->origin.z+=1;									//the RespawnThink function. Uses DoRespawn()
			UTIL_SetOrigin(this,pev->origin);
		}else{
			pev->solid = SOLID_BSP;	
		}
		*/
		DoRespawn();	//AJH Fix for respawnable breakable pushables (BY HAWK777)
		SetUse(&CBreakable:: BreakUse );
		pev->effects &= ~EF_NODRAW;
		pev->health = m_iInitialHealth;
		
		if ( !FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) )
			pev->takedamage	= DAMAGE_YES;

		// trigger the "fire on respawn" target
		FireTargets( STRING(pev->netname), this, this, USE_TOGGLE, 0);
	}
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether or not it is OK to make an NPC at this instant.
//-----------------------------------------------------------------------------
bool CHL1NPCMaker::CanMakeNPC( void )
{
	if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren )
	{// not allowed to make a new one yet. Too many live ones out right now.
		return false;
	}

	if ( !m_flGround )
	{
		// set altitude. Now that I'm activated, any breakables, etc should be out from under me. 
		trace_t tr;

		UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() - Vector ( 0, 0, 2048 ), MASK_NPCSOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr );
		m_flGround = tr.endpos.z;
	}

	Vector mins = GetAbsOrigin() - Vector( 34, 34, 0 );
	Vector maxs = GetAbsOrigin() + Vector( 34, 34, 0 );
	maxs.z = GetAbsOrigin().z;
	
	//Only adjust for the ground if we want it
	if ( ( m_spawnflags & SF_NPCMakerHL1_NO_DROP ) == false )
	{
		mins.z = m_flGround;
	}

	CBaseEntity *pList[128];
	
	int count = UTIL_EntitiesInBox( pList, 128, mins, maxs, FL_CLIENT|FL_NPC );
	if ( count )
	{
		//Iterate through the list and check the results
		for ( int i = 0; i < count; i++ )
		{
			//Don't build on top of another entity
			if ( pList[i] == NULL )
				continue;

			//If one of the entities is solid, then we can't spawn now
			if ( ( pList[i]->GetSolidFlags() & FSOLID_NOT_SOLID ) == false )
				return false;
		}
	}

	return true;
}
//------------------------------------------------------------------------------
// Purpose : Reset the OnGround flags for any entities that may have been
//			 resting on me
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CBreakable::ResetOnGroundFlags(void)
{
	// !!! HACK  This should work!
	// Build a box above the entity that looks like an 9 inch high sheet
	Vector mins, maxs;
	CollisionProp()->WorldSpaceAABB( &mins, &maxs );
	mins.z -= 1;
	maxs.z += 8;

	// BUGBUG -- can only find 256 entities on a breakable -- should be enough
	CBaseEntity *pList[256];
	int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND );
	if ( count )
	{
		for ( int i = 0; i < count; i++ )
		{
			pList[i]->SetGroundEntity( (CBaseEntity *)NULL );
		}
	}

#ifdef PORTAL
	// !!! HACK  This should work!
	// Tell touching portals to fizzle
	int iPortalCount = CProp_Portal_Shared::AllPortals.Count();
	if( iPortalCount != 0 )
	{
		Vector vMin, vMax;
		CollisionProp()->WorldSpaceAABB( &vMin, &vMax );

		Vector vBoxCenter = ( vMin + vMax ) * 0.5f;
		Vector vBoxExtents = ( vMax - vMin ) * 0.5f;

		CProp_Portal **pPortals = CProp_Portal_Shared::AllPortals.Base();
		for( int i = 0; i != iPortalCount; ++i )
		{
			CProp_Portal *pTempPortal = pPortals[i];
			if( UTIL_IsBoxIntersectingPortal( vBoxCenter, vBoxExtents, pTempPortal ) )
			{
				pTempPortal->DoFizzleEffect( PORTAL_FIZZLE_KILLED, false );
				pTempPortal->Fizzle();
			}
		}
	}
#endif
}
Exemple #12
0
//------------------------------------------------------------------------------
// Purpose : Reset the OnGround flags for any entities that may have been
//			 resting on me
// Input   :
// Output  :
//------------------------------------------------------------------------------
void CBreakable::ResetOnGroundFlags(void)
{
	// !!! HACK  This should work!
	// Build a box above the entity that looks like an 9 inch high sheet
	Vector mins, maxs;
	CollisionProp()->WorldSpaceAABB( &mins, &maxs );
	mins.z -= 1;
	maxs.z += 8;

	// BUGBUG -- can only find 256 entities on a breakable -- should be enough
	CBaseEntity *pList[256];
	int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND );
	if ( count )
	{
		for ( int i = 0; i < count; i++ )
		{
			pList[i]->SetGroundEntity( (CBaseEntity *)NULL );
		}
	}
}
	BOOL CanLayCrab( void ) 
	{ 
		if ( m_crabTime < gpGlobals->curtime && m_crabCount < BIG_MAXCHILDREN )
		{
			// Don't spawn crabs inside each other
			Vector mins = GetAbsOrigin() - Vector( 32, 32, 0 );
			Vector maxs = GetAbsOrigin() + Vector( 32, 32, 0 );

			CBaseEntity *pList[2];
			int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_NPC );
			for ( int i = 0; i < count; i++ )
			{
				if ( pList[i] != this )	// Don't hurt yourself!
					return COND_NONE;
			}
			return COND_CAN_MELEE_ATTACK2;
		}

		return COND_NONE;
	}
Exemple #14
0
	BOOL CanLayCrab( void ) 
	{ 
		if ( m_crabTime < gpGlobals->time && m_crabCount < BIG_MAXCHILDREN )
		{
			// Don't spawn crabs inside each other
			Vector mins = pev->origin - Vector( 32, 32, 0 );
			Vector maxs = pev->origin + Vector( 32, 32, 0 );

			CBaseEntity *pList[2];
			int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_MONSTER );
			for ( int i = 0; i < count; i++ )
			{
				if ( pList[i] != this )	// Don't hurt yourself!
					return FALSE;
			}
			return TRUE;
		}

		return FALSE;
	}
Exemple #15
0
bool C_DynamicProp::TestBoneFollowers( const Ray_t &ray, unsigned int fContentsMask, trace_t& tr )
{
	// UNDONE: There is no list of the bone followers that is networked to the client
	// so instead we do a search for solid stuff here.  This is not really great - a list would be
	// preferable.
	CBaseEntity	*pList[128];
	Vector mins, maxs;
	CollisionProp()->WorldSpaceAABB( &mins, &maxs );
	int count = UTIL_EntitiesInBox( pList, ARRAYSIZE(pList), mins, maxs, 0, PARTITION_CLIENT_SOLID_EDICTS );
	for ( int i = 0; i < count; i++ )
	{
		if ( pList[i]->GetOwnerEntity() == this )
		{
			if ( pList[i]->TestCollision(ray, fContentsMask, tr) )
			{
				return true;
			}
		}
	}
	return false;
}
//LRC
void CBreakable::RespawnThink( void )
{
//	ALERT(at_debug,"RespawnThink: ");
	CBaseEntity *pList[2];
	int count = UTIL_EntitiesInBox( pList, 2, pev->mins, pev->maxs, FL_MONSTER | FL_CLIENT );
	if ( count )
	{
		// Can't respawn right now, a monster or player is in the way. Wait a bit.
//		ALERT(at_debug,"Respawn failed, count is %d\n",count);
		SetThink(&CBreakable:: RespawnThink );
		SetNextThink( 2 ); // CONSIDER: change this number?
	}
	else
	{
		// fade in, don't just appear(?)
		if (pev->spawnflags & SF_BREAK_FADE_RESPAWN)
		{
			SetThink(&CBreakable:: RespawnFadeThink );
			SetNextThink( 0.1 );
			pev->renderamt = 0;
			if (m_iInitialRenderMode == kRenderNormal)
			{
				pev->rendermode = kRenderTransTexture;
				m_iInitialRenderAmt = 255;
			}
		}
//		ALERT(at_debug,"Respawn OK\n");
		pev->solid = SOLID_BSP;
		pev->effects &= ~EF_NODRAW;
		pev->health = m_iInitialHealth;
		SetUse(&CBreakable:: BreakUse );
		if ( !FBitSet( pev->spawnflags, SF_BREAK_TRIGGER_ONLY ) )
			pev->takedamage	= DAMAGE_YES;

		// trigger the "fire on respawn" target
		FireTargets( STRING(pev->netname), this, this, USE_TOGGLE, 0);
	}
}
Exemple #17
0
void CXenTree :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
	switch( pEvent->event )
	{
		case TREE_AE_ATTACK:
		{
			CBaseEntity *pList[8];
			BOOL sound = FALSE;
			int count = UTIL_EntitiesInBox( pList, 8, m_pTrigger->pev->absmin, m_pTrigger->pev->absmax, FL_MONSTER|FL_CLIENT );
			Vector forward;

			UTIL_MakeVectorsPrivate( pev->angles, forward, NULL, NULL );

			for ( int i = 0; i < count; i++ )
			{
				if ( pList[i] != this )
				{
					if ( pList[i]->pev->owner != edict() )
					{
						sound = TRUE;
						pList[i]->TakeDamage( pev, pev, 25, DMG_CRUSH | DMG_SLASH );
						pList[i]->pev->punchangle.x = 15;
						pList[i]->pev->velocity = pList[i]->pev->velocity + forward * 100;
					}
				}
			}
					
			if ( sound )
			{
				EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackHitSounds );
			}
		}
		return;
	}

	CActAnimating::HandleAnimEvent( pEvent );
}
Exemple #18
0
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CBigMomma :: HandleAnimEvent( MonsterEvent_t *pEvent )
{
	switch( pEvent->event )
	{
		case BIG_AE_MELEE_ATTACKBR:
		case BIG_AE_MELEE_ATTACKBL:
		case BIG_AE_MELEE_ATTACK1:
		{
			Vector forward, right;

			UTIL_MakeVectorsPrivate( pev->angles, forward, right, NULL );

			Vector center = pev->origin + forward * 128;
			Vector mins = center - Vector( 64, 64, 0 );
			Vector maxs = center + Vector( 64, 64, 64 );

			CBaseEntity *pList[8];
			int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_MONSTER|FL_CLIENT );
			CBaseEntity *pHurt = NULL;

			for ( int i = 0; i < count && !pHurt; i++ )
			{
				if ( pList[i] != this )
				{
					if ( pList[i]->pev->owner != edict() )
						pHurt = pList[i];
				}
			}
					
			if ( pHurt )
			{
				pHurt->TakeDamage( pev, pev, gSkillData.bigmommaDmgSlash, DMG_CRUSH | DMG_SLASH );
				pHurt->pev->punchangle.x = 15;
				switch( pEvent->event )
				{
					case BIG_AE_MELEE_ATTACKBR:
						pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) - (right * 200);
					break;

					case BIG_AE_MELEE_ATTACKBL:
						pHurt->pev->velocity = pHurt->pev->velocity + (forward * 150) + Vector(0,0,250) + (right * 200);
					break;

					case BIG_AE_MELEE_ATTACK1:
						pHurt->pev->velocity = pHurt->pev->velocity + (forward * 220) + Vector(0,0,200);
					break;
				}

				pHurt->pev->flags &= ~FL_ONGROUND;
				EMIT_SOUND_DYN( edict(), CHAN_WEAPON, RANDOM_SOUND_ARRAY(pAttackHitSounds), 1.0, ATTN_NORM, 0, 100 + RANDOM_LONG(-5,5) );
			}
		}
		break;
		
		case BIG_AE_SCREAM:
			EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pAlertSounds );
			break;
		
		case BIG_AE_PAIN_SOUND:
			EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pPainSounds );
			break;
		
		case BIG_AE_ATTACK_SOUND:
			EMIT_SOUND_ARRAY_DYN( CHAN_WEAPON, pAttackSounds );
			break;

		case BIG_AE_BIRTH_SOUND:
			EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pBirthSounds );
			break;

		case BIG_AE_SACK:
			if ( RANDOM_LONG(0,100) < 30 )
				EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pSackSounds );
			break;

		case BIG_AE_DEATHSOUND:
			EMIT_SOUND_ARRAY_DYN( CHAN_VOICE, pDeathSounds );
			break;

		case BIG_AE_STEP1:		// Footstep left
		case BIG_AE_STEP3:		// Footstep back left
			EMIT_SOUND_ARRAY_DYN( CHAN_ITEM, pFootSounds );
			break;

		case BIG_AE_STEP4:		// Footstep back right
		case BIG_AE_STEP2:		// Footstep right
			EMIT_SOUND_ARRAY_DYN( CHAN_BODY, pFootSounds );
			break;

		case BIG_AE_MORTAR_ATTACK1:
			LaunchMortar();
			break;

		case BIG_AE_LAY_CRAB:
			LayHeadcrab();
			break;

		case BIG_AE_JUMP_FORWARD:
			ClearBits( pev->flags, FL_ONGROUND );

			UTIL_SetOrigin (pev, pev->origin + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground 
			UTIL_MakeVectors ( pev->angles );

			pev->velocity = (gpGlobals->v_forward * 200) + gpGlobals->v_up * 500;
			break;

		case BIG_AE_EARLY_TARGET:
			{
				CBaseEntity *pTarget = m_hTargetEnt;
				if ( pTarget && pTarget->pev->message )
					FireTargets( STRING(pTarget->pev->message), this, this, USE_TOGGLE, 0 );
				Remember( bits_MEMORY_FIRED_NODE );
			}
			break;

		default:
			CBaseMonster::HandleAnimEvent( pEvent );
			break;
	}
}
Exemple #19
0
//-----------------------------------------------------------------------------
// Purpose: Pulls physical objects towards the vortex center, killing them if they come too near
//-----------------------------------------------------------------------------
void CGravityVortexController::PullThink( void )
{
	// Pull any players close enough to us
	PullPlayersInRange();

	Vector mins, maxs;
	mins = GetAbsOrigin() - Vector( m_flRadius, m_flRadius, m_flRadius );
	maxs = GetAbsOrigin() + Vector( m_flRadius, m_flRadius, m_flRadius );

	// Draw debug information
	if ( g_debug_hopwire.GetBool() )
	{
		NDebugOverlay::Box( GetAbsOrigin(), mins - GetAbsOrigin(), maxs - GetAbsOrigin(), 0, 255, 0, 16, 4.0f );
	}

	CBaseEntity *pEnts[128];
	int numEnts = UTIL_EntitiesInBox( pEnts, 128, mins, maxs, 0 );

	for ( int i = 0; i < numEnts; i++ )
	{
		IPhysicsObject *pPhysObject = NULL;

		// Attempt to kill and ragdoll any victims in range
		if ( KillNPCInRange( pEnts[i], &pPhysObject ) == false )
		{	
			// If we didn't have a valid victim, see if we can just get the vphysics object
			pPhysObject = pEnts[i]->VPhysicsGetObject();
			if ( pPhysObject == NULL )
				continue;
		}

		float mass;

		CRagdollProp *pRagdoll = dynamic_cast< CRagdollProp* >( pEnts[i] );
		if ( pRagdoll != NULL )
		{
			ragdoll_t *pRagdollPhys = pRagdoll->GetRagdoll();
			mass = 0.0f;
			
			// Find the aggregate mass of the whole ragdoll
			for ( int j = 0; j < pRagdollPhys->listCount; ++j )
			{
				mass += pRagdollPhys->list[j].pObject->GetMass();
			}
		}
		else
		{
			mass = pPhysObject->GetMass();
		}

		Vector	vecForce = GetAbsOrigin() - pEnts[i]->WorldSpaceCenter();
		Vector	vecForce2D = vecForce;
		vecForce2D[2] = 0.0f;
		float	dist2D = VectorNormalize( vecForce2D );
		float	dist = VectorNormalize( vecForce );
		
		// FIXME: Need a more deterministic method here
		if ( dist < 48.0f )
		{
			ConsumeEntity( pEnts[i] );
			continue;
		}

		// Must be within the radius
		if ( dist > m_flRadius )
			continue;

		// Find the pull force
		vecForce *= ( 1.0f - ( dist2D / m_flRadius ) ) * m_flStrength * mass;
		
		if ( pEnts[i]->VPhysicsGetObject() )
		{
			// Pull the object in
			pEnts[i]->VPhysicsTakeDamage( CTakeDamageInfo( this, this, vecForce, GetAbsOrigin(), m_flStrength, DMG_BLAST ) );
		}
	}

	// Keep going if need-be
	if ( m_flEndTime > gpGlobals->curtime )
	{
		SetThink( &CGravityVortexController::PullThink );
		SetNextThink( gpGlobals->curtime + 0.1f );
	}
	else
	{
		//Msg( "Consumed %.2f kilograms\n", m_flMass );
		//CreateDenseBall();
	}
}
Exemple #20
0
//-----------------------------------------------------------------------------
// Purpose: Update the fire and its children
//-----------------------------------------------------------------------------
void CFire::Update( float simTime )
{
	VPROF_FIRE( "CFire::Update" );

	if ( m_flFuel != 0 )
	{
		m_flFuel -= simTime;
		if ( m_flFuel <= 0 )
		{
			GoOutInSeconds( 1 );
			return;
		}
	}

	float strength = m_flHeatLevel / FIRE_MAX_HEAT_LEVEL;
	if ( m_flHeatLevel != m_flLastHeatLevel )
	{
		m_flLastHeatLevel = m_flHeatLevel;
		// Make the effect the appropriate size given the heat level
		m_hEffect->Scale( strength, 0.5f );		
	}
	// add heat to myself (grow)
	float addedHeat = (m_flAttackTime > 0) ? m_flMaxHeat / m_flAttackTime : m_flMaxHeat;
	addedHeat *= simTime * fire_growthrate.GetFloat();
	AddHeat( addedHeat, true );

	// add heat to nearby fires
	float outputHeat = strength * m_flHeatLevel;

	Vector fireMins;
	Vector fireMaxs;
	Vector fireEntityDamageMins;
	Vector fireEntityDamageMaxs;

	GetFireDimensions( &fireMins, &fireMaxs );

	if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 ) // if set to 1.0, optimizer will remove this code
	{
		fireEntityDamageMins = fireMins / FIRE_SPREAD_DAMAGE_MULTIPLIER;
		fireEntityDamageMaxs = fireMaxs / FIRE_SPREAD_DAMAGE_MULTIPLIER;
	}

	//NDebugOverlay::Box( GetAbsOrigin(), fireMins, fireMaxs, 255, 255, 255, 0, fire_dmginterval.GetFloat() );
	fireMins += GetAbsOrigin();
	fireMaxs += GetAbsOrigin();

	if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 )
	{
		fireEntityDamageMins += GetAbsOrigin();
		fireEntityDamageMaxs += GetAbsOrigin();
	}

	CBaseEntity *pNearby[256];
	CFire *pFires[16];
	int nearbyCount = UTIL_EntitiesInBox( pNearby, ARRAYSIZE(pNearby), fireMins, fireMaxs, 0 );
	int fireCount = 0;
	int i;

	// is it time to do damage?
	bool damage = false;
	int outputDamage = 0;
	if ( m_flDamageTime <= gpGlobals->curtime )
	{
		m_flDamageTime = gpGlobals->curtime + fire_dmginterval.GetFloat();
		outputDamage = (fire_dmgbase.GetFloat() + outputHeat * fire_dmgscale.GetFloat() * m_flDamageScale) * fire_dmginterval.GetFloat();
		if ( outputDamage )
		{
			damage = true;
		}
	}
	int damageFlags = (m_nFireType == FIRE_NATURAL) ? DMG_BURN : DMG_PLASMA;
	for ( i = 0; i < nearbyCount; i++ )
	{
		CBaseEntity *pOther = pNearby[i];

		if ( pOther == this )
		{
			continue;
		}
		else if ( FClassnameIs( pOther, "env_fire" ) )
		{
			if ( fireCount < ARRAYSIZE(pFires) )
			{
				pFires[fireCount] = (CFire *)pOther;
				fireCount++;
			}
			continue;
		}
		else if ( pOther->m_takedamage == DAMAGE_NO )
		{
			pNearby[i] = NULL;
		}
		else if ( damage )
		{
			bool bDoDamage;

			if ( FIRE_SPREAD_DAMAGE_MULTIPLIER != 1.0 && !pOther->IsPlayer() ) // if set to 1.0, optimizer will remove this code
			{
				Vector otherMins, otherMaxs;
				pOther->CollisionProp()->WorldSpaceAABB( &otherMins, &otherMaxs );
				bDoDamage = IsBoxIntersectingBox( otherMins, otherMaxs, 
												  fireEntityDamageMins, fireEntityDamageMaxs );

			}
			else
				bDoDamage = true;

			if ( bDoDamage )
			{
				// Make sure can actually see entity (don't damage through walls)
				trace_t tr;
				UTIL_TraceLine( this->WorldSpaceCenter(), pOther->WorldSpaceCenter(), MASK_FIRE_SOLID, pOther, COLLISION_GROUP_NONE, &tr );

				if (tr.fraction == 1.0 && !tr.startsolid)
				{
					pOther->TakeDamage( CTakeDamageInfo( this, this, outputDamage, damageFlags ) );
				}
			}
		}
	}

	outputHeat *= fire_heatscale.GetFloat() * simTime;

	if ( fireCount > 0 )
	{
		outputHeat /= fireCount;
		for ( i = 0; i < fireCount; i++ )
		{
			pFires[i]->AddHeat( outputHeat, false );
		}
	}
}
Exemple #21
0
void CBreakable::Die( void )
{
	Vector vecSpot;// shard origin
	Vector vecVelocity;// shard velocity
	CBaseEntity *pEntity = NULL;
	char cFlag = 0;
	int pitch;
	float fvol;
	
	pitch = 95 + RANDOM_LONG(0,29);

	if (pitch > 97 && pitch < 103)
		pitch = 100;

	// The more negative pev->health, the louder
	// the sound should be.

	fvol = RANDOM_FLOAT(0.85, 1.0) + (abs(pev->health) / 100.0);

	if (fvol > 1.0)
		fvol = 1.0;


	switch (m_Material)
	{
	case matGlass:
		switch ( RANDOM_LONG(0,1) )
		{
		case 0:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch);	
			break;
		case 1:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass2.wav", fvol, ATTN_NORM, 0, pitch);	
			break;
		}
		cFlag = BREAK_GLASS;
		break;

	case matWood:
		switch ( RANDOM_LONG(0,1) )
		{
		case 0:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch);	
			break;
		case 1:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch);	
			break;
		}
		cFlag = BREAK_WOOD;
		break;

	case matComputer:
	case matMetal:
		switch ( RANDOM_LONG(0,1) )
		{
		case 0:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch);	
			break;
		case 1:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch);	
			break;
		}
		cFlag = BREAK_METAL;
		break;

	case matFlesh:
		switch ( RANDOM_LONG(0,1) )
		{
		case 0:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch);	
			break;
		case 1:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch);	
			break;
		}
		cFlag = BREAK_FLESH;
		break;

	case matRocks:
	case matCinderBlock:
		switch ( RANDOM_LONG(0,1) )
		{
		case 0:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch);	
			break;
		case 1:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete2.wav", fvol, ATTN_NORM, 0, pitch);	
			break;
		}
		cFlag = BREAK_CONCRETE;
		break;

	case matCeilingTile:
		EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch);
		break;
	}
    
		
	if (m_Explosion == expDirected)
		vecVelocity = g_vecAttackDir * 200;
	else
	{
		vecVelocity.x = 0;
		vecVelocity.y = 0;
		vecVelocity.z = 0;
	}

	vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5;
	MESSAGE_BEGIN( MSG_PVS, SVC_TEMPENTITY, vecSpot );
		WRITE_BYTE( TE_BREAKMODEL);

		// position
		WRITE_COORD( vecSpot.x );
		WRITE_COORD( vecSpot.y );
		WRITE_COORD( vecSpot.z );

		// size
		WRITE_COORD( pev->size.x);
		WRITE_COORD( pev->size.y);
		WRITE_COORD( pev->size.z);

		// velocity
		WRITE_COORD( vecVelocity.x ); 
		WRITE_COORD( vecVelocity.y );
		WRITE_COORD( vecVelocity.z );

		// randomization
		WRITE_BYTE( 10 ); 

		// Model
		WRITE_SHORT( m_idShard );	//model id#

		// # of shards
		WRITE_BYTE( 0 );	// let client decide

		// duration
		WRITE_BYTE( 25 );// 2.5 seconds

		// flags
		WRITE_BYTE( cFlag );
	MESSAGE_END();

	float size = pev->size.x;
	if ( size < pev->size.y )
		size = pev->size.y;
	if ( size < pev->size.z )
		size = pev->size.z;

	// !!! HACK  This should work!
	// Build a box above the entity that looks like an 8 pixel high sheet
	Vector mins = pev->absmin;
	Vector maxs = pev->absmax;
	mins.z = pev->absmax.z;
	maxs.z += 8;

	// BUGBUG -- can only find 256 entities on a breakable -- should be enough
	CBaseEntity *pList[256];
	int count = UTIL_EntitiesInBox( pList, 256, mins, maxs, FL_ONGROUND );
	if ( count )
	{
		for ( int i = 0; i < count; i++ )
		{
			ClearBits( pList[i]->pev->flags, FL_ONGROUND );
			pList[i]->pev->groundentity = NULL;
		}
	}

	// Don't fire something that could fire myself
	pev->targetname = 0;

	pev->solid = SOLID_NOT;
	// Fire targets on break
	SUB_UseTargets( NULL, USE_TOGGLE, 0 );

	SetThink( &CBreakable::SUB_Remove );
	pev->nextthink = pev->ltime + 0.1;
	if ( m_iszSpawnObject )
		CBaseEntity::Create( (char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict() );


	if ( Explodable() )
	{
		ExplosionCreate( Center(), pev->angles, edict(), ExplosionMagnitude(), TRUE );
	}
}
//-----------------------------------------------------------------------------
// Purpose: Give the buster a slight attraction to striders.
//			Ported back from the magnade.
//-----------------------------------------------------------------------------
void CWeaponStriderBuster::BusterFlyThink()
{
	if (IsAttachedToStrider())
		return; // early out. Think no more.

	// If we're nosediving, forget about magnetism.
	if ( m_bNoseDiving )
	{
		if ( VPhysicsGetObject() )
			VPhysicsGetObject()->ApplyForceCenter( Vector( 0, 0, striderbuster_dive_force.GetFloat() ) );
		SetNextThink(gpGlobals->curtime + 0.01f);
		return;
	}

	// seek?	
	const float magradius = 38.0 * sk_striderbuster_magnet_multiplier.GetFloat(); // radius of strider hull times multiplier
	if (magradius > 0 &&
		GetMoveType() == MOVETYPE_VPHYSICS &&
		VPhysicsGetObject()
		)
	{
		// find the nearest enemy.
		CBaseEntity *pList[16];
		Vector origin = GetAbsOrigin();

		// do a find in box ( a little faster than sphere )
		int count;
		{
			Vector mins,maxs;
			mins = origin; 
			mins -= magradius;
			
			maxs = origin; 
			maxs += magradius;

			count = UTIL_EntitiesInBox(pList, 16, mins, maxs, FL_NPC); 
		}

		float magradiusSq = Square( magradius );	
		float nearestDistSq = magradiusSq + 1;
		int bestFit = -1;
		Vector toTarget; // will be garbage unless something good is found
		CNPC_Strider *pBestStrider  = NULL;

		for ( int ii = 0 ; ii < count ; ++ii )
		{
			CNPC_Strider *pStrider = dynamic_cast<CNPC_Strider *>(pList[ii]);
			if ( pStrider && !pStrider->CarriedByDropship() ) // ShouldStickToEntity() doesn't work because the strider NPC isn't what we glue to
			{
				// get distance squared
				VectorSubtract( pStrider->GetAdjustedOrigin(), GetAbsOrigin(), toTarget );

				//NDebugOverlay::Line( GetAbsOrigin(), GetAbsOrigin() + toTarget, 128, 0, 128, false, 0.1 );

				float dSq = toTarget.LengthSqr();
				if (dSq < nearestDistSq)
				{
					bestFit = ii; nearestDistSq = dSq;
					pBestStrider = pStrider;
				}
			}
		}

		if (bestFit >= 0) // we found something and should attract towards it. (hysterisis later?)
		{
			if ( striderbuster_debugseek.GetBool() )
			{
				NDebugOverlay::Circle( GetAbsOrigin() + toTarget, magradius, 255, 255, 255, 255, true, .1 );
				NDebugOverlay::Cross3D( GetAbsOrigin() + toTarget, magradius, 255, 255, 255, true, .1 );
			}

			// force magnitude. 
			float magnitude = GetMass() * striderbuster_magnetic_force_strider.GetFloat();
			int falloff = striderbuster_falloff_power.GetInt();
			switch (falloff) 
			{
			case 1:
				VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / nearestDistSq) ); // dividing through by distance squared normalizes toTarget and gives a linear falloff
				break;
			case 2:
				VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / (nearestDistSq * sqrtf(nearestDistSq))) ); // dividing through by distance cubed normalizes toTarget and gives a quadratic falloff
				break;
			case 3:
				VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude / (nearestDistSq * nearestDistSq)) ); // dividing through by distance fourth normalizes toTarget and gives a cubic falloff
				break;
			case 4:
				{
					Vector toTarget;
					pBestStrider->GetAttachment( "buster_target", toTarget );

					if ( striderbuster_debugseek.GetBool() )
					{
						NDebugOverlay::Cross3D( toTarget, magradius, 255, 0, 255, true, .1 );
						NDebugOverlay::Cross3D( toTarget, magradius, 255, 0, 255, true, .1 );
					}

					toTarget -= GetAbsOrigin();
					toTarget.NormalizeInPlace();
					VPhysicsGetObject()->ApplyForceCenter( toTarget * magnitude );

				}
				break;
			default: // arbitrary powers
				VPhysicsGetObject()->ApplyForceCenter( toTarget * (magnitude * powf(nearestDistSq,(falloff+1.0f)/2)) );  // square root for distance instead of squared, add one to normalize toTarget 
				break;
			}
		}

		SetNextThink(gpGlobals->curtime + 0.01f);
	}
}
Exemple #23
0
//=========================================================
// MakeMonster-  this is the code that drops the monster
//=========================================================
void CMonsterMaker::MakeMonster( void )
{
	edict_t	*pent;
	entvars_t		*pevCreate;

	if ( m_iMaxLiveChildren > 0 && m_cLiveChildren >= m_iMaxLiveChildren )
	{// not allowed to make a new one yet. Too many live ones out right now.
		return;
	}

	if ( !m_flGround )
	{
		// set altitude. Now that I'm activated, any breakables, etc should be out from under me. 
		TraceResult tr;

		UTIL_TraceLine ( pev->origin, pev->origin - Vector ( 0, 0, 2048 ), ignore_monsters, ENT(pev), &tr );
		m_flGround = tr.vecEndPos.z;
	}

	Vector mins = pev->origin - Vector( 34, 34, 0 );
	Vector maxs = pev->origin + Vector( 34, 34, 0 );
	maxs.z = pev->origin.z;
	mins.z = m_flGround;

	CBaseEntity *pList[2];
	int count = UTIL_EntitiesInBox( pList, 2, mins, maxs, FL_CLIENT|FL_MONSTER );
	if ( count )
	{
		// don't build a stack of monsters!
		return;
	}

	pent = CREATE_NAMED_ENTITY( m_iszMonsterClassname );

	if ( FNullEnt( pent ) )
	{
		ALERT ( at_console, "NULL Ent in MonsterMaker!\n" );
		return;
	}
	
	// If I have a target, fire!
	if ( !FStringNull ( pev->target ) )
	{
		// delay already overloaded for this entity, so can't call SUB_UseTargets()
		FireTargets( STRING(pev->target), this, this, USE_TOGGLE, 0 );
	}

	pevCreate = VARS( pent );
	pevCreate->origin = pev->origin;
	pevCreate->angles = pev->angles;
	SetBits( pevCreate->spawnflags, SF_MONSTER_FALL_TO_GROUND );

	// Children hit monsterclip brushes
	if ( pev->spawnflags & SF_MONSTERMAKER_MONSTERCLIP )
		SetBits( pevCreate->spawnflags, SF_MONSTER_HITMONSTERCLIP );

	DispatchSpawn( ENT( pevCreate ) );
	pevCreate->owner = edict();

	if ( !FStringNull( pev->netname ) )
	{
		// if I have a netname (overloaded), give the child monster that name as a targetname
		pevCreate->targetname = pev->netname;
	}

	m_cLiveChildren++;// count this monster
	m_cNumMonsters--;

	if ( m_cNumMonsters == 0 )
	{
		// Disable this forever.  Don't kill it because it still gets death notices
		SetThink( NULL );
		SetUse( NULL );
	}
}
Exemple #24
0
void CBreakable::Die()
{
	Vector vecSpot;	// shard origin
	Vector vecVelocity;	// shard velocity
	CBaseEntity *pEntity = NULL;
	char cFlag = 0;
	int pitch;
	float fvol;

	pev->takedamage = DAMAGE_NO;
	pev->deadflag = DEAD_DEAD;
	pev->effects = EF_NODRAW;

	pitch = 95 + RANDOM_LONG(0, 29);

	if (pitch > 97 && pitch < 103)
		pitch = 100;

	// The more negative pev->health, the louder
	// the sound should be.
	fvol = RANDOM_FLOAT(0.85, 1.0) + (abs((int)pev->health) / 100.0f);

	if (fvol > 1.0f)
		fvol = 1.0f;

	switch (m_Material)
	{
	case matGlass:
		switch (RANDOM_LONG(0, 1))
		{
		case 0:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass1.wav", fvol, ATTN_NORM, 0, pitch);
			break;
		case 1:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustglass2.wav", fvol, ATTN_NORM, 0, pitch);
			break;
		}
		cFlag = BREAK_GLASS;

		if (TheBots != NULL)
		{
			TheBots->OnEvent(EVENT_BREAK_GLASS, this);
		}
		break;
	case matWood:
		switch (RANDOM_LONG(0, 1))
		{
		case 0:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate1.wav", fvol, ATTN_NORM, 0, pitch);
			break;
		case 1:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustcrate2.wav", fvol, ATTN_NORM, 0, pitch);
			break;
		}
		cFlag = BREAK_WOOD;

		if (TheBots != NULL)
		{
			TheBots->OnEvent(EVENT_BREAK_WOOD, this);
		}
		break;

	case matMetal:
	case matComputer:
		switch (RANDOM_LONG(0, 1))
		{
		case 0:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal1.wav", fvol, ATTN_NORM, 0, pitch);
			break;
		case 1:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustmetal2.wav", fvol, ATTN_NORM, 0, pitch);
			break;
		}
		cFlag = BREAK_METAL;

		if (TheBots != NULL)
		{
			TheBots->OnEvent(EVENT_BREAK_METAL, this);
		}
		break;

	case matFlesh:
		switch (RANDOM_LONG(0, 1))
		{
		case 0:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh1.wav", fvol, ATTN_NORM, 0, pitch);
			break;
		case 1:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustflesh2.wav", fvol, ATTN_NORM, 0, pitch);
			break;
		}
		cFlag = BREAK_FLESH;

		if (TheBots != NULL)
		{
			TheBots->OnEvent(EVENT_BREAK_FLESH, this);
		}
		break;

	case matCinderBlock:
	case matRocks:
		switch (RANDOM_LONG(0, 1))
		{
		case 0:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete1.wav", fvol, ATTN_NORM, 0, pitch);
			break;
		case 1:	EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustconcrete2.wav", fvol, ATTN_NORM, 0, pitch);
			break;
		}
		cFlag = BREAK_CONCRETE;

		if (TheBots != NULL)
		{
			TheBots->OnEvent(EVENT_BREAK_CONCRETE, this);
		}
		break;

	case matCeilingTile:
		EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, "debris/bustceiling.wav", fvol, ATTN_NORM, 0, pitch);
		break;
	default:
		break;
	}

	if (m_Explosion == expDirected)
	{
		vecVelocity = g_vecAttackDir * 200.0f;
	}
	else
	{
		vecVelocity.x = 0;
		vecVelocity.y = 0;
		vecVelocity.z = 0;
	}

	vecSpot = pev->origin + (pev->mins + pev->maxs) * 0.5;

	MESSAGE_BEGIN(MSG_PVS, SVC_TEMPENTITY, vecSpot);
		WRITE_BYTE(TE_BREAKMODEL);
		WRITE_COORD(vecSpot.x);		// position
		WRITE_COORD(vecSpot.y);
		WRITE_COORD(vecSpot.z);
		WRITE_COORD(pev->size.x);	// size
		WRITE_COORD(pev->size.y);
		WRITE_COORD(pev->size.z);
		WRITE_COORD(vecVelocity.x);	// velocity
		WRITE_COORD(vecVelocity.y);
		WRITE_COORD(vecVelocity.z);
		WRITE_BYTE(10);			// randomization
		WRITE_SHORT(m_idShard);		// model id#
		WRITE_BYTE(0);			// # of shards, let client decide
		WRITE_BYTE(25);			// duration, 2.5 seconds
		WRITE_BYTE(cFlag);		// flags
	MESSAGE_END();

	float size = pev->size.x;

	if (size < pev->size.y)
		size = pev->size.y;

	if (size < pev->size.z)
		size = pev->size.z;

	Vector mins = pev->absmin;
	Vector maxs = pev->absmax;
	mins.z = pev->absmax.z;
	maxs.z += 8;

	CBaseEntity *pList[256];
	int count = UTIL_EntitiesInBox(pList, ARRAYSIZE(pList), mins, maxs, FL_ONGROUND);

	if (count)
	{
		for (int i = 0; i < count; ++i)
		{
			pList[i]->pev->flags &= ~FL_ONGROUND;
			pList[i]->pev->groundentity = NULL;
		}
	}

	pev->solid = SOLID_NOT;
	SUB_UseTargets(NULL, USE_TOGGLE, 0);
	SetThink(NULL);

	pev->nextthink = pev->ltime + 0.1f;

	if (m_iszSpawnObject)
	{
		CBaseEntity::Create((char *)STRING(m_iszSpawnObject), VecBModelOrigin(pev), pev->angles, edict());
	}

	if (Explodable())
	{
		ExplosionCreate(Center(), pev->angles, edict(), ExplosionMagnitude(), TRUE);
	}
}
//-----------------------------------------------------------------------------
// Purpose: Returns whether or not it is OK to make an NPC at this instant.
//-----------------------------------------------------------------------------
bool CBaseNPCMaker::CanMakeNPC( bool bIgnoreSolidEntities )
{
	if( ai_inhibit_spawners.GetBool() )
		return false;

	if ( m_nMaxLiveChildren > 0 && m_nLiveChildren >= m_nMaxLiveChildren )
	{// not allowed to make a new one yet. Too many live ones out right now.
		return false;
	}

	if ( m_iszIngoreEnt != NULL_STRING )
	{
		m_hIgnoreEntity = gEntList.FindEntityByName( NULL, m_iszIngoreEnt );
	}

	Vector mins = GetAbsOrigin() - Vector( 34, 34, 0 );
	Vector maxs = GetAbsOrigin() + Vector( 34, 34, 0 );
	maxs.z = GetAbsOrigin().z;
	
	// If we care about not hitting solid entities, look for 'em
	if ( !bIgnoreSolidEntities )
	{
		CBaseEntity *pList[128];

		int count = UTIL_EntitiesInBox( pList, 128, mins, maxs, FL_CLIENT|FL_NPC );
		if ( count )
		{
			//Iterate through the list and check the results
			for ( int i = 0; i < count; i++ )
			{
				//Don't build on top of another entity
				if ( pList[i] == NULL )
					continue;

				//If one of the entities is solid, then we may not be able to spawn now
				if ( ( pList[i]->GetSolidFlags() & FSOLID_NOT_SOLID ) == false )
				{
					// Since the outer method doesn't work well around striders on account of their huge bounding box.
					// Find the ground under me and see if a human hull would fit there.
					trace_t tr;
					UTIL_TraceHull( GetAbsOrigin() + Vector( 0, 0, 2 ),
									GetAbsOrigin() - Vector( 0, 0, 8192 ),
									NAI_Hull::Mins(HULL_HUMAN),
									NAI_Hull::Maxs(HULL_HUMAN),
									MASK_NPCSOLID,
									m_hIgnoreEntity,
									COLLISION_GROUP_NONE,
									&tr );

					if( !HumanHullFits( tr.endpos + Vector( 0, 0, 1 ) ) )
					{
						return false;
					}
				}
			}
		}
	}

	// Do we need to check to see if the player's looking?
	if ( HasSpawnFlags( SF_NPCMAKER_HIDEFROMPLAYER ) )
	{
		for ( int i = 1; i <= gpGlobals->maxClients; i++ )
		{
			CBasePlayer *pPlayer = UTIL_PlayerByIndex(i);
			if ( pPlayer )
			{
				// Only spawn if the player's looking away from me
				if( pPlayer->FInViewCone( GetAbsOrigin() ) && pPlayer->FVisible( GetAbsOrigin() ) )
				{
					if ( !(pPlayer->GetFlags() & FL_NOTARGET) )
						return false;
					DevMsg( 2, "Spawner %s spawning even though seen due to notarget\n", STRING( GetEntityName() ) );
				}
			}
		}
	}

	return true;
}
//=========================================================
// HandleAnimEvent - catches the monster-specific messages
// that occur when tagged animation frames are played.
//
// Returns number of events handled, 0 if none.
//=========================================================
void CNPC_BigMomma::HandleAnimEvent( animevent_t *pEvent )
{
	CPASAttenuationFilter filter( this );

	Vector vecFwd, vecRight, vecUp;
	QAngle angles;
	angles = GetAbsAngles();
	AngleVectors( angles, &vecFwd, &vecRight, &vecUp );

	switch( pEvent->event )
	{
		case BIG_AE_MELEE_ATTACKBR:
		case BIG_AE_MELEE_ATTACKBL:
		case BIG_AE_MELEE_ATTACK1:
		{
			Vector center = GetAbsOrigin() + vecFwd * 128;
			Vector mins = center - Vector( 64, 64, 0 );
			Vector maxs = center + Vector( 64, 64, 64 );

			CBaseEntity *pList[8];
			int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_NPC | FL_CLIENT );
			CBaseEntity *pHurt = NULL;

			for ( int i = 0; i < count && !pHurt; i++ )
			{
				if ( pList[i] != this )
				{
					if ( pList[i]->GetOwnerEntity() != this )
					{
						pHurt = pList[i];
					}
				}
			}
					
			if ( pHurt )
			{
				CTakeDamageInfo info( this, this, 15, DMG_CLUB | DMG_SLASH );
				CalculateMeleeDamageForce( &info, (pHurt->GetAbsOrigin() - GetAbsOrigin()), pHurt->GetAbsOrigin() );
				pHurt->TakeDamage( info );
				QAngle newAngles = angles;
				newAngles.x = 15;
				if ( pHurt->IsPlayer() )
				{
					((CBasePlayer *)pHurt)->SetPunchAngle( newAngles );
				}
				switch( pEvent->event )
				{
					case BIG_AE_MELEE_ATTACKBR:
//						pHurt->pev->velocity = pHurt->pev->velocity + (vecFwd * 150) + Vector(0,0,250) - (vecRight * 200);
						pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 150) + Vector(0,0,250) - (vecRight * 200) );
					break;

					case BIG_AE_MELEE_ATTACKBL:
						pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 150) + Vector(0,0,250) + (vecRight * 200) );
					break;

					case BIG_AE_MELEE_ATTACK1:
						pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 220) + Vector(0,0,200) );
					break;
				}

				pHurt->SetGroundEntity( NULL );
				EmitSound( filter, entindex(), "BigMomma.AttackHit" );
			}
		}
		break;
		
		case BIG_AE_SCREAM:
			EmitSound( filter, entindex(), "BigMomma.Alert" );
			break;
		
		case BIG_AE_PAIN_SOUND:
			EmitSound( filter, entindex(), "BigMomma.Pain" );
			break;
		
		case BIG_AE_ATTACK_SOUND:
			EmitSound( filter, entindex(), "BigMomma.Attack" );
			break;

		case BIG_AE_BIRTH_SOUND:
			EmitSound( filter, entindex(), "BigMomma.Birth" );
			break;

		case BIG_AE_SACK:
			if ( RandomInt(0,100) < 30 )
			{
				EmitSound( filter, entindex(), "BigMomma.Sack" );
			}
			break;

		case BIG_AE_DEATHSOUND:
			EmitSound( filter, entindex(), "BigMomma.Die" );
			break;

		case BIG_AE_STEP1:		// Footstep left
		case BIG_AE_STEP3:		// Footstep back left
			EmitSound( filter, entindex(), "BigMomma.FootstepLeft" );
			break;

		case BIG_AE_STEP4:		// Footstep back right
		case BIG_AE_STEP2:		// Footstep right
			EmitSound( filter, entindex(), "BigMomma.FootstepRight" );
			break;

		case BIG_AE_MORTAR_ATTACK1:
			LaunchMortar();
			break;

		case BIG_AE_LAY_CRAB:
			LayHeadcrab();
			break;

		case BIG_AE_JUMP_FORWARD:
			SetGroundEntity( NULL );
			SetAbsOrigin(GetAbsOrigin() + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground 
			SetAbsVelocity(vecFwd * 200 + vecUp * 500 );
			break;

		case BIG_AE_EARLY_TARGET:
			{
				CInfoBM *pTarget = (CInfoBM*) GetTarget();

				if ( pTarget )
				{
					pTarget->m_OnAnimationEvent.FireOutput( this, this );
				}
				
				Remember( bits_MEMORY_FIRED_NODE );
			}
			break;

		default:
			BaseClass::HandleAnimEvent( pEvent );
			break;
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponHarpoon::SecondaryAttack( void )
{
	CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
	if ( !pPlayer )
		return;

	// Slap things in front of me
	Vector vecForward;
	Vector vecBox = Vector( FIST_RANGE,FIST_RANGE,FIST_RANGE * 1.5 ) * 0.5;
	pPlayer->EyeVectors( &vecForward );
	Vector vecSrc = pPlayer->Weapon_ShootPosition( );
	Vector vecCenter = vecSrc + (FIST_RANGE * 0.5 * vecForward);

#if !defined( CLIENT_DLL )
	//NDebugOverlay::Box( vecCenter, -Vector(2,2,2), Vector(2,2,2), 255,0,0,20,2.0);
	//NDebugOverlay::Box( vecCenter, -vecBox, vecBox, 255,255,255,20,2.0);

	bool bHitMetal = false;
	bool bHitPlayer = false;

	CBaseEntity	*pList[100];
	int count = UTIL_EntitiesInBox( pList, 100, vecSrc - vecBox, vecSrc + vecBox, FL_CLIENT|FL_NPC|FL_OBJECT );
	for ( int i = 0; i < count; i++ )
	{
		CBaseEntity *pEntity = pList[i];
		if ( !pEntity->m_takedamage )
			continue;
		if ( pEntity->InSameTeam( this ) )
			continue;

		//NDebugOverlay::EntityBounds( pEntity, 0,255,0,20,2.0);
		if ( pEntity->IsPlayer() )
		{
			bHitPlayer = true;
			CTakeDamageInfo info( this, pPlayer, weapon_fist_damage.GetFloat(), DMG_CLUB );
			CalculateMeleeDamageForce( &info, (pEntity->GetAbsOrigin() - vecCenter), pEntity->GetAbsOrigin() );
			pEntity->TakeDamage( info );
		}
		else if ( pEntity->Classify() == CLASS_MILITARY )
		{
			bHitMetal = true;
			CTakeDamageInfo info( this, pPlayer, weapon_fist_damage_objects.GetFloat(), DMG_CLUB );
			CalculateMeleeDamageForce( &info, (pEntity->GetAbsOrigin() - vecCenter), pEntity->GetAbsOrigin() );
			pEntity->TakeDamage( info );
		}
		else
		{
			bHitMetal = true;
			CTakeDamageInfo info( this, pPlayer, weapon_fist_damage.GetFloat(), DMG_CLUB );
			CalculateMeleeDamageForce( &info, (pEntity->GetAbsOrigin() - vecCenter), pEntity->GetAbsOrigin() );
			pEntity->TakeDamage( info );
		}
	}

	// Play the right sound
	if ( bHitPlayer )
	{
		EmitSound( "Harpoon.HitFlesh" );
	}
	else if ( bHitMetal )
	{
		EmitSound( "Harpoon.HitMetal" );
	}
#endif
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CASWEnvShake::ApplyShake( ShakeCommand_t command )
{
	if ( !HasSpawnFlags( SF_ASW_SHAKE_NO_VIEW ) )
	{
		bool air = (GetSpawnFlags() & SF_ASW_SHAKE_INAIR) ? true : false;
		UTIL_ASW_ScreenShake( GetAbsOrigin(), Amplitude(), Frequency(), Duration(), Radius(), command, air );
	}
		
	if ( GetSpawnFlags() & SF_ASW_SHAKE_ROPES )
	{
		CRopeKeyframe::ShakeRopes( GetAbsOrigin(), Radius(), Frequency() );
	}

	if ( GetSpawnFlags() & SF_ASW_SHAKE_PHYSICS )
	{
		if ( !m_pShakeController )
		{
			m_pShakeController = physenv->CreateMotionController( &m_shakeCallback );
		}
		// do physics shake
		switch( command )
		{
		case SHAKE_START:
			{
				m_stopTime = gpGlobals->curtime + Duration();
				m_nextShake = 0;
				m_pShakeController->ClearObjects();
				SetNextThink( gpGlobals->curtime );
				m_currentAmp = Amplitude();
				CBaseEntity *list[1024];
				float radius = Radius();
				
				// probably checked "Shake Everywhere" do a big radius
				if ( !radius )
				{
					radius = MAX_COORD_INTEGER;
				}
				Vector extents = Vector(radius, radius, radius);
				Vector mins = GetAbsOrigin() - extents;
				Vector maxs = GetAbsOrigin() + extents;
				int count = UTIL_EntitiesInBox( list, 1024, mins, maxs, 0 );

				for ( int i = 0; i < count; i++ )
				{
					//
					// Only shake physics entities that players can see. This is one frame out of date
					// so it's possible that we could miss objects if a player changed PVS this frame.
					//
					if ( ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS ) )
					{
						IPhysicsObject *pPhys = list[i]->VPhysicsGetObject();
						if ( pPhys && pPhys->IsMoveable() )
						{
							m_pShakeController->AttachObject( pPhys, false );
							pPhys->Wake();
						}
					}
				}
			}
			break;
		case SHAKE_STOP:
			m_pShakeController->ClearObjects();
			break;
		case SHAKE_AMPLITUDE:
			m_currentAmp = Amplitude();
		case SHAKE_FREQUENCY:
			m_pShakeController->WakeObjects();
			break;
		}
	}
}
//=========================================================
// Look - Base class monster function to find enemies or 
// food by sight. iDistance is distance ( in units ) that the 
// monster can see.
//
// Sets the sight bits of the m_afConditions mask to indicate
// which types of entities were sighted.
// Function also sets the Looker's m_pLink 
// to the head of a link list that contains all visible ents.
// (linked via each ent's m_pLink field)
//
//=========================================================
void CBaseMonster :: Look ( int iDistance )
{
	int	iSighted = 0;

	// DON'T let visibility information from last frame sit around!
	ClearConditions(bits_COND_SEE_HATE | bits_COND_SEE_DISLIKE | bits_COND_SEE_ENEMY | bits_COND_SEE_FEAR | bits_COND_SEE_NEMESIS | bits_COND_SEE_CLIENT);

	m_pLink = NULL;

	CBaseEntity	*pSightEnt = NULL;// the current visible entity that we're dealing with

	CBaseEntity *pList[100];

	Vector delta = Vector( iDistance, iDistance, iDistance );

	// Find only monsters/clients in box, NOT limited to PVS
	int count = UTIL_EntitiesInBox( pList, 100, pev->origin - delta, pev->origin + delta, FL_CLIENT|FL_MONSTER );
	for ( int i = 0; i < count; i++ )
	{
		pSightEnt = pList[i];
		if ( pSightEnt != this && pSightEnt->pev->health > 0 )
		{
			// the looker will want to consider this entity
			// don't check anything else about an entity that can't be seen, or an entity that you don't care about.
			if ( IRelationship( pSightEnt ) != R_NO && FInViewCone( pSightEnt ) && !FBitSet( pSightEnt->pev->flags, FL_NOTARGET ) && FVisible( pSightEnt ) )
			{
				if ( pSightEnt->IsPlayer() )
				{
					// if we see a client, remember that (mostly for scripted AI)
					iSighted |= bits_COND_SEE_CLIENT;
				}

				pSightEnt->m_pLink = m_pLink;
				m_pLink = pSightEnt;

				if ( pSightEnt == m_hEnemy )
				{
					// we know this ent is visible, so if it also happens to be our enemy, store that now.
					iSighted |= bits_COND_SEE_ENEMY;
				}

				// don't add the Enemy's relationship to the conditions. We only want to worry about conditions when
				// we see monsters other than the Enemy.
				switch ( IRelationship ( pSightEnt ) )
				{
				case	R_NM:
					iSighted |= bits_COND_SEE_NEMESIS;		
					break;
				case	R_HT:		
					iSighted |= bits_COND_SEE_HATE;		
					break;
				case	R_DL:
					iSighted |= bits_COND_SEE_DISLIKE;
					break;
				case	R_FR:
					iSighted |= bits_COND_SEE_FEAR;
					break;
				case    R_AL:
					break;
				default:
					ALERT ( at_aiconsole, "%s can't assess %s\n", STRING(pev->classname), STRING(pSightEnt->pev->classname ) );
					break;
				}
			}
		}
	}
	
	SetConditions( iSighted );
}
Exemple #30
0
//-----------------------------------------------------------------------------
// Purpose: Activate any nearby bugbait targets
//			Returns true if the bugbait target wants to suppress the call.
//-----------------------------------------------------------------------------
bool CGrenadeBugBait::ActivateBugbaitTargets( CBaseEntity *pOwner, Vector vecOrigin, bool bSqueezed )
{
	//Attempt to activate any spawners in a radius around the bugbait
	CBaseEntity*	pList[100];
	Vector			delta( bugbait_grenade_radius.GetFloat(), bugbait_grenade_radius.GetFloat(), bugbait_grenade_radius.GetFloat() );
	bool			suppressCall = false;

	int count = UTIL_EntitiesInBox( pList, 100, vecOrigin - delta, vecOrigin + delta, 0 );
	
	// If the bugbait's been thrown, look for nearby targets to affect
	if ( !bSqueezed )
	{
		for ( int i = 0; i < count; i++ )
		{
			// If close enough, make combine soldiers freak out when hit
			if ( UTIL_DistApprox( pList[i]->WorldSpaceCenter(), vecOrigin ) < bugbait_grenade_radius.GetFloat() )
			{
				// Must be a soldier
				if ( FClassnameIs( pList[i], "npc_combine_s") )
				{
					CAI_BaseNPC *pCombine = pList[i]->MyNPCPointer();

					if ( pCombine != NULL )
					{
						trace_t tr;
						UTIL_TraceLine( vecOrigin, pCombine->EyePosition(), MASK_ALL, pOwner, COLLISION_GROUP_NONE, &tr);

						if ( tr.fraction == 1.0 || tr.m_pEnt == pCombine )
						{
							// Randomize the start time a little so multiple combine hit by 
							// the same bugbait don't all dance in synch.
							g_EventQueue.AddEvent( pCombine, "HitByBugbait", RandomFloat(0, 0.5), pOwner, pOwner );
						}
					}
				}
			}
		}
	}
	// Iterate over all sensors to see if they detected this impact
	for ( CBugBaitSensor *pSensor = GetBugBaitSensorList(); pSensor != NULL; pSensor = pSensor->m_pNext )
	{
		if ( pSensor == NULL )
			continue;

		if ( pSensor->IsDisabled() )
			continue;

		if ( bSqueezed && pSensor->DetectsSqueeze() == false )
			continue;

		if ( !bSqueezed && pSensor->DetectsThrown() == false )
			continue;

		//Make sure we're within range of the sensor
		if ( pSensor->GetRadius() > ( pSensor->GetAbsOrigin() - vecOrigin ).Length() )
		{
			//Tell the sensor it's been hit
			if ( pSensor->Baited( pOwner ) )
			{
				//If we're suppressing the call to antlions, then don't make a bugbait sound
				if ( pSensor->SuppressCall() )
				{
					suppressCall = true;
				}
			}
		}
	}

	return suppressCall;
}