/*
================

AI.h

================
*/

#ifndef __AI_H__
#define __AI_H__

// moved all motion related code to AI_Move.h
#ifndef __AI_MOVE_H__
	#include "AI_Move.h"
#endif
#ifndef __AAS_TACTICAL_H__
	#include "AAS_tactical.h"
#endif	

typedef enum {
	AITACTICAL_NONE,
	AITACTICAL_MELEE,					// Rush towards the enemy and perform melee attacks when within range
	AITACTICAL_MOVE_FOLLOW,				// Move towards leader, stop when within range
	AITACTICAL_MOVE_TETHER,				// Move within tether, stop when within tether
	AITACTICAL_MOVE_PLAYERPUSH,			// Move away when the player pushes us (or another ai entity pushes us that was pushe by player)
	AITACTICAL_COVER,					// Move to cover and perform attacks from that cover position
 	AITACTICAL_COVER_FLANK,
 	AITACTICAL_COVER_ADVANCE,
 	AITACTICAL_COVER_RETREAT,
 	AITACTICAL_COVER_AMBUSH,
	AITACTICAL_RANGED,					// Move to position in which the enemy can be attacked from range, stop when there and attack enemy
	AITACTICAL_TURRET,					// Stay in current position and attack enemy
	AITACTICAL_HIDE,					// Move to a position where we cannot be seen by our enemy
	AITACTICAL_PASSIVE,					// Stay in current position with multiple idles, twitch animations, and conversations

	AITACTICAL_MAX
} aiTactical_t;

typedef enum  {
	AICTRESULT_OK,
	AICTRESULT_SKIP,
	AICTRESULT_NOMOVE,
} aiCTResult_t;

const int AITACTICAL_NONE_BIT				= BIT(AITACTICAL_NONE);
const int AITACTICAL_MELEE_BIT				= BIT(AITACTICAL_MELEE);
const int AITACTICAL_MOVE_FOLLOW_BIT		= BIT(AITACTICAL_MOVE_FOLLOW);
const int AITACTICAL_MOVE_TETHER_BIT		= BIT(AITACTICAL_MOVE_TETHER);
const int AITACTICAL_MOVE_PLAYERPUSH_BIT	= BIT(AITACTICAL_MOVE_PLAYERPUSH);
const int AITACTICAL_COVER_BIT				= BIT(AITACTICAL_COVER);
const int AITACTICAL_COVER_FLANK_BIT		= BIT(AITACTICAL_COVER_FLANK);
const int AITACTICAL_COVER_ADVANCE_BIT		= BIT(AITACTICAL_COVER_ADVANCE);
const int AITACTICAL_COVER_RETREAT_BIT		= BIT(AITACTICAL_COVER_RETREAT);
const int AITACTICAL_COVER_AMBUSH_BIT		= BIT(AITACTICAL_COVER_AMBUSH);
const int AITACTICAL_RANGED_BIT				= BIT(AITACTICAL_RANGED);
const int AITACTICAL_TURRET_BIT				= BIT(AITACTICAL_TURRET);
const int AITACTICAL_HIDE_BIT				= BIT(AITACTICAL_HIDE);
const int AITACTICAL_PASSIVE_BIT			= BIT(AITACTICAL_PASSIVE);

const int AITACTICAL_COVER_BITS				= (AITACTICAL_COVER_BIT|AITACTICAL_COVER_FLANK_BIT|AITACTICAL_COVER_ADVANCE_BIT|AITACTICAL_COVER_RETREAT_BIT|AITACTICAL_COVER_AMBUSH_BIT);
const int AITACTICAL_RANGED_BITS			= (AITACTICAL_RANGED_BIT);
const int AITACTICAL_NONMOVING_BITS			= (AITACTICAL_NONE_BIT|AITACTICAL_TURRET_BIT|AITACTICAL_PASSIVE_BIT);

typedef enum {
	TALKMSG_NONE,
	TALKMSG_PRIMARY,
	TALKMSG_SECONDARY,
	TALKMSG_LOOP,
} talkMessage_t;

typedef enum {
	AIFLAGOVERRIDE_DAMAGE,
	AIFLAGOVERRIDE_DISABLEPAIN,
	AIFLAGOVERRIDE_NOTURN,
	AIFLAGOVERRIDE_NOGRAVITY
} aiFlagOverride_t;

typedef enum {
	TALK_NEVER,						// Never talk to the player
	TALK_DEAD,						// Cant talk due to being dead
	TALK_OK,						// Can talk
	TALK_FOLLOW,					// Talking to will cause a follow
	TALK_BUSY,						// Cant talk right now, is busy
	TALK_WAIT,						// Wait a bit - he's probably in the middle of a conversation (this is so you can still see their names but they won't talk to you when clicked on)
	NUM_TALK_STATES
} talkState_t;

//chance that AI will make an announcement when they have the option (0 - 1.0f)
#define AISPEAK_CHANCE 0.2f

typedef enum {
	AIFOCUS_NONE,
	AIFOCUS_LEADER,
	AIFOCUS_TARGET,
	AIFOCUS_TALK,
	AIFOCUS_PLAYER,
	AIFOCUS_USE_DIRECTIONAL_MOVE,
	AIFOCUS_ENEMY = AIFOCUS_USE_DIRECTIONAL_MOVE,
	AIFOCUS_COVER,
	AIFOCUS_COVERLOOK,
	AIFOCUS_HELPER,
	AIFOCUS_TETHER,
	AIFOCUS_MAX
} aiFocus_t;

typedef enum {
	AIMOVESPEED_DEFAULT,			// Choose run/walk depending on situation
	AIMOVESPEED_RUN,				// Always run
	AIMOVESPEED_WALK,				// alwasy walk
} aiMoveSpeed_t;

typedef struct rvAIFuncs_s {
	rvScriptFuncUtility		first_sight;		// script to run when an enemy is first sighted
	rvScriptFuncUtility		sight;				// script to run every time an enemy is sighted
	rvScriptFuncUtility		pain;				// script to run when the AI takes pain
	rvScriptFuncUtility		damage;				// script to run when the AI takes damage
	rvScriptFuncUtility		death;				// script to run when the AI dies
	rvScriptFuncUtility		attack;				// script to run when attacking an enemy
	rvScriptFuncUtility		init;				// script to run on initialization
	rvScriptFuncUtility		onclick;			// script to run when a friendly AI is clicked on
	rvScriptFuncUtility		launch_projectile;	// script to run when a projectile is launched
	rvScriptFuncUtility		footstep;			// script to run on a footstep
} rvAIFuncs_t;

