//----------------------------------------------------------------------------- // Purpose: // Input : *pTask - //----------------------------------------------------------------------------- void CAI_BehaviorAlyxInjured::StartTask( const Task_t *pTask ) { switch( pTask->iTask ) { case TASK_FIND_COVER_FROM_ENEMY: { CBaseEntity *pLeader = GetFollowTarget(); if ( !pLeader ) { BaseClass::StartTask( pTask ); break; } // Find a position behind our follow target Vector coverPos = vec3_invalid; if ( FindCoverFromEnemyBehindTarget( pLeader, COVER_DISTANCE, &coverPos ) ) { AI_NavGoal_t goal( GOALTYPE_LOCATION, coverPos, ACT_RUN, AIN_HULL_TOLERANCE, AIN_DEF_FLAGS ); GetOuter()->GetNavigator()->SetGoal( goal ); GetOuter()->m_flMoveWaitFinished = gpGlobals->curtime + pTask->flTaskData; TaskComplete(); return; } // Couldn't find anything TaskFail( FAIL_NO_COVER ); break; } default: BaseClass::StartTask( pTask ); break; } }
//----------------------------------------------------------------------------- // Purpose: Pick up failure cases and handle them //----------------------------------------------------------------------------- int CAI_BehaviorAlyxInjured::SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ) { // Failed schedules switch( failedSchedule ) { case SCHED_RUN_FROM_ENEMY: case SCHED_RUN_FROM_ENEMY_MOB: case SCHED_FOLLOW: return SCHED_INJURED_COWER; } // Failed tasks switch( failedTask ) { case TASK_FIND_COVER_FROM_ENEMY: case TASK_FIND_INJURED_COVER_FROM_ENEMY: // Only cower if we're already near enough to our follow target float flDistToFollowTargetSqr = ( GetOuter()->GetAbsOrigin() - GetFollowTarget()->GetAbsOrigin() ).LengthSqr(); if ( flDistToFollowTargetSqr > Square( 256 ) ) return SCHED_FOLLOW; return SCHED_INJURED_COWER; break; } return BaseClass::SelectFailSchedule( failedSchedule, failedTask, taskFailCode ); }
//----------------------------------------------------------------------------- // Purpose: See if we need to follow our goal // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CAI_BehaviorAlyxInjured::ShouldRunToFollowGoal( void ) { // If we're too far from our follow target, we need to chase after them float flDistToFollowGoalSqr = ( GetOuter()->GetAbsOrigin() - GetFollowTarget()->GetAbsOrigin() ).LengthSqr(); if ( flDistToFollowGoalSqr > Square(MAX_DIST_FROM_FOLLOW_TARGET) ) return true; return false; }
void CHL1NPCTalker::StopFollowing( void ) { if ( !(m_afMemory & bits_MEMORY_PROVOKED) ) { if ( !HasSpawnFlags( SF_NPC_GAG ) ) { Speak( TLK_UNUSE ); SetSpeechTarget( GetFollowTarget() ); } } BaseClass::StopFollowing(); }
//----------------------------------------------------------------------------- // Purpose: Determines if Alyx should run away from enemies or stay put // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CAI_BehaviorAlyxInjured::ShouldRunToCover( void ) { Vector vecRetreatPos; float flRetreatRadius = 128.0f; // See how far off from our cover position we are if ( FindCoverFromEnemyBehindTarget( GetFollowTarget(), flRetreatRadius, &vecRetreatPos ) ) { float flDestDistSqr = ( GetOuter()->WorldSpaceCenter() - vecRetreatPos ).LengthSqr(); if ( flDestDistSqr > Square( flRetreatRadius ) ) return true; } return false; }
void CHL1NPCTalker::StopFollowing( void ) { if ( !(m_afMemory & bits_MEMORY_PROVOKED) ) { if ( !HasSpawnFlags( SF_NPC_GAG ) ) { if ( m_iszUnUse != NULL_STRING ) { PlaySentence( STRING( m_iszUnUse ), 0.0f ); } else { Speak( TLK_STOPFOLLOW ); } SetSpeechTarget( GetFollowTarget() ); } } BaseClass::StopFollowing(); }
//========================================================= // SelectSchedule - Decides which type of schedule best suits // the monster's current state and conditions. Then calls // monster's member function to get a pointer to a schedule // of the proper type. //========================================================= int CNPC_HL1Barney::SelectSchedule( void ) { if ( m_NPCState == NPC_STATE_COMBAT || GetEnemy() != NULL ) { // Priority action! if (!m_fGunDrawn ) return SCHED_ARM_WEAPON; } if ( GetFollowTarget() == NULL ) { if ( HasCondition( COND_PLAYER_PUSHING ) && !(GetSpawnFlags() & SF_NPC_PREDISASTER ) ) // Player wants me to move return SCHED_HL1TALKER_FOLLOW_MOVE_AWAY; } if ( BehaviorSelectSchedule() ) return BaseClass::SelectSchedule(); if ( HasCondition( COND_HEAR_DANGER ) ) { CSound *pSound; pSound = GetBestSound(); ASSERT( pSound != NULL ); if ( pSound && pSound->IsSoundType( SOUND_DANGER ) ) return SCHED_TAKE_COVER_FROM_BEST_SOUND; } if ( HasCondition( COND_ENEMY_DEAD ) && IsOkToSpeak() ) { Speak( BA_KILL ); } switch( m_NPCState ) { case NPC_STATE_COMBAT: { // dead enemy if ( HasCondition( COND_ENEMY_DEAD ) ) return BaseClass::SelectSchedule(); // call base class, all code to handle dead enemies is centralized there. // always act surprized with a new enemy if ( HasCondition( COND_NEW_ENEMY ) && HasCondition( COND_LIGHT_DAMAGE) ) return SCHED_SMALL_FLINCH; if ( HasCondition( COND_HEAVY_DAMAGE ) ) return SCHED_TAKE_COVER_FROM_ENEMY; if ( !HasCondition(COND_SEE_ENEMY) ) { // we can't see the enemy if ( !HasCondition(COND_ENEMY_OCCLUDED) ) { // enemy is unseen, but not occluded! // turn to face enemy return SCHED_COMBAT_FACE; } else { return SCHED_CHASE_ENEMY; } } } break; case NPC_STATE_ALERT: case NPC_STATE_IDLE: if ( HasCondition( COND_LIGHT_DAMAGE ) || HasCondition( COND_HEAVY_DAMAGE ) ) { // flinch if hurt return SCHED_SMALL_FLINCH; } if ( GetEnemy() == NULL && GetFollowTarget() ) { if ( !GetFollowTarget()->IsAlive() ) { // UNDONE: Comment about the recently dead player here? StopFollowing(); break; } else { return SCHED_TARGET_FACE; } } // try to say something about smells TrySmellTalk(); break; } return BaseClass::SelectSchedule(); }
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; } } }