
#ifndef __ENEMIES_H__
#define __ENEMIES_H__

#ifndef __ROUTE_H__
#include "route.h"
#endif
#ifndef _COLLIDE_H_
#include "collide.h"
#endif

#ifndef _OVERLAYS_H_
#include "overlays.h"
#endif

#ifndef __LIGHTS_H__
#include "lights.h"
#endif

#ifndef __SCENICS_H__
#include "scenics.h"
#endif

#ifndef _PUZZLES_H_
#include "puzzles.h"
#endif

#define GRAVITY	(16)
// CPW: #define GRAVITY	(8)


#define DOG_INSTANT_PERSUIT

enum
{
	ENEMY_UNDEFINED,
	ENEMY_DOG,
	ENEMY_CHICKEN,
	ENEMY_SLEEPYDOG,
	ENEMY_MRT_TORCH,
	ENEMY_MRT_PATROL,
	ENEMY_MRST_PATROL,
	ENEMY_MRST_CLIP_PATROL,
	ENEMY_SCENIC_CHICKEN,
};


#define STATE_NUMBER		(17)

// CPW: Generic actions don't need to be local to a particular enemy
#define STATE_NULL				(0)
#define STATE_SLEEPING			(1)
#define STATE_WANDERING			(2)
#define STATE_PERSUIT			(3)
#define STATE_GETTINGUP			(4)
#define STATE_SITTINGDOWN		(5)
#define STATE_WAITING			(6)
#define STATE_AGAINSTWALL		(7)
#define STATE_CRAWLING			(8)
#define STATE_JUMPING			(9)
#define STATE_SHOULDERPUSHING	(10)
#define STATE_PICKINGUP			(11)
#define STATE_LANDING			(12)
#define STATE_HIDING			(13)
#define STATE_PUSHBUTTON		(14)
#define STATE_CLINGING			(15)

// CPW: these aren't generic
#define STATE_ABANDONING		(32)
#define STATE_GROWLING			(33)
#define STATE_ALERTED			(34)
#define STATE_TURNEDOFF			(35)
#define STATE_STUNNED			(36)
#define STATE_THINKING			(37)


#define RUNFLAGS_NONE			(0)
#define RUNFLAGS_PUSHINGPLAT	(1)
#define RUNFLAGS_VISIBLE		(2)
#define RUNFLAGS_FORCEFACE		(4)
#define RUNFLAGS_DJUMPPENDING	(8)
#define RUNFLAGS_DJUMPALLOWED	(16)
#define RUNFLAGS_ONGROUND		(32)
#define RUNFLAGS_FORCETOFRONT	(64)
#define RUNFLAGS_NOTLOOKING		(128)
#define RUNFLAGS_NOGRAVITY		(256)
#define RUNFLAGS_RESTORECTRL	(512)
#define RUNFLAGS_BEENONGROUND	(1024)

#define ENEMYMESSAGE_NULL		(0)
#define ENEMYMESSAGE_FOLLOW		(1)

#define ENEMYMOVE_SET			(0)
#define ENEMYMOVE_TENDTO		(1)

#define ENEMYFACING_NO			(0)
#define ENEMYFACING_YES			(1)
#define ENEMYFACING_MUTUALLY	(2)

#define ANIM_DONTBLEND			(1)
#define ANIM_DONTLOOP			(2)
#define ANIM_DONTQUEUE			(4)

#define ENEMYFLAGS_NOTANENEMY		(1)
#define ENEMYFLAGS_MAINCHARACTER	(2)

/*
typedef struct tagENEMY_POINT
{
	VECTOR v;
	int pause;
}ENEMY_POINT;
*/

typedef struct ENEMYBFFLIST
{
	unsigned long id;		// Standard BFF header
	unsigned long len;
	unsigned long crc;

// Followed by the first header of the list
}ENEMYBFFLIST;



typedef struct ENEMYDEF
{
	struct ENEMYDEF *next;
	int tag;
	
	int x,y,z;
	int type;

	unsigned long mesh_crc;

	short ya;
	short sdummy;
//	int dummies[3];	// little bit of expansion...
	char mesh_name[12];	// rqd for anim-eyes

	int nPoints;
}ENEMYDEF;


typedef struct tagENEMYPOINT
{
	VECTOR v;
	int pause;
	int lookAtTag;
}ENEMYPOINT;

typedef struct tagENEMY *ENEMYPOINTER;
typedef void * VOIDPOINTER;