typedef struct rvAICombat_s{
	struct combatFlags_s {
		bool		ignoreEnemies		:1;
		bool		alert				:1;
 		bool		aware				:1;
		bool		tetherNoBreak		:1;				// Set to true to prevent enemies from breaking tethers
		bool		tetherAutoBreak		:1;				// Set to true to automatically break tethers when within range
		bool		tetherOutOfRange	:1;				// Set to true when we are out of range of our curren tether
		bool		seenEnemyDirectly	:1;				// Has directly seen an enemy (as opposed to having heard or been told about him)
		bool		noChatter			:1;				// No combat announcements
		bool		crouchViewClear		:1;				// Can I crouch at the position that I stopped at?
	} fl;
	
	float					max_chasing_turn;
	float					shotAtTime;
	float					shotAtAngle;
	idVec2					hideRange;
	idVec2					attackRange;
	int						attackSightDelay;
	float					meleeRange;
	float					aggressiveRange;			// Range to become more aggressive
	float					aggressiveScale;			// Scale to use when altering numbers due to aggression
 	int						investigateTime;

	float					visStandHeight;				// Height to check enemy visibiliy while standing
	float					visCrouchHeight;			// Height to check enemy visiblity while crouching
 	float					visRange;					// Maximum distance to check enemy visibility
 	float					earRange;					// Maximum distance to check hearing an enemy from
 	float					awareRange;					// Distance to become automatically aware of an enemy
	
	int						tacticalMaskAvailable;		// Currently available tactical states
	int						tacticalMaskUpdate;			// states currently being evaluated
	aiTactical_t			tacticalCurrent;			// Current tactical state	
	int						tacticalUpdateTime;			// Last time the tacitcal state was updated (for delaying updating)
 	int						tacticalPainTaken;			// Amount of damage taken in the current tactical state
 	int						tacticalPainThreshold;		// Threshold of pain before invalidating the current tactical state
 	int						tacticalFlinches;			// Number of flinches that have occured at the current tactical state

	float					threatBase;					// Base amount of threat generated by AI
	float					threatCurrent;				// Current amount of threat generatd by AI based on current state

 	int						maxLostVisTime;

	int						coverValidTime;
	int						maxInvalidCoverTime;
} rvAICombat_t;

typedef struct rvAIPain_s {
	float					threshold;
	float					takenThisFrame;
	int						lastTakenTime;
	int						loopEndTime;
	idStr					loopType;
} rvAIPain_t;

typedef struct rvAIEnemy_s {
	struct flags_s {
		bool		lockOrigin		:1;					// Stop tracking enemy origin until state changes
		bool		dead			:1;					// Enemy is dead
		bool		inFov			:1;					// Enemy is currently in fov
		bool		sighted			:1;					// Enemy was sighted at least once
		bool		visible			:1;					// Enemy is visible?
	} fl;

	idEntityPtr<idEntity>	ent;
	int						lastVisibleChangeTime;			// last time the visible state of the enemy changed
	idVec3					lastVisibleFromEyePosition;		// Origin used in last successfull visibility check
	idVec3					lastVisibleEyePosition;			// Origin of last known visible eye position
	idVec3					lastVisibleChestPosition;		// Origin of last known visible chest position
	int						lastVisibleTime;				// Time we last saw and enemy

	idVec3					smoothedLinearVelocity;			
	idVec3					smoothedPushedVelocity;			
	float					smoothVelocityRate;

	idVec3					lastKnownPosition;				// last place the enemy was known to be (does not mean visiblity)

	float					range;							// range to enemy
	float					range2d;						// 2d range to enemy
	int						changeTime;						// Time enemy was last changed
	int						checkTime;						// Time we last checked for a new enemy
} rvAIEnemy_t;

typedef struct rvAIPassive_s {
	struct flags_s {
		bool		disabled		:1;						// No advanced passive state
		bool		multipleIdles	:1;						// Has multiple idle animations to play
		bool		fidget			:1;						// Has fidget animations
	} fl;

	idStr					animIdlePrefix;
	idStr					animFidgetPrefix;
	idStr					animTalkPrefix;
	//idStr					talkPrefix;
	
	idStr					prefix;
	idStr					idleAnim;
	int						idleAnimChangeTime;
	int						fidgetTime;
	int						talkTime;
} rvAIPassive_t;

typedef struct rvAIAttackAnimInfo_s {
	idVec3					attackOffset;
	idVec3					eyeOffset;
} rvAIAttackAnimInfo_t;

#define AIACTIONF_ATTACK	BIT(0)
#define AIACTIONF_MELEE		BIT(1)

class rvAIActionTimer {
public:

	rvAIActionTimer ( void );

	bool	Init			( const idDict& args, const char* name );
				
	void	Save			( idSaveGame *savefile ) const;
	void	Restore			( idRestoreGame *savefile );
				
	void	Clear			( int currentTime );
	void	Reset			( int currentTime, float diversity = 0.0f, float scale = 1.0f );
	void	Add				( int _time, float diversity = 0.0f );

	bool	IsDone			( int currentTime ) const;

	int		GetTime			( void ) const;
	int		GetRate			( void ) const;
		
protected:

	int			time;
	int			rate;
};

ID_INLINE bool rvAIActionTimer::IsDone ( int currentTime ) const {
	return currentTime >= time;
}

ID_INLINE int rvAIActionTimer::GetTime ( void ) const {
	return time;
}

ID_INLINE int rvAIActionTimer::GetRate ( void ) const {
	return rate;
}
class rvAIAction {
public:

	rvAIAction ( void );
	
	bool	Init			( const idDict& args, const char* name, const char* defaultState, int flags );

	void	Save			( idSaveGame *savefile ) const;
	void	Restore			( idRestoreGame *savefile );
	
	enum EStatus {
		STATUS_UNUSED,
		STATUS_OK,								// action was performed
		STATUS_FAIL_DISABLED,					// action is current disabled
		STATUS_FAIL_TIMER,						// actions timer has not finished
		STATUS_FAIL_EXTERNALTIMER,				// external timer passed in to PerformAction has not finished
		STATUS_FAIL_MINRANGE,					// enemy is not within minimum range
		STATUS_FAIL_MAXRANGE,					// enemy is out of maximum range
		STATUS_FAIL_CHANCE,						// action chance check failed
		STATUS_FAIL_ANIM,						// bad animation
		STATUS_FAIL_CONDITION,					// condition given to PerformAction failed
		STATUS_FAIL_NOENEMY,					// enemy cant be attacked
		STATUS_MAX
	};
	
	struct flags_s {
		bool		disabled			:1;		// action disabled?
		bool		noPain				:1;		// no pain during action
		bool		noTurn				:1;		// no turning during action
		bool		isAttack			:1;		// attack?
		bool		isMelee				:1;		// melee?
		bool		overrideLegs		:1;		// override legs on this action?
		bool		noSimpleThink		:1;		// dont use simple think logic for this action
	} fl;
	
	
	idStrList			anims;
	idStr				state;

	rvAIActionTimer		timer;
	
	int					blendFrames;
	int					failRate;
	
	float				minRange;
	float				maxRange;
	float				minRange2d;
	float				maxRange2d;
	
