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

Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.

This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").

Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.

In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

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

#ifndef __AI_H__
#define __AI_H__

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

	idAI

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

const float	SQUARE_ROOT_OF_2			= 1.414213562f;
const float	AI_TURN_PREDICTION			= 0.2f;
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 int	DEFAULT_FLY_OFFSET			= 68;

#define ATTACK_IGNORE			0
#define ATTACK_ON_DAMAGE		1
#define ATTACK_ON_ACTIVATE		2
#define ATTACK_ON_SIGHT			4

typedef struct ballistics_s
{
	float				angle;		// angle in degrees in the range [-180, 180]
	float				time;		// time it takes before the projectile arrives
} ballistics_t;

extern int Ballistics( const idVec3& start, const idVec3& end, float speed, float gravity, ballistics_t bal[2] );

// defined in script/ai_base.script.  please keep them up to date.
typedef enum
{
	MOVETYPE_DEAD,
	MOVETYPE_ANIM,
	MOVETYPE_SLIDE,
	MOVETYPE_FLY,
	MOVETYPE_STATIC,
	NUM_MOVETYPES
} moveType_t;

typedef enum
{
	MOVE_NONE,
	MOVE_FACE_ENEMY,
	MOVE_FACE_ENTITY,

	// commands < NUM_NONMOVING_COMMANDS don't cause a change in position
	NUM_NONMOVING_COMMANDS,

	MOVE_TO_ENEMY = NUM_NONMOVING_COMMANDS,
	MOVE_TO_ENEMYHEIGHT,
	MOVE_TO_ENTITY,
	MOVE_OUT_OF_RANGE,
	MOVE_TO_ATTACK_POSITION,
	MOVE_TO_COVER,
	MOVE_TO_POSITION,
	MOVE_TO_POSITION_DIRECT,
	MOVE_SLIDE_TO_POSITION,
	MOVE_WANDER,
	NUM_MOVE_COMMANDS
} moveCommand_t;

typedef enum
{
	TALK_NEVER,
	TALK_DEAD,
	TALK_OK,
	TALK_BUSY,
	NUM_TALK_STATES
} talkState_t;

//
// status results from move commands
// make sure to change script/doom_defs.script if you add any, or change their order
//
typedef enum
{
	MOVE_STATUS_DONE,
	MOVE_STATUS_MOVING,
	MOVE_STATUS_WAITING,
	MOVE_STATUS_DEST_NOT_FOUND,
	MOVE_STATUS_DEST_UNREACHABLE,
	MOVE_STATUS_BLOCKED_BY_WALL,
	MOVE_STATUS_BLOCKED_BY_OBJECT,
	MOVE_STATUS_BLOCKED_BY_ENEMY,
	MOVE_STATUS_BLOCKED_BY_MONSTER
} moveStatus_t;

#define	DI_NODIR	-1

// obstacle avoidance
typedef struct obstaclePath_s
{
	idVec3				seekPos;					// seek position avoiding obstacles
	idEntity* 			firstObstacle;				// if != NULL the first obstacle along the path
	idVec3				startPosOutsideObstacles;	// start position outside obstacles
	idEntity* 			startPosObstacle;			// if != NULL the obstacle containing the start position
	idVec3				seekPosOutsideObstacles;	// seek position outside obstacles
	idEntity* 			seekPosObstacle;			// if != NULL the obstacle containing the seek position
} obstaclePath_t;

// path prediction
typedef enum
{
	SE_BLOCKED			= BIT( 0 ),
	SE_ENTER_LEDGE_AREA	= BIT( 1 ),
	SE_ENTER_OBSTACLE	= BIT( 2 ),
	SE_FALL				= BIT( 3 ),
	SE_LAND				= BIT( 4 )
} stopEvent_t;

typedef struct predictedPath_s
{
	idVec3				endPos;						// final position
	idVec3				endVelocity;				// velocity at end position
	idVec3				endNormal;					// normal of blocking surface
	int					endTime;					// time predicted
	int					endEvent;					// event that stopped the prediction
	const idEntity* 	blockingEntity;				// entity that blocks the movement
} predictedPath_t;

