CBaseEntity* CASW_Spawn_Manager::SpawnAlienAt(const char* szAlienClass, const Vector& vecPos, const QAngle &angle)
{	
	CBaseEntity	*pEntity = NULL;	
	pEntity = CreateEntityByName( szAlienClass );
	CAI_BaseNPC	*pNPC = dynamic_cast<CAI_BaseNPC*>(pEntity);

	if ( pNPC )
	{
		pNPC->AddSpawnFlags( SF_NPC_FALL_TO_GROUND );		
	}

	// Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC.
	QAngle angles = angle;
	angles.x = 0.0;
	angles.z = 0.0;	
	pEntity->SetAbsOrigin( vecPos );	
	pEntity->SetAbsAngles( angles );

	IASW_Spawnable_NPC* pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>(pEntity);
	ASSERT(pSpawnable);	
	if ( !pSpawnable )
	{
		Warning("NULL Spawnable Ent in CASW_Spawn_Manager::SpawnAlienAt! AlienClass = %s\n", szAlienClass);
		UTIL_Remove(pEntity);
		return NULL;
	}

	// have drones unburrow by default, so we don't worry so much about them spawning onscreen
	if ( !Q_strcmp( szAlienClass, "asw_drone" ) )
	{			
		pSpawnable->StartBurrowed();
		pSpawnable->SetUnburrowIdleActivity( NULL_STRING );
		pSpawnable->SetUnburrowActivity( NULL_STRING );
	}

	DispatchSpawn( pEntity );	
	pEntity->Activate();	

	// give our aliens the orders
	pSpawnable->SetAlienOrders(AOT_MoveToNearestMarine, vec3_origin, NULL);

	// reactivedrop: fixed horde aliens falling through floor and stuck in walls
	// by moving this function call to the bottom of SpawnAlienAt()
	
	// riflemod: temporary comment to test whether parasites fall throught floor 
	//UTIL_DropToFloor(pEntity, MASK_SOLID);

	return pEntity;
}
void CASW_Spawn_Manager::PrespawnAlienAtRandomNode(const char *szAlienClass, const int iNumAliens, const int iHull, const Vector &playerStartPos, const int iNumNodes)
{
	for (int i = 0; i < iNumAliens; ++i)
	{
		CAI_Node *pNode = NULL;
		for (int k = 0; k < 30; ++k)
		{
			int node_id = RandomInt(0, iNumNodes - 1);
			pNode = g_pBigAINet->GetNode(node_id);
			if (!pNode || pNode->GetType() != NODE_GROUND)
				continue;
			else if (pNode->GetOrigin().DistToSqr(playerStartPos) < 1000 * 1000)
			{
				continue;
			}

			if (ValidSpawnPoint(pNode->GetPosition(iHull), NAI_Hull::Mins(iHull), NAI_Hull::Maxs(iHull), true, false))
			{
				// Raise the end position a little up off the floor, place the npc and drop him down
				CBaseEntity *pAlien = SpawnAlienAt(szAlienClass, pNode->GetPosition(iHull) + Vector(0.f, 0.f, 12.f), RandomAngle(0, 360));
				IASW_Spawnable_NPC *pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>(pAlien);
				if (pSpawnable)
				{
					pSpawnable->SetAlienOrders(AOT_SpreadThenHibernate, vec3_origin, NULL);
				}
				if (asw_director_debug.GetBool() && pAlien)
				{
					Msg("Spawned alien at %f %f %f\n", pAlien->GetAbsOrigin());
					NDebugOverlay::Cross3D(pAlien->GetAbsOrigin(), 8.0f, 255, 0, 0, true, 20.0f);
				}
				if (pAlien)
					break;
			}
		}
	}
}
IASW_Spawnable_NPC* CASW_Base_Spawner::SpawnAlien( const char *szAlienClassName, const Vector &vecHullMins, const Vector &vecHullMaxs )
{
	if ( !IsValidOnThisSkillLevel() )
	{
		UTIL_Remove(this);		// delete ourself if this spawner isn't valid on this difficulty level
		return NULL;
	}

	if ( !CanSpawn( vecHullMins, vecHullMaxs ) )	// this may turn off m_bCurrentlySpawningUber if there's no room
		return NULL;

	CBaseEntity	*pEntity = CreateEntityByName( szAlienClassName );
	if ( !pEntity )
	{
		Msg( "Failed to spawn %s\n", szAlienClassName );
		return NULL;
	}

	CAI_BaseNPC	*pNPC = pEntity->MyNPCPointer();
	if ( pNPC )
	{
		pNPC->AddSpawnFlags( SF_NPC_FALL_TO_GROUND );		
	}

	// check if he can see far
	if ( m_bLongRangeNPC )
		pEntity->AddSpawnFlags( SF_NPC_LONG_RANGE );

	if ( HasSpawnFlags( ASW_SF_NEVER_SLEEP ) )
		pEntity->AddSpawnFlags( SF_NPC_ALWAYSTHINK );

	// Strip pitch and roll from the spawner's angles. Pass only yaw to the spawned NPC.
	QAngle angles = GetAbsAngles();
	angles.x = 0.0;
	angles.z = 0.0;	
	pEntity->SetAbsOrigin( GetAbsOrigin() );	
	pEntity->SetAbsAngles( angles );

	IASW_Spawnable_NPC* pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>(pEntity);
	Assert( pSpawnable );	
	if ( !pSpawnable )
	{
		Warning( "NULL Spawnable Ent in asw_spawner! AlienClass = %s\n", szAlienClassName );
		UTIL_Remove( pEntity );
		return NULL;
	}
	m_flLastSpawnTime = gpGlobals->curtime;
	if ( m_bStartBurrowed )
	{
		pSpawnable->StartBurrowed();
	}

	if ( m_bStartBurrowed )
	{
		pSpawnable->SetUnburrowIdleActivity( m_UnburrowIdleActivity );
		pSpawnable->SetUnburrowActivity( m_UnburrowActivity );
	}

	DispatchSpawn( pEntity );	

	pEntity->SetOwnerEntity( this );
	pEntity->Activate();

	if ( m_AlienName != NULL_STRING )
	{
		pEntity->SetName( m_AlienName );
	}
	
	pSpawnable->SetSpawner( this );

	RemoveObstructingProps( pEntity );	
	
	// give our aliens the orders
	pSpawnable->SetAlienOrders( m_AlienOrders, vec3_origin, GetOrderTarget() );

	m_OnSpawned.FireOutput(pEntity, this);

	return pSpawnable;
}
bool CASW_Spawn_Manager::SpawnRandomShieldbug()
{
    int iNumNodes = g_pBigAINet->NumNodes();
    if ( iNumNodes < 6 )
        return false;

    int nHull = HULL_WIDE_SHORT;
    CUtlVector<CASW_Open_Area*> aAreas;
    for ( int i = 0; i < 6; i++ )
    {
        CAI_Node *pNode = NULL;
        int nTries = 0;
        while ( nTries < 5 && ( !pNode || pNode->GetType() != NODE_GROUND ) )
        {
            pNode = g_pBigAINet->GetNode( RandomInt( 0, iNumNodes ) );
            nTries++;
        }

        if ( pNode )
        {
            CASW_Open_Area *pArea = FindNearbyOpenArea( pNode->GetOrigin(), HULL_MEDIUMBIG );
            if ( pArea && pArea->m_nTotalLinks > 30 )
            {
                // test if there's room to spawn a shieldbug at that spot
                if ( ValidSpawnPoint( pArea->m_pNode->GetPosition( nHull ), NAI_Hull::Mins( nHull ), NAI_Hull::Maxs( nHull ), true, false ) )
                {
                    aAreas.AddToTail( pArea );
                }
                else
                {
                    delete pArea;
                }
            }
        }
        // stop searching once we have 3 acceptable candidates
        if ( aAreas.Count() >= 3 )
            break;
    }

    // find area with the highest connectivity
    CASW_Open_Area *pBestArea = NULL;
    for ( int i = 0; i < aAreas.Count(); i++ )
    {
        CASW_Open_Area *pArea = aAreas[i];
        if ( !pBestArea || pArea->m_nTotalLinks > pBestArea->m_nTotalLinks )
        {
            pBestArea = pArea;
        }
    }

    if ( pBestArea )
    {
        CBaseEntity *pAlien = SpawnAlienAt( "asw_shieldbug", pBestArea->m_pNode->GetPosition( nHull ), RandomAngle( 0, 360 ) );
        IASW_Spawnable_NPC *pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>( pAlien );
        if ( pSpawnable )
        {
            pSpawnable->SetAlienOrders(AOT_SpreadThenHibernate, vec3_origin, NULL);
        }
        aAreas.PurgeAndDeleteElements();
        return true;
    }

    aAreas.PurgeAndDeleteElements();
    return false;
}
bool CASW_Spawn_Manager::SpawnRandomParasitePack( int nParasites )
{
	int iNumNodes = g_pBigAINet->NumNodes();
	if ( iNumNodes < 6 )
		return false;

	int nHull = HULL_TINY;
	CUtlVector<CASW_Open_Area*> aAreas;
	for ( int i = 0; i < 6; i++ )
	{
		CAI_Node *pNode = NULL;
		int nTries = 0;
		while ( nTries < 5 && ( !pNode || pNode->GetType() != NODE_GROUND ) )
		{
			pNode = g_pBigAINet->GetNode( RandomInt( 0, iNumNodes ) );
			nTries++;
		}

		if ( pNode )
		{
			CASW_Open_Area *pArea = FindNearbyOpenArea( pNode->GetOrigin(), HULL_MEDIUMBIG );
			if ( pArea && pArea->m_nTotalLinks > 30 )
			{
				// test if there's room to spawn a shieldbug at that spot
				if ( ValidSpawnPoint( pArea->m_pNode->GetPosition( nHull ), NAI_Hull::Mins( nHull ), NAI_Hull::Maxs( nHull ), true, false ) )
				{
					aAreas.AddToTail( pArea );
				}
				else
				{
					delete pArea;
				}
			}
		}
		// stop searching once we have 3 acceptable candidates
		if ( aAreas.Count() >= 3 )
			break;
	}

	// find area with the highest connectivity
	CASW_Open_Area *pBestArea = NULL;
	for ( int i = 0; i < aAreas.Count(); i++ )
	{
		CASW_Open_Area *pArea = aAreas[i];
		if ( !pBestArea || pArea->m_nTotalLinks > pBestArea->m_nTotalLinks )
		{
			pBestArea = pArea;
		}
	}

	if ( pBestArea )
	{
		for ( int i = 0; i < nParasites; i++ )
		{
			// raise the position by 12 units, a workaround for parasites
			// falling through displacements
			CBaseEntity *pAlien = SpawnAlienAt( "asw_parasite", pBestArea->m_pNode->GetPosition( nHull )  + Vector(0.f, 0.f, 12.f), RandomAngle( 0, 360 ) );
			IASW_Spawnable_NPC *pSpawnable = dynamic_cast<IASW_Spawnable_NPC*>( pAlien );
			if ( pSpawnable )
			{
				pSpawnable->SetAlienOrders(AOT_SpreadThenHibernate, vec3_origin, NULL);
			}
			if ( asw_director_debug.GetBool() && pAlien )
			{
				Msg( "Spawned parasite at %f %f %f\n", pAlien->GetAbsOrigin() );
				NDebugOverlay::Cross3D( pAlien->GetAbsOrigin(), 8.0f, 255, 0, 0, true, 20.0f );
			}
		}
		aAreas.PurgeAndDeleteElements();
		return true;
	}

	aAreas.PurgeAndDeleteElements();
	return false;
}