#include	"world.h"
#include	"client.h"

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

static	userEntity_t	*last_ass = NULL;

static	Vector			set_origin;
static	Vector			set_angles;
static	Vector			set_viewangles;

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

void	drop_change_owner (userEntity_t *self)
{
	self->owner = self;
	self->nextthink = -1;
}

///////////////////////////////////////////////////////////////////////////////
//	drop_
//
//	for taking screenshots with content that hasn't been completely integrated
///////////////////////////////////////////////////////////////////////////////

void	drop_monster (userEntity_t *self)
{
	int				argc;
	char			name [128];
	userEntity_t	*ass;

	argc = gstate->GetArgc();

	if (argc < 2)
		strcpy (name, "models/lycanthir/lycanthir.md2");
	else if (argc == 2)
		sprintf (name, "models/%s/%s.md2", gstate->GetArgv (1), gstate->GetArgv (1));
	else
	{
		gstate->Con_Printf ("You are an ass!!  Type a model name, ass!!\n");
		return;
	}

	ass = gstate->SpawnEntity ();

	ass->owner = self;
	ass->solid = SOLID_BBOX;
	ass->movetype = MOVETYPE_TOSS;
	ass->className = "ass";
	
	ass->s.modelindex = gstate->ModelIndex (name);
	gstate->SetSize (ass, -16, -16, -24, 16, 16, 32);
	gstate->SetOrigin2 (ass, self->s.origin);
	gstate->LinkEntity (ass);

//	ass->nextthink = gstate->time + 2.0;
//	ass->think = drop_change_owner;

	ass->s.frame = 0;

	last_ass = ass;
}

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

void	drop_frame (userEntity_t *self)
{
	int		frame;
	char	arg_str [128];

	if (!last_ass)
	{
		gstate->Con_Printf ("No ass selected, ass!\n");
		return;
	}

	if (gstate->GetArgc () != 2)
	{
		gstate->Con_Printf ("  usage, ass: drop_frame [frame number]\n");
		return;
	}

	sprintf (arg_str, "%s", gstate->GetArgv (1));

	if (arg_str [0] == '+' || arg_str [0] == '-')
	{
		frame = atoi (arg_str);

		if ((int)last_ass->s.frame + frame < 0)
		{
			gstate->Con_Printf ("You can't have negative frames, ass.\n");
			return;
		}
		last_ass->s.frame += frame;
	}
	else
		last_ass->s.frame = atoi (arg_str);
}

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

void	drop_rotate (userEntity_t *self)
{
	int		argc;
	int		frame;
	Vector	ang;
	char	arg_str [3][128];

	if (!last_ass)
	{
		gstate->Con_Printf ("No ass selected, ass!!!\n");
		return;
	}

	argc = gstate->GetArgc ();

	if (argc != 2 && argc != 4)
	{
		gstate->Con_Printf ("  usage: drop_rotate [yaw angle]\n  Angle should be 0 - 360.");
		gstate->Con_Printf ("               OR\n");
		gstate->Con_Printf ("  usage: drop_rotate [pitch] [yaw] [roll]\n");
		return;
	}

	sprintf (arg_str [0], "%s", gstate->GetArgv (1));
	sprintf (arg_str [1], "%s", gstate->GetArgv (2));
	sprintf (arg_str [2], "%s", gstate->GetArgv (3));

	if (argc == 2)
	{
		ang = Vector (last_ass->s.angles);

		if (arg_str [0][0] == '+' || arg_str [0][0] == '-')
			ang.y += atof (arg_str [0]);
		else
			ang.y = atof (gstate->GetArgv (1));
	}
	else
	{
		if (arg_str [0][0] == '+')
			ang.x += atof (arg_str [0]);
		else
			ang.x = atof (arg_str [0]);

		if (arg_str [1][0] == '+')
			ang.y += atof (arg_str [1]);
		else
			ang.y = atof (arg_str [1]);

		if (arg_str [2][0] == '+')
			ang.z += atof (arg_str [2]);
		else
			ang.z = atof (arg_str [2]);
	}

	ang.set (last_ass->s.angles);
}

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

void	drop_select (userEntity_t *self)
{
	vec3_t	mins = {-8, -8, -8};
	vec3_t	maxs = {8, 8, 8};
	Vector	ang, end, start;

	ang = Vector (self->client->v_angle);
	ang.AngleVectors (forward, right, up);

	start = Vector (self->s.origin) + forward * 32.0;
	start.z += 32;
	end = start + forward * 1000.0;

	tr = gstate->trace_q2 (start.vec (), mins, maxs, end.vec (), NULL, MASK_PLAYERSOLID);

//	com->SpawnMarker (self, Vector (tr.endpos), "models/skel/skel.md2", 0.25);
//	com_Laser (self, start, Vector (tr.endpos), 0.25);

	if (!tr.ent)
	{
		gstate->Con_Printf ("Nothing there, ass.\n");
		return;
	}

	if (stricmp (tr.ent->className, "ass"))
	{
		gstate->Con_Printf ("%s is not an ass, ass.\n", tr.ent->className);
		return;
	}

	last_ass = tr.ent;
	last_ass->velocity [2] = 270;
}

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