//
// events
//
extern const idEventDef AI_BeginAttack;
extern const idEventDef AI_EndAttack;
extern const idEventDef AI_MuzzleFlash;
extern const idEventDef AI_CreateMissile;
extern const idEventDef AI_AttackMissile;
extern const idEventDef AI_FireMissileAtTarget;
extern const idEventDef AI_LaunchProjectile;
extern const idEventDef AI_TriggerFX;
extern const idEventDef AI_StartEmitter;
extern const idEventDef AI_StopEmitter;
extern const idEventDef AI_AttackMelee;
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_TriggerParticles;
extern const idEventDef AI_RandomPath;

class idPathCorner;

typedef struct particleEmitter_s
{
	particleEmitter_s()
	{
		particle = NULL;
		time = 0;
		joint = INVALID_JOINT;
	};
	const idDeclParticle* particle;
	int					time;
	jointHandle_t		joint;
} particleEmitter_t;

typedef struct funcEmitter_s
{
	char				name[64];
	idFuncEmitter*		particle;
	jointHandle_t		joint;
} funcEmitter_t;

class idMoveState
{
public:
	idMoveState();

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

	moveType_t				moveType;
	moveCommand_t			moveCommand;
	moveStatus_t			moveStatus;
	idVec3					moveDest;
	idVec3					moveDir;			// used for wandering and slide moves
	idEntityPtr<idEntity>	goalEntity;
	idVec3					goalEntityOrigin;	// move to entity uses this to avoid checking the floor position every frame
	int						toAreaNum;
	int						startTime;
	int						duration;
	float					speed;				// only used by flying creatures
	float					range;
	float					wanderYaw;
	int						nextWanderTime;
	int						blockTime;
	idEntityPtr<idEntity>	obstacle;
	idVec3					lastMoveOrigin;
	int						lastMoveTime;
	int						anim;
};

class idAASFindCover : public idAASCallback
{
public:
	idAASFindCover( const idVec3& hideFromPos );
	~idAASFindCover();

	virtual bool		TestArea( const idAAS* aas, int areaNum );

private:
	pvsHandle_t			hidePVS;
	int					PVSAreas[ idEntity::MAX_PVS_AREAS ];
};

class idAASFindAreaOutOfRange : public idAASCallback
{
public:
	idAASFindAreaOutOfRange( const idVec3& targetPos, float maxDist );

	virtual bool		TestArea( const idAAS* aas, int areaNum );

private:
	idVec3				targetPos;
	float				maxDistSqr;
};

class idAASFindAttackPosition : public idAASCallback
{
public:
	idAASFindAttackPosition( const idAI* self, const idMat3& gravityAxis, idEntity* target, const idVec3& targetPos, const idVec3& fireOffset );
	~idAASFindAttackPosition();

	virtual bool		TestArea( const idAAS* aas, int areaNum );

private:
	const idAI*			self;
	idEntity*			target;
	idBounds			excludeBounds;
	idVec3				targetPos;
	idVec3				fireOffset;
	idMat3				gravityAxis;
	pvsHandle_t			targetPVS;
	int					PVSAreas[ idEntity::MAX_PVS_AREAS ];
};

class idAI : public idActor
{
public:
	CLASS_PROTOTYPE( idAI );

	idAI();
	~idAI();

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

	void					Spawn();
	void					HeardSound( idEntity* ent, const char* action );
	idActor*					GetEnemy() const;
	void					TalkTo( idActor* actor );
	talkState_t				GetTalkState() const;

	bool					GetAimDir( const idVec3& firePos, idEntity* aimAtEnt, const idEntity* ignore, idVec3& aimDir ) const;

	void					TouchedByFlashlight( idActor* flashlight_owner );

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

	// 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();
	// 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 );
	// 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 );

	virtual void			Gib( const idVec3& dir, const char* damageDefName );

protected:
	// navigation
	idAAS* 					aas;
	int						travelFlags;

	idMoveState				move;
	idMoveState				savedMove;

	float					kickForce;
	bool					ignore_obstacles;
	float					blockedRadius;
	int						blockedMoveTime;
	int						blockedAttackTime;

	// turning
	float					ideal_yaw;
	float					current_yaw;
	float					turnRate;
	float					turnVel;
	float					anim_turn_yaw;
	float					anim_turn_amount;
	float					anim_turn_angles;

