// *************************************
//	New AI system defines

#define MAX_CAST_GROUPS		16
#define MAX_CHARACTERS		1024	  // formerly 64	// this includes players
#define	DEFAULT_MAX_ATTACK_DISTANCE		1024			// stand and attack enemies within this range
#define	DEFAULT_MAX_SIGHTING_DISTANCE	2048			// can't see things outside this range

#define	FACE_ANIM_DIST		2048	// AI will play an animation to straighten while attacking if beyind this distance

#define	AI_NOT_HOLSTERED_RANGE_1		200
#define	AI_NOT_HOLSTERED_RANGE_2		384
#define	AI_NOT_HOLSTERED_RANGE_3		800

#define	ENEMY_SIGHT_DURATION	3		// enemies sighted "less than this time" ago will be attacked

#define	SPAWNFLAG_IMMEDIATE_FOLLOW_PATH		32

// Cast Memory defines
#define NUM_MEMORY_TYPES		3

#define MEMORY_TYPE_FRIEND		0
#define MEMORY_TYPE_NEUTRAL		1
#define MEMORY_TYPE_ENEMY		2

// Pain orientation checks
#define	ORIENTATION_CENTER		0
#define	ORIENTATION_LEFT		1
#define	ORIENTATION_RIGHT		2

// Player order commands
#define ORDER_MOVE		1
#define ORDER_HOLD		2
#define ORDER_FOLLOWME	3	

// Side Trace
#define	SIDE_RANDOM		0
#define	SIDE_RIGHT		1
#define	SIDE_LEFT		-1

// General movement stuff
#define AI_TOO_CLOSE_DIST	48.0
#define AI_GUARDING_DIST	140.0

// ai flags
#define AI_NOWALK_FACE			0x00000001		// don't walk when turning to face
#define AI_TEMP_STAND_GROUND	0x00000002
#define	AI_NO_TALK				0x00000004		// prevent this character from talking (good for waiting in ambush)
#define	AI_GOAL_RUN				0x00000008		// set this for entities that the AI should run towards
#define	AI_FACE_ATTACK			0x00000010		// always face the enemy when attacking
#define	AI_MOVEOUT				0x00000020
#define	AI_MELEE				0x00000040		// this character can only do melee attacks
#define AI_GRENADE_GUY			0x00000080
#define	AI_DUCKATTACK			0x00000100		// only ducking for attack
#define	AI_GOAL_IGNOREENEMY		0x00000200
#define AI_NOSTEP				0x00000400
#define	AI_RELOAD				0x00000800		// need to reload before we can fire again
#define	AI_TAKECOVER_IGNOREHEALTH	0x00001000	// don't do health checks to see if we should resume attacking
#define	AI_GOALENT_MANUAL_CLEAR	0x00002000		// set this on the goal_ent if we should NOT set our ->goal_ent = NULL when we get there
#define	AI_DOKEY				0x00004000
#define	AI_IMMORTAL				0x00008000
#define AI_REPEAT_TALK_JESTURE	0x00010000		// keep making talking jesture
#define AI_SKILL_LADDER			0x00020000
#define AI_HOLD_POSITION		0x00040000
#define AI_TAKE_COVER			0x00080000
#define	AI_IGNORE_ENEMY			0x00100000
#define	AI_FASTWALK				0x00200000		// characters will WALK at twice the speed (including faster animation)
#define	AI_PLAYERCLIP			0x00400000		// uses PLAYERCLIP bounding instead of MONSTERCLIP
#define	AI_NO_TAKE_COVER		0x00800000		// don't take cover from anything
#define	AI_ADJUSTPITCH			0x01000000		// used for dogs so they angle up for stairs, ramps, etc
#define AI_TALK					0x02000000		// stop "avoid walking" when we're facing the character
#define	AI_SIDE_ATTACK			0x04000000
#define	AI_TURN_BLOCKED			0x08000000
#define AI_RUN_LIKE_HELL		0x10000000
#define AI_RUSH_THE_PLAYER		0x20000000
#define AI_HEARD_GUN_SHOT		0x40000000
#define AI_SIT_TALK				0x80000000


typedef enum
{
	resp_yes,
	resp_no
} response_t;


#define	STATE_NORMAL		0		// each character does their own thing
#define	STATE_FLEE			1		// abort attack, everyone flee
#define	STATE_CHARGE		2		// berzerk at charge_ent

// cast_group_t holds information relating to each team in the game, including fighting formations, etc

typedef struct
{
	int		state;
	int		charge_ent;				// index into g_edicts[]
} cast_group_t;

// Memory flags
#define	MEMORY_PERSONAL_OPINION		0x00000001		// set this if we have a personal vendetta on the character, which is not necessarily that of the group
#define	MEMORY_CONFIDENTIAL			0x00000002		// only share this information to a fellow group member, or under extreme conditions (like we are neutral and are bribed, or we are tortured)
#define MEMORY_HOSTILE_ENEMY		0x00000004		// attack upon sighting this character
#define	MEMORY_ASSHOLE				0x00000008		// we don't like this person, but they're not an enemy (just effects speech)
#define MEMORY_LASTWARNING			0x00000010		// we want to give a final warning to the player before we become hostile
#define	MEMORY_UPSET				0x00000020		// will use specific upset speech