void	drop_move (userEntity_t *self)
{
	char	arg_str [128];
	Vector	dir, start, end;
	float	dist;
	int		zmove = false;

	if (!last_ass)
	{
		gstate->Con_Printf ("No ass selected, ass!!!\n");
		return;
	}

	if (gstate->GetArgc () > 1)
	{
		//	move along a vector towards user
		sprintf (arg_str, "%s", gstate->GetArgv (1));
		if ((arg_str [strlen (arg_str) - 1] == 'z') || (arg_str [strlen (arg_str) - 1] == 'Z'))
		{
			zmove = true;		
			arg_str [strlen (arg_str) - 1] = 0x00;
		}

		dist = atof (arg_str);

		start = Vector (last_ass->s.origin);
		if (!zmove)
			start.z = 0;
		end = Vector (self->s.origin);
		if (!zmove)
			end.z = 0;

		dir = start - end;
		dir.Normalize ();

		if (dist > 0)
			gstate->Con_Printf ("Don't hurt me, Daddy!!\n");
		else 
			gstate->Con_Printf ("I love you, Mommy!!\n");

		start = Vector (last_ass->s.origin);
		end = Vector (last_ass->s.origin) + dir * dist;

		//	look for a step
		tr = gstate->trace_q2 (start.vec (), last_ass->s.mins, last_ass->s.maxs,
			end.vec (), last_ass, MASK_MONSTERSOLID);

		if (tr.fraction != 1.0)
		{
			start.z += 18;
			end.z += 18;

			tr = gstate->trace_q2 (start.vec (), last_ass->s.mins, last_ass->s.maxs,
				end.vec (), last_ass, MASK_MONSTERSOLID);
			
			if (tr.fraction != 1.0)
			{
				dist = dist * tr.fraction;
				end = Vector (last_ass->s.origin) + dir * dist;
			}
		}

		last_ass->groundEntity = NULL;
		end.set (last_ass->s.origin);
		gstate->LinkEntity (last_ass);
	}
	else
		gstate->SetOrigin2 (last_ass, self->s.origin);
}

///////////////////////////////////////////////////////////////////////////////
//	drop_gravity
//
///////////////////////////////////////////////////////////////////////////////

void	drop_gravity (userEntity_t *self)
{
	if (!last_ass)
	{
		gstate->Con_Printf ("No ass selected, ass!!!\n");
		return;
	}
	
	if (last_ass->movetype == MOVETYPE_TOSS)
	{
		gstate->Con_Printf ("Gravity OFF.\n");
		last_ass->movetype = MOVETYPE_NONE;
	}
	else
	{
		gstate->Con_Printf ("Gravity ON.\n");
		last_ass->movetype = MOVETYPE_TOSS;
	}
}

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

void	drop_remove (userEntity_t *self)
{
	if (!last_ass)
	{
		gstate->Con_Printf ("No ass selected, ass!!!\n");
		return;
	}

	gstate->RemoveEntity (last_ass);
	gstate->Con_Printf ("Ass removed.  Select another ass, ass.\n");

	last_ass = NULL;
}

///////////////////////////////////////////////////////////////////////////////
//	drop_deco
//
//	for taking screenshots with content that hasn't been completely integrated
///////////////////////////////////////////////////////////////////////////////

void	drop_deco (userEntity_t *self)
{
	int				argc;
	char			name [128];
	userEntity_t	*ass;

	argc = gstate->GetArgc();

	if (argc < 3)
		strcpy (name, "models/deco/e4/sodacan/sodacan.md2");
	else if (argc == 3)
		sprintf (name, "models/deco/%s/%s/%s.md2", gstate->GetArgv (1), gstate->GetArgv (2), gstate->GetArgv (2));
	else
	{
		gstate->Con_Printf ("You are an ass!!  Type a model name, ass!!\n");
		gstate->Con_Printf ("  USAGE: drop_deco [episode] [modelname]\n");
		return;
	}

	ass = gstate->SpawnEntity ();

	ass->owner = self;
	ass->solid = SOLID_BBOX;
	ass->movetype = MOVETYPE_TOSS;
	ass->className = "deco_ass";
	
	ass->s.modelindex = gstate->ModelIndex (name);
	gstate->SetSize (ass, -16, -16, -24, 16, 16, 32);
	gstate->SetOrigin2 (ass, self->s.origin);
	gstate->LinkEntity (ass);

	ass->s.frame = 0;

	last_ass = ass;
}