enum
{
	COLLIDE_WITH_MAINCHAR,
	COLLIDE_WITH_SPROUT
};

typedef struct tagENEMYINFO
{// CPW: name of enemy
	char *sName;						
	int (*pHandler)(ENEMYPOINTER);		// CPW: pointer to handler function
	void (*pCollide)(ENEMYPOINTER, VOIDPOINTER, int);	// When a chicken collides with a dog...
	int	defaultState;					// CPW: state that enemy is initialised to
	unsigned long flags;				// CPW: flags
	int collRadius;						// CPW: radius of collision sphere
	int collYoffset;					// CPW: Y offset of collision sphere
	void **ppSpecial;					// CPW: pointer to special data for this enemy

	int capsule_r;			// enemy->chicken interaction capsule
	VECTOR capsule_back;	// back. +ve z
	VECTOR capsule_front;	// front. -ve z

	char nme_type;
	char dummy[3];
}ENEMYINFO;

#define DOG_ROUTE_MAX	20

typedef struct tagENEMY
{
	struct tagENEMY *prev;
	struct tagENEMY *next;

	struct{
		ENEMYDEF *pDef;
		ENEMYPOINT *pPoints;
		PSIOBJECT *pHead;
		ENEMYINFO *pInfo;
		SfxSampleType **ppSamples;

		unsigned long nameCRC;

		struct{
			int			nFrames;
			TextureAnimType *pAnim;
			TextureType *pDummy;
			TextureType *pFrames[4];	// CPW: only 4 frames allowed at the moment
		}animeyes;

		PSIMODEL	*pModel;	// CPW: original PSI model
		ACTOR		*pActor;	// CPW: pointer to the actor

	}readData;


	struct{
		COLLDATA	collision;	// CPW: enemy's own collision

		VECTOR		collPos;
		VECTOR		collVel;

// CPW: 		int			collRadius;	// CPW: radius of collision sphere
// CPW: 		int			collYoffset;// CPW: Y offset of collision sphere
	}coll;


	struct{
		short		desiredAngle;
		short		actualAngle;
		short		desiredElevation;
		short		actualElevation;
	}head;	// CPW: Ever tried eating your head? Eat this instead, it's more intense. Stay hungry!
/*
	struct{
		int			num;
		OVERRIDE	data[4];
	}override;
*/
	struct{
		short		pointFrom;
		short		pointTo;
		int			timer;
		VECTOR		pointLookAt;

		VECTOR		pointComingFrom;	// Where the dog was when it made the decision to go somewhere
		VECTOR		pointGoingTo;		// Where it's going.
		short		turnspeed_thiscorner;
		short		dummy;
	}points;

	struct{
		int			tag;
		SCENIC		*pScenic;
	}ratClimbing;

	struct{
		int			heightAtJumpStart;
		int			timeAtJumpTop;
	}jump;

	void *extras;

	short		route_len;
	char		route_truncated;
	ROUTEBOX_VECTOR	route[DOG_ROUTE_MAX];	// relevant for the dogs. And possibly Mr & Mrs T.
	VECTOR	route_target;

// RFW - There's a little array of inventories in the gameSaveData,
// of which we always use ginger's anyway (!) see the inventory doc on X
//	inventoryType	inv;

	struct tagENEMY *pKilledBy;	// CPW: enemy that chicken was killed by
	long		flags;
	long		runFlags;	// CPW: run time flags, ie. pushing platform, etc
	// CPW: int			upThrust;	// CPW: anti-gravity force, i.e. jump
	int			blinkCtr;
	int			blinkOverride;	// If you set this every raster, then the eyes will be locked at the given frame
	TEXINSTANCE *texinstance;	// Different eyes on different dogs

	int			moveSpeed;	// CPW: current movement speed (use to calculate anim speed, and mevement of model)
	int			dir;		// CPW: current facing direction
	int			desiredDir;	// CPW: the direction we want
	VECTOR		pos;		// CPW: current game position of enemy
	VECTOR		vel;		// CPW: current game velocity of enemy
	int			animSpeed;	// CPW: current animation speed
	int			stateCtr;	// CPW: number of frames the character has been in this state
	short		state;		// CPW: whatever the enemy is doing at the moment
	short		oldState;	// CPW: old state
	short		turning;
	short		lastTurning;

	int			view_range_current;	// RFW: Interface from the enemy vision checks to the onscreen map
	int			view_fov_current;
	int			view_range_rqd;		// can grow & shrink wiv alert state
	int			view_fov_rqd;
}ENEMY;

