#include	"world.h"

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

#include	"ai_move.h"
#include	"ai_weapons.h"
#include	"ai_task.h"
#include	"ai_frames.h"

#include	"skat.h"
#include	"nodelist.h"

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

DllExport	void	monster_chaingang (userEntity_t *self);

///////////////////////////////////////////////////////////////////////////////////
// chaingunner specific funcitons
///////////////////////////////////////////////////////////////////////////////////

////////////////////////////////
//	chaingang_init_frametable
//
////////////////////////////////

void	chaingang_init_frametable (userEntity_t *self)
{
	playerHook_t	*hook = (playerHook_t *) self->userHook;
	
	ai_set_sequence_data (self, hook->frames->atak [0], 0, "monsters/cgang/cgangattack1.wav", -1, NULL, 0, -1, 0, -1, FRAME_ONCE);
	ai_set_sequence_data (self, hook->frames->atak [1], 0, "monsters/cgang/cgangattack1.wav", -1, NULL, 0, -1, 0, -1, FRAME_ONCE);
	ai_set_sequence_data (self, hook->frames->atak [5], 0, "monsters/cgang/cgangattack1.wav", -1, NULL, 0, -1, 0, -1, FRAME_ONCE);

	ai_set_sequence_data (self, hook->frames->stand [0], -1, NULL, -1, NULL, 0, -1, 0, -1, FRAME_LOOP);

	ai_set_sequence_data (self, hook->frames->trans [0], -1, NULL, -1, NULL, 0, -1, 0, -1, FRAME_ONCE);
	ai_set_sequence_data (self, hook->frames->trans [2], -1, NULL, -1, NULL, 0, -1, 0, -1, FRAME_ONCE);
}

////////////////////////////////
//  chaingang_pitch_back
//
//	go back to a 0 pitch after killing enemy
////////////////////////////////

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

	if (self->ideal_ang [0] == self->s.angles [0])
	{
		ai_set_think (self, hook->begin_wander, "chaingang_pitch_back 1");

		//	pop off everything thru TASK_CHASE for this enemy
		ai_killed_enemy (self);
	}
	else
	{
		com->ChangePitch (self);

		ai_set_think (self, chaingang_pitch_back, "chaingang_pitch_back 2");
	}
}

////////////////////////////////
//  chaingang_attack
//
//	ai for following/approaching an enemy
////////////////////////////////

void	chaingang_attack (userEntity_t *self)
{
	playerHook_t	*hook = (playerHook_t *) self->userHook;
	int				i, task_type, task_type2;
	float			dist;
	Vector			temp;
	taskData_t		*task_data, *task_data2;
	taskStack_t		*stack;

	//ai_face_enemy (self);
	hook->dflags |= DFL_FACEENEMY;

	if (self->movetype == MOVETYPE_FLY)
	{
		temp = Vector (self->enemy->s.origin) - Vector (self->s.origin);
		temp.Normalize ();
		com->VecToAngles (temp, temp);
		self->ideal_ang [0] = temp.x;

		com->ChangePitch (self);
	}

	dist = qv_dist (self->enemy->s.origin, self->s.origin);

	if (hook->frame_flags & FRAME_PLAYSOUND1)
	{
		hook->frame_flags = hook->frame_flags - FRAME_PLAYSOUND1;

		ai_fire_curWeapon (self, Vector (self->s.origin) + Vector (self->view_ofs), Vector (self->enemy->s.origin) + Vector (self->enemy->view_ofs), 0.064, 0.064);
	}
	
	if (hook->frame_flags & FRAME_STATIC)
	{
		hook->frame_flags -= FRAME_STATIC;

		if (self->enemy->deadflag != DEAD_NO)
		{
			if (self->movetype == MOVETYPE_FLY)
			{
				self->ideal_ang [0] = 0.0;
				chaingang_pitch_back (self);
			}
			else
			{
				ai_set_think (self, hook->begin_wander, "chaingang_attack 1");

				//	pop off everything thru TASK_CHASE for this enemy
				ai_killed_enemy (self);
			}

			return;
		}
		else if (dist > hook->attack_dist + 64.0 || !com->Visible (self, self->enemy))
		{
			//	check the next task to make sure it's not screwed
			stack = hook->task_stack->next;
			task_current (stack, &task_data, &task_type);
			if (task_type == TASK_CHASE && task_data->goal_type != GOAL_ENEMY)
				com->Error ("chaingang: TASK_CHASE on stack without GOAL_ENEMY.\n");

			//	leaving, so pop off TASK_ATTACK
			task_pop (&hook->task_stack);

			task_current (hook->task_stack, &task_data, &task_type);
			if (task_type == TASK_CHASE && task_data->goal_type != GOAL_ENEMY)
				com->Error ("chaingang: TASK_CHASE without GOAL_ENEMY.\n");

			ai_should_follow (self);

			return;
		}
		else
		{
			if (self->movetype == MOVETYPE_FLY)
				ai_init_sequence (self, hook->frames->atak [5], SEQUENCE_ATAK, 5);
			else
				ai_init_sequence (self, hook->frames->atak [1], SEQUENCE_ATAK, 1);
		}
	}

	ai_attack_move (self);

	if (!(hook->ai_flags & AI_JUMP) && !(hook->ai_flags & AI_TURN))
		ai_set_think (self, chaingang_attack, "chaingang_attack 2");
}