#define MEMORY_AFRAID				0x00000040
#define MEMORY_TAUNT				0x00000080
#define	MEMORY_WARNED_BACKOFF		0x00000100		// we've warned this person to backoff already

#define	MEMORY_HIRE_FIRST_TIME		0x00000200
#define MEMORY_HIRE_ASK				0x00000400
#define MEMORY_HIRED				0x00000800
#define	MEMORY_NO_TALK				0x00001000		// don't talk to this person
#define	MEMORY_STARTED_ATTACK		0x00002000		// so AI friends only attack enemies that are attacking (and not evading)

// cast_memory_t stores a particular character's memory and opinion of another cast member, 
// for which it is aware of (has either seen, or is associated with)
typedef struct cast_memory_s
{
	int			cast_ent;		// "other" character index in the g_edicts[]

	vec3_t		last_known_origin;
	int			flags;			// deafult to 0, set various flags under certain conditions
	int			memory_type;	// one of MEMORY_TYPE_* constants, defines which cast_memory type this is in, for fast references

	float		timestamp;		// time that this information was updated 
											// (when gaining information from another character, 
											// this information is simply copied across, so we 
											// don't share information infinitely)
	float		timestamp_dist;	// distance at last sighting

	float		not_holstered_attack_time;
	float		ignore_time;	// pretend we can't see them until this time

	byte		inc;			// this can be used for anything, like counting the times we've warned this person, etc

	void		(*response)(edict_t *self, edict_t *other, response_t response);		// when a player talks to us, call this response routine

	short		last_known_closest_node;	// so we can speed things up

	struct cast_memory_s
				*next, *prev;
} cast_memory_t;

// *************************************

// New Procedure defines

// g_ai.c

void ai_onfire_run( edict_t *self, float dist );

void ai_sidestep( edict_t *self, float dist);

void AI_CheckEvade( edict_t *self );

qboolean AI_ClearSight ( edict_t *self, edict_t *other, qboolean boxtrace );

int AI_SideTrace( edict_t *self, float dist, float inyaw, int side );
int AI_YawTrace( edict_t *self, float dist, float inyaw );

void AI_MoveToPlatCenter( edict_t *self, edict_t *plat);
qboolean AI_TooClose(edict_t *self, edict_t *goal);
void AI_CheckStillInair(edict_t *self);
qboolean AI_CheckAttack(edict_t *self);
void AI_StartAttack(edict_t *self, edict_t *enemy);

void AI_StartRun( edict_t *self );

void AI_CheckStillClimbingLadder( edict_t *self );

void AI_EndAttack(edict_t *self);
void AI_EndJump(edict_t *self);
void AI_EndDeath(edict_t *self);
void AI_EndRun(edict_t *self);

void AI_End_CrouchStand_Down(edict_t *self);
void AI_End_CrouchStand_Up(edict_t *self);

int AI_GetOrientation( edict_t *self, edict_t *other );
qboolean AI_CheckTalk( edict_t *self );
void AI_TalkThink( edict_t *self, qboolean ismale );

qboolean ValidBoxAtLoc(vec3_t org, vec3_t mins, vec3_t maxs, edict_t *ignore, int mask);

qboolean AI_CheckTakeCover( edict_t *self );
qboolean AI_ForceTakeCover( edict_t *self, edict_t *enemy, qboolean ignorehealth );

// g_ai_fight.c

qboolean AI_Goto_CombatTarget( edict_t *self );
qboolean AI_BeginAttack( edict_t *self );
qboolean AI_HasLeaderButGoForEnemy( edict_t *self, edict_t *enemy );
void AI_CheckMakeEnemy( edict_t *self, edict_t *other );
void AI_AvoidDangerousEntity( edict_t *ent );

// g_ai_memory.c

qboolean AddCharacterToGame(edict_t *self);
void AI_RemoveFromMemory ( edict_t *self, cast_memory_t *memory );
void AI_AddToMemory ( edict_t *self, cast_memory_t *memory, int memory_type );
void AI_InitMemory( edict_t *self );
void AI_UnloadCastMemory (edict_t *self);

void AI_ShareEnemies ( edict_t *self, edict_t *other );
void AI_RecordSighting(edict_t *src, edict_t *dest, float dist);
void AI_UpdateCharacterMemories( int max_iterations );
void AI_MakeEnemy ( edict_t *self, edict_t *other, int memory_flags );

// g_ai_ents.c

void AI_Ent_droptofloor ( edict_t *self );
void ai_button_think (edict_t *self);
void ai_button_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf);



qboolean directly_infront_angle (vec3_t ang1, edict_t *self, edict_t *other);


