//--------------------------------------------------------- // Purpose: Applies the desired relationships to an entity //--------------------------------------------------------- void CAI_Relationship::ApplyRelationship( CBaseEntity *pActivator, CBaseEntity *pCaller ) { // @TODO (toml 10-22-04): sort out MP relationships // The player spawns slightly after the NPCs, meaning that if we don't wait, the // player will miss any relationships placed on them. #ifdef SecobMod__Enable_Fixed_Multiplayer_AI if ( UTIL_GetLocalPlayer() ) { SetThink( &CAI_Relationship::ApplyRelationshipThink ); SetNextThink( gpGlobals->curtime ); } #else if ( AI_IsSinglePlayer() && !UTIL_GetLocalPlayer() ) { SetThink( &CAI_Relationship::ApplyRelationshipThink ); SetNextThink( gpGlobals->curtime ); } #endif //SecobMod__Enable_Fixed_Multiplayer_AI if ( !m_bIsActive ) { SetActive( true ); } ChangeRelationships( m_iDisposition, NOT_REVERTING, pActivator, pCaller ); }
void CNPCSimpleTalker::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_TALKER_WAIT_FOR_SEMAPHORE: if ( GetExpresser()->SemaphoreIsAvailable( this ) ) TaskComplete(); break; case TASK_TALKER_CLIENT_STARE: case TASK_TALKER_LOOK_AT_CLIENT: if ( pTask->iTask == TASK_TALKER_CLIENT_STARE && AI_IsSinglePlayer() ) { // Get edict for one player CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); Assert( pPlayer ); // fail out if the player looks away or moves away. if ( ( pPlayer->GetAbsOrigin() - GetAbsOrigin() ).Length2D() > TALKER_STARE_DIST ) { // player moved away. TaskFail("Player moved away"); } Vector forward; AngleVectors( pPlayer->GetLocalAngles(), &forward ); if ( UTIL_DotPoints( pPlayer->GetAbsOrigin(), GetAbsOrigin(), forward ) < m_flFieldOfView ) { // player looked away TaskFail("Player looked away"); } } if ( IsWaitFinished() ) { TaskComplete(); } break; case TASK_TALKER_EYECONTACT: if (IsMoving() || !GetExpresser()->IsSpeaking() || GetSpeechTarget() == NULL) { TaskComplete(); } break; case TASK_WAIT_FOR_MOVEMENT: FIdleSpeakWhileMoving(); BaseClass::RunTask( pTask ); break; default: BaseClass::RunTask( pTask ); } }
//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CAI_AllyManager::CountAllies( int *pTotal, int *pMedics ) { (*pTotal) = (*pMedics) = 0; if ( !AI_IsSinglePlayer() ) { // @TODO (toml 10-22-04): no MP support right now return; } const Vector & vPlayerPos = UTIL_GetLocalPlayer()->GetAbsOrigin(); CAI_BaseNPC ** ppAIs = g_AI_Manager.AccessAIs(); int nAIs = g_AI_Manager.NumAIs(); for ( int i = 0; i < nAIs; i++ ) { if ( ppAIs[i]->IsAlive() && ppAIs[i]->IsPlayerAlly() ) { // Vital allies do not count. if( ppAIs[i]->Classify() == CLASS_PLAYER_ALLY_VITAL ) continue; // They only count if I can use them. if( ppAIs[i]->HasSpawnFlags(SF_CITIZEN_NOT_COMMANDABLE) ) continue; // They only count if I can use them. if( ppAIs[i]->IRelationType( UTIL_GetLocalPlayer() ) != D_LI ) continue; // Skip distant NPCs if ( !ppAIs[i]->IsInPlayerSquad() && !UTIL_FindClientInPVS( ppAIs[i]->edict() ) && ( ( ppAIs[i]->GetAbsOrigin() - vPlayerPos ).LengthSqr() > 150*12 || fabsf( ppAIs[i]->GetAbsOrigin().z - vPlayerPos.z ) > 192 ) ) continue; if( FClassnameIs( ppAIs[i], "npc_citizen" ) ) { CNPC_Citizen *pCitizen = assert_cast<CNPC_Citizen *>(ppAIs[i]); if ( !pCitizen->CanJoinPlayerSquad() ) continue; if ( pCitizen->WasInPlayerSquad() && !pCitizen->IsInPlayerSquad() ) continue; if ( ppAIs[i]->HasSpawnFlags( SF_CITIZEN_MEDIC ) ) (*pMedics)++; } (*pTotal)++; } } }
bool CGib::SUB_AllowedToFade( void ) { if( VPhysicsGetObject() ) { if( VPhysicsGetObject()->GetGameFlags() & FVPHYSICS_PLAYER_HELD || GetEFlags() & EFL_IS_BEING_LIFTED_BY_BARNACLE ) return false; } CBasePlayer *pPlayer = ( AI_IsSinglePlayer() ) ? UTIL_GetLocalPlayer() : NULL; if ( pPlayer && pPlayer->FInViewCone( this ) && m_bForceRemove == false ) { return false; } return true; }
void CAI_LeadBehavior::LeadPlayer( const AI_LeadArgs_t &leadArgs, CAI_LeadBehaviorHandler *pSink ) { CAI_PlayerAlly *pOuter = dynamic_cast<CAI_PlayerAlly*>(GetOuter()); if ( pOuter && AI_IsSinglePlayer() ) { pOuter->SetSpeechTarget( UTIL_GetLocalPlayer() ); } if( SetGoal( leadArgs ) ) { SetCondition( COND_PROVOKED ); Connect( pSink ); NotifyChangeBehaviorStatus(); } else { DevMsg( "*** Warning! LeadPlayer() has a NULL Goal Ent\n" ); } }
int CNPCSimpleTalker::SelectNonCombatSpeechSchedule() { if ( !IsOkToSpeak() ) return SCHED_NONE; // talk about world if ( ShouldSpeakRandom( m_nSpeak * 2, GetSpeechFilter() ? GetSpeechFilter()->GetIdleModifier() : 1.0 ) ) { //Msg("standing idle speak\n" ); return SCHED_TALKER_IDLE_SPEAK; } // failed to speak, so look at the player if he's around if ( AI_IsSinglePlayer() && GetExpresser()->CanSpeak() && HasCondition ( COND_SEE_PLAYER ) && random->RandomInt( 0, 6 ) == 0 ) { CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); Assert( pPlayer ); if ( pPlayer ) { // watch the client. Vector forward; AngleVectors( pPlayer->GetLocalAngles(), &forward ); if ( ( pPlayer->GetAbsOrigin() - GetAbsOrigin() ).Length2D() < TALKER_STARE_DIST && UTIL_DotPoints( pPlayer->GetAbsOrigin(), GetAbsOrigin(), forward ) >= m_flFieldOfView ) { // go into the special STARE schedule if the player is close, and looking at me too. return SCHED_TALKER_IDLE_WATCH_CLIENT_STARE; } return SCHED_TALKER_IDLE_WATCH_CLIENT; } } else { // look at who we're talking to if ( GetSpeechTarget() && GetExpresser()->IsSpeaking() ) return SCHED_TALKER_IDLE_EYE_CONTACT; } return SCHED_NONE; }
//------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ void CNPC_EnemyFinder::StartNPC ( void ) { AddSpawnFlags(SF_NPC_FALL_TO_GROUND); // this prevents CAI_BaseNPC from slamming the finder to // the ground just because it's not MOVETYPE_FLY BaseClass::StartNPC(); if ( AI_IsSinglePlayer() && m_PlayerFreePass.GetParams().duration > 0.1 ) { m_PlayerFreePass.SetPassTarget( UTIL_PlayerByIndex(1) ); AI_FreePassParams_t freePassParams = m_PlayerFreePass.GetParams(); freePassParams.coverDist = 120; freePassParams.peekEyeDist = 1.75; freePassParams.peekEyeDistZ = 4; m_PlayerFreePass.SetParams( freePassParams ); } if (!m_nStartOn) { SetThink(NULL); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CNPCEventResponseSystem::FrameUpdatePreEntityThink() { if ( !m_ActiveEvents.Count() || !AI_IsSinglePlayer() || !UTIL_GetLocalPlayer() ) return; if ( m_flNextEventPoll > gpGlobals->curtime ) return; m_flNextEventPoll = gpGlobals->curtime + 0.2; // Move through all events, removing expired ones and finding NPCs for active ones. for ( int i = m_ActiveEvents.First(); i != m_ActiveEvents.InvalidIndex(); ) { float flTime = m_ActiveEvents[i].flEventTime; const char *pResponse = m_ActiveEvents.GetElementName(i); // Save off the next index so we can safely remove this one int iNext = m_ActiveEvents.Next(i); // Should it have expired by now? if ( !m_ActiveEvents[i].bPreventExpiration && (flTime + NPCEVENTRESPONSE_GIVEUP_TIME) < gpGlobals->curtime ) { if ( ai_debug_eventresponses.GetBool() ) { Msg( "NPCEVENTRESPONSE: (%.2f) Removing expired event named: %s\n", gpGlobals->curtime, pResponse ); } m_ActiveEvents.RemoveAt(i); } else if ( m_ActiveEvents[i].flNextResponseTime < gpGlobals->curtime ) { // If we've fired once, and our current event should expire now, then expire. if ( m_ActiveEvents[i].bPreventExpiration && (flTime + NPCEVENTRESPONSE_GIVEUP_TIME) < gpGlobals->curtime ) { if ( ai_debug_eventresponses.GetBool() ) { Msg( "NPCEVENTRESPONSE: (%.2f) Removing expired fired event named: %s\n", gpGlobals->curtime, pResponse ); } m_ActiveEvents.RemoveAt(i); } else { float flNearestDist = NPCEVENTRESPONSE_DISTANCE_SQR; CAI_BaseNPC *pNearestNPC = NULL; Vector vecPlayerCenter = UTIL_GetLocalPlayer()->WorldSpaceCenter(); // Try and find the nearest NPC to the player CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); for ( int j = 0; j < g_AI_Manager.NumAIs(); j++ ) { if ( ppAIs[j]->CanRespondToEvent( pResponse )) { float flDistToPlayer = ( vecPlayerCenter - ppAIs[j]->WorldSpaceCenter()).LengthSqr(); if ( flDistToPlayer < flNearestDist ) { flNearestDist = flDistToPlayer; pNearestNPC = ppAIs[j]; } } } // Found one? if ( pNearestNPC ) { if ( pNearestNPC->RespondedTo( pResponse, m_ActiveEvents[i].bForce, m_ActiveEvents[i].bCancelScript ) ) { // Don't remove the response yet. Leave it around until the refire time has expired. // This stops repeated firings of the same concept from spamming the NPCs. m_ActiveEvents[i].bPreventExpiration = true; m_ActiveEvents[i].flNextResponseTime = gpGlobals->curtime + NPCEVENTRESPONSE_REFIRE_TIME; if ( ai_debug_eventresponses.GetBool() ) { Msg( "NPCEVENTRESPONSE: (%.2f) Event '%s' responded to by NPC '%s'. Refire available at: %.2f\n", gpGlobals->curtime, pResponse, pNearestNPC->GetDebugName(), m_ActiveEvents[i].flNextResponseTime ); } // Don't issue multiple responses at once return; } } } } i = iNext; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CAI_BehaviorAlyxInjured::GatherConditions( void ) { BaseClass::GatherConditions(); // Always stomp over this ClearCondition( COND_INJURED_TOO_FAR_FROM_PLAYER ); ClearCondition( COND_INJURED_OVERWHELMED ); // See if we're overwhelmed by foes if ( NumKnownEnemiesInRadius( GetOuter()->GetAbsOrigin(), COVER_DISTANCE ) >= MIN_ENEMY_MOB ) { SetCondition( COND_INJURED_OVERWHELMED ); } // Determines whether we consider ourselves in danger bool bInDanger = ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) || HasCondition( COND_INJURED_OVERWHELMED ) ); // See if we're too far away from the player and in danger if ( AI_IsSinglePlayer() && bInDanger ) { bool bWarnPlayer = false; // This only works in single-player CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 ); if ( pPlayer != NULL ) { // FIXME: This distance may need to be the length of the shortest walked path between the follower and the target // Get our approximate distance to the player float flDistToPlayer = UTIL_DistApprox2D( GetOuter()->GetAbsOrigin(), pPlayer->GetAbsOrigin() ); if ( flDistToPlayer > injured_help_plee_range.GetFloat() ) { bWarnPlayer = true; } else if ( flDistToPlayer > (injured_help_plee_range.GetFloat()*0.5f) && HasCondition( COND_SEE_PLAYER ) == false ) { // Cut our distance in half if we can't see the player bWarnPlayer = true; } } // Yell for help! if ( bWarnPlayer ) { // FIXME: This should be routed through the normal speaking code with a system to emit from the player's suit. CBasePlayer *pPlayer = UTIL_PlayerByIndex( 1 ); //float flPlayerDistSqr = ( GetOuter()->GetAbsOrigin() - pPlayer->GetAbsOrigin() ).LengthSqr(); // If the player is too far away or we can't see him //if ( HasCondition( COND_SEE_PLAYER ) == false || flPlayerDistSqr > Square( 128 ) ) { if ( m_flNextWarnTime < gpGlobals->curtime ) { pPlayer->EmitSound( "npc_alyx.injured_too_far" ); m_flNextWarnTime = gpGlobals->curtime + random->RandomFloat( 3.0f, 5.0f ); } } /* else { SpeakIfAllowed( TLK_INJURED_FOLLOW_TOO_FAR ); m_flNextWarnTime = gpGlobals->curtime + random->RandomFloat( 3.0f, 5.0f ); } */ SetCondition( COND_INJURED_TOO_FAR_FROM_PLAYER ); } } }