////////////////////////////////
//	chaingang_begin_attack
//
//	ai for following/approaching an enemy
////////////////////////////////

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

//	com->ZeroVector (self->velocity);

	if (self->movetype == MOVETYPE_FLY)
	{
		if (self->s.frame < hook->frames->atak [5]->first ||
			self->s.frame > hook->frames->atak [5]->last)
			ai_init_sequence (self, hook->frames->trans [0], SEQUENCE_TRANS, 0);

		chaingang_attack (self);
	}
	else
	{
		if (self->s.frame < hook->frames->atak [1]->first ||
			self->s.frame > hook->frames->atak [1]->last)
		ai_init_sequence (self, hook->frames->trans [2], SEQUENCE_TRANS, 2);

		chaingang_attack (self);
	}

	hook->th_state = TH_ATTACK;
	hook->attack_finished = gstate->time + (hook->endFrame - hook->endFrame) * 0.1;

}

////////////////////////////////
//  chaingang_follow_attack
//
//	attacking an enemy while still moving towards a goal
////////////////////////////////

void	chaingang_follow_attack (userEntity_t *self)
{
	playerHook_t	*hook = (playerHook_t *) self->userHook;
	int				i, goal_status;
	float			dist, goal_dist, yaw;
	Vector			temp;

	//ai_face_enemy (self);
	hook->dflags |= DFL_FACEENEMY;

	if (self->movetype == MOVETYPE_FLY)
	{
		temp = Vector (self->enemy->s.origin) - Vector (self->s.origin);
		temp.Normalize ();
		com->VecToAngles (temp, temp);
		self->ideal_ang [0] = temp.x;

		com->ChangePitch (self);
	}

	dist = qv_dist (self->enemy->s.origin, self->s.origin);

	if (hook->frame_flags & FRAME_PLAYSOUND1)
	{
		hook->frame_flags = hook->frame_flags - FRAME_PLAYSOUND1;

		ai_fire_curWeapon (self, Vector (self->s.origin) + Vector (self->view_ofs), Vector (self->enemy->s.origin) + Vector (self->enemy->view_ofs), 0.064, 0.064);
	}
	
	if (hook->frame_flags & FRAME_STATIC)
	{
		hook->frame_flags -= FRAME_STATIC;

		if (self->movetype == MOVETYPE_FLY)
		{
			ai_init_sequence (self, hook->frames->atak [5], SEQUENCE_ATAK, 5);
		}
		else
		{
			ai_init_sequence (self, hook->frames->atak [1], SEQUENCE_ATAK, 1);
		}
		hook->frameInc = 1;
	}

	yaw = self->s.angles [1];

	forward = Vector (self->goalentity->s.origin) - Vector (self->s.origin);
	forward.Normalize ();
	self->s.angles [1] = com->VecToYaw (forward);

	ai_movetogoal (self, hook->attack_speed, MOVE_FORWARD);

	self->s.angles [1] = yaw;
}

