void CAI_Expresser::ForceNotSpeaking( void ) { if ( IsSpeaking() ) { m_flStopTalkTime = gpGlobals->curtime; m_flStopTalkTimeWithoutDelay = gpGlobals->curtime; CAI_TimedSemaphore *pSemaphore = GetMySpeechSemaphore( GetOuter() ); if ( pSemaphore ) { if ( pSemaphore->GetOwner() == GetOuter() ) { pSemaphore->Release(); } } } }
void CAI_LeadBehavior::RunTask( const Task_t *pTask ) { switch ( pTask->iTask ) { case TASK_LEAD_SUCCEED: { if ( !IsSpeaking() ) { TaskComplete(); NotifyEvent( LBE_DONE ); } break; } case TASK_LEAD_ARRIVE: { if ( !IsSpeaking() ) { TaskComplete(); NotifyEvent( LBE_ARRIVAL_DONE ); } break; } case TASK_LEAD_MOVE_TO_RANGE: { // If we haven't spoken our start speech, move closer if ( !m_hasspokenstart) { ChainRunTask( TASK_MOVE_TO_GOAL_RANGE, m_leaddistance - 24 ); } else { ChainRunTask( TASK_MOVE_TO_GOAL_RANGE, m_retrievedistance ); if ( !TaskIsComplete() ) { // Transition to a walk when we get near the player // Check Z first, and only check 2d if we're within that Vector vecGoalPos = GetNavigator()->GetGoalPos(); float distance = fabs(vecGoalPos.z - GetLocalOrigin().z); bool bWithinZ = false; if ( distance < m_retrievedistance ) { distance = ( vecGoalPos - GetLocalOrigin() ).Length2D(); bWithinZ = true; } if ( distance > m_retrievedistance ) { Activity followActivity = ACT_WALK; if ( GetOuter()->GetState() == NPC_STATE_COMBAT || ( (!bWithinZ || distance < (m_retrievedistance*4)) && GetOuter()->GetState() != NPC_STATE_COMBAT ) ) { followActivity = ACT_RUN; } // Don't confuse move and shoot by resetting the activity every think Activity curActivity = GetNavigator()->GetMovementActivity(); switch( curActivity ) { case ACT_WALK_AIM: curActivity = ACT_WALK; break; case ACT_RUN_AIM: curActivity = ACT_RUN; break; } if ( curActivity != followActivity ) { GetNavigator()->SetMovementActivity(followActivity); } GetNavigator()->SetArrivalDirection( GetOuter()->GetTarget() ); } } } break; } case TASK_LEAD_RETRIEVE_WAIT: { ChainRunTask( TASK_WAIT_INDEFINITE ); break; } case TASK_LEAD_WALK_PATH: { // If we're leading, and we're supposed to run, run instead of walking if ( m_run && ( IsCurSchedule( SCHED_LEAD_WAITFORPLAYER, false ) || IsCurSchedule( SCHED_LEAD_PLAYER, false ) || IsCurSchedule( SCHED_LEAD_SPEAK_THEN_LEAD_PLAYER, false )|| IsCurSchedule( SCHED_LEAD_RETRIEVE, false ) ) ) { ChainRunTask( TASK_RUN_PATH ); } else { ChainRunTask( TASK_WALK_PATH ); } // While we're walking if ( TaskIsRunning() && IsCurSchedule( SCHED_LEAD_PLAYER, false ) ) { // If we're not speaking, and we haven't tried for a while, try to speak lead idle if ( m_flNextLeadIdle < gpGlobals->curtime && !IsSpeaking() ) { m_flNextLeadIdle = gpGlobals->curtime + RandomFloat( 10,15 ); if ( !m_args.iRetrievePlayer && HasCondition( COND_LEAD_FOLLOWER_LOST ) && HasCondition(COND_SEE_PLAYER) ) { Speak( TLK_LEAD_COMINGBACK ); } else { Speak( TLK_LEAD_IDLE ); } } } break; } default: BaseClass::RunTask( pTask); } }
int CAI_LeadBehavior::SelectSchedule() { if ( HasGoal() ) { if( HasCondition(COND_LEAD_SUCCESS) ) { return SCHED_LEAD_SUCCEED; } // Player's here, but does he have the weapon we want him to have? if ( m_weaponname != NULL_STRING ) { CBasePlayer *pFollower = AI_GetSinglePlayer(); if ( pFollower && !pFollower->Weapon_OwnsThisType( STRING(m_weaponname) ) ) { // If the safety timeout has run out, just give the player the weapon if ( !m_flWeaponSafetyTimeOut || (m_flWeaponSafetyTimeOut > gpGlobals->curtime) ) return SCHED_LEAD_PLAYERNEEDSWEAPON; string_t iszItem = AllocPooledString( "weapon_bugbait" ); pFollower->GiveNamedItem( STRING(iszItem) ); } } // If we have a waitpoint, we want to wait at it for the player. if( HasWaitPoint() && !PlayerIsAheadOfMe( true ) ) { bool bKeepWaiting = true; // If we have no wait distance, trigger as soon as the player comes in view if ( !m_waitdistance ) { if ( HasCondition( COND_SEE_PLAYER ) ) { // We've spotted the player, so stop waiting bKeepWaiting = false; } } else { // We have to collect data about the person we're leading around. CBaseEntity *pFollower = AI_GetSinglePlayer(); if( pFollower ) { float flFollowerDist = ( WorldSpaceCenter() - pFollower->WorldSpaceCenter() ).Length(); if ( flFollowerDist < m_waitdistance ) { bKeepWaiting = false; } } } // Player still not here? if ( bKeepWaiting ) return SCHED_LEAD_WAITFORPLAYER; // We're finished waiting m_waitpoint = vec3_origin; Speak( TLK_LEAD_WAITOVER ); // Don't speak the start line, because we've said m_hasspokenstart = true; return SCHED_WAIT_FOR_SPEAK_FINISH; } // If we haven't spoken our start speech, do that first if ( !m_hasspokenstart ) { if ( HasCondition(COND_LEAD_HAVE_FOLLOWER_LOS) && HasCondition(COND_LEAD_FOLLOWER_VERY_CLOSE) ) return SCHED_LEAD_SPEAK_START; // We haven't spoken to him, and we still need to. Go get him. return SCHED_LEAD_RETRIEVE; } if( HasCondition( COND_LEAD_FOLLOWER_LOST ) ) { if( m_args.iRetrievePlayer ) { // If not, we want to go get the player. DevMsg( GetOuter(), "Follower lost. Spoke COMING_BACK.\n"); Speak( TLK_LEAD_COMINGBACK ); m_MoveMonitor.ClearMark(); // If we spoke something, wait for it to finish if ( m_args.iComingBackWaitForSpeak && IsSpeaking() ) return SCHED_LEAD_SPEAK_THEN_RETRIEVE_PLAYER; return SCHED_LEAD_RETRIEVE; } else { // Just stay right here and wait. return SCHED_LEAD_WAITFORPLAYERIDLE; } } if( HasCondition( COND_LEAD_FOLLOWER_LAGGING ) ) { DevMsg( GetOuter(), "Follower lagging. Spoke CATCHUP.\n"); Speak( TLK_LEAD_CATCHUP ); return SCHED_LEAD_PAUSE; } else { // If we're at the goal, wait for the player to get here if ( ( WorldSpaceCenter() - m_goal ).LengthSqr() < (64*64) ) return SCHED_LEAD_AWAIT_SUCCESS; // If we were retrieving the player, speak the resume if ( IsCurSchedule( SCHED_LEAD_RETRIEVE, false ) || IsCurSchedule( SCHED_LEAD_WAITFORPLAYERIDLE, false ) ) { Speak( TLK_LEAD_RETRIEVE ); // If we spoke something, wait for it to finish, if the mapmakers wants us to if ( m_args.iRetrieveWaitForSpeak && IsSpeaking() ) return SCHED_LEAD_SPEAK_THEN_LEAD_PLAYER; } DevMsg( GetOuter(), "Leading Follower.\n"); return SCHED_LEAD_PLAYER; } } return BaseClass::SelectSchedule(); }
//----------------------------------------------------------------------------- // Purpose: Dispatches the result // Input : *response - //----------------------------------------------------------------------------- bool CAI_Expresser::SpeakDispatchResponse( AIConcept_t concept, AI_Response *result, IRecipientFilter *filter /* = NULL */ ) { char response[ 256 ]; result->GetResponse( response, sizeof( response ) ); float delay = result->GetDelay(); bool spoke = false; soundlevel_t soundlevel = result->GetSoundLevel(); if ( IsSpeaking() && concept[0] != 0 ) { DevMsg( "SpeakDispatchResponse: Entity ( %i/%s ) already speaking, forcing '%s'\n", GetOuter()->entindex(), STRING( GetOuter()->GetEntityName() ), concept ); // Tracker 15911: Can break the game if we stop an imported map placed lcs here, so only // cancel actor out of instanced scripted scenes. ywb RemoveActorFromScriptedScenes( GetOuter(), true /*instanced scenes only*/ ); GetOuter()->SentenceStop(); if ( IsRunningScriptedScene( GetOuter() ) ) { DevMsg( "SpeakDispatchResponse: Entity ( %i/%s ) refusing to speak due to scene entity, tossing '%s'\n", GetOuter()->entindex(), STRING( GetOuter()->GetEntityName() ), concept ); delete result; return false; } } switch ( result->GetType() ) { default: case RESPONSE_NONE: break; case RESPONSE_SPEAK: { if ( !result->ShouldntUseScene() ) { // This generates a fake CChoreoScene wrapping the sound.txt name spoke = SpeakAutoGeneratedScene( response, delay ); } else { float speakTime = GetResponseDuration( result ); GetOuter()->EmitSound( response ); DevMsg( "SpeakDispatchResponse: Entity ( %i/%s ) playing sound '%s'\n", GetOuter()->entindex(), STRING( GetOuter()->GetEntityName() ), response ); NoteSpeaking( speakTime, delay ); spoke = true; } } break; case RESPONSE_SENTENCE: { spoke = ( -1 != SpeakRawSentence( response, delay, VOL_NORM, soundlevel ) ) ? true : false; } break; case RESPONSE_SCENE: { spoke = SpeakRawScene( response, delay, result, filter ); } break; case RESPONSE_RESPONSE: { // This should have been recursively resolved already Assert( 0 ); } break; case RESPONSE_PRINT: { if ( g_pDeveloper->GetInt() > 0 ) { Vector vPrintPos; GetOuter()->CollisionProp()->NormalizedToWorldSpace( Vector(0.5,0.5,1.0f), &vPrintPos ); NDebugOverlay::Text( vPrintPos, response, true, 1.5 ); spoke = true; } } break; } if ( spoke ) { m_flLastTimeAcceptedSpeak = gpGlobals->curtime; if ( DebuggingSpeech() && g_pDeveloper->GetInt() > 0 && response && result->GetType() != RESPONSE_PRINT ) { Vector vPrintPos; GetOuter()->CollisionProp()->NormalizedToWorldSpace( Vector(0.5,0.5,1.0f), &vPrintPos ); NDebugOverlay::Text( vPrintPos, CFmtStr( "%s: %s", concept, response ), true, 1.5 ); } if ( result->IsApplyContextToWorld() ) { CBaseEntity *pEntity = CBaseEntity::Instance( engine->PEntityOfEntIndex( 0 ) ); if ( pEntity ) { pEntity->AddContext( result->GetContext() ); } } else { GetOuter()->AddContext( result->GetContext() ); } SetSpokeConcept( concept, result ); } else { delete result; } return spoke; }