示例#1
0
void CASW_Alien_Jumper::BuildScheduleTestBits( void )
{
	//Don't allow any modifications when scripted
	if ( m_NPCState == NPC_STATE_SCRIPT )
		return;

	BaseClass::BuildScheduleTestBits();

	//Make sure we interrupt a run schedule if we can jump
	if ( IsCurSchedule(SCHED_CHASE_ENEMY) && GetNavType() == NAV_GROUND )
	{
		SetCustomInterruptCondition( COND_ASW_ALIEN_CAN_JUMP );
		SetCustomInterruptCondition( COND_ENEMY_UNREACHABLE );
	}

	
	//Interrupt any schedule unless already fleeing, burrowing, burrowed, or unburrowing.
	if(!IsCurSchedule(SCHED_ASW_ALIEN_JUMP)					&&	
		( GetFlags() & FL_ONGROUND ) )
	{
		// Only do these if not jumping as well
		if (!IsCurSchedule(SCHED_ASW_ALIEN_JUMP))
		{
			if ( GetEnemy() == NULL )
			{
				SetCustomInterruptCondition( COND_HEAR_PHYSICS_DANGER );
			}
			//if ( GetNavType() != NAV_JUMP )
				 //SetCustomInterruptCondition( COND_ANTLION_RECEIVED_ORDERS );
		}

		//SetCustomInterruptCondition( COND_ANTLION_ON_NPC );
	}
}
示例#2
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_Monk::BuildScheduleTestBits( void )
{
	// FIXME: we need a way to make scenes non-interruptible
	if ( IsCurSchedule( SCHED_RANGE_ATTACK1 ) || IsCurSchedule( SCHED_SCENE_SEQUENCE ) || IsCurSchedule( SCHED_SCENE_WALK ) )
	{
		ClearCustomInterruptCondition( COND_LIGHT_DAMAGE );
		ClearCustomInterruptCondition( COND_HEAVY_DAMAGE );
		ClearCustomInterruptCondition( COND_NEW_ENEMY );
		ClearCustomInterruptCondition( COND_HEAR_DANGER );
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CAI_PolicingBehavior::BuildScheduleTestBits( void )
{
	if ( IsCurSchedule( SCHED_IDLE_STAND ) || IsCurSchedule( SCHED_ALERT_STAND ) )
	{
		if ( m_flNextHarassTime < gpGlobals->curtime )
		{
			GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal( COND_POLICE_TARGET_TOO_CLOSE_HARASS ) );
		}

		GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS ) );
	}
}
示例#4
0
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_FearBehavior::BuildScheduleTestBits()
{
	BaseClass::BuildScheduleTestBits();

	if( GetOuter()->GetState() != NPC_STATE_SCRIPT )
	{
		// Stop doing ANYTHING if we get scared.
		//GetOuter()->SetCustomInterruptCondition( COND_HEAR_DANGER );

		if( !IsCurSchedule(SCHED_FEAR_MOVE_TO_SAFE_PLACE_RETRY, false) && !IsCurSchedule(SCHED_FEAR_MOVE_TO_SAFE_PLACE, false) )
		{
			GetOuter()->SetCustomInterruptCondition( GetClassScheduleIdSpace()->ConditionLocalToGlobal(COND_FEAR_SEPARATED_FROM_PLAYER) );
		}
	}
}
//-----------------------------------------------------------------------------
// Purpose: Allows for modification of the interrupt mask for the current schedule.
//			In the most cases the base implementation should be called first.
//-----------------------------------------------------------------------------
void CNPC_PoisonZombie::BuildScheduleTestBits( void )
{
	BaseClass::BuildScheduleTestBits();

	if ( IsCurSchedule( SCHED_CHASE_ENEMY ) )
	{
		SetCustomInterruptCondition( COND_LIGHT_DAMAGE );
		SetCustomInterruptCondition( COND_HEAVY_DAMAGE );
	}
	else if ( IsCurSchedule( SCHED_RANGE_ATTACK1 ) || IsCurSchedule( SCHED_RANGE_ATTACK2 ) )
	{
		ClearCustomInterruptCondition( COND_LIGHT_DAMAGE );
		ClearCustomInterruptCondition( COND_HEAVY_DAMAGE );
	}
}
示例#6
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CAI_AssaultBehavior::BuildScheduleTestBits()
{
	BaseClass::BuildScheduleTestBits();

	// If we're allowed to divert, add the appropriate interrupts to our movement schedules
	if ( IsAllowedToDivert() )
	{
		if ( IsCurSchedule( SCHED_MOVE_TO_ASSAULT_POINT ) ||
			IsCurSchedule( SCHED_MOVE_TO_RALLY_POINT ) || 
			IsCurSchedule( SCHED_HOLD_RALLY_POINT ) )
		{
			GetOuter()->SetCustomInterruptCondition( COND_NEW_ENEMY );
			GetOuter()->SetCustomInterruptCondition( COND_SEE_ENEMY );
		}
	}
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_OperatorBehavior::GatherConditions( void )
{
    if( GetGoalEntity() )
    {
        if( GetGoalEntity()->GetState() == OPERATOR_STATE_FINISHED )
        {
            if( IsCurSchedule(SCHED_OPERATOR_OPERATE) )
            {
                // Break us out of the operator schedule if the operation completes.
                SetCondition(COND_PROVOKED);
            }

            m_hGoalEntity.Set(NULL);
            m_hPositionEnt.Set(NULL);
        }
        else
        {
            if( CanSeePositionEntity() )
            {
                ClearCondition( COND_OPERATOR_LOST_SIGHT_OF_POSITION );
            }
            else
            {
                SetCondition( COND_OPERATOR_LOST_SIGHT_OF_POSITION );
            }
        }
    }

    BaseClass::GatherConditions();

    // Ignore player pushing.
    ClearCondition( COND_PLAYER_PUSHING );
}
示例#8
0
void CZombie::BuildScheduleTestBits( void )
{
	BaseClass::BuildScheduleTestBits();

	if( !IsCurSchedule( SCHED_FLINCH_PHYSICS ) && !m_ActBusyBehavior.IsActive() )
		SetCustomInterruptCondition( COND_PHYSICS_DAMAGE );
}
void CAI_StandoffBehavior::BuildScheduleTestBits()
{
	BaseClass::BuildScheduleTestBits();

	if ( IsCurSchedule( SCHED_TAKE_COVER_FROM_ENEMY ) )
		GetOuter()->ClearCustomInterruptCondition( COND_NEW_ENEMY );
}
示例#10
0
//-----------------------------------------------------------------------------
// Purpose: Allows for modification of the interrupt mask for the current schedule.
//			In the most cases the base implementation should be called first.
//-----------------------------------------------------------------------------
void CNPC_AntlionGrub::BuildScheduleTestBits( void )
{
	//Always squirm if we're being squashed
	if ( !IsCurSchedule( SCHED_SMALL_FLINCH ) )
	{
		SetCustomInterruptCondition( COND_ANTLIONGRUB_BEING_SQUASHED );
	}
}
void CNPC_SO_BaseZombie::BuildScheduleTestBits( void )
{
	BaseClass::BuildScheduleTestBits();

	// Add a custom rally point entity for NPC spawners
	if( IsCurSchedule( SCHED_ZOMBIE_AMBUSH_MODE ) )
		SetCustomInterruptCondition( COND_RECEIVED_ORDERS );
}
示例#12
0
void CASW_Harvester::BuildScheduleTestBits()
{
	BaseClass::BuildScheduleTestBits();

	if ( IsCurSchedule( SCHED_RUN_FROM_ENEMY ) )
	{
		SetCustomInterruptCondition( COND_CAN_RANGE_ATTACK1 );
	}
}
//-----------------------------------------------------------------------------
// Purpose: Allows for modification of the interrupt mask for the current schedule.
//			In the most cases the base implementation should be called first.
//-----------------------------------------------------------------------------
void CNPC_CombineShot::BuildScheduleTestBits(void)
{
	//Interrupt any schedule with physics danger (as long as I'm not moving or already trying to block)
	if ( m_flGroundSpeed == 0.0 && !IsCurSchedule( SCHED_FLINCH_PHYSICS ) )
	{
		SetCustomInterruptCondition( COND_HEAR_PHYSICS_DANGER );
	}

	BaseClass::BuildScheduleTestBits();
}
示例#14
0
//-----------------------------------------------------------------------------
// Purpose: Allows for modification of the interrupt mask for the current schedule.
//			In the most cases the base implementation should be called first.
//-----------------------------------------------------------------------------
void CNPC_Monster::BuildScheduleTestBits( void )
{
	BaseClass::BuildScheduleTestBits();

	if ( IsCurSchedule( SCHED_CHASE_ENEMY ) )
	{
		SetCustomInterruptCondition( COND_LIGHT_DAMAGE );
		SetCustomInterruptCondition( COND_HEAVY_DAMAGE );
	}
}
bool CAI_StandoffBehavior::IsValidCover( const Vector &vecCoverLocation, const CAI_Hint *pHint )
{
	if ( !BaseClass::IsValidCover( vecCoverLocation, pHint ) )
		return false;

	if ( IsCurSchedule( SCHED_TAKE_COVER_FROM_BEST_SOUND ) )
		return true;

	return ( m_fIgnoreFronts || IsBehindBattleLines( vecCoverLocation ) );
}
//-----------------------------------------------------------------------------
// Purpose: Handle specific interactions with other NPCs
//-----------------------------------------------------------------------------
bool CNPC_Bug_Warrior::HandleInteraction( int interactionType, void *data, CBaseCombatCharacter *sender )
{
	// Check for a target found while burrowed
	if ( interactionType == g_interactionBugSquadAttacking )
	{
		// Ignore ones sent by me
		if ( sender == this )
			return false;

		// Interrupt me if I'm fleeing
		if ( IsCurSchedule(SCHED_WBUG_FLEE_ENEMY) || 
			 IsCurSchedule(SCHED_WBUG_CHASE_ENEMY_FAILED) )
		{
			SetCondition( COND_WBUG_STOP_FLEEING );
		}

		return true;
	}

	return false;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CAI_PolicingBehavior::GatherConditions( void )
{
	BaseClass::GatherConditions();

	// Mapmaker may have removed our goal while we're running our schedule
	if ( !m_hPoliceGoal )
	{
		Disable();
		return;
	}

	ClearCondition( COND_POLICE_TARGET_TOO_CLOSE_HARASS );
	ClearCondition( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS );

	CBaseEntity *pTarget = m_hPoliceGoal->GetTarget();

	if ( pTarget == NULL )
	{
		DevMsg( "ai_goal_police with NULL target entity!\n" );
		return;
	}

	// See if we need to knock out our target immediately
	if ( ShouldKnockOutTarget( pTarget ) )
	{
		SetCondition( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS );
	}

	float flDistSqr = ( m_hPoliceGoal->WorldSpaceCenter() - pTarget->WorldSpaceCenter() ).Length2DSqr();
	float radius = ( m_hPoliceGoal->GetRadius() * PATROL_RADIUS_RATIO );
	float zDiff = fabs( m_hPoliceGoal->WorldSpaceCenter().z - pTarget->WorldSpaceCenter().z );

	// If we're too far away, don't bother
	if ( flDistSqr < (radius*radius) && zDiff < 32.0f )
	{
		SetCondition( COND_POLICE_TARGET_TOO_CLOSE_HARASS );

		if ( flDistSqr < (m_hPoliceGoal->GetRadius()*m_hPoliceGoal->GetRadius()) )
		{
			SetCondition( COND_POLICE_TARGET_TOO_CLOSE_SUPPRESS );
		}
	}

	// If we're supposed to stop chasing (aggression over), return
	if ( m_bTargetIsHostile && m_flAggressiveTime < gpGlobals->curtime && IsCurSchedule(SCHED_CHASE_ENEMY) )
	{
		// Force me to re-evaluate my schedule
		GetOuter()->ClearSchedule( "Stopped chasing, aggression over" );
	}
}
示例#18
0
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_Assassin::BuildScheduleTestBits( void )
{
	SetNextThink( gpGlobals->curtime + 0.05 );

		//Don't allow any modifications when scripted
	if ( m_NPCState == NPC_STATE_SCRIPT )
		return;

	//Become interrupted if we're targetted when shooting an enemy
	if ( IsCurSchedule( SCHED_RANGE_ATTACK1 ) )
	{
		SetCustomInterruptCondition( COND_ASSASSIN_ENEMY_TARGETTING_ME );
	}
	
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CNPC_Monk::BuildScheduleTestBits( void )
{
	// FIXME: we need a way to make scenes non-interruptible
#if 0
	if ( IsCurSchedule( SCHED_RANGE_ATTACK1 ) || IsCurSchedule( SCHED_SCENE_GENERIC ) )
	{
		ClearCustomInterruptCondition( COND_LIGHT_DAMAGE );
		ClearCustomInterruptCondition( COND_HEAVY_DAMAGE );
		ClearCustomInterruptCondition( COND_NEW_ENEMY );
		ClearCustomInterruptCondition( COND_HEAR_DANGER );
	}
#endif

	// Don't interrupt while shooting the gun
	const Task_t* pTask = GetTask();
	if ( pTask && (pTask->iTask == TASK_RANGE_ATTACK1) )
	{
		ClearCustomInterruptCondition( COND_HEAVY_DAMAGE );
		ClearCustomInterruptCondition( COND_ENEMY_OCCLUDED );
		ClearCustomInterruptCondition( COND_HEAR_DANGER );
		ClearCustomInterruptCondition( COND_WEAPON_BLOCKED_BY_FRIEND );
		ClearCustomInterruptCondition( COND_WEAPON_SIGHT_OCCLUDED );
	}
}
示例#20
0
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void CAI_AssaultBehavior::GatherConditions( void )
{
	BaseClass::GatherConditions();

	// If this NPC is moving towards an assault point which
	//		a) Has a Next Assault Point, and 
	//		b) Is flagged to Clear On Arrival,
	// then hit and clear the assault point (fire all entity I/O) and move on to the next one without
	// interrupting the NPC's schedule. This provides a more fluid movement from point to point.
	if( IsCurSchedule( SCHED_MOVE_TO_ASSAULT_POINT ) && hl2_episodic.GetBool() )
	{
		if( m_hAssaultPoint && m_hAssaultPoint->HasSpawnFlags(SF_ASSAULTPOINT_CLEARONARRIVAL) && m_hAssaultPoint->m_NextAssaultPointName != NULL_STRING )
		{
			float flDist = GetAbsOrigin().DistTo( m_hAssaultPoint->GetAbsOrigin() );

			if( flDist <= GetOuter()->GetMotor()->MinStoppingDist() )
			{
				OnHitAssaultPoint();
				ClearAssaultPoint();

				AI_NavGoal_t goal( m_hAssaultPoint->GetAbsOrigin() );
				goal.pTarget = m_hAssaultPoint;
				
				if ( GetNavigator()->SetGoal( goal ) == false )
				{
					TaskFail( "Can't refresh assault path" );
				}
			}
		}

		if( OnStrictAssault() )
		{
			// Don't get distracted. Die trying if you have to.
			ClearCondition( COND_HEAR_DANGER );
		}
	}

	if ( IsForcingCrouch() && GetOuter()->IsCrouching() )
	{
		ClearCondition( COND_HEAR_BULLET_IMPACT );
	}
}
示例#21
0
void CASW_Parasite::BuildScheduleTestBits( void )
{
	//Don't allow any modifications when scripted
	if ( m_NPCState == NPC_STATE_SCRIPT )
		return;

	//Make sure we interrupt a run schedule if we can jump
	if ( IsCurSchedule(SCHED_CHASE_ENEMY) )
	{
		SetCustomInterruptCondition( COND_ENEMY_UNREACHABLE );
	}

	//Interrupt any schedule unless already fleeing, burrowing, burrowed, or unburrowing.
	if( GetFlags() & FL_ONGROUND )
	{
		if ( GetEnemy() == NULL )
		{
			SetCustomInterruptCondition( COND_HEAR_PHYSICS_DANGER );
		}					
	}
}
//-----------------------------------------------------------------------------
// Purpose: Return true if the player is further ahead on the lead route than I am
//-----------------------------------------------------------------------------
bool CAI_LeadBehavior::PlayerIsAheadOfMe( bool bForce )
{
	// Find the nearest point on our route to the player, and see if that's further 
	// ahead of us than our nearest point. 

	// If we're not leading, our route doesn't lead to the goal, so we can't use it.
	// If we just started leading, go ahead and test, and we'll build a temp route.
	if ( !m_bInitialAheadTest && !IsCurSchedule( SCHED_LEAD_PLAYER, false ) && !bForce )
		return false;

	m_bInitialAheadTest = false;

	Vector vecClosestPoint;
	if ( GetClosestPointOnRoute( AI_GetSinglePlayer()->GetAbsOrigin(), &vecClosestPoint ) )
	{
		// If the closest point is not right next to me, then 
		// the player is somewhere ahead of me on the route.
		if ( (vecClosestPoint - GetOuter()->GetAbsOrigin()).LengthSqr() > (32*32) )
			return true;
	}

	return false;
}
示例#23
0
int CASW_Harvester::SelectFlinchSchedule_ASW()
{
	// only flinch in easy mode
	if (ASWGameRules() && ASWGameRules()->GetSkillLevel() != 1)
		return SCHED_NONE;

	if ( !HasCondition(COND_HEAVY_DAMAGE) && !HasCondition(COND_LIGHT_DAMAGE) )
		return SCHED_NONE;

	if ( IsCurSchedule( SCHED_BIG_FLINCH ) )
		return SCHED_NONE;

	// only flinch if shot during a laying a critter
	if (! (GetTask() && (GetTask()->iTask == TASK_LAY_CRITTER)) )
		return SCHED_NONE;
		
	// Any damage. Break out of my current schedule and flinch.
	Activity iFlinchActivity = GetFlinchActivity( true, false );
	if ( HaveSequenceForActivity( iFlinchActivity ) )
		return SCHED_BIG_FLINCH;

	return SCHED_NONE;
}
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: 
//-----------------------------------------------------------------------------
void CAI_LeadBehavior::GatherConditions( void )
{
	BaseClass::GatherConditions();

	if ( HasGoal() )
	{
		// Fix for bad transition case (to investigate)
		if ( ( WorldSpaceCenter() - m_goal ).LengthSqr() > (64*64) && IsCurSchedule( SCHED_LEAD_AWAIT_SUCCESS, false)  )
		{
			GetOuter()->ClearSchedule( "Lead behavior - bad transition?" );
		}

		// We have to collect data about the person we're leading around.
		CBaseEntity *pFollower = AI_GetSinglePlayer();

		if( pFollower )
		{
			ClearCondition( COND_LEAD_FOLLOWER_VERY_CLOSE );
			ClearCondition( COND_LEAD_FOLLOWER_MOVING_TOWARDS_ME );

			// Check distance to the follower
			float flFollowerDist = ( WorldSpaceCenter() - pFollower->WorldSpaceCenter() ).Length();
			bool bLagging = flFollowerDist > (m_leaddistance*4);
			if ( bLagging )
			{
				if ( PlayerIsAheadOfMe() )
				{
					bLagging = false;
				}
			}

			// Player heading towards me?
			// Only factor this in if you're not too far from them
			if ( flFollowerDist < (m_leaddistance*4) )
			{
				Vector vecVelocity = pFollower->GetSmoothedVelocity();
				if ( VectorNormalize(vecVelocity) > 50 )
				{
					Vector vecToPlayer = (GetAbsOrigin() - pFollower->GetAbsOrigin());
					VectorNormalize( vecToPlayer );
					if ( DotProduct( vecVelocity, vecToPlayer ) > 0.5 )
					{
						SetCondition( COND_LEAD_FOLLOWER_MOVING_TOWARDS_ME );
						bLagging = false;
					}
				}
			}

			// If he's outside our lag range, consider him lagging
			if ( bLagging )
			{
				SetCondition( COND_LEAD_FOLLOWER_LAGGING );
				ClearCondition( COND_LEAD_FOLLOWER_NOT_LAGGING );
			}
			else
			{
				ClearCondition( COND_LEAD_FOLLOWER_LAGGING );
				SetCondition( COND_LEAD_FOLLOWER_NOT_LAGGING );

				// If he's really close, note that
				if ( flFollowerDist < m_leaddistance )
				{
					SetCondition( COND_LEAD_FOLLOWER_VERY_CLOSE );
				}
			}

			// To be considered not lagging, the follower must be visible, and within the lead distance
			if ( GetOuter()->FVisible( pFollower ) && GetOuter()->GetSenses()->ShouldSeeEntity( pFollower ) )
			{
				SetCondition( COND_LEAD_HAVE_FOLLOWER_LOS );
				m_LostLOSTimer.Stop();
			}
			else
			{
				ClearCondition( COND_LEAD_HAVE_FOLLOWER_LOS );

				// We don't have a LOS. But if we did have LOS, don't clear it until the timer is up.
				if ( m_LostLOSTimer.IsRunning() )
				{
					if ( m_LostLOSTimer.Expired() )
					{
						SetCondition( COND_LEAD_FOLLOWER_LAGGING );
						ClearCondition( COND_LEAD_FOLLOWER_NOT_LAGGING );
					}
				}
				else
				{
					m_LostLOSTimer.Start();
				}
			}

			// Now we want to see if the follower is lost. Being lost means being (far away || out of LOS ) 
			// && some time has passed. Also, lagging players are considered lost if the NPC's never delivered
			// the start speech, because it means the NPC should run to the player to start the lead.
			if( HasCondition( COND_LEAD_FOLLOWER_LAGGING ) )
			{
				if ( !m_hasspokenstart )
				{
					SetCondition( COND_LEAD_FOLLOWER_LOST );
				}
				else
				{
					if ( m_args.bStopScenesWhenPlayerLost )
					{
						// Try and stop me speaking my monolog, if I am
						if ( !m_hasPausedScenes && IsRunningScriptedScene( GetOuter() ) )
						{
							//Msg("Stopping scenes.\n");
							PauseActorsScriptedScenes( GetOuter(), false );
							m_hasPausedScenes = true;
						}
					}

					if( m_LostTimer.IsRunning() )
					{
						if( m_LostTimer.Expired() )
						{
							SetCondition( COND_LEAD_FOLLOWER_LOST );
						}
					}
					else
					{
						m_LostTimer.Start();
					}
				}
			}
			else
			{
				// If I was speaking a monolog, resume it
				if ( m_args.bStopScenesWhenPlayerLost && m_hasPausedScenes )
				{
					if ( IsRunningScriptedScene( GetOuter() ) )
					{
						//Msg("Resuming scenes.\n");
						ResumeActorsScriptedScenes( GetOuter(), false );
					}

					m_hasPausedScenes = false;
				}

				m_LostTimer.Stop();
				ClearCondition( COND_LEAD_FOLLOWER_LOST );
			}

			// Evaluate for success
			// Success right now means being stationary, close to the goal, and having the player close by
			if ( !( m_args.flags & AILF_NO_DEF_SUCCESS ) )
			{
				ClearCondition( COND_LEAD_SUCCESS );

				// Check Z first, and only check 2d if we're within that
				bool bWithinZ = fabs(GetLocalOrigin().z - m_goal.z) < 64;
				if ( bWithinZ && (GetLocalOrigin() - m_goal).Length2D() <= 64 )
				{
					if ( HasCondition( COND_LEAD_FOLLOWER_VERY_CLOSE ) )
					{
						SetCondition( COND_LEAD_SUCCESS );
					}
					else if ( m_successdistance )
					{
						float flDistSqr = (pFollower->GetAbsOrigin() - GetLocalOrigin()).Length2DSqr();
						if ( flDistSqr < (m_successdistance*m_successdistance) )
						{
							SetCondition( COND_LEAD_SUCCESS );
						}
					}
				}
			}
			if ( m_MoveMonitor.IsMarkSet() && m_MoveMonitor.TargetMoved( pFollower ) )
				SetCondition( COND_LEAD_FOLLOWER_MOVED_FROM_MARK );
			else
				ClearCondition( COND_LEAD_FOLLOWER_MOVED_FROM_MARK );
		}
	}

	if( m_args.bLeadDuringCombat )
	{
		ClearCondition( COND_LIGHT_DAMAGE );
		ClearCondition( COND_HEAVY_DAMAGE );
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CAI_LeadBehavior::GetClosestPointOnRoute( const Vector &targetPos, Vector *pVecClosestPoint )
{
	AI_Waypoint_t *waypoint = GetOuter()->GetNavigator()->GetPath()->GetCurWaypoint();
	AI_Waypoint_t *builtwaypoints = NULL;
	if ( !waypoint )
	{
		// We arrive here twice when lead behaviour starts:
		//	- When the lead behaviour is first enabled. We have no schedule. We want to know if the player is ahead of us.
		//	- A frame later when we've chosen to lead the player, but we still haven't built our route. We know that the
		//	  the player isn't lagging, so it's safe to go ahead and simply say he's ahead of us. This avoids building 
		//	  the temp route twice.
		if ( IsCurSchedule( SCHED_LEAD_PLAYER, false ) )
			return true;

		// Build a temp route to the gold and use that
		builtwaypoints = GetOuter()->GetPathfinder()->BuildRoute( GetOuter()->GetAbsOrigin(), m_goal, NULL, GetOuter()->GetDefaultNavGoalTolerance(), GetOuter()->GetNavType(), true );
		if ( !builtwaypoints )
			return false;

		GetOuter()->GetPathfinder()->UnlockRouteNodes( builtwaypoints );
		waypoint = builtwaypoints;
	}

	// Find the nearest node to the target (going forward)
	float		flNearestDist2D	= 999999999;
	float		flNearestDist	= 999999999;
	float		flPathDist, flPathDist2D;

	Vector vecNearestPoint(0, 0, 0);
	Vector vecPrevPos = GetOuter()->GetAbsOrigin();
	for ( ; (waypoint != NULL) ; waypoint = waypoint->GetNext() )
	{
		// Find the closest point on the line segment on the path
		Vector vecClosest;
		CalcClosestPointOnLineSegment( targetPos, vecPrevPos, waypoint->GetPos(), vecClosest );
		/*
		if ( builtwaypoints )
		{
			NDebugOverlay::Line( vecPrevPos, waypoint->GetPos(), 0,0,255,true, 10.0 );
		}
		*/
		vecPrevPos = waypoint->GetPos();

		// Find the distance between this test point and our goal point
		flPathDist2D = vecClosest.AsVector2D().DistToSqr( targetPos.AsVector2D() );
		if ( flPathDist2D > flNearestDist2D )
			continue;

		flPathDist = vecClosest.z - targetPos.z;
		flPathDist *= flPathDist;
		flPathDist += flPathDist2D;
		if (( flPathDist2D == flNearestDist2D ) && ( flPathDist >= flNearestDist ))
			continue;

		flNearestDist2D	= flPathDist2D;
		flNearestDist	= flPathDist;
		vecNearestPoint	= vecClosest;
	}

	if ( builtwaypoints )
	{
		//NDebugOverlay::Line( vecNearestPoint, targetPos, 0,255,0,true, 10.0 );
		DeleteAll( builtwaypoints );
	}

	*pVecClosestPoint = vecNearestPoint;
	return true;
}
示例#27
0
bool CASW_Alien_Jumper::IsJumping()
{	
	return IsCurSchedule(SCHED_ASW_ALIEN_JUMP);
}
void CAI_LeadBehavior::StartTask( const Task_t *pTask )
{
	switch ( pTask->iTask )
	{
		case TASK_LEAD_FACE_GOAL:
		{
			if ( m_goalyaw != -1 )
			{
				GetMotor()->SetIdealYaw( m_goalyaw ); 
			}

			TaskComplete();
			break;
		}

		case TASK_LEAD_SUCCEED:
		{
			Speak( TLK_LEAD_SUCCESS );
			NotifyEvent( LBE_SUCCESS );

			break;
		}

		case TASK_LEAD_ARRIVE:
		{
			// Only speak the first time we arrive
			if ( !m_hasspokenarrival )
			{
				Speak( TLK_LEAD_ARRIVAL );
				NotifyEvent( LBE_ARRIVAL );

				m_hasspokenarrival = true;
			}
			else
			{
				TaskComplete();
			}
			
			break;
		}
		
		case TASK_STOP_LEADING:
		{
			ClearGoal();
			TaskComplete();
			break;
		}

		case TASK_GET_PATH_TO_LEAD_GOAL:
		{
			if ( GetNavigator()->SetGoal( m_goal ) )
			{
				TaskComplete();
			}
			else
			{
				TaskFail("NO PATH");
			}
			break;
		}
		
		case TASK_LEAD_GET_PATH_TO_WAITPOINT:
		{
			if ( GetNavigator()->SetGoal( m_waitpoint ) )
			{
				TaskComplete();
			}
			else
			{
				TaskFail("NO PATH");
			}
			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 ) ) )
			{
				ChainStartTask( TASK_RUN_PATH );
			}
			else
			{
				ChainStartTask( TASK_WALK_PATH );
			}
			break;
		}

		case TASK_LEAD_WAVE_TO_PLAYER:
		{
			// Wave to the player if we can see him. Otherwise, just idle.
			if ( HasCondition( COND_SEE_PLAYER ) )
			{
				Speak( TLK_LEAD_ATTRACTPLAYER );
				if ( HaveSequenceForActivity(ACT_SIGNAL1) )
				{
					SetActivity(ACT_SIGNAL1);
				}
			}
			else
			{
				SetActivity(ACT_IDLE);
			}

			TaskComplete();
			break;
		}

		case TASK_LEAD_PLAYER_NEEDS_WEAPON:
		{
			float flAvailableTime = GetOuter()->GetExpresser()->GetSemaphoreAvailableTime( GetOuter() );

			// if someone else is talking, don't speak
			if ( flAvailableTime <= gpGlobals->curtime )
			{
				Speak( TLK_LEAD_MISSINGWEAPON );
			}

			SetActivity(ACT_IDLE);
			TaskComplete();
			break;
		}

		case TASK_LEAD_SPEAK_START:
		{
			m_hasspokenstart = true;

			Speak( TLK_LEAD_START );
			SetActivity(ACT_IDLE);
			TaskComplete();
			break;
		}

		case TASK_LEAD_MOVE_TO_RANGE:
		{
			// If we haven't spoken our start speech, move closer
			if ( !m_hasspokenstart)
			{
				ChainStartTask( TASK_MOVE_TO_GOAL_RANGE, m_leaddistance - 24 );
			}
			else
			{
				ChainStartTask( TASK_MOVE_TO_GOAL_RANGE, m_retrievedistance );
			}
			break;
		}

		case TASK_LEAD_RETRIEVE_WAIT:
		{
			m_MoveMonitor.SetMark( AI_GetSinglePlayer(), 24 );
			ChainStartTask( TASK_WAIT_INDEFINITE );
			break;
		}

		case TASK_STOP_MOVING:
		{
			BaseClass::StartTask( pTask);

			if ( IsCurSchedule( SCHED_LEAD_PAUSE, false ) && pTask->flTaskData == 1 )
			{
				GetNavigator()->SetArrivalDirection( GetTarget() );
			}
			break;
		}

		case TASK_WAIT_FOR_SPEAK_FINISH:
		{
			BaseClass::StartTask( pTask);

			if( GetOuter()->GetState() == NPC_STATE_COMBAT )
			{
				// Don't stand around jabbering in combat. 
				TaskComplete();
			}

			// If we're not supposed to wait for the player, don't wait for speech to finish.
			// Instead, just wait a wee tad, and then start moving. NPC will speak on the go.
			if ( TaskIsRunning() && !m_args.iRetrievePlayer )
			{
				if ( gpGlobals->curtime - GetOuter()->GetTimeTaskStarted() > 0.3 )
				{
					TaskComplete();
				}
			}
			break;
		}

		default:
			BaseClass::StartTask( pTask);
	}
}
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);
	}
}
示例#30
0
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pTask - 
//-----------------------------------------------------------------------------
void CAI_AssaultBehavior::RunTask( const Task_t *pTask )
{
	switch( pTask->iTask )
	{
	case TASK_WAIT_ASSAULT_DELAY:
	case TASK_AWAIT_ASSAULT_TIMEOUT:
		if ( m_hAssaultPoint )
		{
			if ( m_hAssaultPoint->m_bInputForcedClear || (m_hAssaultPoint->m_bClearOnContact && HasCondition( COND_SEE_ENEMY )) )
			{
				// If we're on an assault that should clear on contact, clear when we see an enemy
				TaskComplete();
			}
		}

		if( GetOuter()->IsWaitFinished() && ( pTask->iTask == TASK_WAIT_ASSAULT_DELAY || !m_hAssaultPoint->m_bNeverTimeout ) )
		{
			TaskComplete();
		}
		break;

	case TASK_FACE_RALLY_POINT:
	case TASK_FACE_ASSAULT_POINT:
		GetMotor()->UpdateYaw();

		if( HasCondition( COND_CAN_RANGE_ATTACK1 ) )
		{
			// Out early if the NPC can attack.
			TaskComplete();
		}

		if ( GetOuter()->FacingIdeal() )
		{
			TaskComplete();
		}
		break;

	case TASK_AWAIT_CUE:
		// If we've lost our rally point, abort
		if ( !m_hRallyPoint )
		{
			TaskFail("No rally point.");
			break;
		}

		if( PollAssaultCue() )
		{
			TaskComplete();
		}

		if ( IsForcingCrouch() )
			break;

		if( GetOuter()->GetEnemy() && m_hRallyPoint->m_RallySequenceName == NULL_STRING )
		{
			// I have an enemy and I'm NOT playing a custom animation.
			ChainRunTask( TASK_FACE_ENEMY, 0 );
		}
		break;

	case TASK_WAIT_FOR_MOVEMENT:
		if ( ai_debug_assault.GetBool() )
		{
			if ( IsCurSchedule( SCHED_MOVE_TO_ASSAULT_POINT ) )
			{
				NDebugOverlay::Line( WorldSpaceCenter(), GetNavigator()->GetGoalPos(), 255,0,0, true,0.1);
				NDebugOverlay::Box( GetNavigator()->GetGoalPos(), -Vector(10,10,10), Vector(10,10,10), 255,0,0, 8, 0.1 );
			}
			else if ( IsCurSchedule( SCHED_MOVE_TO_RALLY_POINT ) )
			{
				NDebugOverlay::Line( WorldSpaceCenter(), GetNavigator()->GetGoalPos(), 0,255,0, true,0.1);
				NDebugOverlay::Box( GetNavigator()->GetGoalPos(), -Vector(10,10,10), Vector(10,10,10), 0,255,0, 8, 0.1 );
			}
		}

		if ( m_hAssaultPoint && (m_hAssaultPoint->m_bInputForcedClear || (m_hAssaultPoint->m_bClearOnContact && HasCondition( COND_SEE_ENEMY ))) )
		{
			DevMsg( "Assault Cleared due to Contact or Input!\n" );
			ClearAssaultPoint();
			TaskComplete();
			return;
		}

		BaseClass::RunTask( pTask );
		break;

	default:
		BaseClass::RunTask( pTask );
		break;
	}
}