////////////////////////////////
//	chaingang_begin_follow_attack
//
//	ai for following/approaching an enemy
////////////////////////////////

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

//	com->ZeroVector (self->velocity);

	if (self->movetype == MOVETYPE_FLY)
	{
		if (self->s.frame < hook->frames->atak [5]->first ||
			self->s.frame > hook->frames->atak [5]->last)
			ai_init_sequence (self, hook->frames->trans [0], SEQUENCE_TRANS, 0);
	}
	else
	{
		if (self->s.frame < hook->frames->atak [1]->first ||
			self->s.frame > hook->frames->atak [1]->last)
			ai_init_sequence (self, hook->frames->trans [2], SEQUENCE_TRANS, 2);
	}

	hook->frameInc = 2;

	hook->attack_finished = gstate->time + (hook->endFrame - hook->endFrame) * 0.1;
}

////////////////////////////////
//	monster_chaingang
//
//	creates the superfly entity and sets him up to smack down
//	everything that gets in his way.
////////////////////////////////

void	monster_chaingang (userEntity_t *self)
{
	playerHook_t		*hook;
	int					i;
	float				s;

	hook = ai_init_monster (self, TYPE_CHAINGANG);

	self->className = "monster_chaingang";
	self->netname = "flying chaingunner";

	gstate->Precache_Sound ("monsters/cgang/cgangattack1.wav");
	gstate->Precache_Sound ("monsters/cgang/cgangattack2.wav");
	gstate->Precache_Sound ("monsters/cgang/cgangdeath1.wav");
	gstate->Precache_Sound ("monsters/cgang/cgangdeath2.wav");
	gstate->Precache_Sound ("monsters/cgang/cgangpain1.wav");
	gstate->Precache_Sound ("monsters/cgang/cgangpain2.wav");
	gstate->Precache_Sound ("monsters/cgang/cgangsight1.wav");
	gstate->Precache_Sound ("monsters/cgang/cgangsight2.wav");
	gstate->Precache_Sound ("monsters/cgang/cgangwander1.wav");
	gstate->Precache_Sound ("monsters/cgang/cgangwander2.wav");

	self->s.modelindex = gstate->ModelIndex ("models/flyinggang/flyinggang.md2");
	gstate->SetSize (self, -16.0, -16.0, -24.0, 16.0, 16.0, 32.0);

	////////////////////////////////////////////////////////////////
	// set up animation stuff
	////////////////////////////////////////////////////////////////

	ai_get_sequences (self);

	chaingang_init_frametable (self);

	///////////////////////////////////////////////////////////
	// set up pointers to this creature's ai functions
	///////////////////////////////////////////////////////////

	hook->begin_attack = chaingang_begin_attack;
	hook->follow_attack = chaingang_follow_attack;
	hook->begin_follow_attack = chaingang_begin_follow_attack;

	hook->run_speed = 250;
	hook->walk_speed = 120;
	hook->attack_speed = 120;
	hook->pain_chance = 20;

	hook->dflags |= DFL_RANGEDATTACK;
	hook->attack_dist = 768;

	self->think = ai_get_spawn_node;
	self->nextthink = gstate->time + 0.2;

	self->translucent = 0;

	self->movetype = MOVETYPE_FLY;

	//////////////////////////////////////////////
	//	give chaingunner his chaingun
	//////////////////////////////////////////////
/*
	self->curWeapon = ai_weapon_create ("chaingun", chaingun_fire, ai_weapon_command);
	i = 5;	ai_weapon_command (self->curWeapon, "base_damage", &i);
	i = 7;	ai_weapon_command (self->curWeapon, "rnd_damage", &i);
	s = 0.064;	ai_weapon_command (self->curWeapon, "spread_x", &s);
	s = 0.064;	ai_weapon_command (self->curWeapon, "spread_z", &s);
*/

	self->curWeapon = ai_init_weapon (self, 2, 3, 0.064, 0.064, 0, hook->attack_dist, Vector (0, 0, 0), "chaingun", chaingun_fire, WEAPON_BULLET);
//	gstate->InventoryAddItem (self->inventory, self->curWeapon);
}