	float				chance;
	float				diversity;
	
	EStatus				status;
};

typedef bool (idAI::*checkAction_t)(rvAIAction*,int);

class rvPlaybackDriver
{
public:
							rvPlaybackDriver( void ) { mPlaybackDecl = NULL; mOldPlaybackDecl = NULL; }

	bool					Start( const char *playback, idEntity *owner, int flags, int numFrames );
	bool					UpdateFrame( idEntity *ent, rvDeclPlaybackData &out );
	void					EndFrame( void );
	bool					IsActive( void ) { return( !!mPlaybackDecl || !!mOldPlaybackDecl ); }

	const char				*GetDestination( void );

// cnicholson: Begin  Added save/restore functionality
	void					Save			( idSaveGame *savefile ) const;
	void					Restore			( idRestoreGame *savefile );
// cnicholson: End  Added save/restore functionality

private:
	int						mLastTime;
	int						mTransitionTime;

	int						mStartTime;
	int						mFlags;
	const rvDeclPlayback	*mPlaybackDecl;
	idVec3					mOffset;

	int						mOldStartTime;
	int						mOldFlags;
	const rvDeclPlayback	*mOldPlaybackDecl;
	idVec3					mOldOffset;
};

/*
===============================================================================

	idAI

===============================================================================
*/

const float	AI_TURN_SCALE				= 60.0f;
const float	AI_SEEK_PREDICTION			= 0.3f;
const float	AI_FLY_DAMPENING			= 0.15f;
const float	AI_HEARING_RANGE			= 2048.0f;
const float AI_COVER_MINRANGE			= 4.0f;
const float AI_PAIN_LOOP_DELAY			= 200;
const int	DEFAULT_FLY_OFFSET			= 68.0f;

#define ATTACK_IGNORE					0
#define ATTACK_ON_DAMAGE				BIT(0)
#define ATTACK_ON_ACTIVATE				BIT(1)
#define ATTACK_ON_SIGHT					BIT(2)

// defined in script/ai_base.script.  please keep them up to date.

#define	DI_NODIR	-1


//
// events
//
extern const idEventDef AI_DirectDamage;
extern const idEventDef AI_JumpFrame;
extern const idEventDef AI_EnableClip;
extern const idEventDef AI_DisableClip;
extern const idEventDef AI_EnableGravity;
extern const idEventDef AI_DisableGravity;
extern const idEventDef AI_EnablePain;
extern const idEventDef AI_DisablePain;
extern const idEventDef AI_EnableTarget;
extern const idEventDef AI_DisableTarget;
extern const idEventDef AI_EnableMovement;
extern const idEventDef AI_DisableMovement;
extern const idEventDef AI_Vagary_ChooseObjectToThrow;
extern const idEventDef AI_Speak;
extern const idEventDef AI_SpeakRandom;
extern const idEventDef AI_Attack;
extern const idEventDef AI_AttackMelee;
extern const idEventDef AI_WaitMove;
extern const idEventDef AI_EnableDamage;
extern const idEventDef AI_DisableDamage;
extern const idEventDef AI_LockEnemyOrigin;
extern const idEventDef AI_SetEnemy;
extern const idEventDef AI_ScriptedAnim;
extern const idEventDef AI_ScriptedDone;
extern const idEventDef AI_ScriptedStop;
extern const idEventDef AI_SetScript;
extern const idEventDef AI_BecomeSolid;
extern const idEventDef AI_BecomePassive;
extern const idEventDef AI_BecomeAggressive;
extern const idEventDef AI_SetHealth;
extern const idEventDef AI_TakeDamage;
extern const idEventDef AI_EnableBlink;
extern const idEventDef AI_DisableBlink;
extern const idEventDef AI_EnableAutoBlink;
extern const idEventDef AI_DisableAutoBlink;

class idPathCorner;
class idProjectile;
class rvSpawner;
class rvAIHelper;
class rvAITether;

class idAI : public idActor {
friend class rvAIManager;
friend class idAASFindAttackPosition;
public:
	CLASS_PROTOTYPE( idAI );

							idAI();
							~idAI();

	void					Save							( idSaveGame *savefile ) const;
	void					Restore							( idRestoreGame *savefile );

	void					Spawn							( void );
	virtual void			TalkTo							( idActor *actor );

	idEntity*				GetEnemy						( void ) const;
 	idEntity*				GetGoalEntity					( void ) const;
	talkState_t				GetTalkState					( void ) const;
	const idVec2&			GetAttackRange					( void ) const;
	const idVec2&			GetFollowRange					( void ) const;
	int						GetTravelFlags					( void ) const;

	void					TouchedByFlashlight				( idActor *flashlight_owner );

 	idEntity *				FindEnemy						( bool inFov, bool forceNearest, float maxDistSqr = 0.0f );
	void					SetSpawner						( rvSpawner* _spawner );
	rvSpawner*				GetSpawner						( void );

	idActor*				GetLeader						( void ) const;

							// Outputs a list of all monsters to the console.
	static void				List_f( const idCmdArgs &args );


	// Add some dynamic externals for debugging
	virtual void			GetDebugInfo					( debugInfoProc_t proc, void* userData );


   	bool					IsEnemyVisible					( void ) const;
  	bool					InCoverMode						( void ) const;
  	bool					InCrouchCoverMode				( void ) const;
 	bool					LookAtCoverTall					( void ) const;
 	bool					InLookAtCoverMode				( void ) const;
 	bool					IsBehindCover					( void ) const;
 	bool					IsLipSyncing					( void ) const;
 	bool					IsSpeaking						( void ) const;
   	bool					IsFacingEnt						( idEntity* targetEnt );
 	bool					IsCoverValid					( void ) const;
	virtual bool			IsCrouching						( void ) const;


public:

	idLinkList<idAI>		simpleThinkNode;

	// navigation
	idAAS*					aas;
	idAASCallback*			aasFind;

	// movement
	idMoveState				move;
	idMoveState				savedMove;

	// physics
	idPhysics_Monster		physicsObj;
	
	// weapon/attack vars
	bool					lastHitCheckResult;
	int						lastHitCheckTime;
	int						lastAttackTime;
	float					projectile_height_to_distance_ratio;	// calculates the maximum height a projectile can be thrown
	idList<rvAIAttackAnimInfo_t>	attackAnimInfo;
	
	mutable idClipModel*	projectileClipModel;
	idEntityPtr<idProjectile> projectile;

	// chatter/talking
	int						chatterTime;
	int						chatterRateCombat;
	int						chatterRateIdle;
	talkState_t				talkState;
	idEntityPtr<idActor>	talkTarget;
	talkMessage_t			talkMessage;
	int						talkBusyCount;
	int						speakTime;

	// Focus
	idEntityPtr<idEntity>	lookTarget;
	aiFocus_t				focusType;	
	idEntityPtr<idEntity>	focusEntity;
	float					focusRange;
	int						focusAlignTime;
	int						focusTime;
	idVec3					currentFocusPos;