///////////////////////////////////////////////////////////////////////////////
//	drop_scale
//
///////////////////////////////////////////////////////////////////////////////

void	drop_scale (userEntity_t *self)
{
	int		argc;
	float	scale;

	if (!last_ass)
	{
		gstate->Con_Printf ("No ass selected, ass!!!\n");
		return;
	}

	argc = gstate->GetArgc ();

	if (argc != 2 && argc != 4)
	{
		gstate->Con_Printf ("  usage: drop_scale [scale factor]\n");
		return;
	}

	scale = atof (gstate->GetArgv (1));

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

///////////////////////////////////////////////////////////////////////////////
//	drop_set
//
///////////////////////////////////////////////////////////////////////////////

void	drop_set (userEntity_t *self)
{
	set_origin = Vector (self->s.origin);
	set_angles = Vector (self->s.angles);
	set_viewangles = Vector (self->client->ps.viewangles);

	gstate->Con_Printf ("View locked.  Use drop_restore to come return here, ass.\n");
}

///////////////////////////////////////////////////////////////////////////////
//	drop_restore
//
///////////////////////////////////////////////////////////////////////////////

void	drop_restore (userEntity_t *self)
{
	float	r;

	set_origin.set (self->s.origin);
	gstate->LinkEntity (self);

	set_angles.set (self->s.angles);

	self->flags |= FL_FIXANGLES;
	gstate->SetClientAngles (self, set_viewangles.vec ());				

	r = floor (rnd () * 3);

	if (r == 0)
		gstate->Con_Printf ("BOINNG!!!\n");
	else if (r == 1)
		gstate->Con_Printf ("ZING!!!\n");
	else
		gstate->Con_Printf ("BLIP!!!\n");

}

///////////////////////////////////////////////////////////////////////////////
//	drop_sprite
//
///////////////////////////////////////////////////////////////////////////////

void	drop_sprite (userEntity_t *self)
{
	int				argc;
	char			name [128];
	userEntity_t	*ass;

	argc = gstate->GetArgc();

	if (argc < 2)
		strcpy (name, "models/flare/flare.sp2");
	else if (argc == 2)
		sprintf (name, "models/%s/%s.sp2", gstate->GetArgv (1), gstate->GetArgv (1));
	else
	{
		gstate->Con_Printf ("You are an ass!!  Type a sprite name, ass!!\n");
		return;
	}

	ass = gstate->SpawnEntity ();

	ass->owner = self;
	ass->solid = SOLID_BBOX;
	ass->movetype = MOVETYPE_NONE;
	ass->className = "ass";

	ass->s.renderfx |= SPR_ALPHACHANNEL;

	ass->s.modelindex = gstate->ModelIndex (name);
	gstate->SetSize (ass, -16, -16, -24, 16, 16, 32);
	gstate->SetOrigin2 (ass, self->s.origin);
	gstate->LinkEntity (ass);

//	ass->nextthink = gstate->time + 2.0;
//	ass->think = drop_change_owner;

	ass->s.frame = 0;

	last_ass = ass;
}

///////////////////////////////////////////////////////////////////////////////
//	drop_help
//
///////////////////////////////////////////////////////////////////////////////

void	drop_help (userEntity_t *self)
{
	gstate->Con_Printf ("Drop commands are: ");
	gstate->Con_Printf ("  drop_monster [model name]\n");
	gstate->Con_Printf ("  drop_rotate [degrees] or +[degrees]\n");
	gstate->Con_Printf ("  drop_select -- point at entity to select\n");
	gstate->Con_Printf ("  drop_move +/-[distance][z]\n");
	gstate->Con_Printf ("  drop_deco [episode] [model name]\n");
	gstate->Con_Printf ("  drop_scale [scale factor]\n");
	gstate->Con_Printf ("  drop_gravity -- toggles on and off\n");
	gstate->Con_Printf ("  drop_set -- save current view\n");
	gstate->Con_Printf ("  drop_restore - restore view\n");
	gstate->Con_Printf ("  drop_sprite [sprite name]\n");
	gstate->Con_Printf ("  drop_movez +/-[distance]\n");
}
///////////////////////////////////////////////////////////////////////////////
//
//
///////////////////////////////////////////////////////////////////////////////

void	drop_movez (userEntity_t *self)
{
	float	dist;

	if (!last_ass)
	{
		gstate->Con_Printf ("No ass selected, ass!!!\n");
		return;
	}

	if (gstate->GetArgc () != 2)
	{
		gstate->Con_Printf ("USAGE: drop_movez [+/-][distance], ass!!!\n");
		return;
	}

	dist = atof (gstate->GetArgv (1));

	last_ass->s.origin [2] += dist;
	last_ass->groundEntity = NULL;
	last_ass->gravity = MOVETYPE_NONE;

	gstate->LinkEntity (last_ass);
}