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; } } } }
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; }
// spawn a group of aliens at the target point int CASW_Spawn_Manager::SpawnAlienBatch( const char* szAlienClass, int iNumAliens, const Vector &vecPosition, const QAngle &angFacing, float flMarinesBeyondDist ) { int iSpawned = 0; bool bCheckGround = true; Vector vecMins = NAI_Hull::Mins(HULL_MEDIUMBIG); Vector vecMaxs = NAI_Hull::Maxs(HULL_MEDIUMBIG); GetAlienBounds( szAlienClass, vecMins, vecMaxs ); float flAlienWidth = vecMaxs.x - vecMins.x; float flAlienDepth = vecMaxs.y - vecMins.y; // spawn one in the middle if ( ValidSpawnPoint( vecPosition, vecMins, vecMaxs, bCheckGround, flMarinesBeyondDist ) ) { if ( SpawnAlienAt( szAlienClass, vecPosition, angFacing ) ) iSpawned++; } // try to spawn a 5x5 grid of aliens, starting at the centre and expanding outwards Vector vecNewPos = vecPosition; for ( int i=1; i<=5 && iSpawned < iNumAliens; i++ ) { QAngle angle = angFacing; angle[YAW] += RandomFloat( -20, 20 ); // spawn aliens along top of box for ( int x=-i; x<=i && iSpawned < iNumAliens; x++ ) { vecNewPos = vecPosition; vecNewPos.x += x * flAlienWidth; vecNewPos.y -= i * flAlienDepth; if ( !LineBlockedByGeometry( vecPosition, vecNewPos) && ValidSpawnPoint( vecNewPos, vecMins, vecMaxs, bCheckGround, flMarinesBeyondDist ) ) { if ( SpawnAlienAt( szAlienClass, vecNewPos, angle ) ) iSpawned++; } } // spawn aliens along bottom of box for ( int x=-i; x<=i && iSpawned < iNumAliens; x++ ) { vecNewPos = vecPosition; vecNewPos.x += x * flAlienWidth; vecNewPos.y += i * flAlienDepth; if ( !LineBlockedByGeometry( vecPosition, vecNewPos) && ValidSpawnPoint( vecNewPos, vecMins, vecMaxs, bCheckGround, flMarinesBeyondDist ) ) { if ( SpawnAlienAt( szAlienClass, vecNewPos, angle ) ) iSpawned++; } } // spawn aliens along left of box for ( int y=-i + 1; y<i && iSpawned < iNumAliens; y++ ) { vecNewPos = vecPosition; vecNewPos.x -= i * flAlienWidth; vecNewPos.y += y * flAlienDepth; if ( !LineBlockedByGeometry( vecPosition, vecNewPos) && ValidSpawnPoint( vecNewPos, vecMins, vecMaxs, bCheckGround, flMarinesBeyondDist ) ) { if ( SpawnAlienAt( szAlienClass, vecNewPos, angle ) ) iSpawned++; } } // spawn aliens along right of box for ( int y=-i + 1; y<i && iSpawned < iNumAliens; y++ ) { vecNewPos = vecPosition; vecNewPos.x += i * flAlienWidth; vecNewPos.y += y * flAlienDepth; if ( !LineBlockedByGeometry( vecPosition, vecNewPos) && ValidSpawnPoint( vecNewPos, vecMins, vecMaxs, bCheckGround, flMarinesBeyondDist ) ) { if ( SpawnAlienAt( szAlienClass, vecNewPos, angle ) ) iSpawned++; } } } return iSpawned; }
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; }
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; }
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; }