//=========================================================
// 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;
}
//=========================================================
// 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;
	}
}
Пример #3
0
void CASW_Alien_Jumper::LockJumpNode( void )
{
	if ( HasSpawnFlags( SF_ANTLION_USE_GROUNDCHECKS ) == false )
		 return;
	
	if ( GetNavigator()->GetPath() == NULL )
		 return;

	if ( asw_test_new_alien_jump.GetBool() == false )
		 return;

	AI_Waypoint_t *pWaypoint = GetNavigator()->GetPath()->GetCurWaypoint();

	while ( pWaypoint )
	{
		AI_Waypoint_t *pNextWaypoint = pWaypoint->GetNext();
		if ( pNextWaypoint && pNextWaypoint->NavType() == NAV_JUMP && pWaypoint->iNodeID != NO_NODE )
		{
			CAI_Node *pNode = GetNavigator()->GetNetwork()->GetNode( pWaypoint->iNodeID );

			if ( pNode )
			{
				//NDebugOverlay::Box( pNode->GetOrigin(), Vector( -16, -16, -16 ), Vector( 16, 16, 16 ), 255, 0, 0, 0, 2 );
				pNode->Lock( 0.5f );
				break;
			}
		}
		else
		{
			pWaypoint = pWaypoint->GetNext();
		}
	}
}
Пример #4
0
//-----------------------------------------------------------------------------
// Purpose: For destroying nodes in wc edit mode
// Input  :
// Output :
//-----------------------------------------------------------------------------
void NWCEdit::DestroyAINode( CBasePlayer *pPlayer )
{
	// -------------------------------------------------------------
	//  Check that WC is running with the right map version
	// -------------------------------------------------------------
	if (!IsWCVersionValid())
	{
		return;
	}

	if (!pPlayer)
	{
		return;
	}

	NodeType_e nNodeType = NODE_GROUND;
	if (g_pAINetworkManager->GetEditOps()->m_bAirEditMode)
	{
		nNodeType = NODE_AIR;
	}

	CAI_Node* pAINode = FindPickerAINode(pPlayer, nNodeType);
	if (pAINode)
	{
		int status = Editor_DeleteNode(g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[pAINode->GetId()], false);

		if (status == Editor_BadCommand)
		{
			Msg( "Worldcraft failed on deletion...\n" );
		}
		else if (status == Editor_OK)
		{
			// Mark this node as deleted and changed
			pAINode->SetType( NODE_DELETED );
			pAINode->m_eNodeInfo   |= bits_NODE_WC_CHANGED;

			// Note that network needs to be rebuild
			g_pAINetworkManager->GetEditOps()->SetRebuildFlags();
			g_pAINetworkManager->GetEditOps()->m_pLastDeletedNode	= pAINode;

			// Now go through at delete any dynamic links that were attached to this node
			for (int link = 0; link < pAINode->NumLinks(); link++)
			{
				int nSrcID = pAINode->GetLinkByIndex(link)->m_iSrcID;
				int nDstID = pAINode->GetLinkByIndex(link)->m_iDestID;
				if (CAI_DynamicLink::GetDynamicLink(nSrcID, nDstID))
				{
					int nWCSrcID = g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[nSrcID];
					int nWCDstID = g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[nDstID];
					int	status	 = Editor_DeleteNodeLink(nWCSrcID, nWCDstID);

					if (status == Editor_BadCommand)
					{
						Msg( "Worldcraft failed on node link deletion...\n" );
					}
				}				
			}
		}
	}
}
//-----------------------------------------------------------------------------
// Computes the link type
//-----------------------------------------------------------------------------
Navigation_t CAI_Pathfinder::ComputeWaypointType( CAI_Node **ppNodes, int parentID, int destID )
{
	Navigation_t navType = NAV_NONE;

	CAI_Node *pNode = ppNodes[parentID];
	for (int link=0; link < pNode->NumLinks();link++) 
	{
		if (pNode->GetLinkByIndex(link)->DestNodeID(parentID) == destID)
		{
			// BRJ 10/1/02
			// FIXME: pNPC->CapabilitiesGet() is actually the mechanism by which fliers
			// filter out the bitfields in the waypoint type (most importantly, bits_MOVE_CAP_GROUND)
			// that would cause the waypoint distance to be computed in a 2D, as opposed to 3D fashion
			// This is a super-scary weak link if you ask me.
			int linkMoveTypeBits = pNode->GetLinkByIndex(link)->m_iAcceptedMoveTypes[GetHullType()];
			int moveTypeBits = ( linkMoveTypeBits & CapabilitiesGet());
			if ( !moveTypeBits && linkMoveTypeBits == bits_CAP_MOVE_JUMP )
			{
				Assert( pNode->GetHint() && pNode->GetHint()->HintType() == HINT_JUMP_OVERRIDE );
				ppNodes[destID]->Lock(0.3);
				moveTypeBits = linkMoveTypeBits;
			}
			Navigation_t linkType = MoveBitsToNavType( moveTypeBits );

			// This will only trigger if the links disagree about their nav type
			Assert( (navType == NAV_NONE) || (navType == linkType) );
			navType = linkType; 
			break;
		}
	}

	// @TODO (toml 10-15-02): one would not expect to come out of the above logic
	// with NAV_NONE. However, if a graph is newly built, it can contain malformed
	// links that are referred to by the destination node, not the source node.
	// This has to be fixed
	if ( navType == NAV_NONE )
	{
		pNode = ppNodes[destID];
		for (int link=0; link < pNode->NumLinks();link++) 
		{
			if (pNode->GetLinkByIndex(link)->DestNodeID(parentID) == destID)
			{
				int npcMoveBits = CapabilitiesGet();
				int nodeMoveBits = pNode->GetLinkByIndex(link)->m_iAcceptedMoveTypes[GetHullType()];
				int moveTypeBits = ( npcMoveBits & nodeMoveBits );
				Navigation_t linkType = MoveBitsToNavType( moveTypeBits );

				Assert( (navType == NAV_NONE) || (navType == linkType) );
				navType = linkType; 

				DevMsg( "Note: Strange link found between nodes in AI node graph\n" );
				break;
			}
		}
	}

	AssertMsg( navType != NAV_NONE, "Pathfinder appears to have output a path with consecutive nodes thate are not actually connected\n" );

	return navType;
}
Пример #6
0
void CAI_DynamicLinkController::GenerateLinksFromVolume()
{
	Assert( m_ControlledLinks.Count() == 0 );

	int nNodes = g_pBigAINet->NumNodes();
	CAI_Node **ppNodes = g_pBigAINet->AccessNodes();

	const float MinDistCareSq = Square(MAX_NODE_LINK_DIST + 0.1);

	const Vector &origin = WorldSpaceCenter();
	Vector vAbsMins, vAbsMaxs;
	CollisionProp()->WorldSpaceAABB( &vAbsMins, &vAbsMaxs );
	vAbsMins -= Vector( 1, 1, 1 );
	vAbsMaxs += Vector( 1, 1, 1 );

	for ( int i = 0; i < nNodes; i++ )
	{
		CAI_Node *pNode = ppNodes[i];
		const Vector &nodeOrigin = pNode->GetOrigin();
		if ( origin.DistToSqr(nodeOrigin) < MinDistCareSq )
		{
			int nLinks = pNode->NumLinks();
			for ( int j = 0; j < nLinks; j++ )
			{
				CAI_Link *pLink = pNode->GetLinkByIndex( j );
				int iLinkDest = pLink->DestNodeID( i );
				if ( iLinkDest > i )
				{
					const Vector &originOther = ppNodes[iLinkDest]->GetOrigin();
					if ( origin.DistToSqr(originOther) < MinDistCareSq )
					{
						if ( IsBoxIntersectingRay( vAbsMins, vAbsMaxs, nodeOrigin, originOther - nodeOrigin ) )
						{
							Assert( IsBoxIntersectingRay( vAbsMins, vAbsMaxs, originOther, nodeOrigin - originOther ) );

							CAI_DynamicLink *pLink = (CAI_DynamicLink *)CreateEntityByName( "info_node_link" );
							pLink->m_nSrcID = i;
							pLink->m_nDestID = iLinkDest;
							pLink->m_nSrcEditID = g_pAINetworkManager->GetEditOps()->GetWCIdFromNodeId( pLink->m_nSrcID );
							pLink->m_nDestEditID = g_pAINetworkManager->GetEditOps()->GetWCIdFromNodeId( pLink->m_nDestID );
							pLink->m_nLinkState = m_nLinkState;
							pLink->m_strAllowUse = m_strAllowUse;
							pLink->m_bFixedUpIds = true;
							pLink->m_bNotSaved = true;

							pLink->Spawn();
							m_ControlledLinks.AddToTail( pLink );
						}
					}
				}
			}
		}
	}
}
Пример #7
0
void CAI_RadialLinkController::ModifyNodeLinks( bool bMakeStale )
{
	int nNodes = g_pBigAINet->NumNodes();
	CAI_Node **ppNodes = g_pBigAINet->AccessNodes();

	VPROF_BUDGET("ModifyLinks", "ModifyLinks");

	const float MinDistCareSq = Square( ai_radial_max_link_dist.GetFloat() + 0.1 );

	for ( int i = 0; i < nNodes; i++ )
	{
		CAI_Node *pNode = ppNodes[i];
		const Vector &nodeOrigin = pNode->GetOrigin();
		if ( m_vecAtRestOrigin.DistToSqr(nodeOrigin) < MinDistCareSq )
		{
			int nLinks = pNode->NumLinks();
			for ( int j = 0; j < nLinks; j++ )
			{
				CAI_Link *pLink = pNode->GetLinkByIndex( j );
				int iLinkDest = pLink->DestNodeID( i );

				if ( iLinkDest > i )
				{
					bool bQualify = true;

					if( ( (pLink->m_iAcceptedMoveTypes[HULL_HUMAN]||pLink->m_iAcceptedMoveTypes[HULL_WIDE_HUMAN]) & bits_CAP_MOVE_GROUND) == 0 )
					{
						// Micro-optimization: Ignore any connection that's not a walking connection for humans.(sjb)
						bQualify = false;
					}

					const Vector &originOther = ppNodes[iLinkDest]->GetOrigin();
					if ( bQualify && m_vecAtRestOrigin.DistToSqr(originOther) < MinDistCareSq )
					{
						if ( IsRayIntersectingSphere(nodeOrigin, originOther - nodeOrigin, m_vecAtRestOrigin, m_flRadius) )
						{
							if( bMakeStale )
							{
								pLink->m_LinkInfo |= bits_LINK_STALE_SUGGESTED;
								pLink->m_timeStaleExpires = FLT_MAX;
							}
							else
							{
								pLink->m_LinkInfo &= ~bits_LINK_STALE_SUGGESTED;
							}
						}
					}
				}
			}
		}
	}
}
void CAI_StandoffBehavior::UnlockHintNode()
{
	CAI_Hint *pHintNode = GetOuter()->m_pHintNode;
	if ( pHintNode )
	{
		if ( pHintNode->IsLocked() && pHintNode->IsLockedBy( GetOuter() ) )
			pHintNode->Unlock();
		CAI_Node *pNode = pHintNode->GetNode();
		if ( pNode && pNode->IsLocked() )
			pNode->Unlock();
		GetOuter()->m_pHintNode = NULL;
	}
}
//=========================================================
// 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;
}
Пример #10
0
bool CASW_Alien_Jumper::IsUnusableNode(int iNodeID, CAI_Hint *pHint)
{
	bool iBaseReturn = BaseClass::IsUnusableNode( iNodeID, pHint );

	if ( asw_test_new_alien_jump.GetBool() == 0 )
		 return iBaseReturn;

	CAI_Node *pNode = GetNavigator()->GetNetwork()->GetNode( iNodeID );

	if ( pNode )
	{
		if ( pNode->IsLocked() )
			 return true;
	}

	return iBaseReturn;
}
//=========================================================
// 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;
	}
}
Пример #12
0
void CAI_Hint::OnRestore()
{
	BaseClass::OnRestore();

	m_NodeData.nNodeID = g_pAINetworkManager->GetEditOps()->GetNodeIdFromWCId( m_NodeData.nWCNodeID );
	FixupTargetNode();

	CAI_Node *pNode = GetNode();
	
	if ( !pNode )
	{
		if ( m_NodeData.nWCNodeID > 0 )
			DevMsg("Warning: AI hint has incorrect or no AI node\n");
	}
	else
	{
		m_NodeData.vecPosition = pNode->GetOrigin();
		Teleport( &m_NodeData.vecPosition, NULL, NULL );
		pNode->SetHint( this );
	}
}
Пример #13
0
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
CAI_Link *CAI_DynamicLink::FindLink()
{
	CAI_Node *	pSrcNode = g_pBigAINet->GetNode(m_nSrcID, false);
	if ( pSrcNode )
	{
		int	numLinks = pSrcNode->NumLinks();
		for (int i=0;i<numLinks;i++)
		{
			CAI_Link* pLink = pSrcNode->GetLinkByIndex(i);

			if (((pLink->m_iSrcID  == m_nSrcID )&&
				(pLink->m_iDestID == m_nDestID))   ||

				((pLink->m_iSrcID  == m_nDestID)&&
				(pLink->m_iDestID == m_nSrcID ))   )
			{
				return pLink;
			}
		}
	}
	return NULL;
}
Пример #14
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;
			}
		}
	}
}
Пример #15
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;
}
//=========================================================
// 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);
	}
}
Пример #17
0
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;
}
Пример #18
0
bool CASW_Weapon_Blink::SetBlinkDestination()
{
	CASW_Player *pPlayer = GetCommander();
	if ( !pPlayer )
		return false;

	CASW_Marine *pMarine = GetMarine();
	if ( !pMarine )
		return false;

	Vector vecStart = pPlayer->GetCrosshairTracePos() + Vector( 0, 0, 30 );
	Vector vecEnd = pPlayer->GetCrosshairTracePos() - Vector( 0, 0, 30 );
	trace_t tr;
	UTIL_TraceHull( vecStart, vecEnd, pMarine->WorldAlignMins(), pMarine->WorldAlignMaxs(), MASK_PLAYERSOLID_BRUSHONLY, pMarine, COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
	if ( tr.startsolid || tr.allsolid )
	{
		m_vecInvalidDestination = vecStart;
		return false;
	}

	if ( pMarine->GetAbsOrigin().DistTo( tr.endpos ) > asw_blink_range.GetFloat() )
	{
		m_vecInvalidDestination = tr.endpos;
		return false;
	}

	Vector vecDest = tr.endpos;

	// now see if we can build an AI path from the marine to this spot
	bool bValidRoute = false;

	if ( !pMarine->GetPathfinder() )
	{
		m_vecInvalidDestination = vecDest;
		return false;
	}

	AI_Waypoint_t *pRoute = pMarine->GetPathfinder()->BuildRoute( pMarine->GetAbsOrigin(), vecDest, NULL, 30, NAV_GROUND, bits_BUILD_GROUND | bits_BUILD_IGNORE_NPCS );
	if ( pRoute && !UTIL_ASW_DoorBlockingRoute( pRoute, true ) )
	{
		if ( !UTIL_ASW_BrushBlockingRoute( pRoute, MASK_PLAYERSOLID_BRUSHONLY, COLLISION_GROUP_PLAYER_MOVEMENT ) )
		{
			// if end node of the route is too Z different, then abort, to stop people jumping on top of walls
			AI_Waypoint_t *pLast = pRoute->GetLast();
			if ( pLast )
			{
				AI_Waypoint_t *pNode = pLast->GetPrev();
				if ( !pNode || fabs( pNode->GetPos().z - pLast->GetPos().z ) < 80.0f )
				{
					bValidRoute = true;
				}
			}
		}
	}
	
	if ( !bValidRoute )
	{
		// find the closest node to the dest and try to path there instead
		CAI_Network *pNetwork = pMarine->GetNavigator() ? pMarine->GetNavigator()->GetNetwork() : NULL;
		if ( pNetwork )
		{
			int nNode = pNetwork->NearestNodeToPoint( vecDest, false );
			if ( nNode != NO_NODE )
			{
				CAI_Node *pNode = pNetwork->GetNode( nNode );
				if ( pNode && pNode->GetType() == NODE_GROUND )
				{
					vecDest = pNode->GetOrigin();
					if ( pRoute )
					{
						ASWPathUtils()->DeleteRoute( pRoute );
						pRoute = NULL;
					}
					pRoute = pMarine->GetPathfinder()->BuildRoute( pMarine->GetAbsOrigin(), vecDest, NULL, 30, NAV_GROUND, bits_BUILD_GROUND | bits_BUILD_IGNORE_NPCS );
					if ( pRoute && !UTIL_ASW_DoorBlockingRoute( pRoute, true ) )
					{
						if ( !UTIL_ASW_BrushBlockingRoute( pRoute, MASK_PLAYERSOLID_BRUSHONLY, COLLISION_GROUP_PLAYER_MOVEMENT ) )
						{
							bValidRoute = true;
						}
					}
					if ( !bValidRoute )
					{
						m_vecInvalidDestination = vecDest;
					}
				}
			}
		}
	}

	if ( !bValidRoute )
	{
		if ( pRoute )
		{
			ASWPathUtils()->DeleteRoute( pRoute );
			pRoute = NULL;
		}
		return false;
	}

	if ( asw_blink_debug.GetBool() )
	{
		ASWPathUtils()->DebugDrawRoute( pMarine->GetAbsOrigin(), pRoute );
	}

	m_vecAbilityDestination = vecDest;

	if ( pRoute )
	{
		ASWPathUtils()->DeleteRoute( pRoute );
		pRoute = NULL;
	}

	return true;
}
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;   
}
Пример #21
0
//=========================================================
//=========================================================
void CNodeEnt::Spawn( void )
{
	// ---------------------------------------------------------------------------------
	//  If just a hint node (not used for navigation) just create a hint and bail
	// ---------------------------------------------------------------------------------
	if (FClassnameIs( this, "info_hint" ))
	{
		if (m_eHintType)
		{
			CAI_Hint::CreateHint(GetEntityName(),GetAbsOrigin(),(Hint_e)m_eHintType,NO_NODE,m_strGroup);
		}
		else
		{
			Msg("WARNING: Hint node with no hint type!\n");
		}
		UTIL_RemoveImmediate( this );
		return;
	}
	
	// ---------------------------------------------------------------------------------
	//  First check if this node has a hint.  If so create a hint entity
	// ---------------------------------------------------------------------------------
	CAI_Hint *pHint = NULL;
	if (m_eHintType || m_strGroup != NULL_STRING)
	{
		pHint = CAI_Hint::CreateHint(GetEntityName(),GetAbsOrigin(),(Hint_e)m_eHintType,m_nNodeCount,m_strGroup);
	}


	// ---------------------------------------------------------------------------------
	//  If we loaded from disk, we can discard all these node ents as soon as they spawn
	//  unless we are in WC edited mode
	// ---------------------------------------------------------------------------------
	if ( g_pAINetworkManager->NetworksLoaded() && !engine->IsInEditMode())
	{
		// If hint exists for this node, set it
		if (pHint)
		{
			CAI_Node *pNode = g_pBigAINet->GetNode(m_nNodeCount);
			if (pNode)
				pNode->SetHint( pHint );
			else
			{
				Msg("AI node graph corrupt\n");
			}
		}
		m_nNodeCount++;
		UTIL_RemoveImmediate( this );
		return;
	}	
	else
	{
		m_nNodeCount++;
	}

	// ---------------------------------------------------------------------------------
	//	Add a new node to the network
	// ---------------------------------------------------------------------------------
	// For now just using one big AI network
	CAI_Node *new_node = g_pBigAINet->AddNode( GetAbsOrigin(), GetAbsAngles().y );
	new_node->SetHint( pHint );

	// -------------------------------------------------------------------------
	//  Update table of how each WC id relates to each engine ID	
	// -------------------------------------------------------------------------
	if (g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable)
	{
		g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[new_node->GetId()]	= m_nWCNodeID;
	}
	// Keep track of largest index used by WC
	if (g_pAINetworkManager->GetEditOps()->m_nNextWCIndex <= m_nWCNodeID)
	{
		g_pAINetworkManager->GetEditOps()->m_nNextWCIndex = m_nWCNodeID+1;
	}

	// -------------------------------------------------------------------------
	// If in WC edit mode:
	// 	Remember the original positions of the nodes before
	//	they drop so we can send the undropped positions to wc.
	// -------------------------------------------------------------------------
	if (engine->IsInEditMode())
	{
		if (g_pAINetworkManager->GetEditOps()->m_pWCPosition)
		{
			g_pAINetworkManager->GetEditOps()->m_pWCPosition[new_node->GetId()]		= new_node->GetOrigin();
		}
	}
	
	if (FClassnameIs( this, "info_node_air" ) || FClassnameIs( this, "info_node_air_hint" ))
	{
		new_node->SetType( NODE_AIR );
	}
	else if (FClassnameIs( this, "info_node_climb" ))
	{
		new_node->SetType( NODE_CLIMB );
	}
	else
	{
		new_node->SetType( NODE_GROUND );
	}

	// If changed as part of WC editing process note that network must be rebuilt
	if (m_debugOverlays & OVERLAY_WC_CHANGE_ENTITY)
	{
		g_pAINetworkManager->GetEditOps()->SetRebuildFlags();
		new_node->m_eNodeInfo			|= bits_NODE_WC_CHANGED;

		// Initialize the new nodes position.  The graph may not be rebuild
		// right away but the node should at least be positioned correctly
		g_AINetworkBuilder.InitNodePosition( g_pBigAINet, new_node );
	}

	UTIL_RemoveImmediate( this );
}
Пример #22
0
// heuristic to find reasonably open space - searches for areas with high node connectivity
CASW_Open_Area* CASW_Spawn_Manager::FindNearbyOpenArea( const Vector &vecSearchOrigin, int nSearchHull )
{
    CBaseEntity *pStartEntity = gEntList.FindEntityByClassname( NULL, "info_player_start" );
    int iNumNodes = g_pBigAINet->NumNodes();
    CAI_Node *pHighestConnectivity = NULL;
    int nHighestLinks = 0;
    for ( int i=0 ; i<iNumNodes; i++ )
    {
        CAI_Node *pNode = g_pBigAINet->GetNode( i );
        if ( !pNode || pNode->GetType() != NODE_GROUND )
            continue;

        Vector vecPos = pNode->GetOrigin();
        float flDist = vecPos.DistTo( vecSearchOrigin );
        if ( flDist > 400.0f )
            continue;

        // discard if node is too near start location
        if ( pStartEntity && vecPos.DistTo( pStartEntity->GetAbsOrigin() ) < 1400.0f )  // NOTE: assumes all start points are clustered near one another
            continue;

        // discard if node is inside an escape area
        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;

        // count links that drones could follow
        int nLinks = pNode->NumLinks();
        int nValidLinks = 0;
        for ( int k = 0; k < nLinks; k++ )
        {
            CAI_Link *pLink = pNode->GetLinkByIndex( k );
            if ( !pLink )
                continue;

            if ( !( pLink->m_iAcceptedMoveTypes[nSearchHull] & bits_CAP_MOVE_GROUND ) )
                continue;

            nValidLinks++;
        }
        if ( nValidLinks > nHighestLinks )
        {
            nHighestLinks = nValidLinks;
            pHighestConnectivity = pNode;
        }
        if ( asw_director_debug.GetBool() )
        {
            NDebugOverlay::Text( vecPos, UTIL_VarArgs( "%d", nValidLinks ), false, 10.0f );
        }
    }

    if ( !pHighestConnectivity )
        return NULL;

    // now, starting at the new node, find all nearby nodes with a minimum connectivity
    CASW_Open_Area *pArea = new CASW_Open_Area();
    pArea->m_vecOrigin = pHighestConnectivity->GetOrigin();
    pArea->m_pNode = pHighestConnectivity;
    int nMinLinks = nHighestLinks * 0.3f;
    nMinLinks = MAX( nMinLinks, 4 );

    pArea->m_aAreaNodes.AddToTail( pHighestConnectivity );
    if ( asw_director_debug.GetBool() )
    {
        Msg( "minLinks = %d\n", nMinLinks );
    }
    pArea->m_nTotalLinks = 0;
    for ( int i=0 ; i<iNumNodes; i++ )
    {
        CAI_Node *pNode = g_pBigAINet->GetNode( i );
        if ( !pNode || pNode->GetType() != NODE_GROUND )
            continue;

        Vector vecPos = pNode->GetOrigin();
        float flDist = vecPos.DistTo( pArea->m_vecOrigin );
        if ( flDist > 400.0f )
            continue;

        // discard if node is inside an escape area
        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;

        // count links that drones could follow
        int nLinks = pNode->NumLinks();
        int nValidLinks = 0;
        for ( int k = 0; k < nLinks; k++ )
        {
            CAI_Link *pLink = pNode->GetLinkByIndex( k );
            if ( !pLink )
                continue;

            if ( !( pLink->m_iAcceptedMoveTypes[nSearchHull] & bits_CAP_MOVE_GROUND ) )
                continue;

            nValidLinks++;
        }
        if ( nValidLinks >= nMinLinks )
        {
            pArea->m_aAreaNodes.AddToTail( pNode );
            pArea->m_nTotalLinks += nValidLinks;
        }
    }
    // highlight and measure bounds
    Vector vecAreaMins = Vector( FLT_MAX, FLT_MAX, FLT_MAX );
    Vector vecAreaMaxs = Vector( -FLT_MAX, -FLT_MAX, -FLT_MAX );

    for ( int i = 0; i < pArea->m_aAreaNodes.Count(); i++ )
    {
        vecAreaMins = VectorMin( vecAreaMins, pArea->m_aAreaNodes[i]->GetOrigin() );
        vecAreaMaxs = VectorMax( vecAreaMaxs, pArea->m_aAreaNodes[i]->GetOrigin() );

        if ( asw_director_debug.GetBool() )
        {
            if ( i == 0 )
            {
                NDebugOverlay::Cross3D( pArea->m_aAreaNodes[i]->GetOrigin(), 20.0f, 255, 255, 64, true, 10.0f );
            }
            else
            {
                NDebugOverlay::Cross3D( pArea->m_aAreaNodes[i]->GetOrigin(), 10.0f, 255, 128, 0, true, 10.0f );
            }
        }
    }

    Vector vecArea = ( vecAreaMaxs - vecAreaMins );
    float flArea = vecArea.x * vecArea.y;

    if ( asw_director_debug.GetBool() )
    {
        Msg( "area mins = %f %f %f\n", VectorExpand( vecAreaMins ) );
        Msg( "area maxs = %f %f %f\n", VectorExpand( vecAreaMaxs ) );
        NDebugOverlay::Box( vec3_origin, vecAreaMins, vecAreaMaxs, 255, 128, 128, 10, 10.0f );
        Msg( "Total links = %d Area = %f\n", pArea->m_nTotalLinks, flArea );
    }

    return pArea;
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pMapData - 
//-----------------------------------------------------------------------------
int CNodeEnt::Spawn( const char *pMapData )
{
	m_NodeData.strEntityName = GetEntityName();
	m_NodeData.vecPosition = GetAbsOrigin();
	m_NodeData.nNodeID = NO_NODE;
	if ( m_NodeData.minState == NPC_STATE_NONE )
		m_NodeData.minState = NPC_STATE_IDLE;
	if ( m_NodeData.maxState == NPC_STATE_NONE )
		m_NodeData.maxState = NPC_STATE_COMBAT;
	// ---------------------------------------------------------------------------------
	//  If just a hint node (not used for navigation) just create a hint and bail
	// ---------------------------------------------------------------------------------
	if (FClassnameIs( this, "info_hint" ))
	{
		if (m_NodeData.nHintType)
		{
			CAI_HintManager::CreateHint( &m_NodeData, pMapData );
		}
		else
		{
			Warning("info_hint (HammerID: %d, position (%.2f, %.2f, %.2f)) with no hint type.\n", m_NodeData.nWCNodeID, m_NodeData.vecPosition.x, m_NodeData.vecPosition.y, m_NodeData.vecPosition.z );
		}
		UTIL_RemoveImmediate( this );
		return -1;
	}
	
	// ---------------------------------------------------------------------------------
	//  First check if this node has a hint.  If so create a hint entity
	// ---------------------------------------------------------------------------------
	CAI_Hint *pHint = NULL;

	if ( ClassMatches( "info_node_hint" ) || ClassMatches( "info_node_air_hint" ) )
	{
		if ( m_NodeData.nHintType || m_NodeData.strGroup != NULL_STRING || m_NodeData.strEntityName != NULL_STRING )
		{
			m_NodeData.nNodeID = m_nNodeCount;
			pHint = CAI_HintManager::CreateHint( &m_NodeData, pMapData );
			pHint->AddSpawnFlags( GetSpawnFlags() );
		}
	}


	// ---------------------------------------------------------------------------------
	//  If we loaded from disk, we can discard all these node ents as soon as they spawn
	//  unless we are in WC edited mode
	// ---------------------------------------------------------------------------------
	if ( g_pAINetworkManager->NetworksLoaded() && !engine->IsInEditMode())
	{
		// If hint exists for this node, set it
		if (pHint)
		{
			CAI_Node *pNode = g_pBigAINet->GetNode(m_nNodeCount);
			if (pNode)
				pNode->SetHint( pHint );
			else
			{
				DevMsg("AI node graph corrupt\n");
			}
		}
		m_nNodeCount++;
		UTIL_RemoveImmediate( this );
		return -1;
	}	
	else
	{
		m_nNodeCount++;
	}

	// ---------------------------------------------------------------------------------
	//	Add a new node to the network
	// ---------------------------------------------------------------------------------
	// For now just using one big AI network
	CAI_Node *new_node = g_pBigAINet->AddNode( GetAbsOrigin(), GetAbsAngles().y );
	new_node->SetHint( pHint );

	// -------------------------------------------------------------------------
	//  Update table of how each WC id relates to each engine ID	
	// -------------------------------------------------------------------------
	if (g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable)
	{
		g_pAINetworkManager->GetEditOps()->m_pNodeIndexTable[new_node->GetId()]	= m_NodeData.nWCNodeID;
	}
	// Keep track of largest index used by WC
	if (g_pAINetworkManager->GetEditOps()->m_nNextWCIndex <= m_NodeData.nWCNodeID)
	{
		g_pAINetworkManager->GetEditOps()->m_nNextWCIndex = m_NodeData.nWCNodeID+1;
	}

	// -------------------------------------------------------------------------
	// If in WC edit mode:
	// 	Remember the original positions of the nodes before
	//	they drop so we can send the undropped positions to wc.
	// -------------------------------------------------------------------------
	if (engine->IsInEditMode())
	{
		if (g_pAINetworkManager->GetEditOps()->m_pWCPosition)
		{
			g_pAINetworkManager->GetEditOps()->m_pWCPosition[new_node->GetId()]		= new_node->GetOrigin();
		}
	}
	
	if (FClassnameIs( this, "info_node_air" ) || FClassnameIs( this, "info_node_air_hint" ))
	{
		new_node->SetType( NODE_AIR );
	}
	else if (FClassnameIs( this, "info_node_climb" ))
	{
		new_node->SetType( NODE_CLIMB );
	}
	else
	{
		new_node->SetType( NODE_GROUND );
	}

	new_node->m_eNodeInfo = ( m_spawnflags << NODE_ENT_FLAGS_SHIFT );

	// If changed as part of WC editing process note that network must be rebuilt
	if (m_debugOverlays & OVERLAY_WC_CHANGE_ENTITY)
	{
		g_pAINetworkManager->GetEditOps()->SetRebuildFlags();
		new_node->m_eNodeInfo			|= bits_NODE_WC_CHANGED;

		// Initialize the new nodes position.  The graph may not be rebuild
		// right away but the node should at least be positioned correctly
		g_AINetworkBuilder.InitNodePosition( g_pBigAINet, new_node );
	}

	UTIL_RemoveImmediate( this );

	return -1;
}
Пример #24
0
//------------------------------------------------------------------------------
// Purpose : Returns false if the dynamic link doesn't have a corresponding
//			 node link
// Input   :
// Output  :
//------------------------------------------------------------------------------
bool CAI_DynamicLink::IsLinkValid( void )
{
	CAI_Node *pNode = g_pBigAINet->GetNode(m_nSrcID);

	return ( pNode->GetLink( m_nDestID ) != NULL );
}
Пример #25
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;
}
int CAI_TacticalServices::FindLosNode(const Vector &vThreatPos, const Vector &vThreatEyePos, float flMinThreatDist, float flMaxThreatDist, float flBlockTime, FlankType_t eFlankType, const Vector &vecFlankRefPos, float flFlankParam )
{
	if ( !CAI_NetworkManager::NetworksLoaded() )
		return NO_NODE;

	AI_PROFILE_SCOPE( CAI_TacticalServices_FindLosNode );

	MARK_TASK_EXPENSIVE();

	int iMyNode	= GetPathfinder()->NearestNodeToNPC();
	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;
	}

	// ------------------------------------------------------------------------------------
	// We're going to search for a shoot node by expanding to our current node's neighbors
	// and then their neighbors, until a shooting position 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
	wasVisited.Set( iMyNode );
	list.Insert( AI_NearNode_t(iMyNode, 0) );

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

	while ( list.Count() )
	{
		int nodeIndex = list.ElementAtHead().nodeIndex;
		// remove this item from the list
		list.RemoveAtHead();

		const Vector &nodeOrigin = GetNetwork()->GetNode(nodeIndex)->GetPosition(GetHullType());

		// HACKHACK: Can't we rework this loop and get rid of this?
		// skip the starting node, or we probably wouldn't have called this function.
		if ( nodeIndex != iMyNode )
		{
			bool skip = false;

			// See if the node satisfies the flanking criteria.
			switch ( eFlankType )
			{
				case FLANKTYPE_NONE:
					break;
					
				case FLANKTYPE_RADIUS:
				{
					Vector vecDist = nodeOrigin - vecFlankRefPos;
					if ( vecDist.Length() < flFlankParam )
					{
						skip = true;
					}
					
					break;
				}
				
				case FLANKTYPE_ARC:
				{
					Vector vecEnemyToRef = vecFlankRefPos - vThreatPos;
					VectorNormalize( vecEnemyToRef );

					Vector vecEnemyToNode = nodeOrigin - vThreatPos;
					VectorNormalize( vecEnemyToNode );
					
					float flDot = DotProduct( vecEnemyToRef, vecEnemyToNode );
					
					if ( RAD2DEG( acos( flDot ) ) < flFlankParam )
					{
						skip = true;
					}
					
					break;
				}
			}

			// Don't accept climb nodes, and assume my nearest node isn't valid because
			// we decided to make this check in the first place.  Keep moving
			if ( !skip && !GetNetwork()->GetNode(nodeIndex)->IsLocked() &&
				GetNetwork()->GetNode(nodeIndex)->GetType() != NODE_CLIMB )
			{
				// Now check its distance and only accept if in range
				float flThreatDist = ( nodeOrigin - vThreatPos ).Length();

				if ( flThreatDist < flMaxThreatDist &&
					 flThreatDist > flMinThreatDist )
				{
					CAI_Node *pNode = GetNetwork()->GetNode(nodeIndex);
					if ( GetOuter()->IsValidShootPosition( nodeOrigin, pNode, pNode->GetHint() ) )
					{
						if (GetOuter()->TestShootPosition(nodeOrigin,vThreatEyePos))
						{
							// Note when this node was used, so we don't try 
							// to use it again right away.
							GetNetwork()->GetNode(nodeIndex)->Lock( flBlockTime );

#if 0
							if ( GetOuter()->GetHintNode() )
							{
								GetOuter()->GetHintNode()->Unlock(GetOuter()->GetHintDelay(GetOuter()->GetHintNode()->HintType()));
								GetOuter()->SetHintNode( NULL );
							}

							// This used to not be set, why? (kenb)
							// @Note (toml 05-19-04): I think because stomping  the hint can lead to
							// unintended side effects. The hint node is primarily a high level
							// tool, and certain NPCs break if it gets slammed here. If we need
							// this, we should propagate it out and let the schedule selector
							// or task decide to set the hint node
							GetOuter()->SetHintNode( GetNetwork()->GetNode(nodeIndex)->GetHint() );
#endif
							if ( ShouldDebugLos( nodeIndex ) )
							{
								NDebugOverlay::Text( nodeOrigin, CFmtStr( "%d:los!", nodeIndex), false, 1 );
							}

							// The next NPC who searches should use a slight different pattern
							nSearchRandomizer = nodeIndex;
							return nodeIndex;
						}
						else
						{
							if ( ShouldDebugLos( nodeIndex ) )
							{
								NDebugOverlay::Text( nodeOrigin, CFmtStr( "%d:!shoot", nodeIndex), false, 1 );
							}
						}
					}
					else
					{
						if ( ShouldDebugLos( nodeIndex ) )
						{
							NDebugOverlay::Text( nodeOrigin, CFmtStr( "%d:!valid", nodeIndex), false, 1 );
						}
					}
				}
				else
				{
					if ( ShouldDebugLos( nodeIndex ) )
					{
						CFmtStr msg( "%d:%s", nodeIndex, ( flThreatDist < flMaxThreatDist ) ? "too close" : "too far" );
						NDebugOverlay::Text( nodeOrigin, msg, false, 1 );
					}
				}
			}
		}

		// Go through each link and add connected nodes to the list
		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 visited, add to the list
			if (!wasVisited.IsBitSet(newID))
			{
				float dist = (GetLocalOrigin() - GetNetwork()->GetNode(newID)->GetPosition(GetHullType())).LengthSqr();
				list.Insert( AI_NearNode_t(newID, dist) );
				wasVisited.Set( newID );
			}
		}
	}
	// We failed.  No range attack node node was found
	return NO_NODE;
}
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;
}
Пример #28
0
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;
}
Пример #29
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;
}
Пример #30
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 );
            }
        }
    }
}