typedef struct tagENEMYLIST
{
	ENEMY head;
	int numEntries;
}ENEMYLIST;

extern	ENEMYLIST	enemyList;

extern char enemyEndingLevelFlag;	// invulnerability, in essence
extern char enemyControllingLeadFlag;



// "Extra" type-dependant structures

typedef struct MRT_TORCH_STR
{
	VECTOR alertpoint;

	int torch_counter;
	int torch_ya;
	EXLIGHT_TYPE *torchlight;
}MRT_TORCH_STR;

#define DOG_PERSUING_CHICKEN	0
#define DOG_PERSUING_SPROUT		1
typedef struct PATROLDOGSTR
{
	PSIOBJECT *bend_objects[7];
	short corner_time;	// total amount of time to be spent turning the corner
	short corner_angle;	// total angle of the corner
	short angle;

	VECTOR alertpoint;

	VECTOR	alertvel;
	int		alertcountdown;
	int		persuing_what;
	// pE->turning counter
}PATROLDOGSTR;

//	SPINE			temp->rotate.vy = -angle / 4;
//	LEFTHIP			temp->rotate.vy = -angle / 2;
//	RIGHTHIP		temp->rotate.vy = -angle / 2;
//	TAIL			temp->rotate.vy = -angle / 2;
//	LEFTSHOULDER	temp->rotate.vy = angle / 2;
//			temp->matrix.t[0] = - rsin(angle / 4) * 19 / 4096  + rcos(angle / 4) * 104 / 4096;
//			temp->matrix.t[2] = - rcos(angle / 4) * 19 / 4096  - rsin(angle / 4) * 104 / 4096;
//	RIGHTSHOULDER	temp->rotate.vy = angle / 2;
//			temp->matrix.t[0] = - rsin(angle / 4) * 19 / 4096  + rcos(angle / 4) * -104 / 4096;
//			temp->matrix.t[2] = - rcos(angle / 4) * 19 / 4096  - rsin(angle / 4) * -104 / 4096;
//	HEAD			temp->rotate.vy = angle * 3 /5;
//			temp->matrix.t[0] = - rsin(angle / 4) * 162 / 4096;
//			temp->matrix.t[2] = - rcos(angle / 4) * 162 / 4096;



typedef struct
{
	int numCollBoxes;
	COLLBOX *pCollBoxes;
}ENEMYGLOBALS;

extern ENEMYLIST	enemyList;
extern ENEMYGLOBALS	enemyGlobals;



extern ENEMYINFO enemyInfo[];
extern TextureType *hourglass_texes[8];




ENEMY *enemyAdd(ENEMYINFO *pInf);
void enemyDelete(ENEMY *pE);
void enemyDeleteAll(void);

void enemyTellThemAboutCollision(int numCollBoxes, COLLBOX *pCollBoxes);
int enemyInitialiseList(void);
int enemyProcessAll(void);
int enemyDrawAll(void);
void enemySendMessage(ENEMY *pE, int messageCode, void *pMessBlk);
int	enemyTendTowards(int desired, int actual, int maxturn);
//ENEMY *enemyIsThereAnythingToPickUp(ENEMY *);
void enemyMakeMain(ENEMY *pME);
void enemyBlinkHandler(ENEMY *);

int enemyUpdateChicken(ENEMY *);


void enemyLookAtPos(ENEMY *pE, VECTOR *vec);
// Only use on those enemies that have well-defined heads
void enemyLookAtPos3D(ENEMY *pE, VECTOR *vec);

int enemyCanSeeCheck(ENEMY *pE, VECTOR *vec, int fov, int range);
int enemyCanSeeCheckWellyTest(ENEMY *pE, VECTOR *vec, int fov, int range);


void enemyLinkBFF(ENEMYBFFLIST *list);


ENEMY *enemyFind(int tag);

int enemyAngleCalc(ENEMY *pE, int pointno);
int enemyFindDeltaAngleTo(ENEMY *pE, VECTOR *vec);
int enemyFindAbsAngleTo(ENEMY *pE, VECTOR *vec);


// These are actually defines...
void enemyEnable(ENEMY *enemy, int enable);
int enemyIsEnabled(ENEMY *enemy);

// Here's the defines for quick & easy functions
#define enemyEnable(enemy, enable)  {if(enable) { (enemy)->runFlags |= RUNFLAGS_VISIBLE;} else { (enemy)->runFlags &= ~RUNFLAGS_VISIBLE; } }
#define enemyIsEnabled(enemy)  (((enemy)->runFlags & RUNFLAGS_VISIBLE) != 0)

