//----------------------------------------------------------------------------- int CAI_HintManager::FindAllHints( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria, CUtlVector<CAI_Hint *> *pResult ) { // If we have no hints, bail int c = CAI_HintManager::gm_AllHints.Count(); if ( !c ) return NULL; // Remove the nearest flag. It makes now sense with random. bool hadNearest = hintCriteria.HasFlag( bits_HINT_NODE_NEAREST ); (const_cast<CHintCriteria &>(hintCriteria)).ClearFlag( bits_HINT_NODE_NEAREST ); // Now loop till we find a valid hint or return to the start CAI_Hint *pTestHint; for ( int i = 0; i < c; ++i ) { pTestHint = CAI_HintManager::gm_AllHints[ i ]; Assert( pTestHint ); if ( pTestHint->HintMatchesCriteria( pNPC, hintCriteria, position, NULL ) ) pResult->AddToTail( pTestHint ); } if ( hadNearest ) (const_cast<CHintCriteria &>(hintCriteria)).SetFlag( bits_HINT_NODE_NEAREST ); return pResult->Count(); }
//----------------------------------------------------------------------------- // Purpose: // Input : *hintCriteria - // Output : CAI_Hint //----------------------------------------------------------------------------- CAI_Hint *CAI_HintManager::FindHint( CAI_BaseNPC *pNPC, const Vector &position, const CHintCriteria &hintCriteria ) { #if defined( HINT_PROFILING ) CFastTimer timer; timer.Start(); #endif bool singleType = hintCriteria.MatchesSingleHintType(); bool lookingForNearest = hintCriteria.HasFlag( bits_HINT_NODE_NEAREST ); bool bIgnoreHintType = true; CUtlVector< CAIHintVector * > lists; if ( singleType ) { int slot = CAI_HintManager::gm_TypedHints.Find( hintCriteria.GetFirstHintType() ); if ( slot != CAI_HintManager::gm_TypedHints.InvalidIndex() ) { lists.AddToTail( &CAI_HintManager::gm_TypedHints[ slot ] ); } } else { int typeCount = hintCriteria.NumHintTypes(); if ( typeCount > 0 ) { for ( int listType = 0; listType < typeCount; ++listType ) { int slot = CAI_HintManager::gm_TypedHints.Find( hintCriteria.GetHintType( listType ) ); if ( slot != CAI_HintManager::gm_TypedHints.InvalidIndex() ) { lists.AddToTail( &CAI_HintManager::gm_TypedHints[ slot ] ); } } } else { // Still need to check hint type in this case lists.AddToTail( &CAI_HintManager::gm_AllHints ); bIgnoreHintType = false; } } CAI_Hint *pBestHint = NULL; int visited = 0; int listCount = lists.Count(); if ( listCount == 0 ) return NULL; // Try the fast match path int i, count; // Start with hint after the last one used CAI_Hint *pTestHint = NULL; float flBestDistance = MAX_TRACE_LENGTH; if ( !lookingForNearest ) { // Fast check of previous results count = CAI_HintManager::GetFoundHintCount(); for ( i = 0; i < count; ++i ) { pTestHint = CAI_HintManager::GetFoundHint( i ); if ( pTestHint ) { Assert( dynamic_cast<CAI_Hint *>(pTestHint) != NULL ); ++visited; if ( pTestHint->HintMatchesCriteria( pNPC, hintCriteria, position, &flBestDistance ) ) { #if defined( HINT_PROFILING ) Msg( "fast result visited %d\n", visited ); #endif return pTestHint; } } } } // Longer search, reset best distance flBestDistance = MAX_TRACE_LENGTH; for ( int listNum = 0; listNum < listCount; ++listNum ) { CAIHintVector *list = lists[ listNum ]; count = list->Count(); // ------------------------------------------- // If we have no hints, bail // ------------------------------------------- if ( !count ) continue; // Now loop till we find a valid hint or return to the start for ( i = 0 ; i < count; ++i ) { pTestHint = list->Element( i ); Assert( pTestHint ); ++visited; Assert( dynamic_cast<CAI_Hint *>(pTestHint) != NULL ); if ( pTestHint->HintMatchesCriteria( pNPC, hintCriteria, position, &flBestDistance, false, bIgnoreHintType ) ) { // If we were searching for the nearest, just note that this is now the nearest node if ( lookingForNearest ) { pBestHint = pTestHint; } else { // If we're not looking for the nearest, we're done CAI_HintManager::AddFoundHint( pTestHint ); #if defined( HINT_PROFILING ) Msg( "visited %d\n", visited ); #endif return pTestHint; } } } } // Return the nearest node that we found if ( pBestHint ) { CAI_HintManager::AddFoundHint( pBestHint ); } #if defined( HINT_PROFILING ) timer.End(); Msg( "visited %d\n", visited ); if ( !pBestHint ) { Msg( "%i search failed for [%d] at pos %.3f %.3f %.3f [%.4f msec ~ %.4f msec per node]\n", gpGlobals->tickcount, pNPC ? pNPC->entindex() : -1, position.x, position.y, position.z, timer.GetDuration().GetMillisecondsF(), timer.GetDuration().GetMillisecondsF()/max( (float)visited, 1.0f ) ); } #endif return pBestHint; }