#include "..\game\game.h"
#include "..\game\fish.h"

#define	PIRAHNA_DAMAGE	4

#define	X	0
#define	Y	1
#define	Z	2
#define	XYZ	3

extern short rcossin_tbl[];
long	PirahnaHitWait = 0;

LEADER_INFO 	lead_info[MAX_FISH];
FISH_INFO		fish[MAX_FISH+(MAX_FISH*24)];		// MAX_FISH lead fish + 24 followers for each shoal.

long	fish_ranges[8][3] = {	5<<2,5<<2,4,
						7<<2,8<<2,5,
						5<<2,13<<2,5,
						5<<2,6<<2,6,
						5<<2,5<<2,5,
						6<<2,9<<2,6,
						0,0,0,
						0,0,0,
						0,0,0	};


void ControlFish(short item_number)
{
	ITEM_INFO	*item;
	long		lp,leader;
	long		angle,angadd,diff;
	long		result[XYZ];
	long		scr[3][XYZ];
	long		dx,dz;
	long		x,z,dist;
	long		ftx,ftz;
	long		pirahna_attack,fish_Xrange,fish_Zrange,fish_Yrange;

	PHD_3DPOS pos;
	FISH_INFO	*fptr;
	FISH_INFO	*fptr2;

	item = &items[item_number];
	if (item->active == 0)
		return;
	leader = item->hit_points;
	if (leader == -1)
		return;
	if (!lead_info[leader].on)
		SetupFish(leader,item);

	if (item->object_number == PIRAHNAS)
		pirahna_attack = (lara_item->room_number == item->room_number);
	else
		pirahna_attack = 0;

	if (PirahnaHitWait)
		PirahnaHitWait--;
//
// Control the leader!!!
//
	fptr = (FISH_INFO *) &fish[leader];

	if (pirahna_attack)
	{
		lead_info[leader].angle = fptr->angle = (-(mGetAngle(fptr->x+item->pos.x_pos,fptr->z+item->pos.z_pos,lara_item->pos.x_pos,lara_item->pos.z_pos)+0x4000)>>4)&4095;
		lead_info[leader].speed = (rand()&63)+192;
	}

	diff = fptr->angle-lead_info[leader].angle;

	if (diff > 2048)
		diff -= 4096;
	else if (diff < -2048)
		diff += 4096;

	if (diff > 128)
	{
		fptr->angadd-=4;
		if (fptr->angadd < -120)
			fptr->angadd = -120;
	}
	else	if (diff < -128)
	{
		fptr->angadd+=4;
		if (fptr->angadd > 120)
			fptr->angadd = 120;
	}
	else
	{
		fptr->angadd-=fptr->angadd>>2;
		if (abs(fptr->angadd)<4)
			fptr->angadd=0;
	}

	fptr->angle += fptr->angadd;

	if (diff > 1024)
		fptr->angle += fptr->angadd>>2;
	fptr->angle &= 4095;

	diff = fptr->speed - lead_info[leader].speed;

	if (diff < -4)
	{
		diff = fptr->speed + (rand()&3)+1;
		if (diff<0)
			diff = 0;
		fptr->speed = diff;

	}
	else	if (diff > 4)
	{
		diff = fptr->speed - (rand()&3)-1;
		if (diff > 255)
			diff = 255;
		fptr->speed = diff;
	}

	fptr->swim += fptr->speed>>4;
	fptr->swim &= 63;

	z = fptr->z;
	x = fptr->x;

	z += (((rcossin_tbl[(fptr->angle<<1)+1])*(fptr->speed))>>13);
	x += -(((rcossin_tbl[(fptr->angle<<1)])*(fptr->speed))>>13);

	if (pirahna_attack == 0)
	{
		fish_Xrange = lead_info[leader].Xrange;
		fish_Zrange = lead_info[leader].Zrange;
		if (z < -fish_Zrange)
		{
			z = -fish_Zrange;
			if (fptr->angle < 2048)
				lead_info[leader].angle = fptr->angle - ((rand()&127)+128);
			else
				lead_info[leader].angle = fptr->angle + ((rand()&127)+128);
			lead_info[leader].angle_time = (rand()&15)+8;
			lead_info[leader].speed_time = 0;
		}
		else if (z > fish_Zrange)
		{
			z = fish_Zrange;
			if (fptr->angle > 3072 )
				lead_info[leader].angle = fptr->angle - ((rand()&127)+128);
			else
				lead_info[leader].angle = fptr->angle + ((rand()&127)+128);
			lead_info[leader].angle_time = (rand()&15)+8;
			lead_info[leader].speed_time = 0;
		}
		if (x < -fish_Xrange)
		{
			x = -fish_Xrange;
			if (fptr->angle < 1024)
				lead_info[leader].angle = fptr->angle - ((rand()&127)+128);
			else
				lead_info[leader].angle = fptr->angle + ((rand()&127)+128);
			lead_info[leader].angle_time = (rand()&15)+8;
			lead_info[leader].speed_time = 0;
		}
		else if (x > fish_Xrange)
		{
			x = fish_Xrange;
			if (fptr->angle < 3072)
				lead_info[leader].angle = fptr->angle - ((rand()&127)+128);
			else
				lead_info[leader].angle = fptr->angle + ((rand()&127)+128);
			lead_info[leader].angle_time = (rand()&15)+8;
			lead_info[leader].speed_time = 0;
		}

		if ((rand()&15)==0)
			lead_info[leader].angle_time=0;

		if (lead_info[leader].angle_time)
			lead_info[leader].angle_time--;
		else
		{
			lead_info[leader].angle_time = (rand()&15)+8;
			angadd = ((rand()&63)+16)-8-32;
			if ((rand()&3)==0)
				lead_info[leader].angle += angadd<<5;
			else
				lead_info[leader].angle += angadd;
			lead_info[leader].angle&=4095;
		}

		if (lead_info[leader].speed_time)
			lead_info[leader].speed_time--;
		else
		{
			lead_info[leader].speed_time = (rand()&31)+32;
			if ((rand()&7)==0)
				lead_info[leader].speed = (rand()&127)+128;
			else if ((rand()&3)==0)
				lead_info[leader].speed += (rand()&127)+32;
			else if (lead_info[leader].speed > 140)
				lead_info[leader].speed -= (rand()&31)+48;
			else
			{
				lead_info[leader].speed_time = (rand()&3)+4;
				lead_info[leader].speed += (rand()&31)-15;
			}
		}
	}

	fptr->x = ftx = x;
	fptr->z = ftz = z;

//
// Follow the leader.
//
	fptr = (FISH_INFO *) &fish[MAX_FISH+(leader*24)];

	for (lp=0;lp<24;lp++)
	{
		if (item->object_number == PIRAHNAS && (lp&1) == 0)
		{
			pos.x_pos = item->pos.x_pos+fptr->x;
			pos.y_pos = item->pos.y_pos+fptr->y;
			pos.z_pos = item->pos.z_pos+fptr->z;
			if (FishNearLara(&pos,256))
			{
				if (PirahnaHitWait == 0)
				{
					DoBloodSplat(item->pos.x_pos+fptr->x,item->pos.y_pos+fptr->y,item->pos.z_pos+fptr->z,0,0,lara_item->room_number);
					PirahnaHitWait = 8;
				}
				lara_item->hit_points -= PIRAHNA_DAMAGE;
			}
		}

//		if ((rand()&3)==0 && lp != 23 && lp != 0)
//		{
//			fptr2 = fptr-1;
//			angle = (-(mGetAngle(fptr->x,fptr->z,fptr2->x,fptr2->z)+0x4000)>>4)&4095;
//		}
//		else
			angle = (-(mGetAngle(fptr->x,fptr->z,ftx,ftz)+0x4000)>>4)&4095;
		dx = fptr->x - ftx + ((24-lp)<<7);
		dz = fptr->z - ftz - ((24-lp)<<7);

		dx *= dx;
		dz *= dz;

		diff = fptr->angle-angle;

		if (diff > 2048)
			diff -= 4096;
		else if (diff < -2048)
			diff += 4096;

		if (diff > 128)
		{
			fptr->angadd-=4;
			if (fptr->angadd < -92-(lp>>1))
				fptr->angadd = -92-(lp>>1);
		}
		else	if (diff < -128)
		{
			fptr->angadd+=4;
			if (fptr->angadd > 92+(lp>>1))
				fptr->angadd = 92+(lp>>1);
		}
		else
		{
			fptr->angadd-=fptr->angadd>>2;
			if (abs(fptr->angadd)<4)
				fptr->angadd=0;
		}

		fptr->angle += fptr->angadd;

		if (diff > 1024)
			fptr->angle += fptr->angadd>>2;
		fptr->angle &= 4095;

		if ((dx+dz) < (0x100000 + ((lp<<7)*(lp<<7))))
		{
			if (fptr->speed > 32+(lp<<1))
				fptr->speed -= fptr->speed>>5;
		}
		else
		{
			if (fptr->speed < 160+(lp>>1))
				fptr->speed += (rand()&3)+1+(lp>>1);
			if (fptr->speed > 160+(lp>>1)-(lp<<2))
				fptr->speed = 160+(lp>>1)-(lp<<2);
		}

		if (rand()&1)
			fptr->speed -= rand()&1;
		else
			fptr->speed += rand()&1;

		if (fptr->speed < 32)
			fptr->speed = 32;
		else if (fptr->speed > 200)
			fptr->speed = 200;

		fptr->swim += (fptr->speed>>4)+(fptr->speed>>5);
		fptr->swim &= 63;

		z = fptr->z + (((rcossin_tbl[(fptr->angle<<1)+1])*(fptr->speed))>>13);
		x = fptr->x - (((rcossin_tbl[(fptr->angle<<1)])*(fptr->speed))>>13);

		if (z < -32000)
			z = -32000;
		else if (z > 32000)
			z = 32000;
		if (x < -32000)
			x = -32000;
		else if (x > 32000)
			x = 32000;

		fptr->x = x;
		fptr->z = z;

		fptr++;
	}
}