	// physics
	idPhysics_Monster		physicsObj;

	// flying
	jointHandle_t			flyTiltJoint;
	float					fly_speed;
	float					fly_bob_strength;
	float					fly_bob_vert;
	float					fly_bob_horz;
	int						fly_offset;					// prefered offset from player's view
	float					fly_seek_scale;
	float					fly_roll_scale;
	float					fly_roll_max;
	float					fly_roll;
	float					fly_pitch_scale;
	float					fly_pitch_max;
	float					fly_pitch;

	bool					allowMove;					// disables any animation movement
	bool					allowHiddenMovement;		// allows character to still move around while hidden
	bool					disableGravity;				// disables gravity and allows vertical movement by the animation
	bool					af_push_moveables;			// allow the articulated figure to push moveable objects

	// weapon/attack vars
	bool					lastHitCheckResult;
	int						lastHitCheckTime;
	int						lastAttackTime;
	float					melee_range;
	float					projectile_height_to_distance_ratio;	// calculates the maximum height a projectile can be thrown
	idList<idVec3, TAG_AI>			missileLaunchOffset;

	const idDict* 			projectileDef;
	mutable idClipModel*		projectileClipModel;
	float					projectileRadius;
	float					projectileSpeed;
	idVec3					projectileVelocity;
	idVec3					projectileGravity;
	idEntityPtr<idProjectile> projectile;
	idStr					attack;
	idVec3					homingMissileGoal;

	// chatter/talking
	const idSoundShader*		chat_snd;
	int						chat_min;
	int						chat_max;
	int						chat_time;
	talkState_t				talk_state;
	idEntityPtr<idActor>	talkTarget;

	// cinematics
	int						num_cinematics;
	int						current_cinematic;

	bool					allowJointMod;
	idEntityPtr<idEntity>	focusEntity;
	idVec3					currentFocusPos;
	int						focusTime;
	int						alignHeadTime;
	int						forceAlignHeadTime;
	idAngles				eyeAng;
	idAngles				lookAng;
	idAngles				destLookAng;
	idAngles				lookMin;
	idAngles				lookMax;
	idList<jointHandle_t, TAG_AI>	lookJoints;
	idList<idAngles, TAG_AI>		lookJointAngles;
	float					eyeVerticalOffset;
	float					eyeHorizontalOffset;
	float					eyeFocusRate;
	float					headFocusRate;
	int						focusAlignTime;

	// special fx
	bool					restartParticles;			// should smoke emissions restart
	bool					useBoneAxis;				// use the bone vs the model axis
	idList<particleEmitter_t, TAG_AI> particles;				// particle data

	renderLight_t			worldMuzzleFlash;			// positioned on world weapon bone
	int						worldMuzzleFlashHandle;
	jointHandle_t			flashJointWorld;
	int						muzzleFlashEnd;
	int						flashTime;

	// joint controllers
	idAngles				eyeMin;
	idAngles				eyeMax;
	jointHandle_t			focusJoint;
	jointHandle_t			orientationJoint;

	// enemy variables
	idEntityPtr<idActor>	enemy;
	idVec3					lastVisibleEnemyPos;
	idVec3					lastVisibleEnemyEyeOffset;
	idVec3					lastVisibleReachableEnemyPos;
	idVec3					lastReachableEnemyPos;
	bool					wakeOnFlashlight;

	bool					spawnClearMoveables;

	idHashTable<funcEmitter_t> funcEmitters;

	idEntityPtr<idHarvestable>	harvestEnt;

	// script variables
	idScriptBool			AI_TALK;
	idScriptBool			AI_DAMAGE;
	idScriptBool			AI_PAIN;
	idScriptFloat			AI_SPECIAL_DAMAGE;
	idScriptBool			AI_DEAD;
	idScriptBool			AI_ENEMY_VISIBLE;
	idScriptBool			AI_ENEMY_IN_FOV;
	idScriptBool			AI_ENEMY_DEAD;
	idScriptBool			AI_MOVE_DONE;
	idScriptBool			AI_ONGROUND;
	idScriptBool			AI_ACTIVATED;
	idScriptBool			AI_FORWARD;
	idScriptBool			AI_JUMP;
	idScriptBool			AI_ENEMY_REACHABLE;
	idScriptBool			AI_BLOCKED;
	idScriptBool			AI_OBSTACLE_IN_PATH;
	idScriptBool			AI_DEST_UNREACHABLE;
	idScriptBool			AI_HIT_ENEMY;
	idScriptBool			AI_PUSHED;

