//=========================================================
// Crea un hijo en un nodo candidato.
//=========================================================
void CDirector_Manager::AddChild()
{
	// Actualizamos los nodos candidatos para la creación.
	UpdateNodes();

	// ¡No hay nodos!
	if ( SpawnNodes.Count() <= 0 )
		return;

	// Intentamos crear al hijo.
	for ( int i = 0; i < MAX_TRIES; ++i )
	{
		// Seleccionamos un nodo candidato al azar.
		CAI_Node *pNode	= GetRandomNode();

		// El nodo no existe.
		if ( !pNode )
			continue;

		// Obtenemos la ubicación del nodo e intentamos crear al hijo.
		Vector vecOrigin	= pNode->GetPosition(HULL_HUMAN);
		bool bSpawn			= AddChild(vecOrigin);

		// El hijo no se ha podido crear.
		if ( !bSpawn )
			continue;

		// Un hijo menos en la cola.
		Director()->SpawnQueue = Director()->SpawnQueue - 1;
		break;
	}
}
//=========================================================
// Crea un jefe.
//=========================================================
void CDirector_Manager::SpawnBoss()
{
	// Actualizamos los nodos candidatos para la creación.
	UpdateNodes();

	// ¡No hay nodos!
	if ( SpawnNodes.Count() <= 0 )
		return;

	for ( int i = 0; i < MAX_TRIES; ++i )
	{
		// Seleccionamos un nodo candidato al azar.
		CAI_Node *pNode	= GetRandomNode();

		// El nodo no existe.
		if ( !pNode )
			continue;

		// Obtenemos la ubicación del nodo.
		Vector vecOrigin	= pNode->GetPosition(HULL_MEDIUM_TALL);
		bool bSpawn			= AddBoss(vecOrigin);

		// El hijo no se ha podido crear.
		if ( !bSpawn )
			continue;
		
		return;
	}

	// No se pudo crear al Jefe, intentarlo en otro momento.
	Director()->BossPendient = true;
}
예제 #3
0
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;
			}
		}
	}
}
//=========================================================
// Verificaciones después de crear al NPC.
//=========================================================
bool CDirector_Manager::PostSpawn(CAI_BaseNPC *pNPC)
{
	bool bStuck = true;

	while ( bStuck )
	{
		trace_t tr;
		UTIL_TraceHull(pNPC->GetAbsOrigin(), pNPC->GetAbsOrigin(), pNPC->WorldAlignMins(), pNPC->WorldAlignMaxs(), MASK_NPCSOLID, pNPC, COLLISION_GROUP_NONE, &tr);

		if ( tr.fraction != 1.0 && tr.m_pEnt )
		{
			// Nos hemos atorado en un objeto con fisicas.
			if ( FClassnameIs(tr.m_pEnt, "prop_physics") )
			{
				// Lo ajustamos como "No solido" para que el bucle lo ignore.
				tr.m_pEnt->AddSolidFlags(FSOLID_NOT_SOLID);
				// Removemos el objeto.
				UTIL_RemoveImmediate(tr.m_pEnt);
				continue;
			}

			// Nos hemos atorado con una pared o algo del mundo.
			if ( tr.m_pEnt->IsWorld() )
			{
				// No... no podemos eliminar una pared...
				// Removemos el NPC para evitar eventos sobrenaturales.
				UTIL_RemoveImmediate(pNPC);
				return false;
			}

			// No es un objeto con físicas ni del mundo.
			// Intentamos encontrar una nueva ubicación para el hijo.

			//DevMsg("[MANAGER] <%s> STUCK!!!! \r\n", tr.m_pEnt->GetClassname());
			CAI_Node *pNode	= GetRandomNode();

			// Nada
			if ( !pNode )
				UTIL_RemoveImmediate(pNPC);

			pNPC->SetAbsOrigin(pNode->GetPosition(HULL_HUMAN));
		}

		bStuck = false;
	}

	return true;
}
//=========================================================
// Crea un bonche de hijos en un nodo candidato.
//=========================================================
void CDirector_Manager::AddHorde(int pMount)
{
	// Actualizamos los nodos candidatos para la creación.
	UpdateNodes();

	// ¡No hay nodos!
	if ( SpawnNodes.Count() <= 0 )
		return;

	for ( int i = 0; i < MAX_TRIES; ++i )
	{
		// Seleccionamos un nodo candidato al azar.
		CAI_Node *pNode	= GetRandomNode();

		// El nodo no existe.
		if ( !pNode )
			continue;

		// Obtenemos la ubicación del nodo.
		Vector vecOrigin = pNode->GetPosition(HULL_HUMAN);

		ConVarRef director_debug("director_debug");

		if ( director_debug.GetBool() )
			NDebugOverlay::Cross3D(vecOrigin, 50.0f, 255, 128, 0, true, 20.0f);

		// Creamos varios hijos en este nodo.
		// Con las colisiones especiales (No colisionan con los otros hijos)
		for ( int h = 0; h < pMount; ++h )
		{
			for ( int s = 0; s < MAX_TRIES; ++s )
			{
				bool pSpawn = AddChild(vecOrigin, SPAWN_NO_COLLISION_AND_POWERFUL);

				if ( pSpawn )
					break;
			}
		}

		break;
	}
}
bool CAI_ASW_PrepareToEngageBehavior::GetPrepareToAttackPath(const Vector &vecThreat )
{
    if ( !CAI_NetworkManager::NetworksLoaded() )
    {
        DevWarning( 2, "Graph not ready for GetPrepareToAttackPath!\n" );
        return false;
    }

    Vector vecToThreat = vecThreat - GetAbsOrigin();
    float flDistToThreat = vecToThreat.NormalizeInPlace();
    /*
    	int iMyNode			= GetOuter()->GetPathfinder()->NearestNodeToNPC();
    	int iThreatNode		= GetOuter()->GetPathfinder()->NearestNodeToPoint( vecThreat );

    	if ( iMyNode == NO_NODE )
    	{
    		DevWarning( 2, "FindPrepareToAttackNode() - %s has no nearest node!\n", GetEntClassname());
    		return false;
    	}
    	if ( iThreatNode == NO_NODE )
    	{
    		// DevWarning( 2, "FindBackAwayNode() - Threat has no nearest node!\n" );
    		iThreatNode = iMyNode;
    		// return false;
    	}

    	// A vector pointing to the threat.
    	Vector vecToThreat;
    	vecToThreat = vecThreat - GetLocalOrigin();

    	// Get my current distance from the threat
    	float flCurDist = VectorNormalize( vecToThreat );

    	// find all nodes within the radius of our target
    	m_flPrepareRadius;
    */
    int iNumNodes = g_pBigAINet->NumNodes();
    CUtlVector<int> candidateNodes;
    for ( int i = 0; i < iNumNodes; i++ )
    {
        CAI_Node *pNode = g_pBigAINet->GetNode( i );
        if ( !pNode || pNode->GetType() != NODE_GROUND )
            continue;

        Vector vecPos = pNode->GetPosition( GetOuter()->GetHullType() );
        Vector vecDir = vecPos - vecThreat;
        float flDist = vecDir.NormalizeInPlace();
        if ( flDist > m_flPrepareRadiusMax || flDist < m_flPrepareRadiusMin )
            continue;

        // Make sure this node doesn't take me past the enemy's position.
        Vector vecToNode = vecPos - GetAbsOrigin();
        float flDistToNode = vecToNode.NormalizeInPlace();

        if( DotProduct( vecToNode, vecToThreat ) > 0.0 && flDistToNode > flDistToThreat )
            continue;

        candidateNodes.AddToTail( i );
    }

    if ( candidateNodes.Count() <= 0 )
        return false;

    int iOffset = RandomInt( 0, candidateNodes.Count() - 1 );
    int iNumCandidateNodes = candidateNodes.Count();
    int iMaxTries = 4;
    for ( int i = 0; i < iNumCandidateNodes && iMaxTries > 0; i++ )
    {
        CAI_Node *pNode = g_pBigAINet->GetNode( candidateNodes[ i + iOffset ] );
        if ( !pNode || pNode->GetType() != NODE_GROUND )
            continue;

        // see if we can reach it
        Vector vecPos = pNode->GetPosition( GetOuter()->GetHullType() );
        AI_NavGoal_t goal( vecPos );

        if ( GetNavigator()->SetGoal( goal, AIN_CLEAR_TARGET ) )
        {
            return true;
        }
        iMaxTries--;
    }
    return false;
}
AI_Waypoint_t *CAI_Pathfinder::FindBestPath(int startID, int endID) 
{
	if ( !GetNetwork()->NumNodes() )
		return NULL;

	int nNodes = GetNetwork()->NumNodes();
	CAI_Node **pAInode = GetNetwork()->AccessNodes();

	CVarBitVec	openBS(nNodes);
	CVarBitVec	closeBS(nNodes);

	// ------------- INITIALIZE ------------------------
	float* nodeG = (float *)stackalloc( nNodes * sizeof(float) );
	float* nodeH = (float *)stackalloc( nNodes * sizeof(float) );
	float* nodeF = (float *)stackalloc( nNodes * sizeof(float) );
	int*   nodeP = (int *)stackalloc( nNodes * sizeof(int) );		// Node parent 

	for (int node=0;node<nNodes;node++)
	{
		nodeG[node] = FLT_MAX;
		nodeP[node] = -1;
	}

	nodeG[startID] = 0;

	nodeH[startID] = 0.1*(pAInode[startID]->GetPosition(GetHullType())-pAInode[endID]->GetPosition(GetHullType())).Length(); // Don't want to over estimate
	nodeF[startID] = nodeG[startID] + nodeH[startID];

	openBS.Set(startID);
	closeBS.Set( startID );

	// --------------- FIND BEST PATH ------------------
	while (!openBS.IsAllClear()) 
	{
		int smallestID = CAI_Network::FindBSSmallest(&openBS,nodeF,nNodes);
	
		openBS.Clear(smallestID);

		CAI_Node *pSmallestNode = pAInode[smallestID];
		
		if (GetOuter()->IsUnusableNode(smallestID, pSmallestNode->m_pHint))
			continue;

		if (smallestID == endID) 
		{
			AI_Waypoint_t* route = MakeRouteFromParents(&nodeP[0], endID);
			return route;
		}

		// Check this if the node is immediately in the path after the startNode 
		// that it isn't blocked
		for (int link=0; link < pSmallestNode->NumLinks();link++) 
		{
			CAI_Link *nodeLink = pSmallestNode->GetLinkByIndex(link);
			
			if (!IsLinkUsable(nodeLink,smallestID))
				continue;

			// FIXME: the cost function should take into account Node costs (danger, flanking, etc).
			int moveType = nodeLink->m_iAcceptedMoveTypes[GetHullType()] & CapabilitiesGet();
			int testID	 = nodeLink->DestNodeID(smallestID);

			Vector r1 = pSmallestNode->GetPosition(GetHullType());
			Vector r2 = pAInode[testID]->GetPosition(GetHullType());
			float dist   = GetOuter()->GetNavigator()->MovementCost( moveType, r1, r2 ); // MovementCost takes ref parameters!!

			if ( dist == FLT_MAX )
				continue;

			float new_g  = nodeG[smallestID] + dist;

			if ( !closeBS.IsBitSet(testID) || (new_g < nodeG[testID]) ) 
			{
				nodeP[testID] = smallestID;
				nodeG[testID] = new_g;
				nodeH[testID] = (pAInode[testID]->GetPosition(GetHullType())-pAInode[endID]->GetPosition(GetHullType())).Length();
				nodeF[testID] = nodeG[testID] + nodeH[testID];

				closeBS.Set( testID );
				openBS.Set( testID );
			}
		}
	}

	return NULL;   
}
int CAI_TacticalServices::FindCoverNode(const Vector &vNearPos, const Vector &vThreatPos, const Vector &vThreatEyePos, float flMinDist, float flMaxDist )
{
	if ( !CAI_NetworkManager::NetworksLoaded() )
		return NO_NODE;

	AI_PROFILE_SCOPE( CAI_TacticalServices_FindCoverNode );

	MARK_TASK_EXPENSIVE();

	DebugFindCover( NO_NODE, GetOuter()->EyePosition(), vThreatEyePos, 0, 255, 255 );

	int iMyNode = GetPathfinder()->NearestNodeToPoint( vNearPos );

	if ( iMyNode == NO_NODE )
	{
		Vector pos = GetOuter()->GetAbsOrigin();
		DevWarning( 2, "FindCover() - %s has no nearest node! (Check near %f %f %f)\n", GetEntClassname(), pos.x, pos.y, pos.z);
		return NO_NODE;
	}

	if ( !flMaxDist )
	{
		// user didn't supply a MaxDist, so work up a crazy one.
		flMaxDist = 784;
	}

	if ( flMinDist > 0.5 * flMaxDist)
	{
		flMinDist = 0.5 * flMaxDist;
	}

	// ------------------------------------------------------------------------------------
	// We're going to search for a cover node by expanding to our current node's neighbors
	// and then their neighbors, until cover is found, or all nodes are beyond MaxDist
	// ------------------------------------------------------------------------------------
	AI_NearNode_t *pBuffer = (AI_NearNode_t *)stackalloc( sizeof(AI_NearNode_t) * GetNetwork()->NumNodes() );
	CNodeList list( pBuffer, GetNetwork()->NumNodes() );
	CVarBitVec wasVisited(GetNetwork()->NumNodes());	// Nodes visited

	// mark start as visited
	list.Insert( AI_NearNode_t(iMyNode, 0) ); 
	wasVisited.Set( iMyNode );
	float flMinDistSqr = flMinDist*flMinDist;
	float flMaxDistSqr = flMaxDist*flMaxDist;

	static int nSearchRandomizer = 0;		// tries to ensure the links are searched in a different order each time;

	// Search until the list is empty
	while( list.Count() )
	{
		// Get the node that is closest in the number of steps and remove from the list
		int nodeIndex = list.ElementAtHead().nodeIndex;
		list.RemoveAtHead();

		CAI_Node *pNode = GetNetwork()->GetNode(nodeIndex);
		Vector nodeOrigin = pNode->GetPosition(GetHullType());

		float dist = (vNearPos - nodeOrigin).LengthSqr();
		if (dist >= flMinDistSqr && dist < flMaxDistSqr)
		{
			Activity nCoverActivity = GetOuter()->GetCoverActivity( pNode->GetHint() );
			Vector vEyePos = nodeOrigin + GetOuter()->EyeOffset(nCoverActivity);

			if ( GetOuter()->IsValidCover( nodeOrigin, pNode->GetHint() ) )
			{
				// Check if this location will block the threat's line of sight to me
				if (GetOuter()->IsCoverPosition(vThreatEyePos, vEyePos))
				{
					// --------------------------------------------------------
					// Don't let anyone else use this node for a while
					// --------------------------------------------------------
					pNode->Lock( 1.0 );

					if ( pNode->GetHint() && ( pNode->GetHint()->HintType() == HINT_TACTICAL_COVER_MED || pNode->GetHint()->HintType() == HINT_TACTICAL_COVER_LOW ) )
					{
						if ( GetOuter()->GetHintNode() )
						{
							GetOuter()->GetHintNode()->Unlock(GetOuter()->GetHintDelay(GetOuter()->GetHintNode()->HintType()));
							GetOuter()->SetHintNode( NULL );
						}

						GetOuter()->SetHintNode( pNode->GetHint() );
					}

					// The next NPC who searches should use a slight different pattern
					nSearchRandomizer = nodeIndex;
					DebugFindCover( pNode->GetId(), vEyePos, vThreatEyePos, 0, 255, 0 );
					return nodeIndex;
				}
				else
				{
					DebugFindCover( pNode->GetId(), vEyePos, vThreatEyePos, 255, 0, 0 );
				}
			}
			else
			{
				DebugFindCover( pNode->GetId(), vEyePos, vThreatEyePos, 0, 0, 255 );
			}
		}

		// Add its children to the search list
		// Go through each link
		// UNDONE: Pass in a cost function to measure each link?
		for ( int link = 0; link < GetNetwork()->GetNode(nodeIndex)->NumLinks(); link++ ) 
		{
			int index = (link + nSearchRandomizer) % GetNetwork()->GetNode(nodeIndex)->NumLinks();
			CAI_Link *nodeLink = GetNetwork()->GetNode(nodeIndex)->GetLinkByIndex(index);

			if ( !m_pPathfinder->IsLinkUsable( nodeLink, iMyNode ) )
				continue;

			int newID = nodeLink->DestNodeID(nodeIndex);

			// If not already on the closed list, add to it and set its distance
			if (!wasVisited.IsBitSet(newID))
			{
				// Don't accept climb nodes or nodes that aren't ready to use yet
				if ( GetNetwork()->GetNode(newID)->GetType() != NODE_CLIMB && !GetNetwork()->GetNode(newID)->IsLocked() )
				{
					// UNDONE: Shouldn't we really accumulate the distance by path rather than
					// absolute distance.  After all, we are performing essentially an A* here.
					nodeOrigin = GetNetwork()->GetNode(newID)->GetPosition(GetHullType());
					dist = (vNearPos - nodeOrigin).LengthSqr();

					// use distance to threat as a heuristic to keep AIs from running toward
					// the threat in order to take cover from it.
					float threatDist = (vThreatPos - nodeOrigin).LengthSqr();

					// Now check this node is not too close towards the threat
					if ( dist < threatDist * 1.5 )
					{
						list.Insert( AI_NearNode_t(newID, dist) );
					}
				}
				// mark visited
				wasVisited.Set(newID);
			}
		}
	}

	// We failed.  Not cover node was found
	// Clear hint node used to set ducking
	GetOuter()->ClearHintNode();
	return NO_NODE;
}
예제 #9
0
bool CASW_Spawn_Manager::FindHordePosition()
{
    // need to find a suitable place from which to spawn a horde
    // this place should:
    //   - be far enough away from the marines so the whole horde can spawn before the marines get there
    //   - should have a clear path to the marines

    UpdateCandidateNodes();

    // decide if the horde is going to come from behind or in front
    bool bNorth = RandomFloat() < 0.7f;
    if ( m_northCandidateNodes.Count() <= 0 )
    {
        bNorth = false;
    }
    else if ( m_southCandidateNodes.Count() <= 0 )
    {
        bNorth = true;
    }

    CUtlVector<int> &candidateNodes = bNorth ? m_northCandidateNodes : m_southCandidateNodes;

    if ( candidateNodes.Count() <= 0 )
    {
        if ( asw_director_debug.GetBool() )
        {
            Msg( "  Failed to find horde pos as there are no candidate nodes\n" );
        }
        return false;
    }

    int iMaxTries = 3; // количество попыток найти место для спавна волны

    for ( int i=0 ; i<iMaxTries ; i++ )
    {
        int iChosen = RandomInt( 0, candidateNodes.Count() - 1);
        CAI_Node *pNode = GetNetwork()->GetNode( candidateNodes[iChosen] );
        if ( !pNode )
            continue;

        float flDistance = 0;
        CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>(UTIL_ASW_NearestMarine( pNode->GetPosition( CANDIDATE_ALIEN_HULL ), flDistance ));
        if ( !pMarine )
        {
            if ( asw_director_debug.GetBool() )
            {
                Msg( "  Failed to find horde pos as there is no nearest marine\n" );
            }
            return false;
        }

        // check if there's a route from this node to the marine(s)
        AI_Waypoint_t *pRoute = ASWPathUtils()->BuildRoute( pNode->GetPosition( CANDIDATE_ALIEN_HULL ), pMarine->GetAbsOrigin(), NULL, 100 );
        if ( !pRoute )
        {
            if ( asw_director_debug.GetInt() >= 2 )
            {
                Msg( "  Discarding horde node %d as there's no route.\n", iChosen );
            }
            continue;
        }

        if ( bNorth && UTIL_ASW_DoorBlockingRoute( pRoute, true ) )
        {
            if ( asw_director_debug.GetInt() >= 2 )
            {
                Msg( "  Discarding horde node %d as there's a door in the way.\n", iChosen );
            }
            DeleteRoute( pRoute );
            continue;
        }

        m_vecHordePosition = pNode->GetPosition( CANDIDATE_ALIEN_HULL ) + Vector( 0, 0, 32 );

        // spawn facing the nearest marine
        Vector vecDir = pMarine->GetAbsOrigin() - m_vecHordePosition;
        vecDir.z = 0;
        vecDir.NormalizeInPlace();
        VectorAngles( vecDir, m_angHordeAngle );

        if ( asw_director_debug.GetInt() >= 2 )
        {
            Msg( "  Accepting horde node %d.\n", iChosen );
        }
        DeleteRoute( pRoute );
        return true;
    }

    if ( asw_director_debug.GetBool() )
    {
        Msg( "  Failed to find horde pos as we tried 3 times to build routes to possible locations, but failed\n" );
    }

    return false;
}
예제 #10
0
void CASW_Spawn_Manager::UpdateCandidateNodes()
{
    // don't update too frequently
    if ( m_CandidateUpdateTimer.HasStarted() && !m_CandidateUpdateTimer.IsElapsed() )
        return;

    m_CandidateUpdateTimer.Start( asw_candidate_interval.GetFloat() );

    if ( !GetNetwork() || !GetNetwork()->NumNodes() )
    {
        m_vecHordePosition = vec3_origin;
        if ( asw_director_debug.GetBool() )
            Msg("Error: Can't spawn hordes as this map has no node network\n");
        return;
    }

    CASW_Game_Resource *pGameResource = ASWGameResource();
    if ( !pGameResource )
        return;

    Vector vecSouthMarine = vec3_origin;
    Vector vecNorthMarine = vec3_origin;
    for ( int i=0; i<pGameResource->GetMaxMarineResources(); i++ )
    {
        CASW_Marine_Resource *pMR = pGameResource->GetMarineResource(i);
        if ( !pMR )
            continue;

        CASW_Marine *pMarine = pMR->GetMarineEntity();
        if ( !pMarine || pMarine->GetHealth() <= 0 )
            continue;

        if ( vecSouthMarine == vec3_origin || vecSouthMarine.y > pMarine->GetAbsOrigin().y )
        {
            vecSouthMarine = pMarine->GetAbsOrigin();
        }
        if ( vecNorthMarine == vec3_origin || vecNorthMarine.y < pMarine->GetAbsOrigin().y )
        {
            vecNorthMarine = pMarine->GetAbsOrigin();
        }
    }
    if ( vecSouthMarine == vec3_origin || vecNorthMarine == vec3_origin )		// no live marines
        return;

    int iNumNodes = GetNetwork()->NumNodes();
    m_northCandidateNodes.Purge();
    m_southCandidateNodes.Purge();
    for ( int i=0 ; i<iNumNodes; i++ )
    {
        CAI_Node *pNode = GetNetwork()->GetNode( i );
        if ( !pNode || pNode->GetType() != NODE_GROUND )
            continue;

        Vector vecPos = pNode->GetPosition( CANDIDATE_ALIEN_HULL );

        // find the nearest marine to this node
        float flDistance = 0;
        CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>(UTIL_ASW_NearestMarine( vecPos, flDistance ));
        if ( !pMarine )
            return;

        if ( flDistance > asw_horde_max_distance.GetFloat() || flDistance < asw_horde_min_distance.GetFloat() )
            continue;

        // check node isn't in an exit trigger
        bool bInsideEscapeArea = false;
        for ( int d=0; d<m_EscapeTriggers.Count(); d++ )
        {
            if ( m_EscapeTriggers[d]->CollisionProp()->IsPointInBounds( vecPos ) )
            {
                bInsideEscapeArea = true;
                break;
            }
        }
        if ( bInsideEscapeArea )
            continue;

        if ( vecPos.y >= vecSouthMarine.y )
        {
            if ( asw_director_debug.GetInt() == 3 )
            {
                NDebugOverlay::Box( vecPos, -Vector( 5, 5, 5 ), Vector( 5, 5, 5 ), 32, 32, 128, 10, 60.0f );
            }
            m_northCandidateNodes.AddToTail( i );
        }
        if ( vecPos.y <= vecNorthMarine.y )
        {
            m_southCandidateNodes.AddToTail( i );
            if ( asw_director_debug.GetInt() == 3 )
            {
                NDebugOverlay::Box( vecPos, -Vector( 5, 5, 5 ), Vector( 5, 5, 5 ), 128, 32, 32, 10, 60.0f );
            }
        }
    }
}
예제 #11
0
bool CASW_Spawn_Manager::SpawnAlientAtRandomNode()
{
    if ( spawnRandomAlienTimer.HasStarted() && !spawnRandomAlienTimer.IsElapsed() )
        return false;
    spawnRandomAlienTimer.Start( MINIMUM_SPAWN_DELAY );

    UpdateCandidateNodes();

    // decide if the alien is going to come from behind or in front
    bool bNorth = RandomFloat() < 0.7f;
    if ( m_northCandidateNodes.Count() <= 0 )
    {
        bNorth = false;
    }
    else if ( m_southCandidateNodes.Count() <= 0 )
    {
        bNorth = true;
    }

    CUtlVector<int> &candidateNodes = bNorth ? m_northCandidateNodes : m_southCandidateNodes;

    if ( candidateNodes.Count() <= 0 )
        return false;

    const char *szAlienClass = wandererQueue[wandererQueueStart];

    Vector vecMins, vecMaxs;
    GetAlienBounds( szAlienClass, vecMins, vecMaxs );

    int alienHull = getAlienHull(szAlienClass);

    int iMaxTries = 3;

    for ( int i=0 ; i<iMaxTries ; i++ )
    {
        int iChosen = RandomInt( 0, candidateNodes.Count() - 1);
        CAI_Node *pNode = GetNetwork()->GetNode( candidateNodes[iChosen] );
        if ( !pNode )
            continue;

        float flDistance = 0;
        CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>(UTIL_ASW_NearestMarine( pNode->GetPosition( alienHull ), flDistance ));
        if ( !pMarine )
            return false;

        // check if there's a route from this node to the marine(s)
        AI_Waypoint_t *pRoute = ASWPathUtils()->BuildRoute( pNode->GetPosition( alienHull ), pMarine->GetAbsOrigin(), NULL, 100 );
        if ( !pRoute )
        {
            if ( asw_director_debug.GetBool() )
            {
                NDebugOverlay::Cross3D( pNode->GetOrigin(), 10.0f, 255, 128, 0, true, 20.0f );
            }
            continue;
        }

        if ( bNorth && UTIL_ASW_DoorBlockingRoute( pRoute, true ) )
        {
            DeleteRoute( pRoute );
            continue;
        }

        Vector vecSpawnPos = pNode->GetPosition( alienHull ) + Vector( 0, 0, 32 );
        bool needsGround = Q_stricmp(szAlienClass, "asw_buzzer") != 0;
        if ( ValidSpawnPoint( vecSpawnPos, vecMins, vecMaxs, needsGround, MARINE_NEAR_DISTANCE ) ) {
            float extraClearanceFactor = 1;
            //the boomer's hull seems to be too small for some reason
            if (Q_stricmp(szAlienClass, "asw_boomer") == 0) {
                extraClearanceFactor = 2;
            }

            Vector shiftSpawnBy = shiftSpawnPosition(vecSpawnPos, vecMins, vecMaxs, extraClearanceFactor);
            if (shiftSpawnBy.z == -1 ) {
                DeleteRoute( pRoute );
                continue;
            }

            Vector shiftedSpawnPos = vecSpawnPos+shiftSpawnBy;



            Vector testShift = shiftSpawnPosition(shiftedSpawnPos, vecMins, vecMaxs, extraClearanceFactor);
            if (testShift.x != 0 || testShift.y != 0 || testShift.z != 0) {
                DeleteRoute( pRoute );
                continue;
            }

            if ( SpawnAlienAt( szAlienClass, shiftedSpawnPos, vec3_angle ) ) {
                wandererQueueStart++;
                wandererQueueStart %= WANDERER_QUEUE_SIZE;
                if ( asw_director_debug.GetBool() )	{
                    NDebugOverlay::Cross3D( vecSpawnPos, 25.0f, 255, 255, 255, true, 20.0f );
                    float flDist;
                    CASW_Marine *pMarine = UTIL_ASW_NearestMarine( vecSpawnPos, flDist );
                    if ( pMarine ) {
                        NDebugOverlay::Line( pMarine->GetAbsOrigin(), vecSpawnPos, 64, 64, 64, true, 60.0f );
                    }
                }
                DeleteRoute( pRoute );
                return true;
            }
        }
        else
        {
            if ( asw_director_debug.GetBool() )
            {
                NDebugOverlay::Cross3D( vecSpawnPos, 25.0f, 255, 0, 0, true, 20.0f );
            }
        }
        DeleteRoute( pRoute );
    }
    return false;
}
//=========================================================
// Actualiza los mejores nodos para la creación de hijos.
//=========================================================
void CDirector_Manager::UpdateNodes()
{
	// Aún no toca actualizar.
	if ( CandidateUpdateTimer.HasStarted() && !CandidateUpdateTimer.IsElapsed() )
		return;

	// Empezar el cronometro.
	CandidateUpdateTimer.Start(director_update_nodes.GetFloat());

	// ¡Este mapa no tiene nodos!
	if ( !GetNetwork() || !GetNetwork()->NumNodes() )
	{
		ClientPrint(UTIL_InPlayerByIndex(1), HUD_PRINTCENTER, "#NoNODES");
		Warning("[NODOS] Este mapa no tiene nodos de movimiento.\r\n");
		return;
	}

	int iNumNodes = GetNetwork()->NumNodes();
	SpawnNodes.Purge(); // Limpiamos la lista de nodos.

	// Revisamos cada nodo.
	for ( int i = 0; i < iNumNodes; ++i )
	{
		CAI_Node *pNode = GetNetwork()->GetNode(i);

		// El nodo ya no existe o no es de suelo.
		if ( !pNode || pNode->GetType() != NODE_GROUND )
			continue;

		// Buscar al jugador más cercano.
		float flDistance	= 0;
		Vector vecPos		= pNode->GetPosition(HULL_HUMAN);
		CIN_Player *pPlayer = UTIL_GetNearestInPlayer(vecPos, flDistance);

		// ¡Ninguno!
		if ( !pPlayer )
			return;

		ConVarRef director_debug("director_debug");
		ConVarRef director_min_distance("director_min_distance");
		ConVarRef director_max_distance("director_max_distance");
		ConVarRef director_spawn_outview("director_spawn_outview");

		CBaseEntity *pChild = gEntList.FindEntityByNameNearest(CHILD_NAME, vecPos, 20);
		CBaseEntity *pSpawn = gEntList.FindEntityByClassname(NULL, "info_player_start");

		if ( pSpawn )
		{
			float spawnDistance = vecPos.DistTo(pSpawn->GetAbsOrigin());

			// Este nodo esta muy cerca del Spawn.
			if ( spawnDistance < SPAWN_OUT_DISTANCE )
				continue;
		}

		// Hay un hijo aquí.
		if ( pChild )
			continue;

		// Este nodo esta muy lejos o muy cerca.
		if ( flDistance > director_max_distance.GetFloat() || flDistance < director_min_distance.GetFloat() )
			continue;

		// No usar nodos que esten a la vista de los jugadores.
		if ( director_spawn_outview.GetBool() )
		{
			if ( UTIL_IsPlayersVisible(vecPos) )
				continue;
		}

		// Marcamos al nodo afortunado.
		if ( director_debug.GetBool() )
			NDebugOverlay::Box(vecPos, -Vector(5, 5, 5), Vector(5, 5, 5), 32, 32, 128, 10, 6.0f);

		// Lo agregamos a la lista.
		SpawnNodes.AddToTail(i);
	}
}
예제 #13
0
bool CASW_Spawn_Manager::SpawnAlientAtRandomNode()
{
	UpdateCandidateNodes();

	// decide if the alien is going to come from behind or in front
	bool bNorth = RandomFloat() < 0.7f;
	if ( m_northCandidateNodes.Count() <= 0 )
	{
		bNorth = false;
	}
	else if ( m_southCandidateNodes.Count() <= 0 )
	{
		bNorth = true;
	}

	CUtlVector<int> &candidateNodes = bNorth ? m_northCandidateNodes : m_southCandidateNodes;

	if ( candidateNodes.Count() <= 0 )
		return false;

	const char *szAlienClass = "asw_drone";
	Vector vecMins, vecMaxs;
	GetAlienBounds( szAlienClass, vecMins, vecMaxs );

	int iMaxTries = 1;
	for ( int i=0 ; i<iMaxTries ; i++ )
	{
		int iChosen = RandomInt( 0, candidateNodes.Count() - 1);
		CAI_Node *pNode = GetNetwork()->GetNode( candidateNodes[iChosen] );
		if ( !pNode )
			continue;

		float flDistance = 0;
		CASW_Marine *pMarine = dynamic_cast<CASW_Marine*>(UTIL_ASW_NearestMarine( pNode->GetPosition( CANDIDATE_ALIEN_HULL ), flDistance ));
		if ( !pMarine )
			return false;

		// check if there's a route from this node to the marine(s)
		AI_Waypoint_t *pRoute = ASWPathUtils()->BuildRoute( pNode->GetPosition( CANDIDATE_ALIEN_HULL ), pMarine->GetAbsOrigin(), NULL, 100 );
		if ( !pRoute )
		{
			if ( asw_director_debug.GetBool() )
			{
				NDebugOverlay::Cross3D( pNode->GetOrigin(), 10.0f, 255, 128, 0, true, 20.0f );
			}
			continue;
		}

		if ( bNorth && UTIL_ASW_DoorBlockingRoute( pRoute, true ) )
		{
			DeleteRoute( pRoute );
			continue;
		}

		// riflemod: preventing wanderers from spawning behind closed airlocks
		if (UTIL_ASW_BrushBlockingRoute(pRoute, MASK_PLAYERSOLID_BRUSHONLY, COLLISION_GROUP_PLAYER_MOVEMENT))
		{
			DeleteRoute(pRoute);
			continue;
		}
		
		Vector vecSpawnPos = pNode->GetPosition( CANDIDATE_ALIEN_HULL ) + Vector( 0, 0, 32 );
		if ( ValidSpawnPoint( vecSpawnPos, vecMins, vecMaxs, true, MARINE_NEAR_DISTANCE ) )
		{
			if ( SpawnAlienAt( szAlienClass, vecSpawnPos, vec3_angle ) )
			{
				if ( asw_director_debug.GetBool() )
				{
					NDebugOverlay::Cross3D( vecSpawnPos, 25.0f, 255, 255, 255, true, 20.0f );
					float flDist;
					CASW_Marine *pMarine = UTIL_ASW_NearestMarine( vecSpawnPos, flDist );
					if ( pMarine )
					{
						NDebugOverlay::Line( pMarine->GetAbsOrigin(), vecSpawnPos, 64, 64, 64, true, 60.0f );
					}
				}
				DeleteRoute( pRoute );
				return true;
			}
		}
		else
		{
			if ( asw_director_debug.GetBool() )
			{
				NDebugOverlay::Cross3D( vecSpawnPos, 25.0f, 255, 0, 0, true, 20.0f );
			}
		}
		DeleteRoute( pRoute );
	}
	return false;
}