//----------------------------------------------------------------------------- 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: Return true if pTestHint passes the criteria specified in hintCriteria //----------------------------------------------------------------------------- bool CAI_Hint::HintMatchesCriteria( CAI_BaseNPC *pNPC, const CHintCriteria &hintCriteria, const Vector &position, float *flNearestDistance, bool bIgnoreLock, bool bIgnoreHintType ) { // Cannot be locked if ( !bIgnoreLock && IsLocked() ) { REPORTFAILURE( "Node is locked." ); return false; } if ( !bIgnoreHintType && !hintCriteria.MatchesHintType( HintType() ) ) { return false; } if ( GetMinState() > NPC_STATE_IDLE || GetMaxState() < NPC_STATE_COMBAT ) { if ( pNPC && ( pNPC->GetState() < GetMinState() || pNPC->GetState() > GetMaxState() ) ) { REPORTFAILURE( "NPC not in correct state." ); return false; } } // See if we're filtering by group name if ( hintCriteria.GetGroup() != NULL_STRING ) { AssertIsValidString( GetGroup() ); AssertIsValidString( hintCriteria.GetGroup() ); if ( GetGroup() == NULL_STRING || GetGroup() != hintCriteria.GetGroup() ) { Assert(GetGroup() == NULL_STRING || strcmp( STRING(GetGroup()), STRING(hintCriteria.GetGroup())) != 0 ); REPORTFAILURE( "Doesn't match NPC hint group." ); return false; } } // If we're watching for include zones, test it if ( ( hintCriteria.HasIncludeZones() ) && ( hintCriteria.InIncludedZone( GetAbsOrigin() ) == false ) ) { REPORTFAILURE( "Not inside include zones." ); return false; } // If we're watching for exclude zones, test it if ( ( hintCriteria.HasExcludeZones() ) && ( hintCriteria.InExcludedZone( GetAbsOrigin() ) ) ) { REPORTFAILURE( "Inside exclude zones." ); return false; } // See if the class handles this hint type if ( ( pNPC != NULL ) && ( pNPC->FValidateHintType( this ) == false ) ) { REPORTFAILURE( "NPC doesn't know how to handle that type." ); return false; } if ( hintCriteria.HasFlag(bits_HINT_NPC_IN_NODE_FOV) ) { if ( pNPC == NULL ) { AssertMsg(0,"Hint node attempted to verify NPC in node FOV without NPC!\n"); } else { if( !IsInNodeFOV(pNPC) ) { REPORTFAILURE( "NPC Not in hint's FOV" ); return false; } } } if ( hintCriteria.HasFlag( bits_HINT_NODE_IN_AIMCONE ) ) { if ( pNPC == NULL ) { AssertMsg( 0, "Hint node attempted to find node in aimcone without specifying NPC!\n" ); } else { if( !pNPC->FInAimCone( GetAbsOrigin() ) ) { REPORTFAILURE( "Hint isn't in NPC's aimcone" ); return false; } } } if ( hintCriteria.HasFlag( bits_HINT_NODE_IN_VIEWCONE ) ) { if ( pNPC == NULL ) { AssertMsg( 0, "Hint node attempted to find node in viewcone without specifying NPC!\n" ); } else { if( !pNPC->FInViewCone( this ) ) { REPORTFAILURE( "Hint isn't in NPC's viewcone" ); return false; } } } { AI_PROFILE_SCOPE( HINT_FVisible ); // See if we're requesting a visible node if ( hintCriteria.HasFlag( bits_HINT_NODE_VISIBLE ) ) { if ( pNPC == NULL ) { //NOTENOTE: If you're hitting this, you've asked for a visible node without specifing an NPC! AssertMsg( 0, "Hint node attempted to find visible node without specifying NPC!\n" ); } else { if( m_NodeData.nNodeID == NO_NODE ) { // This is just an info_hint, not a node. if( !pNPC->FVisible( this ) ) { REPORTFAILURE( "Hint isn't visible to NPC." ); return false; } } else { // This hint associated with a node. trace_t tr; Vector vHintPos; GetPosition(pNPC,&vHintPos); AI_TraceLine ( pNPC->EyePosition(), vHintPos + pNPC->GetViewOffset(), MASK_NPCSOLID_BRUSHONLY, pNPC, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction != 1.0f ) { REPORTFAILURE( "Node isn't visible to NPC." ); return false; } } } } } // Check for clear if requested if ( hintCriteria.HasFlag( bits_HINT_NODE_CLEAR ) ) { if ( pNPC == NULL ) { //NOTENOTE: If you're hitting this, you've asked for a clear node without specifing an NPC! AssertMsg( 0, "Hint node attempted to find clear node without specifying NPC!\n" ); } else { trace_t tr; // Can my bounding box fit there? AI_TraceHull ( GetAbsOrigin(), GetAbsOrigin(), pNPC->WorldAlignMins(), pNPC->WorldAlignMaxs(), MASK_SOLID, pNPC, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction != 1.0 ) { REPORTFAILURE( "Node isn't clear." ); return false; } } } // See if this is our next, closest node if ( hintCriteria.HasFlag( bits_HINT_NODE_NEAREST ) ) { Assert( flNearestDistance ); // Calculate our distance float distance = (GetAbsOrigin() - position).Length(); // Must be closer than the current best if ( distance > *flNearestDistance ) { REPORTFAILURE( "Not the nearest node." ); return false; } // Remember the distance *flNearestDistance = distance; } // Must either be visible or not if requested if ( hintCriteria.HasFlag( bits_HINT_NODE_NOT_VISIBLE_TO_PLAYER|bits_HINT_NODE_VISIBLE_TO_PLAYER ) ) { bool bWasSeen = false; // Test all potential seers for ( int i = 1; i <= gpGlobals->maxClients; i++ ) { CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); if ( pPlayer ) { // Only spawn if the player's looking away from me Vector vLookDir = pPlayer->EyeDirection3D(); Vector vTargetDir = GetAbsOrigin() - pPlayer->EyePosition(); VectorNormalize(vTargetDir); float fDotPr = DotProduct(vLookDir,vTargetDir); if ( fDotPr > 0 ) { trace_t tr; UTIL_TraceLine( pPlayer->EyePosition(), GetAbsOrigin(), MASK_SOLID_BRUSHONLY, pPlayer, COLLISION_GROUP_NONE, &tr); if ( tr.fraction == 1.0 ) { if ( hintCriteria.HasFlag( bits_HINT_NODE_NOT_VISIBLE_TO_PLAYER ) ) { REPORTFAILURE( "Node is visible to player." ); return false; } bWasSeen = true; } } } } if ( !bWasSeen && hintCriteria.HasFlag( bits_HINT_NODE_VISIBLE_TO_PLAYER ) ) { REPORTFAILURE( "Node isn't visible to player." ); return false; } } return true; }