///////////////////////////////////////////////////////////////////////////////
//	goldfish AI
//
///////////////////////////////////////////////////////////////////////////////

#include	"world.h"

#include	"ai.h"
#include	"ai_utils.h"

#include	"ai_move.h"
#include	"ai_frames.h"

///////////////////////////////////////////////////////////////////////////////
//	exports
///////////////////////////////////////////////////////////////////////////////

DllExport	void	goldfish (userEntity_t *self);
DllExport	void	fish_goldfish (userEntity_t *self);
DllExport	void	fish_grayfish (userEntity_t *self);
DllExport	void	fish_guppy1 (userEntity_t *self);
DllExport	void	fish_guppy2 (userEntity_t *self);

///////////////////////////////////////////////////////////////////////////////
//	goldfish_turn
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
//	goldfish_init_frametable
//
///////////////////////////////////////////////////////////////////////////////

void	goldfish_init_frametable (userEntity_t *self)
{
	playerHook_t	*hook = (playerHook_t *) self->userHook;

	if (hook->frames->swim [0])
		ai_set_sequence_data (self, hook->frames->swim [0], 1, NULL, 6, NULL, 0, -1, 0, -1, FRAME_LOOP);
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void	goldfish_swim (userEntity_t *self)
{
	Vector			end, ang;
	playerHook_t	*hook = (playerHook_t *) self->userHook;
	float			speed, dot;

	if (!self->waterlevel)
		return;

	forward = Vector (self->goalentity->s.origin) - Vector (self->s.origin);
	forward.Normalize ();

	end = Vector (self->s.origin) + forward * 16.0;
	tr = gstate->trace_q2 (self->s.origin, self->s.mins, self->s.maxs, end.vec (),
							self, MASK_MONSTERSOLID);

	if (tr.fraction != 1.0)
	{
		if (self->flags & FL_DEBUG)
			gstate->Con_Printf ("wall\n");

		//	turn along normal of wall
		com->VecToAngles (ang, Vector (tr.plane.normal));
			
		//	base turn direction off of time
		if (((int)floor (gstate->time)) % 10 < 5)
			ang = Vector (0, ang.y + 95, 0);
		else
			ang = Vector (0, ang.y - 95, 0);

		ang.AngleVectors (forward, right, up);

		end = Vector (self->s.origin) + forward * 32.0;
		ai_set_goal (self, NULL, end.vec (), GOAL_TEMP);
		hook->tempgoal_search_time = 32.0 / hook->run_speed + 0.25;
	}

	end = forward * hook->run_speed;
	end.set (self->velocity);

	if (self->flags & FL_DEBUG)
		gstate->Con_Printf ("run_speed = %.2f\n", hook->run_speed);
}

///////////////////////////////////////////////////////////////////////////////
//	goldfish_wander
///////////////////////////////////////////////////////////////////////////////

void	goldfish_wander (userEntity_t *self)
{
	Vector			end, ang;
	playerHook_t	*hook = (playerHook_t *) self->userHook;
	float			goal_dist, r_mul, u_mul;

	if (!ai_client_near (self))
	{
		//	no one is around, don't think
		VectorCopy (zero_vector, self->velocity);

		self->nextthink = gstate->time + 0.1;

		return;
	}

	ang = Vector (self->s.angles);
	ang.AngleVectors (forward, right, up);

	if (hook->tempgoal_search_time < gstate->time || 
		qv_dist (self->goalentity->s.origin, self->s.origin) < 4.0)
	{
		if (rnd () < 0.2)
			goal_dist = 16.0 + rnd () * 64.0;
		else
			goal_dist = 64.0 + rnd () * 128.0;

		//	go right or left
		r_mul = (rnd () * 0.5) - 0.25;
		if (r_mul < 0.05 && r_mul > -0.05)
			r_mul = 0.0;

		//	go up or down
		u_mul = (rnd () * 0.25);
		if (u_mul < 0.05)
			u_mul = 0.0;
		else if (((int)floor (gstate->time)) % 4 < 2)
			u_mul = -u_mul;

		//	change speed
		if (hook->jump_time < gstate->time)
		{
			hook->jump_time = gstate->time + 5 + rnd () * 20;
			hook->run_speed = hook->walk_speed + rnd () * (hook->attack_speed - hook->walk_speed);
		}

		end = Vector (self->s.origin) + forward * goal_dist 
			+ right * goal_dist * r_mul
			+ up * goal_dist * u_mul;

		ai_set_goal (self, NULL, end.vec (), GOAL_TEMP);

		forward = Vector (end) - Vector (self->s.origin);
		hook->tempgoal_search_time = forward.vlen () / hook->run_speed + 0.25;
		
		forward.Normalize ();
	}

	goldfish_swim (self);

	self->nextthink = gstate->time + 0.1;
}

///////////////////////////////////////////////////////////////////////////////
//	goldfish_I_am_your_master_now
///////////////////////////////////////////////////////////////////////////////

void	goldfish_I_am_your_master_now (userEntity_t *self)
{
	playerHook_t	*hook = (playerHook_t *) self->userHook;
	userEntity_t	*head;

	self->targetname = self->target;
	self->target = NULL;
	hook->head = NULL;

	//	make all the other fishes who were following the master
	//	follow this one
	for (head = gstate->FirstEntity (); head; head = gstate->NextEntity (head))
	{
		if (head->className && !stricmp (head->className, "goldfish"))
		{
			if (head->target && !stricmp (head->target, self->targetname))
			{
				hook = (playerHook_t *) head->userHook;
				hook->head = self;
			}
		}
	}

	self->think = goldfish_wander;
	goldfish_wander (self);
}

///////////////////////////////////////////////////////////////////////////////
//	goldfish_follow
///////////////////////////////////////////////////////////////////////////////

void	goldfish_follow (userEntity_t *self)
{
	Vector			end, ang, org;
	playerHook_t	*hook = (playerHook_t *) self->userHook;
	float			goal_dist, scale;

	if (!ai_client_near (self))
	{
		//	no one is around, don't think
		VectorCopy (zero_vector, self->velocity);

		self->nextthink = gstate->time + 0.1;

		return;
	}

	if (!hook->head || hook->head->deadflag != DEAD_NO)
	{
		//	make this fish the leader
		goldfish_I_am_your_master_now (self);
		
		return;
	}

	goal_dist = qv_dist (self->s.origin, hook->head->s.origin);
	if (goal_dist < 16.0)
		scale = (goal_dist / 18);
	else if (goal_dist > 64)
		scale = goal_dist / 64;

	hook->run_speed = qv_len (hook->head->velocity) * scale;

	hook->run_speed *= self->delay;

	if (hook->run_speed > hook->attack_speed)
		hook->run_speed = hook->attack_speed;
	else if (hook->run_speed < hook->walk_speed)
		hook->run_speed = hook->walk_speed;

	goal_dist = qv_dist (self->s.origin, self->goalentity->s.origin);
	if (hook->tempgoal_search_time < gstate->time || goal_dist < 8.0)
	{
		org = Vector (hook->head->s.origin);
		org.x += (rnd () * 16.0 - 8.0) * scale;
		org.y += (rnd () * 16.0 - 8.0) * scale;
		org.z += (rnd () * 16.0 - 8.0) * scale;
		ai_set_goal (self, NULL, org.vec (), GOAL_TEMP);
	}

	goldfish_swim (self);

	self->nextthink = gstate->time + 0.1;
}

///////////////////////////////////////////////////////////////////////////////
//	goldfish_find_target
///////////////////////////////////////////////////////////////////////////////

void	goldfish_find_target (userEntity_t *self)
{
	playerHook_t *hook = (playerHook_t *) self->userHook;

	hook->head = com->FindTarget (self->target);
//	hook->owner = hook->head;

	if (!hook->head)
		self->think = goldfish_wander;
	else
		self->think = goldfish_follow;

	self->nextthink = 0.1;
}

///////////////////////////////////////////////////////////////////////////////
//	goldfish_pain
///////////////////////////////////////////////////////////////////////////////

void	goldfish_pain (userEntity_t *self, userEntity_t *other, float kick, int damage)
{

}

///////////////////////////////////////////////////////////////////////////////
//	goldfish_die
//
//	FIXME:	make fish float
///////////////////////////////////////////////////////////////////////////////

void	goldfish_die (userEntity_t *self, userEntity_t *inflictor, userEntity_t *attacker, int damage, vec3_t point)
{
	self->deadflag = DEAD_DEAD;
	self->nextthink = -1;
	self->prethink = NULL;
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void	fish_init (userEntity_t *self)
{
	int				i;
	Vector			temp, ang;
	playerHook_t	*hook;
	float			scale = 1.0;
	
	hook = ai_init_monster (self, TYPE_GOLDFISH);

	self->className = "goldfish";
	self->netname = "goldfish";

	self->ang_speed [1] = 180.0;

	for (i = 0; self->epair [i].key; i++)
	{
		if (!stricmp (self->epair [i].key, "target"))
			self->target = self->epair [i].value;
		else if (!stricmp (self->epair [i].key, "targetname"))
			self->targetname = self->epair [i].value;
		else if (!stricmp (self->epair [i].key, "scale"))
			scale = atof (self->epair [i].value) * 0.5;
	}

	self->s.render_scale [0] = scale;
	self->s.render_scale [1] = scale;
	self->s.render_scale [2] = scale;

	self->movetype = MOVETYPE_FLY;
	self->solid = SOLID_BBOX;
	self->flags |= FL_SWIM;
	self->flags -= FL_MONSTER;
	
	temp = Vector (-2, -2, -2);
	temp.set (self->s.mins);
	temp = Vector (2, 2, 2);
	temp.set (self->s.maxs);

	self->s.modelindex = gstate->ModelIndex ("models/deco/e4/goldfish/goldfish.md2");
	gstate->LinkEntity (self);

	self->prethink = ai_prethink;

	ai_get_sequences (self);

	goldfish_init_frametable (self);

	hook->run_speed = 60;		// starting speed
	hook->walk_speed = 25;		// min speed
	hook->attack_speed = 100;	//	max speed

	self->die = goldfish_die;
	self->pain = goldfish_pain;

//	hook->dflags |= DFL_FACEPITCH;

	self->health = 10;

	//	this is a leader fish
	if (!self->target)
	{
		//	set up a goal immediately
		hook->tempgoal_search_time = -1;

		ai_init_sequence (self, hook->frames->swim [0], SEQUENCE_SWIM, 0);
		hook->frame_flags = FRAME_LOOP;
		hook->frameInc = 1;

		self->think = goldfish_wander;
		self->nextthink = gstate->time + 0.1 + rnd () * 0.5;
	}
	else
	{
//		gstate->RemoveEntity (self);
//		return;
		self->think = goldfish_find_target;
		self->nextthink = gstate->time + 0.1;
		self->delay = 1.1 - rnd () * 0.2;
	}
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void	goldfish (userEntity_t *self)
{
	self->s.modelindex = gstate->ModelIndex ("models/deco/e4/goldfish/goldfish.md2");
	fish_init (self);
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void	fish_goldfish (userEntity_t *self)
{
	fish_init (self);
	self->s.modelindex = gstate->ModelIndex ("models/deco/e4/goldfish/goldfish.md2");
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void	fish_grayfish (userEntity_t *self)
{
	fish_init (self);
	self->s.modelindex = gstate->ModelIndex ("models/deco/e2/grayfish/grayfish.md2");
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void	fish_guppy1 (userEntity_t *self)
{
	playerHook_t	*hook = (playerHook_t *) self->userHook;

	fish_init (self);
	self->s.modelindex = gstate->ModelIndex ("models/deco/e4/guppy1/guppy1.md2");

	hook->startFrame = 0;
	hook->endFrame = 0;
	hook->frame_flags |= FRAME_STATIC;
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void	fish_guppy2 (userEntity_t *self)
{
	playerHook_t	*hook = (playerHook_t *) self->userHook;

	fish_init (self);	
	self->s.modelindex = gstate->ModelIndex ("models/deco/e4/guppy2/guppy2.md2");

	hook->startFrame = 0;
	hook->endFrame = 0;
	hook->frame_flags |= FRAME_STATIC;
}