	//
	// ai/ai.cpp
	//
	void					SetAAS();
	virtual	void			DormantBegin();	// called when entity becomes dormant
	virtual	void			DormantEnd();		// called when entity wakes from being dormant
	void					Think();
	void					Activate( idEntity* activator );
public:
	int						ReactionTo( const idEntity* ent );
protected:
	bool					CheckForEnemy();
	void					EnemyDead();
	virtual bool			CanPlayChatterSounds() const;
	void					SetChatSound();
	void					PlayChatter();
	virtual void			Hide();
	virtual void			Show();
	idVec3					FirstVisiblePointOnPath( const idVec3 origin, const idVec3& target, int travelFlags ) const;
	void					CalculateAttackOffsets();
	void					PlayCinematic();

	// movement
	virtual void			ApplyImpulse( idEntity* ent, int id, const idVec3& point, const idVec3& impulse );
	void					GetMoveDelta( const idMat3& oldaxis, const idMat3& axis, idVec3& delta );
	void					CheckObstacleAvoidance( const idVec3& goalPos, idVec3& newPos );
	void					DeadMove();
	void					AnimMove();
	void					SlideMove();
	void					AdjustFlyingAngles();
	void					AddFlyBob( idVec3& vel );
	void					AdjustFlyHeight( idVec3& vel, const idVec3& goalPos );
	void					FlySeekGoal( idVec3& vel, idVec3& goalPos );
	void					AdjustFlySpeed( idVec3& vel );
	void					FlyTurn();
	void					FlyMove();
	void					StaticMove();

	// 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 );