// Prevent, for example, Mrs Tweedy from looking for chickens when she's behind a closed door.
// (tbd - link into the puzzle engine)
//#define	enemyAlert(enemy,alert)	{if(alert) { ((ENEMY *)(enemy))->runFlags &= ~RUNFLAGS_NOTLOOKING; DB("looking %d\n",((ENEMY *)(enemy))->readData.pDef->tag);} else { (enemy)->runFlags |= RUNFLAGS_NOTLOOKING; DB("not looking %d &%8x\n",(enemy)->readData.pDef->tag,(enemy)->runFlags);} }
#define	enemyAlert(enemy,alert)	{if(alert) { ((ENEMY *)(enemy))->runFlags &= ~RUNFLAGS_NOTLOOKING;} else { (enemy)->runFlags |= RUNFLAGS_NOTLOOKING;} }


#define ENEMY_DEFAULTANIMSPEED (256)

#define SETSTATE(S)	{int copy; copy = (S); pE->oldState=pE->state; pE->state=copy; pE->stateCtr=-1;}
#define SETSPEED(S) {pE->moveSpeed=(S)>>7; pE->animSpeed=(S)>>4;}

// For calling from the puzzle engine with set_scenic_anim
void enemySetAnim(ENEMY *pE, int anim, int flags);
int enemyCheckCollision(void *source, int sourcetype, VECTOR *chickencentre, int radius);

// We're leaving. Tell the dogs that the chicken is invisible and invulnerable whilst the player hasn't got control of it.
void enemyInformEndingLevel();
void enemySendLeadTo(POSMARK *target, int anim, int speed, int dummy);

// ============================================


void enemyMove(ENEMY *pE, int desiredSpeed, int action, int accel);
int enemySteerTowards(ENEMY *pE, VECTOR *pPos, int turning);
int enemyArrivedCheck(VECTOR *comingfrom, VECTOR *pos, VECTOR *target, int distance);
void enemyBeginTrekToNextPoint(ENEMY *pE);

int enemyUpdateMrsTweedy(ENEMY *pE);
void enemyMrsTweedyCollide(ENEMY *pE,void *pWith, int withtype);


void enemyMrsTInitPatrol(ENEMY *pE);
void enemyMrTInitTorch(ENEMY *pE);
void enemyMrTInitPatrol(ENEMY *pE);

void enemyMrTReleaseTorch(ENEMY *pE);

// ============================================

void enemyDogInitPatrol(ENEMY *pE);
void enemyDogInitSleepy(ENEMY *pE);


int enemyUpdateDog(ENEMY *pE);
int enemyUpdateSleeping(ENEMY *pE);

void enemySleepyCollide(ENEMY *pE,void *pWith, int withtype);
void enemyDogCollide(ENEMY *pE,void *pWith, int withtype);
int enemyDogTennisRacketPickup(int item);

void dogInitRoute(ENEMY *pE, VECTOR *target, int resetfrom);



// The hourglass is required on those levels with dogs in.
// (ie, the hg textures needn't be generic. We could sptmerge 'em)
void nmeDogEnsureHourglass();
void nmeDogStartHourglass(int state);
void nmeDogCycleHourglass();
void nmeDogDrawHourglass();

// MK II Hourglass
enum
{
	HOURGLASS_NOWT,					
	HOURGLASS_IN_LIGHT,				
	HOURGLASS_IN_SEARCHLIGHT,		
	HOURGLASS_MAKING_LOUD_NOISE,		
	HOURGLASS_MAKING_QUIET_NOISE,		// Technically - quiet noise whilst in hearing range of something
	HOURGLASS_DOG_IN_PERSUIT_MODE,	
	HOURGLASS_DOG_IN_GROWL_MODE,		
	HOURGLASS_DOG_IN_THINKING_MODE,	
	HOURGLASS_MRT_IN_PERSUIT_MODE,	
	HOURGLASS_IN_DOG_FOV,			
	HOURGLASS_IN_MRT_FOV,			
	HOURGLASS_MRT_COLLIDE,			
	HOURGLASS_OLD_ALERT,
};
void hourglass2Inform(int event, VECTOR *pos);
void hourglass2Cycle();
void hourglass2Draw();




void enemyDogFindAndAlert(VECTOR *position);

void enemyFindInteresting(VECTOR *character_pos, int character_dir, VECTOR **best, int *max_range);

#define HOURGLASS_NEEDS_UPDATING (hourglass_texes[0] != 0)

