//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: Simple, small, free-standing tools for building AIs // //=============================================================================// #ifndef AI_UTILS_H #define AI_UTILS_H #include "simtimer.h" #include "ai_component.h" #if defined( _WIN32 ) #pragma once #endif //----------------------------------------------------------------------------- // // Function to get the local player. AI does not want asserts or warnings, // just NULL result // //----------------------------------------------------------------------------- inline CBasePlayer *AI_GetSinglePlayer() { if ( gpGlobals->maxClients > 1 ) { return NULL; } return UTIL_GetLocalPlayer(); } inline bool AI_IsSinglePlayer() { return ( gpGlobals->maxClients == 1 ); } //----------------------------------------------------------------------------- // // CAI_MoveMonitor // // Purpose: Watch an entity, trigger if moved more than a tolerance // //----------------------------------------------------------------------------- class CAI_MoveMonitor { public: CAI_MoveMonitor() : m_vMark( 0, 0, 0 ), m_flMarkTolerance( NO_MARK ) { } void SetMark( const Vector &v, float tolerance ) { m_vMark = v; m_flMarkTolerance = tolerance; } void SetMark( CBaseEntity *pEntity, float tolerance ) { if ( pEntity ) { m_vMark = pEntity->GetAbsOrigin(); m_flMarkTolerance = tolerance ; } } void ClearMark() { m_flMarkTolerance = NO_MARK; } bool IsMarkSet() { return ( m_flMarkTolerance != NO_MARK ); } bool TargetMoved( const Vector &v ) { if ( IsMarkSet() ) { float distance = ( m_vMark - v ).Length(); if ( distance > m_flMarkTolerance ) return true; } return false; } bool TargetMoved2D( const Vector2D &v ) { if ( IsMarkSet() ) { float distance = ( m_vMark.AsVector2D() - v ).Length(); if ( distance > m_flMarkTolerance ) return true; } return false; } bool TargetMoved( CBaseEntity *pEntity ) { if ( pEntity == NULL ) { return false; } return TargetMoved( pEntity->GetAbsOrigin() ); } bool TargetMoved2D( CBaseEntity *pEntity ) { if ( pEntity == NULL ) { return false; } return TargetMoved2D( pEntity->GetAbsOrigin().AsVector2D() ); } Vector GetMarkPos() { return m_vMark; } private: enum { NO_MARK = -1 }; Vector m_vMark; float m_flMarkTolerance; DECLARE_SIMPLE_DATADESC(); }; //----------------------------------------------------------------------------- // // CAI_ShotRegulator // // Purpose: Assists in creating non-constant bursty shooting style // //----------------------------------------------------------------------------- class CAI_ShotRegulator { public: CAI_ShotRegulator(); // Sets the various parameters for burst (this one's for backwards compatibility) // NOTE: This will modify the next shot time void SetParameters( int minShotsPerBurst, int maxShotsPerBurst, float minRestTime, float maxRestTime = 0.0 ); // NOTE: The next 3 methods will *not* modify the next shot time // Sets the number of shots to shoot in a single burst void SetBurstShotCountRange( int minShotsPerBurst, int maxShotsPerBurst ); // How much time should I rest between bursts? void SetRestInterval( float flMinRestInterval, float flMaxRestInterval ); // How much time should I wait in between shots in a single burst? void SetBurstInterval( float flMinBurstInterval, float flMaxBurstInterval ); // Poll the current parameters void GetBurstShotCountRange( int *pMinShotsPerBurst, int *pMaxShotsPerBurst ) const; void GetRestInterval( float *pMinRestInterval, float *pMaxRestInterval ) const; void GetBurstInterval( float *pMinBurstInterval, float *pMaxBurstInterval ) const; // Reset the state. If true, the next burst time is set to now, // otherwise it'll wait one rest interval before shooting void Reset( bool bStartShooting = true ); // Should we shoot? bool ShouldShoot() const; // When will I shoot next? float NextShotTime() const; // Am I in the middle of a rest period? bool IsInRestInterval() const; // NOTE: These will not modify the next shot time int GetBurstShotsRemaining() const; void SetBurstShotsRemaining( int shots ); // Call this when the NPC fired the weapon; void OnFiredWeapon(); // Causes us to potentially delay our shooting time void FireNoEarlierThan( float flTime ); // Prevent/Allow shooting void EnableShooting( void ); void DisableShooting( void ); private: float m_flNextShotTime; bool m_bInRestInterval; unsigned short m_nBurstShotsRemaining; unsigned short m_nMinBurstShots, m_nMaxBurstShots; float m_flMinRestInterval, m_flMaxRestInterval; float m_flMinBurstInterval, m_flMaxBurstInterval; bool m_bDisabled; DECLARE_SIMPLE_DATADESC(); }; //----------------------------------------------------------------------------- // // CAI_AccelDecay // // Purpose: Maintain a smooth acceleration, deceleration curve // //----------------------------------------------------------------------------- class CAI_AccelDecay { public: CAI_AccelDecay(); void SetParameters( float minVelocity, float maxVelocity, float accelPercent, float decelPercent ); float Update( float flCurrent, float flTarget, float flInterval ); void ResetVelocity( float flVelocity = 0.0f ); void SetMaxVelocity( float maxVelocity ); private: float m_velocity; float m_maxVelocity; // = 300; float m_minVelocity; // = 10; float m_invDecay; // 0.8 // maintain X percent of velocity when slowing down float m_decayTime;// 0.4161 // Sum( 1..cycle, HEIGHTINVDECAY^cycle ) float m_accel; // 0.5 // accel toward maxVelocity by X percent each cycle DECLARE_SIMPLE_DATADESC(); }; //----------------------------------------------------------------------------- // // Purpose: Utility to allow place grace in cover // //----------------------------------------------------------------------------- struct AI_FreePassParams_t { float timeToTrigger; // How long after not detected to issue pass float duration; // How long in the open pass before revoked float moveTolerance; // How far in open needed to move to revoke pass float refillRate; // After hiding again during pass, how quickly to reinstitute pass(seconds per second) float coverDist; // When hiding, how far from an obstructing object needed to be considered in cover float peekTime; // How long allowed to peek float peekTimeAfterDamage; // How long allowed to peek after damaged by float peekEyeDist; // how far spaced out the eyes are float peekEyeDistZ; // how far below eye position to test eyes (handles peek up) DECLARE_SIMPLE_DATADESC(); }; //------------------------------------- class CAI_FreePass : public CAI_Component { public: CAI_FreePass() : m_FreePassTimeRemaining(0) { } void Reset( float passTime = -1, float moveTolerance = -1 ); void SetPassTarget( CBaseEntity *pTarget ) { m_hTarget = pTarget; m_FreePassTimeRemaining = 0; } CBaseEntity * GetPassTarget() { return m_hTarget; } void SetParams( const AI_FreePassParams_t ¶ms ) { m_Params = params; } const AI_FreePassParams_t &GetParams() const { return m_Params; } //--------------------------------- // Free pass //--------------------------------- void Update(); bool HasPass(); void Revoke( bool bUpdateMemory = false ); float GetTimeRemaining() { return m_FreePassTimeRemaining; } void SetTimeRemaining( float passTime ) { m_FreePassTimeRemaining = passTime; } bool ShouldAllowFVisible( bool bBaseResult ); private: EHANDLE m_hTarget; float m_FreePassTimeRemaining; CAI_MoveMonitor m_FreePassMoveMonitor; AI_FreePassParams_t m_Params; DECLARE_SIMPLE_DATADESC(); }; //----------------------------------------------------------------------------- class CTraceFilterNav : public CTraceFilterSimple { public: CTraceFilterNav( CAI_BaseNPC *pProber, bool bIgnoreTransientEntities, const IServerEntity *passedict, int collisionGroup, bool m_bAllowPlayerAvoid = true ); bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ); private: CAI_BaseNPC *m_pProber; bool m_bIgnoreTransientEntities; bool m_bCheckCollisionTable; bool m_bAllowPlayerAvoid; }; extern string_t g_iszFuncBrushClassname; #endif // AI_UTILS_H