	// navigation
	void					KickObstacles( const idVec3& dir, float force, idEntity* alwaysKick );
	bool					ReachedPos( const idVec3& pos, const moveCommand_t moveCommand ) const;
	float					TravelDistance( const idVec3& start, const idVec3& 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					DrawRoute() const;
	bool					GetMovePos( idVec3& seekPos );
	bool					MoveDone() const;
	bool					EntityCanSeePos( idActor* actor, const idVec3& actorOrigin, const idVec3& pos );
	void					BlockedFailSafe();

	// movement control
	void					StopMove( moveStatus_t status );
	bool					FaceEnemy();
	bool					FaceEntity( idEntity* ent );
	bool					DirectMoveToPosition( const idVec3& pos );
	bool					MoveToEnemyHeight();
	bool					MoveOutOfRange( idEntity* entity, float range );
	bool					MoveToAttackPosition( idEntity* ent, int attack_anim );
	bool					MoveToEnemy();
	bool					MoveToEntity( idEntity* ent );
	bool					MoveToPosition( const idVec3& pos );
	bool					MoveToCover( idEntity* entity, const idVec3& pos );
	bool					SlideToPosition( const idVec3& pos, float time );
	bool					WanderAround();
	bool					StepDirection( float dir );
	bool					NewWanderDir( const idVec3& dest );

	// effects
	const idDeclParticle*	SpawnParticlesOnJoint( particleEmitter_t& pe, const char* particleName, const char* jointName );
	void					SpawnParticles( const char* keyName );
	bool					ParticlesActive();

	// turning
	bool					FacingIdeal();
	void					Turn();
	bool					TurnToward( float yaw );
	bool					TurnToward( const idVec3& pos );

	// enemy management
	void					ClearEnemy();
	bool					EnemyPositionValid() const;
	void					SetEnemyPosition();
	void					UpdateEnemyPosition();
	void					SetEnemy( idActor* newEnemy );

	// attacks
	void					CreateProjectileClipModel() const;
	idProjectile*			CreateProjectile( const idVec3& pos, const idVec3& dir );
	void					RemoveProjectile();
	idProjectile*			LaunchProjectile( const char* jointname, idEntity* target, bool clampToAttackCone );
	virtual void			DamageFeedback( idEntity* victim, idEntity* inflictor, int& damage );
	void					DirectDamage( const char* meleeDefName, idEntity* ent );
	bool					TestMelee() const;
	bool					AttackMelee( const char* meleeDefName );
	void					BeginAttack( const char* name );
	void					EndAttack();
	void					PushWithAF();

	// special effects
	void					GetMuzzle( const char* jointname, idVec3& muzzle, idMat3& axis );
	void					InitMuzzleFlash();
	void					TriggerWeaponEffects( const idVec3& muzzle );
	void					UpdateMuzzleFlash();
	virtual bool			UpdateAnimationControllers();
	void					UpdateParticles();
	void					TriggerParticles( const char* jointName );

	void					TriggerFX( const char* joint, const char* fx );
	idEntity*				StartEmitter( const char* name, const char* joint, const char* particle );
	idEntity*				GetEmitter( const char* name );
	void					StopEmitter( const char* name );

	// AI script state management
	void					LinkScriptVariables();
	void					UpdateAIScript();

	//
	// ai/ai_events.cpp
	//
	void					Event_Activate( idEntity* activator );
	void					Event_Touch( idEntity* other, trace_t* trace );
	void					Event_FindEnemy( int useFOV );
	void					Event_FindEnemyAI( int useFOV );
	void					Event_FindEnemyInCombatNodes();
	void					Event_ClosestReachableEnemyOfEntity( idEntity* team_mate );
	void					Event_HeardSound( int ignore_team );
	void					Event_SetEnemy( idEntity* ent );
	void					Event_ClearEnemy();
	void					Event_MuzzleFlash( const char* jointname );
	void					Event_CreateMissile( const char* jointname );
	void					Event_AttackMissile( const char* jointname );
	void					Event_FireMissileAtTarget( const char* jointname, const char* targetname );
	void					Event_LaunchMissile( const idVec3& muzzle, const idAngles& ang );
	void					Event_LaunchHomingMissile();
	void					Event_SetHomingMissileGoal();
	void					Event_LaunchProjectile( const char* entityDefName );
	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_BeginAttack( const char* name );
	void					Event_EndAttack();
	void					Event_MeleeAttackToJoint( const char* jointname, const char* meleeDefName );
	void					Event_RandomPath();
	void					Event_CanBecomeSolid();
	void					Event_BecomeSolid();
	void					Event_BecomeNonSolid();
	void					Event_BecomeRagdoll();
	void					Event_StopRagdoll();
	void					Event_SetHealth( float newHealth );
	void					Event_GetHealth();
	void					Event_AllowDamage();
	void					Event_IgnoreDamage();
	void					Event_GetCurrentYaw();
	void					Event_TurnTo( float angle );
	void					Event_TurnToPos( const idVec3& pos );
	void					Event_TurnToEntity( idEntity* ent );
	void					Event_MoveStatus();
	void					Event_StopMove();
	void					Event_MoveToCover();
	void					Event_MoveToEnemy();
	void					Event_MoveToEnemyHeight();
	void					Event_MoveOutOfRange( idEntity* entity, float range );
	void					Event_MoveToAttackPosition( idEntity* entity, const char* attack_anim );
	void					Event_MoveToEntity( idEntity* ent );
	void					Event_MoveToPosition( const idVec3& pos );
	void					Event_SlideTo( const idVec3& pos, float time );
	void					Event_Wander();
	void					Event_FacingIdeal();
	void					Event_FaceEnemy();
	void					Event_FaceEntity( idEntity* ent );
	void					Event_WaitAction( const char* waitForState );
	void					Event_GetCombatNode();
	void					Event_EnemyInCombatCone( idEntity* ent, int use_current_enemy_location );
	void					Event_WaitMove();
	void					Event_GetJumpVelocity( const idVec3& pos, float speed, float max_height );
	void					Event_EntityInAttackCone( idEntity* ent );
	void					Event_CanSeeEntity( idEntity* ent );
	void					Event_SetTalkTarget( idEntity* target );
	void					Event_GetTalkTarget();
	void					Event_SetTalkState( int state );
	void					Event_EnemyRange();
	void					Event_EnemyRange2D();
	void					Event_GetEnemy();
	void					Event_GetEnemyPos();
	void					Event_GetEnemyEyePos();
	void					Event_PredictEnemyPos( float time );
	void					Event_CanHitEnemy();
	void					Event_CanHitEnemyFromAnim( const char* animname );
	void					Event_CanHitEnemyFromJoint( const char* jointname );
	void					Event_EnemyPositionValid();
	void					Event_ChargeAttack( const char* damageDef );
	void					Event_TestChargeAttack();
	void					Event_TestAnimMoveTowardEnemy( const char* animname );
	void					Event_TestAnimMove( const char* animname );
	void					Event_TestMoveToPosition( const idVec3& position );
	void					Event_TestMeleeAttack();
	void					Event_TestAnimAttack( const char* animname );
	void					Event_Burn();
	void					Event_PreBurn();
	void					Event_ClearBurn();
	void					Event_SetSmokeVisibility( int num, int on );
	void					Event_NumSmokeEmitters();
	void					Event_StopThinking();
	void					Event_GetTurnDelta();
	void					Event_GetMoveType();
	void					Event_SetMoveType( int moveType );
	void					Event_SaveMove();
	void					Event_RestoreMove();
	void					Event_AllowMovement( float flag );
	void					Event_JumpFrame();
	void					Event_EnableClip();
	void					Event_DisableClip();
	void					Event_EnableGravity();
	void					Event_DisableGravity();
	void					Event_EnableAFPush();
	void					Event_DisableAFPush();
	void					Event_SetFlySpeed( float speed );
	void					Event_SetFlyOffset( int offset );
	void					Event_ClearFlyOffset();
	void					Event_GetClosestHiddenTarget( const char* type );
	void					Event_GetRandomTarget( const char* type );
	void					Event_TravelDistanceToPoint( const idVec3& pos );
	void					Event_TravelDistanceToEntity( idEntity* ent );
	void					Event_TravelDistanceBetweenPoints( const idVec3& source, const idVec3& dest );
	void					Event_TravelDistanceBetweenEntities( idEntity* source, idEntity* dest );
	void					Event_LookAtEntity( idEntity* ent, float duration );
	void					Event_LookAtEnemy( float duration );
	void					Event_SetJointMod( int allowJointMod );
	void					Event_ThrowMoveable();
	void					Event_ThrowAF();
	void					Event_SetAngles( idAngles const& ang );
	void					Event_GetAngles();
	void					Event_GetTrajectoryToPlayer();
	void					Event_RealKill();
	void					Event_Kill();
	void					Event_WakeOnFlashlight( int enable );
	void					Event_LocateEnemy();
	void					Event_KickObstacles( idEntity* kickEnt, float force );
	void					Event_GetObstacle();
	void					Event_PushPointIntoAAS( const idVec3& pos );
	void					Event_GetTurnRate();
	void					Event_SetTurnRate( float rate );
	void					Event_AnimTurn( float angles );
	void					Event_AllowHiddenMovement( int enable );
	void					Event_TriggerParticles( const char* jointName );
	void					Event_FindActorsInBounds( const idVec3& mins, const idVec3& maxs );
	void 					Event_CanReachPosition( const idVec3& pos );
	void 					Event_CanReachEntity( idEntity* ent );
	void					Event_CanReachEnemy();
	void					Event_GetReachableEntityPosition( idEntity* ent );
	void					Event_MoveToPositionDirect( const idVec3& pos );
	void					Event_AvoidObstacles( int ignore );
	void					Event_TriggerFX( const char* joint, const char* fx );

	void					Event_StartEmitter( const char* name, const char* joint, const char* particle );
	void					Event_GetEmitter( const char* name );
	void					Event_StopEmitter( const char* name );
};

class idCombatNode : public idEntity
{
public:
	CLASS_PROTOTYPE( idCombatNode );

	idCombatNode();

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

	void				Spawn();
	bool				IsDisabled() const;
	bool				EntityInView( idActor* actor, const idVec3& pos );
	static void			DrawDebugInfo();

private:
	float				min_dist;
	float				max_dist;
	float				cone_dist;
	float				min_height;
	float				max_height;
	idVec3				cone_left;
	idVec3				cone_right;
	idVec3				offset;
	bool				disabled;

	void				Event_Activate( idEntity* activator );
	void				Event_MarkUsed();
};

#endif /* !__AI_H__ */