	// Looking
	bool					allowJointMod;
	int						alignHeadTime;
	int						forceAlignHeadTime;
	idAngles				eyeAng;
	idAngles				lookAng;
	idAngles				destLookAng;
	idAngles				lookMin;
	idAngles				lookMax;
	idList<jointHandle_t>	lookJoints;
	idList<idAngles>		lookJointAngles;
	float					eyeVerticalOffset;
	float					eyeHorizontalOffset;
	float					headFocusRate;
	float					eyeFocusRate;
	
	// joint controllers
	idAngles				eyeMin;
	idAngles				eyeMax;
	jointHandle_t			orientationJoint;

	idEntityPtr<idEntity>	pusher;
	idEntityPtr<idEntity>	scriptedActionEnt;

	// script variables
	struct aiFlags_s {
		bool		awake					:1;			// set to false until state_wakeup is called.
		bool		damage					:1;
		bool		pain					:1;
		bool		dead					:1;
		bool		activated				:1;
		bool		jump					:1;
		bool		hitEnemy				:1;
		bool		pushed					:1;
		bool		disableAttacks			:1;
		bool		scriptedEndWithIdle 	:1;
		bool		scriptedNeverDormant	:1;			// Prevent going dormant while in scripted sequence
		bool		scripted				:1;
		bool		simpleThink				:1;
		bool		ignoreFlashlight		:1;
		bool		action					:1;
		bool		lookAtPlayer			:1;
		bool		disableLook				:1;
		bool		undying					:1;
		bool		tetherMover				:1;			// Currently using a dynamic tether to a mover
		bool		meleeSuperhero			:1;
		bool		killerGuard				:1;			// Do 100 points of damage with each hit
	} aifl;
	
	//
	// ai/ai.cpp
	//
	void					SetAAS							( void );
	virtual	void			DormantBegin					( void );		// called when entity becomes dormant
	virtual	void			DormantEnd						( void );		// called when entity wakes from being dormant
	virtual void			Think							( void );
	void					Activate						( idEntity *activator );
	virtual void			Hide							( void );
	virtual void			Show							( void );
	virtual void			AdjustHealthByDamage			( int inDamage );
	void					CalculateAttackOffsets			( void );

	void					InitNonPersistentSpawnArgs		( void );	

	/*
	===============================================================================
									Speaking & Chatter
	===============================================================================
	*/
public:

	bool					Speak							( const char *speechDecl, bool random = false );
 	void					StopSpeaking					( bool stopAnims );
	virtual void			CheckBlink						( void );

protected:

	virtual bool			CanPlayChatterSounds			( void ) const;
	void					UpdateChatter					( void );


	/*
	===============================================================================
									Movement
	===============================================================================
	*/

	// static helper functions
public:
							// Finds a path around dynamic obstacles.
	static bool				FindPathAroundObstacles			( const idPhysics *physics, const idAAS *aas, const idEntity *ignore, const idVec3 &startPos, const idVec3 &seekPos, obstaclePath_t &path );
							// Frees any nodes used for the dynamic obstacle avoidance.
	static void				FreeObstacleAvoidanceNodes		( void );
							// Predicts movement, returns true if a stop event was triggered.
	static bool				PredictPath						( const idEntity *ent, const idAAS *aas, const idVec3 &start, const idVec3 &velocity, int totalTime, int frameTime, int stopEvent, predictedPath_t &path, const idEntity *ignore = NULL );
							// Return true if the trajectory of the clip model is collision free.
	static bool				TestTrajectory					( const idVec3 &start, const idVec3 &end, float zVel, float gravity, float time, float max_height, const idClipModel *clip, int clipmask, const idEntity *ignore, const idEntity *targetEntity, int drawtime );
							// Finds the best collision free trajectory for a clip model.
	static bool				PredictTrajectory				( const idVec3 &firePos, const idVec3 &target, float projectileSpeed, const idVec3 &projGravity, const idClipModel *clip, int clipmask, float max_height, const idEntity *ignore, const idEntity *targetEntity, int drawtime, idVec3 &aimDir );


	// special flying code
	void					AdjustFlyingAngles				( void );
	void					AddFlyBob						( idVec3 &vel );
	void					AdjustFlyHeight					( idVec3 &vel, const idVec3 &goalPos );
	void					FlySeekGoal						( idVec3 &vel, idVec3 &goalPos );
	void					AdjustFlySpeed					( idVec3 &vel );
	void					FlyTurn							( void );

	// movement types
	void					Move							( void );
	virtual	void			DeadMove						( void );
	void					AnimMove						( void );
	void					SlideMove						( void );
	void					PlaybackMove					( void );
	void					FlyMove							( void );
	void					StaticMove						( void );
	void					RVMasterMove					( void );
	void					SetMoveType						( moveType_t moveType );
	//twhitaker: added custom move type
	virtual void			CustomMove						( void );

	// movement actions
	void					KickObstacles					( const idVec3 &dir, float force, idEntity *alwaysKick );

	// steering
	virtual void			ApplyImpulse					( idEntity *ent, int id, const idVec3 &point, const idVec3 &impulse, bool splash = false );
	void					GetAnimMoveDelta				( const idMat3 &oldaxis, const idMat3 &axis, idVec3 &delta );
	void					CheckObstacleAvoidance			( const idVec3 &goalPos, idVec3 &newPos, idReachability* goalReach=0  );
	bool					GetMovePos						( idVec3 &seekPos, idReachability** seekReach=0 );


	// navigation
	float					TravelDistance					( const idVec3 &end ) const;
	float					TravelDistance					( const idVec3 &start, const idVec3 &end ) const;
	float					TravelDistance					( idEntity* ent ) const;
	float					TravelDistance					( idEntity* start, idEntity* end ) const;
	int						PointReachableAreaNum			( const idVec3 &pos, const float boundsScale = 2.0f ) const;
	bool					PathToGoal						( aasPath_t &path, int areaNum, const idVec3 &origin, int goalAreaNum, const idVec3 &goalOrigin ) const;
	void					BlockedFailSafe					( void );

	// turning
	void					Turn							( void );
	bool					TurnToward						( float yaw );
	bool					TurnToward						( const idVec3 &pos );
	bool					TurnTowardLeader				( bool faceLeaderByDefault=false );
	bool					FacingIdeal						( void );
	bool					DirectionalTurnToward			( const idVec3 &pos );

	// movement control
	bool					FaceEnemy						( void );
	bool					FaceEntity						( idEntity *ent );
  	bool					SlideToPosition					( const idVec3 &pos, float time );
 	bool					WanderAround					( void );
	bool					StepDirection					( float dir );
	bool					NewWanderDir					( const idVec3 &dest );