void SetupFish(long leader, ITEM_INFO *item)
{
	long	lp,fish_Xrange,fish_Zrange, fish_Yrange;

	fish_Xrange = lead_info[leader].Xrange;
	fish_Yrange = lead_info[leader].Yrange;
	fish_Zrange = lead_info[leader].Zrange;

	fish[leader].x = 0;
	fish[leader].y = 0;
	fish[leader].z = 0;
	fish[leader].angle = 0;
	fish[leader].speed = (GetRandomControl()&63)+8;
	fish[leader].swim = GetRandomControl()&63;

	for (lp=0;lp<24;lp++)
	{
		fish[MAX_FISH+(leader*24)+lp].x = (GetRandomControl()%(fish_Xrange<<1))-fish_Xrange;
		if ((lp&7)==0)
			fish[MAX_FISH+(leader*24)+lp].y = fish_Yrange;
		else
			fish[MAX_FISH+(leader*24)+lp].y = (GetRandomControl()%fish_Yrange);
		fish[MAX_FISH+(leader*24)+lp].z = (GetRandomControl()%(fish_Zrange<<1))-fish_Zrange;

		fish[MAX_FISH+(leader*24)+lp].angle = GetRandomControl()&4095;
		fish[MAX_FISH+(leader*24)+lp].speed = (GetRandomControl()&31)+32;
		fish[MAX_FISH+(leader*24)+lp].swim = GetRandomControl()&63;
	}

	lead_info[leader].on = 1;
	lead_info[leader].angle = 0;
	lead_info[leader].speed = (GetRandomControl()&127)+32;
	lead_info[leader].angle_time = 0;
	lead_info[leader].speed_time = 0;
}

long CountActiveShoals()
{
	long	lp,cnt;
	cnt = 0;
	for (lp=0;lp<MAX_FISH;lp++)
	{
		if (lead_info[lp].on)
			cnt++;
	}
	return(cnt);
}