int enemyUpdateMrTweedyPatrol(ENEMY *pE);
void enemyMrTweedyPatrolCollide(ENEMY *pE,void *pWith, int withtype);

void enemyMrTweedyDrawTorch(ENEMY *pE);
void enemyMrTStartPersuit(ENEMY *pE,VECTOR *position, int buzzer);

int enemyPlayEnvironmentFootstep(VECTOR *pPos, int volume);
int enemyPlayEnvironmentFootstepNoDogCheck(VECTOR *pPos, int volume);


#if PALMODE==1
	#define HGLASS_X	140
	#define HGLASS_Y	-120
#else
	#define HGLASS_X	140
	#define HGLASS_Y	-110
#endif


void nmeDrawHourglass(int x, int y, int pos, int sand);
int hourglassTopSprite(TextureType *spr, int x, int y, int t);
int hourglassBotSprite(TextureType *spr, int x, int y, int yb);
extern int hourglass_dog_persuit;
extern int hourglass_game_is_alert;
void enemiesInformAboutPosition(VECTOR *position);

//int enemyUpdateMrTweedyTorch(ENEMY *pE);
//void enemyMrTweedyTorchCollide(ENEMY *pE,ENEMY *pWith);

// ============================================

#define MRST_FORWARD_SPEED 19
#define MRT_FORWARD_SPEED 24

#define DOG_FORWARD_SPEED	36
#define DOG_RUN_FORWARD_SPEED	80

#define PATROL_DOG_KILLER_FOV   1024
#define PATROL_DOG_KILLER_RANGE (100 * 8)

//#define PATROL_DOG_SIGHT_RANGE (250 * 8)
#define PATROL_DOG_SIGHT_RANGE (400 * 8)
#define PATROL_DOG_SIGHT_FOV (1024)

// Dog's been told to specifically look at a point
// (& does so regardless of "alert" state)
#define PATROL_DOG_LOOKINGAT_RANGE (600 * 8)
#define PATROL_DOG_LOOKINGAT_FOV (300)
#define PATROL_DOG_LOOKINGAT_KILLER_RANGE (300 * 8)	// So if it's LOOKING, it can kill you inside boxes

// This is for hearing you running rather than tiptoeing/walking
#define PATROL_DOG_HEARS_RUN_RANGE  (250 * 8)
#define PATROL_DOG_HEARS_WALK_RANGE  (150 * 8)
#define THINKING_DOG_LOOKANGLE 700	// was 900
#define PATROL_DOG_SPROUT_PREDICT_TIME	10



// slightly larger range after it's seen you
#define PATROL_DOG_EXTRA_SIGHT_RANGE ((PATROL_DOG_SIGHT_RANGE) + (150 * 8))
#define PATROL_DOG_EXTRA_SIGHT_FOV ((PATROL_DOG_SIGHT_FOV) + 40)

#define MRT_EXTRA_SIGHT_RANGE ((MRT_SIGHT_RANGE) + (50 * 8))
#define MRT_EXTRA_SIGHT_FOV ((MRT_SIGHT_FOV) + 40)



#define SLEEPY_DOG_KILLER_FOV   1024
#define SLEEPY_DOG_KILLER_RANGE (100 * 8)

//#define SLEEPY_DOG_SIGHT_RANGE (250 * 8)	// how far away you need to be for it to fall asleep again
#define SLEEPY_DOG_SIGHT_RANGE (500 * 8)
#define SLEEPY_DOG_SIGHT_FOV   1800

#define WATCHING_DOG_SIGHT_FOV   300

#define MRST_SIGHT_RANGE (200 * 8)
#define MRST_SIGHT_FOV (1024)

//#define MRT_SIGHT_RANGE (200 * 8)
#define MRT_SIGHT_RANGE (400 * 8)
#define MRT_SIGHT_FOV (1024)

#define MRT_TORCH_DISTANCE	(3000)

//#define MRT_DARK_SIGHT_RANGE (100 * 8)
//#define MRT_DARK_SIGHT_FOV (512)

#define MRT_DARK_SIGHT_RANGE (400 * 8)
#define MRT_DARK_SIGHT_FOV (1024)

#define MRT_KILLER_FOV   1024
#define MRT_KILLER_RANGE (100 * 8)

//#define MRT_TORCH_DISTANCE	(2000)

#define MRT_PIEBARN_SIGHT_FOV	(1024)
#define MRT_PIEBARN_SIGHT_RANGE	(200*8)

#endif


