//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //============================================================================= #ifndef AI_BEHAVIOR_PASSENGER_H #define AI_BEHAVIOR_PASSENGER_H #ifdef _WIN32 #pragma once #endif #include "ai_speech.h" #include "ai_behavior.h" #include "ai_utils.h" #include "vehicle_jeep_episodic.h" #define STOPPED_VELOCITY_THRESHOLD 32.0f #define STOPPED_VELOCITY_THRESHOLD_SQR (STOPPED_VELOCITY_THRESHOLD*STOPPED_VELOCITY_THRESHOLD) #define STARTED_VELOCITY_THRESHOLD 64.0f #define STARTED_VELOCITY_THRESHOLD_SQR (STARTED_VELOCITY_THRESHOLD*STARTED_VELOCITY_THRESHOLD) // Custom activities extern int ACT_PASSENGER_IDLE; extern int ACT_PASSENGER_RANGE_ATTACK1; // --------------------------------------------- // Vehicle state // --------------------------------------------- struct passengerVehicleState_t { Vector m_vecLastLocalVelocity; Vector m_vecDeltaVelocity; QAngle m_vecLastAngles; float m_flNextWarningTime; float m_flLastSpeedSqr; bool m_bPlayerInVehicle; bool m_bWasBoosting; bool m_bWasOverturned; DECLARE_SIMPLE_DATADESC(); }; // --------------------------------------------- // Passenger intent // --------------------------------------------- enum passesngerVehicleIntent_e { PASSENGER_INTENT_NONE, PASSENGER_INTENT_ENTER, // We want to be in the vehicle PASSENGER_INTENT_EXIT, // We want to be outside the vehicle }; // --------------------------------------------- // Passenger state functions // --------------------------------------------- enum PassengerState_e { PASSENGER_STATE_OUTSIDE = 0, // Not in the vehicle PASSENGER_STATE_ENTERING, PASSENGER_STATE_INSIDE, PASSENGER_STATE_EXITING, }; class CAI_PassengerBehavior : public CAI_SimpleBehavior { DECLARE_CLASS( CAI_PassengerBehavior, CAI_SimpleBehavior ); DECLARE_DATADESC() public: CAI_PassengerBehavior( void ); enum { // Schedules SCHED_PASSENGER_IDLE = BaseClass::NEXT_SCHEDULE, SCHED_PASSENGER_ENTER_VEHICLE, SCHED_PASSENGER_EXIT_VEHICLE, SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE, SCHED_PASSENGER_ENTER_VEHICLE_PAUSE, SCHED_PASSENGER_RUN_TO_ENTER_VEHICLE_FAILED, SCHED_PASSENGER_PLAY_SCRIPTED_ANIM, NEXT_SCHEDULE, // Tasks TASK_PASSENGER_ENTER_VEHICLE = BaseClass::NEXT_TASK, TASK_PASSENGER_EXIT_VEHICLE, TASK_PASSENGER_ATTACH_TO_VEHICLE, TASK_PASSENGER_DETACH_FROM_VEHICLE, TASK_PASSENGER_SET_IDEAL_ENTRY_YAW, NEXT_TASK, // Conditions COND_PASSENGER_HARD_IMPACT = BaseClass::NEXT_CONDITION, COND_PASSENGER_ENTERING, COND_PASSENGER_EXITING, COND_PASSENGER_VEHICLE_STARTED, COND_PASSENGER_VEHICLE_STOPPED, COND_PASSENGER_OVERTURNED, COND_PASSENGER_CANCEL_ENTER, COND_PASSENGER_ERRATIC_DRIVING, COND_PASSENGER_PLAYER_ENTERED_VEHICLE, COND_PASSENGER_PLAYER_EXITED_VEHICLE, COND_PASSENGER_JOSTLE_SMALL, NEXT_CONDITION }; bool ForceVehicleInteraction( const char *lpszInteractionName, CBaseCombatCharacter *pOther ); virtual bool CanSelectSchedule( void ); virtual int SelectSchedule( void ); virtual int SelectFailSchedule( int failedSchedule, int failedTask, AI_TaskFailureCode_t taskFailCode ); virtual void RunTask( const Task_t *pTask ); virtual void StartTask( const Task_t *pTask ); virtual void BuildScheduleTestBits( void ); virtual int TranslateSchedule( int scheduleType ); virtual void GetEntryTarget( Vector *vecOrigin, QAngle *vecAngles ); virtual void GatherConditions( void ); virtual void ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet ); virtual void Teleport( const Vector *newPosition, const QAngle *newAngles, const Vector *newVelocity ); virtual void ClearSchedule( const char *szReason ); virtual bool IsInterruptable( void ); virtual void PrescheduleThink( void ); virtual void CancelEnterVehicle( void ); virtual const char *GetName( void ) { return "Passenger"; } virtual string_t GetRoleName( void ) { return MAKE_STRING( "passenger" ); } // Enable/disable code void Enable( CPropJeepEpisodic *pVehicle, bool bImmediateEntrance = false ); void Disable( void ); bool IsEnabled( void ) const { return m_bEnabled; } virtual void EnterVehicle( void ); virtual void ExitVehicle( void ); void AddPhysicsPush( float force ); CPropVehicleDriveable *GetTargetVehicle( void ) const { return m_hVehicle; } PassengerState_e GetPassengerState( void ) const { return m_PassengerState; } virtual void OnRestore(); protected: virtual int SelectTransitionSchedule( void ); bool SpeakIfAllowed( AIConcept_t concept, const char *modifiers = NULL, bool bRespondingToPlayer = false, char *pszOutResponseChosen = NULL, size_t bufsize = 0 ); bool CanExitVehicle( void ); void SetTransitionSequence( int nSequence ); void AttachToVehicle( void ); virtual void OnExitVehicleFailed( void ) { } // NPC attempted to leave vehicle, but was unable to virtual void GatherVehicleStateConditions( void ); // ------------------------------------------ // Entry/exit transition code // ------------------------------------------ virtual void FinishEnterVehicle( void ); virtual void FinishExitVehicle( void ); void DetachFromVehicle( void ); void DrawDebugTransitionInfo( const Vector &vecIdealPos, const QAngle &vecIdealAngles, const Vector &vecAnimPos, const QAngle &vecAnimAngles ); bool GetEntryPoint( int nSequence, Vector *vecEntryPoint, QAngle *vecEntryAngles = NULL ); bool GetExitPoint( int nSequence, Vector *vecExitPoint, QAngle *vecExitAngles = NULL ); bool PointIsNavigable( const Vector &vecTargetPos ); bool ReserveEntryPoint( VehicleSeatQuery_e eSeatSearchType ); bool ReserveExitPoint( void ); bool FindGroundAtPosition( const Vector &in, float flUpDelta, float flDownDelta, Vector *out ); bool DoTransitionMovement( void ); bool GetSequenceBlendAmount( float flCycle, float *posBlend, float *angBlend ); bool LocalIntervalMovement( float flInterval, bool &bMoveSeqFinished, Vector &newPosition, QAngle &newAngles ); void GetTransitionAnimationIdeal( float flCycle, const Vector &vecTargetPos, const QAngle &vecTargetAngles, Vector *idealOrigin, QAngle *idealAngles ); float GetNextCycleForInterval( int nSequence, float flInterval ); void GetLocalVehicleVelocity( Vector *pOut ); void CacheBlendTargets( void ); void InitVehicleState( void ); int FindEntrySequence( bool bNearest = false ); int FindExitSequence( void ); bool IsValidTransitionPoint( const Vector &vecStartPos, const Vector &vecEndPos ); void SetPassengerState( PassengerState_e state ) { m_PassengerState = state; } PassengerState_e m_PassengerState; // State we're in, for the vehicle // --------------------------------------------- bool IsPassengerHostile( void ); passengerVehicleState_t m_vehicleState; // Internal vehicle state CHandle m_hVehicle; // The vehicle we're bound to CHandle m_hBlocker; // Blocking entity for space reservation Vector m_vecTargetPosition; // Target destination for exiting the vehicle QAngle m_vecTargetAngles; // Target angles for exiting the vehicle bool m_bEnabled; // If the behavior is running passesngerVehicleIntent_e m_PassengerIntent; // Gives us information about whether we're meant to get in/out, etc. int m_nTransitionSequence; // Animation we're using to transition with float m_flOriginStartFrame; float m_flOriginEndFrame; float m_flAnglesStartFrame; float m_flAnglesEndFrame; protected: DEFINE_CUSTOM_SCHEDULE_PROVIDER; }; class CTraceFilterVehicleTransition : public CTraceFilterSkipTwoEntities { public: DECLARE_CLASS( CTraceFilterVehicleTransition, CTraceFilterSkipTwoEntities ); CTraceFilterVehicleTransition( const IHandleEntity *passentity, const IHandleEntity *passentity2, int collisionGroup ) : CTraceFilterSkipTwoEntities( passentity, passentity2, collisionGroup ) {} bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) { bool bRet = BaseClass::ShouldHitEntity( pServerEntity, contentsMask ); CBaseEntity *pEntity = EntityFromEntityHandle( pServerEntity ); if ( pEntity ) { IPhysicsObject *pPhys = pEntity->VPhysicsGetObject(); if ( pPhys ) { // Ignore physics objects // TODO: This will have to be fleshed out more as cases arise if ( pPhys->IsMoveable() && pPhys->GetMass() < 80.0f ) return false; } } return bRet; } }; #endif // AI_BEHAVIOR_PASSENGER_H