void CAI_PlayerAlly::RunTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_TALKER_CLIENT_STARE: case TASK_TALKER_LOOK_AT_CLIENT: if ( pTask->iTask == TASK_TALKER_CLIENT_STARE ) { // Get edict for one player CBasePlayer *pPlayer = (CBasePlayer *)CBaseEntity::Instance( engine->PEntityOfEntIndex( 1 ) ); Assert( pPlayer ); // fail out if the player looks away or moves away. if ( ( pPlayer->GetLocalOrigin() - GetLocalOrigin() ).Length2D() > TLK_STARE_DIST ) { // player moved away. TaskFail("Player moved away"); } Vector forward; AngleVectors( pPlayer->GetLocalAngles(), &forward ); if ( UTIL_DotPoints( pPlayer->GetLocalOrigin(), GetLocalOrigin(), forward ) < m_flFieldOfView ) { // player looked away TaskFail("Player looked away"); } } if ( gpGlobals->curtime > m_flWaitFinished ) { TaskComplete(); } break; case TASK_TALKER_EYECONTACT: if (IsMoving() || !GetExpresser()->IsSpeaking() || GetSpeechTarget() == NULL) { TaskComplete(); } break; case TASK_WAIT_FOR_MOVEMENT: if (!GetExpresser()->IsSpeaking() || GetSpeechTarget() == NULL) { // override so that during walk, a scientist may talk and greet player FIdleHello(); if (random->RandomInt(0,m_nSpeak * 20) == 0) { FIdleSpeak(); } } BaseClass::RunTask( pTask ); break; default: BaseClass::RunTask( pTask ); } }
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_PlayerAlly::OnChangeRunningBehavior( CAI_BehaviorBase *pOldBehavior, CAI_BehaviorBase *pNewBehavior ) { BaseClass::OnChangeRunningBehavior( pOldBehavior, pNewBehavior ); CAI_FollowBehavior *pFollowBehavior; if ( dynamic_cast<CAI_FollowBehavior *>(pNewBehavior) != NULL ) { GetExpresser()->SetSpokeConcept( TLK_HELLO, NULL ); // Don't say hi after you've started following if ( IsOkToCombatSpeak() ) Speak( TLK_USE ); SetSpeechTarget( GetTarget() ); ClearCondition( COND_PLAYER_PUSHING ); } else if ( ( pFollowBehavior = dynamic_cast<CAI_FollowBehavior *>(pOldBehavior) ) != NULL ) { if ( !(m_afMemory & bits_MEMORY_PROVOKED) ) { if ( IsOkToCombatSpeak() ) { if ( pFollowBehavior->GetFollowTarget() == NULL ) Speak( TLK_UNUSE ); else Speak( TLK_STOP ); } SetSpeechTarget( FindNearestFriend(true) ); } } }
//========================================================= // IdleHello // Try to greet player first time he's seen //========================================================= int CAI_PlayerAlly::FIdleHello( void ) { if (!IsOkToSpeak()) return false; // if this is first time scientist has seen player, greet him if (!GetExpresser()->SpokeConcept(TLK_HELLO)) { // get a player CBaseEntity *pPlayer = FindNearestFriend(true); if (pPlayer) { if (FInViewCone(pPlayer) && FVisible(pPlayer)) { SetSpeechTarget( pPlayer ); Speak( TLK_HELLO ); return true; } } } return false; }
// Init talk data void CNPC_HL1Barney::TalkInit() { BaseClass::TalkInit(); // get voice for head - just one barney voice for now GetExpresser()->SetVoicePitch( 100 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CNPCSimpleTalker::FIdleSpeakWhileMoving( void ) { if ( GetExpresser()->CanSpeak() ) { if (!GetExpresser()->IsSpeaking() || GetSpeechTarget() == NULL) { // override so that during walk, a scientist may talk and greet player FIdleHello(); if ( ShouldSpeakRandom( m_nSpeak * 20, GetSpeechFilter() ? GetSpeechFilter()->GetIdleModifier() : 1.0 ) ) { FIdleSpeak(); } } } }
// try to smell something void CNPCSimpleTalker::TrySmellTalk( void ) { if ( !IsOkToSpeak() ) return; if ( HasCondition( COND_SMELL ) && GetExpresser()->CanSpeakConcept( TLK_SMELL ) ) Speak( TLK_SMELL ); }
void CNPCSimpleTalker::OnStartingFollow( CBaseEntity *pTarget ) { GetExpresser()->SetSpokeConcept( TLK_HELLO, NULL ); // Don't say hi after you've started following if ( IsOkToSpeak() ) // don't speak if idle talk is blocked. player commanded/use follow will always speak Speak( TLK_STARTFOLLOW ); SetSpeechTarget( GetTarget() ); ClearCondition( COND_PLAYER_PUSHING ); }
//----------------------------------------------------------------------------- // Purpose: Implemented to look at talk target // Input : // Output : //----------------------------------------------------------------------------- CBaseEntity *CAI_PlayerAlly::EyeLookTarget( void ) { if (GetExpresser()->IsSpeaking() && GetSpeechTarget() != NULL) { return GetSpeechTarget(); } return NULL; }
// try to smell something void CAI_PlayerAlly::TrySmellTalk( void ) { if ( !IsOkToSpeak() ) return; if ( HasCondition( COND_SMELL ) && GetExpresser()->CanSpeakConcept( TLK_SMELL ) ) Speak( TLK_SMELL ); }
//----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CNPCSimpleTalker::CanSayHello( void ) { #ifndef HL1_DLL if ( Classify() == CLASS_PLAYER_ALLY_VITAL ) return false; #endif if ( GetSpeechFilter() && GetSpeechFilter()->NeverSayHello() ) return false; if ( !GetExpresser()->CanSpeakConcept(TLK_HELLO) || GetExpresser()->SpokeConcept(TLK_HELLO) ) return false; if ( !IsOkToSpeak() ) return false; return true; }
//------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ bool CAI_PlayerAlly::IsOkToSpeak( void ) { if ( !IsOkToCombatSpeak() ) return false; // don't talk if you're in combat if (GetEnemy() != NULL && FVisible( GetEnemy() )) return false; return ( !GetExpresser()->IsSpeaking() ); }
bool CHL1NPCTalker::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt) { if (interactionType == g_interactionBarnacleVictimDangle) { // Force choosing of a new schedule ClearSchedule( "NPC talker being eaten by a barnacle" ); m_bInBarnacleMouth = true; return true; } else if ( interactionType == g_interactionBarnacleVictimReleased ) { SetState ( NPC_STATE_IDLE ); CPASAttenuationFilter filter( this ); CSoundParameters params; if ( GetParametersForSound( "Barney.Close", params, NULL ) ) { EmitSound_t ep( params ); ep.m_nPitch = GetExpresser()->GetVoicePitch(); EmitSound( filter, entindex(), ep ); } m_bInBarnacleMouth = false; SetAbsVelocity( vec3_origin ); SetMoveType( MOVETYPE_STEP ); return true; } else if ( interactionType == g_interactionBarnacleVictimGrab ) { if ( GetFlags() & FL_ONGROUND ) { SetGroundEntity( NULL ); } if ( GetState() == NPC_STATE_SCRIPT ) { if ( m_hCine ) { m_hCine->CancelScript(); } } SetState( NPC_STATE_PRONE ); ClearSchedule( "NPC talker grabbed by a barnacle" ); CTakeDamageInfo info; PainSound( info ); return true; } return false; }
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; }
bool CNPCSimpleTalker::ShouldSuspendMonolog( void ) { float flDist; flDist = ((assert_cast<CNPCSimpleTalkerExpresser *>(GetExpresser()))->GetMonologueTarget()->GetAbsOrigin() - GetAbsOrigin()).Length(); if( flDist >= 384 ) { return true; } return false; }
bool CAI_PlayerAlly::ShouldSuspendMonolog( void ) { float flDist; flDist = (GetExpresser()->GetMonologueTarget()->GetLocalOrigin() - GetLocalOrigin()).Length(); if( flDist >= 384 ) { return true; } return false; }
//========================================================= // DeathSound //========================================================= void CNPC_HL1Barney::DeathSound( const CTakeDamageInfo &info ) { CPASAttenuationFilter filter( this ); CSoundParameters params; if ( GetParametersForSound( "Barney.Die", params, NULL ) ) { params.pitch = GetExpresser()->GetVoicePitch(); EmitSound_t ep( params ); EmitSound( filter, entindex(), ep ); } }
Activity CNPCSimpleTalker::NPC_TranslateActivity( Activity eNewActivity ) { if ((eNewActivity == ACT_IDLE) && (GetExpresser()->IsSpeaking()) && (SelectWeightedSequence ( ACT_SIGNAL3 ) != ACTIVITY_NOT_AVAILABLE) ) { return ACT_SIGNAL3; } else if ((eNewActivity == ACT_SIGNAL3) && (SelectWeightedSequence ( ACT_SIGNAL3 ) == ACTIVITY_NOT_AVAILABLE) ) { return ACT_IDLE; } return BaseClass::NPC_TranslateActivity( eNewActivity ); }
bool CNPCSimpleTalker::ShouldResumeMonolog( void ) { float flDist; if( HasCondition( COND_SEE_PLAYER ) ) { flDist = ((assert_cast<CNPCSimpleTalkerExpresser *>(GetExpresser()))->GetMonologueTarget()->GetAbsOrigin() - GetAbsOrigin()).Length(); if( flDist <= 256 ) { return true; } } return false; }
bool CAI_PlayerAlly::ShouldResumeMonolog( void ) { float flDist; if( HasCondition( COND_SEE_PLAYER ) ) { flDist = (GetExpresser()->GetMonologueTarget()->GetLocalOrigin() - GetLocalOrigin()).Length(); if( flDist <= 256 ) { return true; } } return false; }
void CAI_PlayerAlly::Touch( CBaseEntity *pOther ) { BaseClass::Touch( pOther ); // Did the player touch me? if ( pOther->IsPlayer() ) { // Ignore if pissed at player if ( m_afMemory & bits_MEMORY_PROVOKED ) return; // Stay put during speech if ( GetExpresser()->IsSpeaking() ) return; TestPlayerPushing( pOther ); } }
//========================================================= // PainSound //========================================================= void CNPC_HL1Barney::PainSound( const CTakeDamageInfo &info ) { if (gpGlobals->curtime < m_flPainTime) return; m_flPainTime = gpGlobals->curtime + random->RandomFloat( 0.5, 0.75 ); CPASAttenuationFilter filter( this ); CSoundParameters params; if ( GetParametersForSound( "Barney.Pain", params, NULL ) ) { params.pitch = GetExpresser()->GetVoicePitch(); EmitSound_t ep( params ); EmitSound( filter, entindex(), ep ); } }
//----------------------------------------------------------------------------- // Purpose: Say hello to the specified player //----------------------------------------------------------------------------- void CNPCSimpleTalker::SayHelloToPlayer( CBaseEntity *pPlayer ) { Assert( !GetExpresser()->SpokeConcept(TLK_HELLO) ); SetSpeechTarget( pPlayer ); Speak( TLK_HELLO ); DeferAllIdleSpeech( random->RandomFloat( 5, 10 ) ); CAI_BaseNPC **ppAIs = g_AI_Manager.AccessAIs(); CAI_PlayerAlly *pTalker; for ( int i = 0; i < g_AI_Manager.NumAIs(); i++ ) { pTalker = dynamic_cast<CAI_PlayerAlly *>(ppAIs[i]); if( pTalker && FVisible( pTalker ) ) { // Tell this guy he's already said hello to the player, too. pTalker->GetExpresser()->SetSpokeConcept( TLK_HELLO, NULL ); } } }
//------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ bool CAI_PlayerAlly::IsOkToCombatSpeak( void ) { // if not alive, certainly don't speak if ( !IsAlive() ) return false; // if someone else is talking, don't speak if ( !GetExpresser()->SemaphoreIsAvailable() ) return false; if ( m_spawnflags & SF_NPC_GAG ) return false; // Don't speak if playing a script. if ( m_NPCState == NPC_STATE_SCRIPT ) return false; // if player is not in pvs, don't speak if ( !UTIL_FindClientInPVS(edict()) ) return false; return true; }
void CHL1NPCTalker::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_HL1TALKER_FOLLOW_WALK_PATH_FOR_UNITS: { float distance; distance = (m_vecLastPosition - GetLocalOrigin()).Length2D(); // Walk path until far enough away if ( distance > pTask->flTaskData || GetNavigator()->GetGoalType() == GOALTYPE_NONE ) { TaskComplete(); GetNavigator()->ClearGoal(); // Stop moving } break; } case TASK_TALKER_CLIENT_STARE: case TASK_TALKER_LOOK_AT_CLIENT: { CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); // track head to the client for a while. if ( m_NPCState == NPC_STATE_IDLE && !IsMoving() && !GetExpresser()->IsSpeaking() ) { if ( pPlayer ) { IdleHeadTurn( pPlayer ); } } else { // started moving or talking TaskFail( "moved away" ); return; } if ( pTask->iTask == TASK_TALKER_CLIENT_STARE ) { // fail out if the player looks away or moves away. if ( ( pPlayer->GetAbsOrigin() - GetAbsOrigin() ).Length2D() > TALKER_STARE_DIST ) { // player moved away. TaskFail( NO_TASK_FAILURE ); } Vector vForward; AngleVectors( GetAbsAngles(), &vForward ); if ( UTIL_DotPoints( pPlayer->GetAbsOrigin(), GetAbsOrigin(), vForward ) < m_flFieldOfView ) { // player looked away TaskFail( "looked away" ); } } if ( gpGlobals->curtime > m_flWaitFinished ) { TaskComplete( NO_TASK_FAILURE ); } break; } case TASK_WAIT_FOR_MOVEMENT: { if ( GetExpresser()->IsSpeaking() && GetSpeechTarget() != NULL) { // ALERT(at_console, "walking, talking\n"); IdleHeadTurn( GetSpeechTarget(), GetExpresser()->GetTimeSpeechComplete() - gpGlobals->curtime ); } else if ( GetEnemy() ) { IdleHeadTurn( GetEnemy() ); } BaseClass::RunTask( pTask ); break; } case TASK_FACE_PLAYER: { CBasePlayer *pPlayer = UTIL_GetLocalPlayer(); if ( pPlayer ) { //GetMotor()->SetIdealYaw( pPlayer->GetAbsOrigin() ); IdleHeadTurn( pPlayer ); if ( gpGlobals->curtime > m_flWaitFinished && GetMotor()->DeltaIdealYaw() < 10 ) { TaskComplete(); } } else { TaskFail( FAIL_NO_PLAYER ); } break; } case TASK_TALKER_EYECONTACT: { if (!IsMoving() && GetExpresser()->IsSpeaking() && GetSpeechTarget() != NULL) { // ALERT( at_console, "waiting %f\n", m_flStopTalkTime - gpGlobals->time ); IdleHeadTurn( GetSpeechTarget(), GetExpresser()->GetTimeSpeechComplete() - gpGlobals->curtime ); } BaseClass::RunTask( pTask ); break; } default: { if ( GetExpresser()->IsSpeaking() && GetSpeechTarget() != NULL) { IdleHeadTurn( GetSpeechTarget(), GetExpresser()->GetTimeSpeechComplete() - gpGlobals->curtime ); } else if ( GetEnemy() && m_NPCState == NPC_STATE_COMBAT ) { IdleHeadTurn( GetEnemy() ); } else if ( GetFollowTarget() ) { IdleHeadTurn( GetFollowTarget() ); } BaseClass::RunTask( pTask ); break; } } }
bool CHL1NPCTalker::HandleInteraction(int interactionType, void *data, CBaseCombatCharacter* sourceEnt) { if (interactionType == g_interactionBarnacleVictimDangle) { // Force choosing of a new schedule ClearSchedule(); m_bInBarnacleMouth = true; return true; } else if ( interactionType == g_interactionBarnacleVictimReleased ) { SetState ( NPC_STATE_IDLE ); CPASAttenuationFilter filter( this ); EmitSound( filter, entindex(), CHAN_VOICE, "barney/ba_close.wav", 1, SNDLVL_TALKING, 0, GetExpresser()->GetVoicePitch()); m_bInBarnacleMouth = false; SetAbsVelocity( vec3_origin ); SetMoveType( MOVETYPE_STEP ); return true; } else if ( interactionType == g_interactionBarnacleVictimGrab ) { if ( GetFlags() & FL_ONGROUND ) { RemoveFlag( FL_ONGROUND ); } if ( GetState() == NPC_STATE_SCRIPT ) { m_hCine->CancelScript(); ClearSchedule(); } SetState( NPC_STATE_PRONE ); PainSound(); return true; } return false; }
void CNPCSimpleTalker::PrescheduleThink( void ) { BaseClass::PrescheduleThink(); (assert_cast<CNPCSimpleTalkerExpresser *>(GetExpresser()))->SpeakMonolog(); }
void CAI_PlayerAlly::PrescheduleThink( void ) { BaseClass::PrescheduleThink(); GetExpresser()->SpeakMonolog(); }
void CNPCSimpleTalker::StartTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_TALKER_WAIT_FOR_SEMAPHORE: if ( GetExpresser()->SemaphoreIsAvailable( this ) ) TaskComplete(); break; case TASK_TALKER_SPEAK: // ask question or make statement FIdleSpeak(); TaskComplete(); break; case TASK_TALKER_RESPOND: // respond to question IdleRespond(); TaskComplete(); break; case TASK_TALKER_HELLO: // greet player FIdleHello(); TaskComplete(); break; case TASK_TALKER_STARE: // let the player know I know he's staring at me. FIdleStare(); TaskComplete(); break; case TASK_TALKER_LOOK_AT_CLIENT: case TASK_TALKER_CLIENT_STARE: // track head to the client for a while. SetWait( pTask->flTaskData ); break; case TASK_TALKER_EYECONTACT: break; case TASK_TALKER_IDEALYAW: if (GetSpeechTarget() != NULL) { GetMotor()->SetIdealYawToTarget( GetSpeechTarget()->GetAbsOrigin() ); } TaskComplete(); break; case TASK_TALKER_HEADRESET: // reset head position after looking at something SetSpeechTarget( NULL ); TaskComplete(); break; case TASK_TALKER_BETRAYED: Speak( TLK_BETRAYED ); TaskComplete(); break; case TASK_TALKER_STOPSHOOTING: // tell player to stop shooting Speak( TLK_NOSHOOT ); TaskComplete(); break; default: BaseClass::StartTask( pTask ); } }
//========================================================= // FIdleSpeak // ask question of nearby friend, or make statement //========================================================= int CNPCSimpleTalker::FIdleSpeak( void ) { // try to start a conversation, or make statement int pitch; if (!IsOkToSpeak()) return false; Assert( GetExpresser()->SemaphoreIsAvailable( this ) ); pitch = GetExpresser()->GetVoicePitch(); // player using this entity is alive and wounded? CBaseEntity *pTarget = GetTarget(); if ( pTarget != NULL ) { if ( pTarget->IsPlayer() ) { if ( pTarget->IsAlive() ) { SetSpeechTarget( GetTarget() ); if (GetExpresser()->CanSpeakConcept( TLK_PLHURT3) && (GetTarget()->m_iHealth <= GetTarget()->m_iMaxHealth / 8)) { Speak( TLK_PLHURT3 ); return true; } else if (GetExpresser()->CanSpeakConcept( TLK_PLHURT2) && (GetTarget()->m_iHealth <= GetTarget()->m_iMaxHealth / 4)) { Speak( TLK_PLHURT2 ); return true; } else if (GetExpresser()->CanSpeakConcept( TLK_PLHURT1) && (GetTarget()->m_iHealth <= GetTarget()->m_iMaxHealth / 2)) { Speak( TLK_PLHURT1 ); return true; } } else { //!!!KELLY - here's a cool spot to have the talkNPC talk about the dead player if we want. // "Oh dear, Gordon Freeman is dead!" -Scientist // "Damn, I can't do this without you." -Barney } } } // ROBIN: Disabled idle question & answer for now /* // if there is a friend nearby to speak to, play sentence, set friend's response time, return CBaseEntity *pFriend = FindNearestFriend(false); // 75% chance of talking to another citizen if one is available. if (pFriend && !(pFriend->IsMoving()) && random->RandomInt( 0, 3 ) != 0 ) { if ( SpeakQuestionFriend( pFriend ) ) { // force friend to answer CAI_PlayerAlly *pTalkNPC = dynamic_cast<CAI_PlayerAlly *>(pFriend); if (pTalkNPC && !pTalkNPC->HasSpawnFlags(SF_NPC_GAG) && !pTalkNPC->IsInAScript() ) { SetSpeechTarget( pFriend ); pTalkNPC->SetAnswerQuestion( this ); pTalkNPC->GetExpresser()->BlockSpeechUntil( GetExpresser()->GetTimeSpeechComplete() ); m_nSpeak++; } // Don't let anyone else butt in. DeferAllIdleSpeech( random->RandomFloat( TALKER_DEFER_IDLE_SPEAK_MIN, TALKER_DEFER_IDLE_SPEAK_MAX ), pTalkNPC ); return true; } } */ // Otherwise, play an idle statement, try to face client when making a statement. CBaseEntity *pFriend = FindNearestFriend(true); if ( pFriend ) { SetSpeechTarget( pFriend ); // If we're about to talk to the player, and we've never said hello, say hello first if ( !GetSpeechFilter() || !GetSpeechFilter()->NeverSayHello() ) { if ( GetExpresser()->CanSpeakConcept( TLK_HELLO ) && !GetExpresser()->SpokeConcept( TLK_HELLO ) ) { SayHelloToPlayer( pFriend ); return true; } } if ( Speak( TLK_IDLE ) ) { DeferAllIdleSpeech( random->RandomFloat( TALKER_DEFER_IDLE_SPEAK_MIN, TALKER_DEFER_IDLE_SPEAK_MAX ) ); m_nSpeak++; } else { // We failed to speak. Don't try again for a bit. m_flNextIdleSpeechTime = gpGlobals->curtime + 3; } return true; } // didn't speak m_flNextIdleSpeechTime = gpGlobals->curtime + 3; return false; }