//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- CAI_Hint *CAI_FearBehavior::FindFearWithdrawalDest() { CAI_Hint *pHint; CHintCriteria hintCriteria; CAI_BaseNPC *pOuter = GetOuter(); Assert(pOuter != NULL); hintCriteria.AddHintType( HINT_PLAYER_ALLY_FEAR_DEST ); hintCriteria.SetFlag( bits_HINT_NODE_VISIBLE_TO_PLAYER | bits_HINT_NOT_CLOSE_TO_ENEMY /*| bits_HINT_NODE_IN_VIEWCONE | bits_HINT_NPC_IN_NODE_FOV*/ ); hintCriteria.AddIncludePosition( AI_GetSinglePlayer()->GetAbsOrigin(), ( ai_fear_player_dist.GetFloat() ) ); pHint = CAI_HintManager::FindHint( pOuter, hintCriteria ); if( pHint ) { // Reserve this node while I try to get to it. When I get there I will lock it. // Otherwise, if I fail to get there, the node will come available again soon. pHint->DisableForSeconds( 4.0f ); } #if 0 else { Msg("DID NOT FIND HINT\n"); NDebugOverlay::Cross3D( GetOuter()->WorldSpaceCenter(), 32, 255, 255, 0, false, 10.0f ); } #endif return pHint; }
//----------------------------------------------------------------------------- // Purpose: Searches for a hint node that this NPC cares about. If one is // claims that hint node for this NPC so that no other NPCs // try to use it. // // Input : nFlags - Search criterea. Can currently be one or more of the following: // bits_HINT_NODE_VISIBLE - searches for visible hint nodes. // bits_HINT_NODE_RANDOM - calls through the FindHintRandom and builds list of all matching // nodes and picks randomly from among them. Note: Depending on number of hint nodes, this // could be slower, so use with care. // // Output : Returns pointer to hint node if available hint node was found that matches the // given criterea that this NPC also cares about. Otherwise, returns NULL //----------------------------------------------------------------------------- CAI_Hint* CAI_HintManager::FindHint( CAI_BaseNPC *pNPC, Hint_e nHintType, int nFlags, float flMaxDist, const Vector *pMaxDistFrom ) { assert( pNPC != NULL ); if ( pNPC == NULL ) return NULL; CHintCriteria hintCriteria; hintCriteria.SetHintType( nHintType ); hintCriteria.SetFlag( nFlags ); // Using the NPC's hint group? if ( nFlags & bits_HINT_NODE_USE_GROUP ) { hintCriteria.SetGroup( pNPC->GetHintGroup() ); } // Add the search position Vector vecPosition = ( pMaxDistFrom != NULL ) ? (*pMaxDistFrom) : pNPC->GetAbsOrigin(); hintCriteria.AddIncludePosition( vecPosition, flMaxDist ); // If asking for a random node, use random logic instead if ( nFlags & bits_HINT_NODE_RANDOM ) return FindHintRandom( pNPC, vecPosition, hintCriteria ); return FindHint( pNPC, vecPosition, hintCriteria ); }
bool CBounceBomb::IsValidLocation() { CBaseEntity *pAvoidObject = NULL; float flAvoidForce = 0.0f; CAI_Hint *pHint; CHintCriteria criteria; criteria.SetHintType( HINT_WORLD_INHIBIT_COMBINE_MINES ); criteria.SetFlag( bits_HINT_NODE_NEAREST ); criteria.AddIncludePosition( GetAbsOrigin(), 12.0f * 15.0f ); pHint = CAI_HintManager::FindHint( GetAbsOrigin(), criteria ); if( pHint ) { pAvoidObject = pHint; flAvoidForce = 120.0f; } else { // Look for other mines that are too close to me. CBaseEntity *pEntity = gEntList.FirstEnt(); Vector vecMyPosition = GetAbsOrigin(); while( pEntity ) { if( pEntity->m_iClassname == m_iClassname && pEntity != this ) { // Don't lock down if I'm near a mine that's already locked down. if( vecMyPosition.DistToSqr(pEntity->GetAbsOrigin()) < MINE_MIN_PROXIMITY_SQR ) { pAvoidObject = pEntity; flAvoidForce = 60.0f; break; } } pEntity = gEntList.NextEnt( pEntity ); } } if( pAvoidObject ) { // Build a force vector to push us away from the inhibitor. // Start by pushing upwards. Vector vecForce = Vector( 0, 0, VPhysicsGetObject()->GetMass() * 200.0f ); // Now add some force in the direction that takes us away from the inhibitor. Vector vecDir = GetAbsOrigin() - pAvoidObject->GetAbsOrigin(); vecDir.z = 0.0f; VectorNormalize( vecDir ); vecForce += vecDir * VPhysicsGetObject()->GetMass() * flAvoidForce; Flip( vecForce, AngularImpulse( 100, 0, 0 ) ); // Tell the code that asked that this position isn't valid. return false; } return true; }
//----------------------------------------------------------------------------- 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: //--------------------------------------------------------- void CNPC_Assassin::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_ASSASSIN_SET_EYE_STATE: { SetEyeState( (eyeState_t) ( (int) pTask->flTaskData ) ); TaskComplete(); } break; case TASK_ASSASSIN_EVADE: { Activity flipAct = ACT_INVALID; const Vector *avoidPos = ( GetEnemy() != NULL ) ? &(GetEnemy()->GetAbsOrigin()) : NULL; for ( int i = FLIP_LEFT; i < NUM_FLIP_TYPES; i++ ) { if ( CanFlip( i, flipAct, avoidPos ) ) { // Don't flip back to where we just were if ( ( ( i == FLIP_LEFT ) && ( m_nLastFlipType == FLIP_RIGHT ) ) || ( ( i == FLIP_RIGHT ) && ( m_nLastFlipType == FLIP_LEFT ) ) || ( ( i == FLIP_FORWARD ) && ( m_nLastFlipType == FLIP_BACKWARD ) ) || ( ( i == FLIP_BACKWARD ) && ( m_nLastFlipType == FLIP_FORWARD ) ) ) { flipAct = ACT_INVALID; continue; } m_nNumFlips--; ResetIdealActivity( flipAct ); m_flNextFlipTime = gpGlobals->curtime + 2.0f; m_nLastFlipType = i; break; } } if ( flipAct == ACT_INVALID ) { m_nNumFlips = 0; m_nLastFlipType = -1; m_flNextFlipTime = gpGlobals->curtime + 2.0f; TaskFail( "Unable to find flip evasion direction!\n" ); } } break; case TASK_ASSASSIN_GET_PATH_TO_VANTAGE_POINT: { assert( GetEnemy() != NULL ); if ( GetEnemy() == NULL ) break; Vector goalPos; CHintCriteria hint; // Find a disadvantage node near the player, but away from ourselves hint.SetHintType( HINT_TACTICAL_ENEMY_DISADVANTAGED ); hint.AddExcludePosition( GetAbsOrigin(), 256 ); hint.AddExcludePosition( GetEnemy()->GetAbsOrigin(), 256 ); if ( ( m_pSquad != NULL ) && ( m_pSquad->NumMembers() > 1 ) ) { AISquadIter_t iter; for ( CAI_BaseNPC *pSquadMember = m_pSquad->GetFirstMember( &iter ); pSquadMember; pSquadMember = m_pSquad->GetNextMember( &iter ) ) { if ( pSquadMember == NULL ) continue; hint.AddExcludePosition( pSquadMember->GetAbsOrigin(), 128 ); } } hint.SetFlag( bits_HINT_NODE_NEAREST ); CAI_Hint *pHint = CAI_HintManager::FindHint( this, GetEnemy()->GetAbsOrigin(), &hint ); if ( pHint == NULL ) { TaskFail( "Unable to find vantage point!\n" ); break; } pHint->GetPosition( this, &goalPos ); AI_NavGoal_t goal( goalPos ); //Try to run directly there if ( GetNavigator()->SetGoal( goal ) == false ) { TaskFail( "Unable to find path to vantage point!\n" ); break; } TaskComplete(); } break; default: BaseClass::StartTask( pTask ); break; } }
//----------------------------------------------------------------------------- // 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; }