	/*
	===============================================================================
									Reactions
	===============================================================================
	*/
	void					ReactToShotAt					( idEntity* attacker, const idVec3 &origOrigin, const idVec3 &origDir );
	void					ReactToPain						( idEntity* attacker, int damage );

	/*
	===============================================================================
									AI helpers
	===============================================================================
	*/

public:

	void					UpdateHelper					( void );
	rvAIHelper*				GetActiveHelper					( void );

	/*
	===============================================================================
									Sensory Perception
	===============================================================================
	*/

public:

	const idVec3&			LastKnownPosition				( const idEntity *ent );
	const idVec3&			LastKnownFacing					( const idEntity *ent );
	idEntity *				HeardSound						( int ignore_team );
	int						ReactionTo						( const idEntity *ent );
	void					SetLastVisibleEnemyTime			( int time=-1/* DEFAULT IS CURRENT TIME*/ );
	bool					IsEnemyRecentlyVisible			( float maxLostVisTimeScale = 1.0f ) const;

	/*
	===============================================================================
									Passive
	===============================================================================
	*/

public:

	void					SetTalkState					( talkState_t state );
	void					SetPassivePrefix				( const char* prefix );

protected:

	bool					GetPassiveAnimPrefix			( const char* animName, idStr& animPrefix );

	/*
	===============================================================================
									Combat
	===============================================================================
	*/

public:

	// enemy managment
	bool					SetEnemy						( idEntity *newEnemy );
	void					ClearEnemy						( bool dead = false );

	void					UpdateEnemy						( void );
	void					UpdateEnemyPosition				( bool force = true );
	void					UpdateEnemyVisibility			( void );

	// Attack direction
	bool					GetAimDir						( const idVec3& source, const idEntity* aimAtEnt, const idDict* projectileDict, idEntity *ignore, idVec3 &aimDir, float aimOffset, float predict ) const;
	void					GetPredictedAimDirOffset		( const idVec3& source, const idVec3& target, float projectileSpeed, const idVec3& targetVelocity, idVec3& offset ) const;

