#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_cerberus (userEntity_t *self);
DllExport	void	monster_cerebus (userEntity_t *self);

////////////////////////////////////////////////////////////////////////////////
//	globals
////////////////////////////////////////////////////////////////////////////////

static	int	cerebus_count	= 0;

///////////////////////////////////////////////////////////////////////////////////
// cerebus specific funcitons
///////////////////////////////////////////////////////////////////////////////////

////////////////////////////////
//	cerebus_init_frametable
//
////////////////////////////////

void	cerebus_init_frametable (userEntity_t *self)
{
	playerHook_t	*hook = (playerHook_t *) self->userHook;
	int				i;

	//	attacks
	ai_set_sequence_data (self, hook->frames->atak [0], 17, "monsters/cerebus/cerebusattack1.wav", -1, NULL, 0, -1, 0, -1, FRAME_ONCE);
	ai_set_sequence_data (self, hook->frames->atak [1], 10, "monsters/cerebus/cerebusattack1.wav", 13, "monsters/cerebus/cerebusattack2.wav", 0, -1, 0, -1, FRAME_ONCE);

	//	ambients
	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->stand [1], -1, NULL, -1, NULL, 0, -1, 0, -1, FRAME_ONCE);

	//	jump
	ai_set_sequence_data (self, hook->frames->jump [0], -1, NULL, -1, NULL, 0, -1, 0, -1, FRAME_ONCE);

	//	deaths
	ai_set_sequence_data (self, hook->frames->death [0], -1, NULL, -1, NULL, 0, -1, 0, -1, FRAME_ONCE);
	ai_set_sequence_data (self, hook->frames->death [1], -1, NULL, -1, NULL, 0, -1, 0, -1, FRAME_ONCE);

	//	pain
	ai_set_sequence_data (self, hook->frames->pain [0], -1, NULL, -1, NULL, 0, -1, 0, -1, FRAME_ONCE);

	//	run
	ai_set_sequence_data (self, hook->frames->run [0], -1, NULL, -1, NULL, 0, -1, 0, -1, FRAME_ONCE);

	//	walk
	ai_set_sequence_data (self, hook->frames->walk [0], -1, NULL, -1, NULL, 0, -1, 0, -1, FRAME_ONCE);

	//	init move_scale for cerebus's run
	hook->frames->run [0]->move_scale [0] = 127;	// 2.0 times
	hook->frames->run [0]->move_scale [1] = 127;		
	hook->frames->run [0]->move_scale [2] = 127;		
	hook->frames->run [0]->move_scale [3] = 96;	
	hook->frames->run [0]->move_scale [4] = 64;		// 1.0 times
	hook->frames->run [0]->move_scale [5] = 0;	
	hook->frames->run [0]->move_scale [6] = -64;	
	hook->frames->run [0]->move_scale [7] =  -96;	
	hook->frames->run [0]->move_scale [8] = -127;	
	hook->frames->run [0]->move_scale [9] = -64;	
	hook->frames->run [0]->move_scale [10] = 64;	
	hook->frames->run [0]->move_scale [11] = 127;	
}

///////////////////////////////////////////////////////////////////////////////
//	cerebus_set_attack_seq
//
///////////////////////////////////////////////////////////////////////////////

void	cerebus_set_attack_seq (userEntity_t *self)
{
	playerHook_t	*hook = (playerHook_t *) self->userHook;
	int				i;

	i = (int) (rnd () * hook->sequence_max [SEQUENCE_ATAK]);

	ai_init_sequence (self, hook->frames->atak [i], SEQUENCE_ATAK, i);
}

///////////////////////////////////////////////////////////////////////////////
//	cerebus_attack
//
///////////////////////////////////////////////////////////////////////////////

void	cerebus_attack (userEntity_t *self)
{
	playerHook_t	*hook = (playerHook_t *) self->userHook;
	float			dist;
	
	hook->dflags |= DFL_FACEENEMY;

	dist = qv_dist (self->s.origin, self->enemy->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->enemy->s.origin), 0, 0);
	}
	
	if (hook->frame_flags & FRAME_PLAYSOUND2)
	{
		hook->frame_flags = hook->frame_flags - FRAME_PLAYSOUND2;
				
		ai_fire_curWeapon (self, Vector (self->s.origin), Vector (self->enemy->s.origin), 0, 0);
	}
	
	if (hook->frame_flags & FRAME_STATIC)
	{
		hook->frame_flags -= FRAME_STATIC;

		cerebus_set_attack_seq (self);

		if (self->enemy->deadflag != DEAD_NO)
		{
			//	pop off everything thru TASK_CHASE and begin wandering
			ai_killed_enemy (self);

			return;
		}
		else if (dist > hook->attack_dist || !com->Visible (self, self->enemy))
		{
			ai_should_follow (self);

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

			return;
		}
	}

	ai_set_think (self, cerebus_attack, "cerebus_attack");
}

///////////////////////////////////////////////////////////////////////////////
//	cerebus_begin_attack
//
///////////////////////////////////////////////////////////////////////////////

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

	com->ZeroVector (self->velocity);

	hook->th_state = TH_ATTACK;
	hook->attack_finished = gstate->time + 1.0;

	cerebus_set_attack_seq (self);

	cerebus_attack (self);
}

///////////////////////////////////////////////////////////////////////////////
//	monster_cerebus
//
//	spawns a skeleton during level load
///////////////////////////////////////////////////////////////////////////////

void	monster_cerebus (userEntity_t *self)
{
	playerHook_t		*hook;
	int					i;

	cerebus_count++;

	hook = ai_init_monster (self, TYPE_CEREBUS);

	self->className = "monster_cerebus";
	self->netname = "cerebus";

	gstate->SoundIndex ("models/cerebus/cerebusattack1.md2");
	gstate->SoundIndex ("models/cerebus/cerebusattack2.md2");
	gstate->SoundIndex ("models/cerebus/cerebuswander1.md2");
	gstate->SoundIndex ("models/cerebus/cerebuswander2.md2");
	gstate->SoundIndex ("models/cerebus/cerebuspain1.md2");
	gstate->SoundIndex ("models/cerebus/cerebusdies1.md2");
	gstate->SoundIndex ("models/cerebus/cerebussight1.md2");
	gstate->SoundIndex ("models/cerebus/cerebussight2.md2");

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

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

	ai_get_sequences (self);
	cerebus_init_frametable (self);

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

	hook->begin_attack = cerebus_begin_attack;

	hook->run_speed = 250;
	hook->walk_speed = 50;
	hook->attack_speed = 250;

	hook->attack_dist = 96;

	self->health = 300;
	hook->max_health = 300;
	hook->pain_chance = 10;
	self->mass = 2.0;

	self->think = ai_get_spawn_node;
	self->nextthink = gstate->time + 0.2;	// node links are set up 0.2 secs after map load

	self->translucent = 0;

	///////////////////////////////////////////////////////////////////////////
	//	give cerebus a weapon
	///////////////////////////////////////////////////////////////////////////

	self->curWeapon = ai_init_weapon (self, 10, 20, 0, 0, 0, hook->attack_dist, Vector (0, 0, 0), "punch", melee_punch, WEAPON_TRACE);
}

void	monster_cerberus (userEntity_t *self)
{
	monster_cerebus (self);
}