	// damage
	virtual bool			Pain							( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
	virtual void			Killed							( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location );
	bool					CheckDeathCausesMissionFailure	( void );

	// attacks
	virtual bool			Attack							( const char* attackName, jointHandle_t joint, idEntity* target, const idVec3& pushVelocity = vec3_origin );
	virtual idProjectile*	AttackRanged					( const char* attackName, const idDict* attackDict, jointHandle_t joint, idEntity* target, const idVec3& pushVelocity = vec3_origin );
	virtual idProjectile*	AttackProjectile				( const idDict* projectileDict, const idVec3 &org, const idAngles &ang );
	virtual bool			AttackMelee						( const char* attackName, const idDict* meleeDict );
	
	void					CreateProjectileClipModel		( void ) const;
	idProjectile*			CreateProjectile				( const idDict* projectileDict, const idVec3 &pos, const idVec3 &dir );
	void					RemoveProjectile				( void );
	virtual void			DamageFeedback					( idEntity *victim, idEntity *inflictor, int &damage );
	void					DirectDamage					( const char *meleeDefName, idEntity *ent );
	bool					TestMelee						( void ) const;
	void					PushWithAF						( void );
	bool					IsMeleeNeeded					( void );

	// special effects
	void					GetMuzzle						( jointHandle_t joint, idVec3 &muzzle, idMat3 &axis );
	void					LerpLookAngles					( idAngles &curAngles, idAngles newAngles, float orientationJointYaw, float focusRate );
	virtual bool			UpdateAnimationControllers		( void );

	// AI script state management
	void					UpdateStates					( void );
	void					UpdateFocus						( const idMat3& orientationAxis );
	void					SetFocus						( aiFocus_t focus, int time );

	// event?
	virtual void			FootStep						( void );

	void					CreateMissile					( jointHandle_t joint  );
	void					RadiusDamageFromJoint			( const char *jointname, const char *damageDefName );
	void					BecomeSolid						( void );
	void					BecomeNonSolid					( void );
	const char *			ChooseAnim						( int channel, const char *animname );

	//
	// ai/ai_events.cpp
	//
public:


	virtual bool			CanTakeDamage					( void ) const;
	virtual bool			CanTakePain						( void ) const;
	virtual bool			CanTurn							( void ) const;
	virtual bool			CanMove							( void ) const;
	virtual bool			CanAnnounce						( float chance ) const;

	virtual bool			SkipCurrentDestination			( void ) const;

// ----------------------------- Functions ------------------------------------

	virtual bool			DoDormantTests					( void );

	void					OverrideFlag					( aiFlagOverride_t flag, bool value );
	void					RestoreFlag						( aiFlagOverride_t flag );

	virtual bool			SkipImpulse						( idEntity *ent, int id );
	
	virtual const char*		GetIdleAnimName					( void );

	bool					RespondToFlashlight				( void )				{ return !aifl.ignoreFlashlight;}
	bool					ForceFaceEnemy					( void )				{ return ( move.moveCommand == MOVE_TO_ENEMY ); }

	bool					CanBecomeSolid					( void );
	bool					CanHitEnemyFromAnim				( int animNum, idVec3 offset = vec3_origin );
	bool					CanHitEnemy						( void );
	bool					CanHitEnemyFromJoint			( const char *jointname );

	float					GetTurnDelta					( void );

	int						TestTrajectory					( const idVec3 &firePos, const idVec3 &target, const char *projectileName );
	bool					TestAnimMove					( int animNum, idEntity *ignore = NULL, idVec3 *pMoveVec = NULL );
	void					ExecScriptFunction				( rvScriptFuncUtility& func, idEntity* parm = NULL );
	void					SetLeader						( idEntity *newLeader );

	int						CheckMelee						( bool disableAttack );
	bool					CheckForEnemy					( bool useFov, bool force = false );
 	bool					CheckForCloserEnemy				( void );
 	bool					CheckForReplaceEnemy			( idEntity* replacement );
	bool					CheckForTeammateEnemy			( void );

 	void					DrawSuspicion					( void );
 	float					RateSuspiciousness				( idActor* shady, bool rateSound = false );
 	void					RateSuspicionLevel				( void );

	void					UpdatePlayback					( idVec3 &goalPos, idVec3 &delta, idVec3 &oldorigin, idMat3 &oldaxis );

	void					LookAtEntity					( idEntity *ent, float duration );

// ----------------------------- Variables ------------------------------------

	int						actionAnimNum;			// Index of animation to use for the upcoming action
	int						actionTime;				// Time line for actions (time is stopped when an action is running)
	int						actionSkipTime;			// Time to use if an action is skipped by another

	int						flagOverrides;

	float					announceRate;			// How often (0 - 1.0f) the AI will make certain announcements.

	rvAICombat_t			combat;					// Members related to combat state
	rvAIPassive_t			passive;				// Members related to passive state
	rvAIEnemy_t				enemy;					// Members related to tracking enemies
	rvAIPain_t				pain;
	rvAIFuncs_t				funcs;

	rvPlaybackDriver		mPlayback;
	rvPlaybackDriver		mLookPlayback;

	rvAASTacticalSensor*	aasSensor;

	idEntityPtr<rvAITether>	tether;
	idEntityPtr<rvAIHelper>	helperCurrent;
	idEntityPtr<rvAIHelper>	helperIdeal;
	idEntityPtr<idActor>	leader;
	idEntityPtr<rvSpawner>	spawner;

	bool						ValidateCover					( void );

	virtual bool				UpdateRunStatus					( void );
	bool						UpdateTactical					( int delay = 0 );
	void						ForceTacticalUpdate				( void );
	bool						UpdateTactical_r				( void );
	virtual int					FilterTactical					( int availableTactical );
	void						WakeUpTargets					( void );

	virtual aiCTResult_t		CheckTactical					( aiTactical_t tactical );

	void						Begin							( void );
	void						WakeUp							( void );

	virtual void				Prethink						( void );
	virtual void				Postthink						( void );

	/*
	===============================================================================
							  Threat Management
	===============================================================================
	*/

protected:

	virtual void			UpdateThreat					( void );
	virtual float			CalculateEnemyThreat			( idEntity* enemy );

	/*
	===============================================================================
									Tethers
	===============================================================================
	*/

public:

	virtual bool			IsTethered						( void ) const;
	bool					IsWithinTether					( void ) const;
	rvAITether*				GetTether						( void );
	virtual void			SetTether						( rvAITether* newTether );

	/*
	===============================================================================
									Scripting
	===============================================================================
	*/

public:

	void					ScriptedMove					( idEntity* destEnt, float minDist, bool endWithIdle );
	void					ScriptedFace					( idEntity* faceEnt, bool endWithIdle );
	void					ScriptedAnim					( const char* animname, int blendFrames, bool loop, bool endWithIdle );
	void					ScriptedPlaybackMove			( const char* playback, int flags, int numFrames );
	void					ScriptedPlaybackAim				( const char* playback, int flags, int numFrames );
	void					ScriptedAction					( idEntity* actionEnt, bool endWithIdle );
	void					ScriptedStop					( void );

	void					SetScript						( const char* scriptName, const char* funcName );

private:

	bool					ScriptedBegin					( bool endWithIdle, bool allowDormant = false );
	void					ScriptedEnd						( void );

	/*
	===============================================================================
									Handlers 
	===============================================================================
	*/

protected:

	virtual void			OnDeath							( void );
	virtual void			OnStateChange					( int channel );
	virtual void			OnUpdatePlayback				( const rvDeclPlaybackData& pbd );
	virtual void			OnEnemyChange					( idEntity* oldEnemy );
	virtual void			OnLeaderChange					( idEntity* oldLeader );
	virtual void			OnStartMoving					( void );
	virtual void			OnStopMoving					( aiMoveCommand_t oldMoveCommand );
	virtual void			OnTacticalChange				( aiTactical_t oldTactical );
	virtual void			OnFriendlyFire					( idActor* attacker );
	virtual void			OnWakeUp						( void );
	virtual void			OnTouch							( idEntity *other, trace_t *trace );
	virtual void			OnCoverInvalidated				( void );
	virtual void			OnCoverNotFacingEnemy			( void );
	virtual void			OnEnemyVisiblityChange			( bool oldVisible );
	virtual void			OnStartAction					( void );
	virtual void			OnStopAction					( void );
	virtual void			OnSetKey						( const char* key, const char* value );

	/*
	===============================================================================
									Movement / Turning
	===============================================================================
	*/
	
protected:

	bool					StartMove						( aiMoveCommand_t command, const idVec3& goalOrigin, int goalArea, idEntity* goalEntity, aasFeature_t* feature, float range );
	void					StopMove						( moveStatus_t status );

	bool					MoveTo							( const idVec3 &pos, float range = 0.0f );
	bool					MoveToAttack					( idEntity *ent, int attack_anim );
	bool					MoveToTether					( rvAITether* tether );
	virtual bool			MoveToEnemy						( void );
	bool					MoveToEntity					( idEntity *ent, float range = 0.0f );
	bool					MoveToCover						( float minRange, float maxRange, aiTactical_t coverType );
	bool					MoveToHide						( void );

	bool					MoveOutOfRange					( idEntity *entity, float range, float minRange=0.0f );

	void					AnimTurn						( float angles, bool force );

	bool					ReachedPos						( const idVec3 &pos, const aiMoveCommand_t moveCommand, float range = 0.0f ) const;

	/*
	===============================================================================
									Debug
	===============================================================================
	*/

public:

	void					DrawRoute						( void ) const;
	void					DrawTactical					( void );

	/*
	===============================================================================
									Announcements
	===============================================================================
	*/

public:

	bool					ActorIsBehindActor				( idActor* ambusher, idActor* victim );
	void					AnnounceNewEnemy				( void );
	void					AnnounceKill					( idActor *victim );
	void					AnnounceTactical				( aiTactical_t newTactical );
	void					AnnounceSuppressed				( idActor *suppressor );
	void					AnnounceSuppressing				( void );
	void					AnnounceFlinch					( idEntity *attacker );
	void					AnnounceInjured					( void );
	void					AnnounceFriendlyFire			( idActor* attacker );
	void					AnnounceGrenade					( void );
	void					AnnounceGrenadeThrow			( void );

	/*
	===============================================================================
									Actions
	===============================================================================
	*/

protected:

	rvAIActionTimer			actionTimerRangedAttack;
	rvAIActionTimer			actionTimerEvade;
	rvAIActionTimer			actionTimerSpecialAttack;
	rvAIActionTimer			actionTimerPain;
	
	rvAIAction				actionEvadeLeft;
	rvAIAction				actionEvadeRight;
	rvAIAction				actionRangedAttack;
	rvAIAction				actionMeleeAttack;
	rvAIAction				actionLeapAttack;	
	rvAIAction				actionJumpBack;

	bool					UpdateAction						( void );
	virtual bool			CheckActions						( void );
	virtual bool			CheckPainActions					( void );

	bool					PerformAction						( rvAIAction* action, bool (idAI::*)(rvAIAction*,int), rvAIActionTimer* timer = NULL );
	void					PerformAction						( const char* stateName, int blendFrames = 0, bool noPain = false );

	// RAVEN BEGIN
	// twhitaker: needed this for difficulty settings
	virtual void			Event_PostSpawn						( void );
	// RAVEN END

public:
		
	virtual bool			CheckAction_EvadeLeft				( rvAIAction* action, int animNum );
	virtual bool			CheckAction_EvadeRight				( rvAIAction* action, int animNum );
	virtual bool			CheckAction_RangedAttack			( rvAIAction* action, int animNum );
	virtual bool			CheckAction_MeleeAttack				( rvAIAction* action, int animNum );
	bool					CheckAction_LeapAttack				( rvAIAction* action, int animNum );
	virtual bool			CheckAction_JumpBack				( rvAIAction* action, int animNum );

	/*
	===============================================================================
									Events
	===============================================================================
	*/

private:
	
	// Orphaned events
	void					Event_ClosestReachableEnemyOfEntity	( idEntity *team_mate );
	void					Event_GetReachableEntityPosition	( idEntity *ent );
	void					Event_EntityInAttackCone			( idEntity *ent );
	void					Event_TestAnimMoveTowardEnemy		( const char *animname );
	void					Event_TestAnimMove					( const char *animname );
	void					Event_TestMoveToPosition			( const idVec3 &position );
	void					Event_TestMeleeAttack				( void );
	void					Event_TestAnimAttack				( const char *animname );
	void					Event_SaveMove						( void );
	void					Event_RestoreMove					( void );
	void					Event_ThrowMoveable					( void );
	void					Event_ThrowAF						( void );
	void					Event_PredictEnemyPos				( float time );
	void					Event_FindActorsInBounds			( const idVec3 &mins, const idVec3 &maxs );

	void					Event_Activate						( idEntity *activator );
	void					Event_Touch							( idEntity *other, trace_t *trace );
	void					Event_LookAt						( idEntity* lookAt );
	
	void					Event_SetAngles						( idAngles const &ang );
	void					Event_SetEnemy						( idEntity *ent );
	void					Event_SetHealth						( float newHealth );
	void					Event_SetTalkTarget					( idEntity *target );
	void					Event_SetTalkState					( int state );
	void					Event_SetLeader						( idEntity *newLeader );
	void					Event_SetScript						( const char* scriptName, const char* funcName );
	void					Event_SetMoveSpeed					( int speed );
	void					Event_SetPassivePrefix				( const char* prefix );

	void					Event_GetAngles						( void );
	void					Event_GetEnemy						( void );
	void					Event_GetLeader						( void );

	void					Event_Attack						( const char* attackName, const char* jointName );
	void					Event_AttackMelee					( const char *meleeDefName );

	void					Event_DirectDamage					( idEntity *damageTarget, const char *damageDefName );
	void					Event_RadiusDamageFromJoint			( const char *jointname, const char *damageDefName );
	void					Event_CanBecomeSolid				( void );
	void					Event_BecomeSolid					( void );
	void					Event_BecomeNonSolid				( void );
	void					Event_BecomeRagdoll					( void );
	void					Event_StopRagdoll					( void );
	void					Event_FaceEnemy						( void );
	void					Event_FaceEntity					( idEntity *ent );
	void					Event_WaitMove						( void );

	void					Event_BecomePassive					( int ignoreEnemies );
	void					Event_BecomeAggressive				( void );

	void					Event_EnableDamage					( void );
	void					Event_EnableClip					( void );
	void					Event_EnableGravity					( void );
	void					Event_EnableAFPush					( void );
	void					Event_EnablePain					( void );
	void					Event_DisableDamage					( void );
	void					Event_DisableClip					( void );
	void					Event_DisableGravity				( void );
	void					Event_DisableAFPush					( void );
	void					Event_DisablePain					( void );
	void					Event_EnableTarget					( void );
	void					Event_DisableTarget					( void );
	void					Event_TakeDamage					( float takeDamage );
	void					Event_SetUndying					( float setUndying );
	void					Event_EnableAutoBlink				( void );
	void					Event_DisableAutoBlink				( void );

	void					Event_LockEnemyOrigin				( void );

	void					Event_StopThinking					( void );
	void					Event_JumpFrame						( void );
	void					Event_RealKill						( void );
	void					Event_Kill							( void );
	void					Event_RemoveUpdateSpawner			( void );
	void					Event_AllowHiddenMovement			( int enable );
	void 					Event_CanReachPosition				( const idVec3 &pos );
	void 					Event_CanReachEntity				( idEntity *ent );
	void					Event_CanReachEnemy					( void );

	void					Event_IsSpeaking					( void );
	void					Event_IsTethered					( void );
	void					Event_IsWithinTether				( void );
	void					Event_IsMoving						( void );
	
	void					Event_Speak							( const char *speechDecl );
	void					Event_SpeakRandom					( const char *speechDecl );

	void					Event_ScriptedMove					( idEntity* destEnt, float minDist, bool endWithIdle );
	void					Event_ScriptedFace					( idEntity* faceEnt, bool endWithIdle );
	void					Event_ScriptedAnim					( const char* animname, int blendFrames, bool loop, bool endWithIdle );
	void					Event_ScriptedPlaybackMove			( const char* playback, int flags, int numFrames );
	void					Event_ScriptedPlaybackAim			( const char* playback, int flags, int numFrames );
	void					Event_ScriptedAction				( idEntity* actionEnt, bool endWithIdle );
	void					Event_ScriptedDone					( void );
	void					Event_ScriptedStop					( void );
	void					Event_ScriptedJumpDown				( float yaw );

	void					Event_FindEnemy						( float distSquare );
	void					Event_SetKey						( const char *key, const char *value );

	
	/*
	===============================================================================
									States
	===============================================================================
	*/

protected:

	// Wait states
	stateResult_t			State_Wait_Activated				( const stateParms_t& parms );
	stateResult_t			State_Wait_ScriptedDone				( const stateParms_t& parms );
	stateResult_t			State_Wait_Action					( const stateParms_t& parms );
	stateResult_t			State_Wait_ActionNoPain				( const stateParms_t& parms );
	
	// Global states
	stateResult_t			State_WakeUp						( const stateParms_t& parms );
	stateResult_t			State_TriggerAnim					( const stateParms_t& parms );
	stateResult_t			State_Wander						( const stateParms_t& parms );
	stateResult_t			State_Killed						( const stateParms_t& parms );
	stateResult_t			State_Dead							( const stateParms_t& parms );
	stateResult_t			State_LightningDeath				( const stateParms_t& parms );
	stateResult_t			State_Burn							( const stateParms_t& parms );
	stateResult_t			State_SinkCorpse					( const stateParms_t& parms );
	stateResult_t			State_Remove						( const stateParms_t& parms );

	stateResult_t			State_Passive						( const stateParms_t& parms );

	stateResult_t			State_Combat						( const stateParms_t& parms );
	stateResult_t			State_CombatCover					( const stateParms_t& parms );
	stateResult_t			State_CombatMelee					( const stateParms_t& parms );
	stateResult_t			State_CombatRanged					( const stateParms_t& parms );
	stateResult_t			State_CombatTurret					( const stateParms_t& parms );
	virtual stateResult_t	State_CombatHide					( const stateParms_t& parms );

	stateResult_t			State_MovePlayerPush				( const stateParms_t& parms );
	stateResult_t			State_MoveTether					( const stateParms_t& parms );
	stateResult_t			State_MoveFollow					( const stateParms_t& parms );

	stateResult_t			State_ScriptedMove					( const stateParms_t& parms );	
	stateResult_t			State_ScriptedFace					( const stateParms_t& parms );	
	stateResult_t			State_ScriptedStop					( const stateParms_t& parms );
	stateResult_t			State_ScriptedPlaybackMove			( const stateParms_t& parms );
	stateResult_t			State_ScriptedPlaybackAim			( const stateParms_t& parms );
	stateResult_t			State_ScriptedJumpDown				( const stateParms_t& parms );

	// Torso States
	stateResult_t			State_Torso_Idle					( const stateParms_t& parms );
	stateResult_t			State_Torso_Sight					( const stateParms_t& parms );
	stateResult_t			State_Torso_CustomCycle				( const stateParms_t& parms );
	stateResult_t			State_Torso_Action					( const stateParms_t& parms );
	stateResult_t			State_Torso_FinishAction			( const stateParms_t& parms );
	stateResult_t			State_Torso_Pain					( const stateParms_t& parms );
	stateResult_t			State_Torso_ScriptedAnim			( const stateParms_t& parms );	
	stateResult_t			State_Torso_PassiveIdle				( const stateParms_t& parms );
	stateResult_t			State_Torso_PassiveFidget			( const stateParms_t& parms );
	
	// Leg States
	stateResult_t			State_Legs_Idle						( const stateParms_t& parms );
	stateResult_t			State_Legs_TurnLeft					( const stateParms_t& parms );
	stateResult_t			State_Legs_TurnRight				( const stateParms_t& parms );
	stateResult_t			State_Legs_Move						( const stateParms_t& parms );
	stateResult_t			State_Legs_MoveThink				( const stateParms_t& parms );
	stateResult_t			State_Legs_ChangeDirection			( const stateParms_t& parms );
	
	// Head states	
	stateResult_t			State_Head_Idle						( const stateParms_t& parms );

	CLASS_STATES_PROTOTYPE ( idAI );
};

/*
===============================================================================

	idAI Inlines

===============================================================================
*/

ID_INLINE int DelayTime( int min, int range ) {
	return min + gameLocal.random.RandomInt ( range + 1 );
}

ID_INLINE const idVec2& idAI::GetAttackRange ( void ) const {
	return combat.attackRange;
}

ID_INLINE const idVec2& idAI::GetFollowRange ( void ) const {
	return move.followRange;
}

ID_INLINE int idAI::GetTravelFlags ( void ) const {
	return move.travelFlags;
}

ID_INLINE bool idAI::IsEnemyVisible ( void ) const {
	return enemy.ent && enemy.fl.visible;
}

ID_INLINE bool idAI::IsEnemyRecentlyVisible( float maxLostVisTimeScale ) const {
	return (enemy.ent
			&& combat.fl.seenEnemyDirectly 
 			&& (enemy.lastVisibleTime && gameLocal.time-enemy.lastVisibleTime < (combat.maxLostVisTime * maxLostVisTimeScale)));
}
 
ID_INLINE bool idAI::LookAtCoverTall( void ) const {
 	return ( aasSensor->Look()
 			&& (aasSensor->Look()->flags&FEATURE_LOOK_OVER)
 			&& aasSensor->Look()->height > 40.0f );
}
 
ID_INLINE bool idAI::InLookAtCoverMode ( void ) const {
 	return (!IsBehindCover() 
 			&& !aifl.action 
			&& move.fl.moving
 			&& (combat.fl.alert || combat.fl.aware)
			&& aasSensor->Look()
 			&& combat.tacticalCurrent != AITACTICAL_MELEE
 			&& combat.tacticalCurrent != AITACTICAL_HIDE
 			&& !IsEnemyRecentlyVisible(0.2f));
}
 
ID_INLINE bool idAI::InCoverMode ( void ) const {	
	return ( (1<<combat.tacticalCurrent) & AITACTICAL_COVER_BITS ) && aasSensor->Reserved ( );
}
 
ID_INLINE bool idAI::InCrouchCoverMode ( void ) const {
	return ( InCoverMode() && (aasSensor->Reserved()->flags&FEATURE_LOOK_OVER) );
}
   
ID_INLINE bool idAI::IsBehindCover ( void ) const {
	return ( InCoverMode() && move.fl.done && (aifl.action || DistanceTo2d ( aasSensor->ReservedOrigin() ) < AI_COVER_MINRANGE) );
}

ID_INLINE bool idAI::IsSpeaking ( void ) const {
	return speakTime && gameLocal.time < speakTime;
}

ID_INLINE bool idAI::IsFacingEnt ( idEntity* targetEnt ) {
	return( move.moveCommand == MOVE_FACE_ENTITY && move.goalEntity == targetEnt && FacingIdeal() );
}

ID_INLINE bool idAI::IsCoverValid (  ) const {
 	return combat.coverValidTime && (gameLocal.time - combat.coverValidTime < combat.maxInvalidCoverTime);
}

ID_INLINE idActor* idAI::GetLeader ( void ) const { 
	return leader;
}

ID_INLINE idEntity* idAI::GetGoalEntity ( void ) const { 
	return move.goalEntity;
}

ID_INLINE bool idAI::CanTakeDamage( void ) const {
	return idActor::CanTakeDamage( );
}

ID_INLINE bool idAI::CanTakePain ( void ) const {
	return !disablePain;
}

ID_INLINE bool idAI::CanTurn ( void ) const {
	return move.turnRate && !move.fl.noTurn && !move.fl.disabled;
}

ID_INLINE bool idAI::CanMove ( void ) const {
	return !move.fl.disabled && !move.fl.blocked && gameLocal.GetTime()>move.blockTime;
}

ID_INLINE bool idAI::CanAnnounce ( float chance ) const {
	return !aifl.dead && !IsSpeaking ( ) && !af.IsActive ( ) && !combat.fl.noChatter && ( gameLocal.random.RandomFloat() < chance );
}

ID_INLINE void idAI::SetFocus ( aiFocus_t focus, int time ) {
	focusType = focus;
	focusTime = gameLocal.time + time;
}

ID_INLINE idEntity *idAI::GetEnemy( void ) const {
	return enemy.ent;
}

ID_INLINE void idAI::ForceTacticalUpdate ( void ) {
	combat.tacticalUpdateTime = 0;
	combat.tacticalMaskUpdate = 0;
	delete aasFind;
	aasFind = NULL;
}	

/*
===============================================================================

	externs

===============================================================================
*/

extern const char* aiActionStatusString [ rvAIAction::STATUS_MAX ];
extern const char* aiTalkMessageString	[ ];
extern const char* aiTacticalString		[ AITACTICAL_MAX ];
extern const char* aiMoveCommandString	[ NUM_MOVE_COMMANDS ];
extern const char* aiFocusString		[ AIFOCUS_MAX ];

#endif /* !__AI_H__ */
 
