//------------------------------------------------------------------------------------
// Razor
//------------------------------------------------------------------------------------

float(entity targ) RSee =
{
	traceline(self.origin, targ.origin, TRUE, self);
	if(trace_fraction == 1)
		return TRUE;
	return FALSE;
};

entity(float rtnum, entity targ) NextRazorTarget =
{
local entity e, best, old;
local float n;

	n = 0;	
	if(RSee(targ))
		return targ;
	e = world;
	best = world;
	e = find(world, classname, "razortarget");
	while(e != world)
	{
		if(e.owner == targ)
		{
			if((e.count == rtnum) && (RSee(e)))
				old = e;
			n = n + 1;
			if((e.count > rtnum) && (RSee(e)) && ((e.count > best.count) || (best == world)))
			{
				best = e;
			}
		}
		e = find(e, classname, "razortarget");
	}
	if(best == world)
		best = old;
	return best;
};

entity() ClosestTarget =
{
local entity e, closest;

	closest = world;

	e = find(world, classname, "player");
	while(e != world)
	{
		if((e != self.owner) && (e.takedamage))
		{
			if((closest == world) || (vlen(e.origin - self.origin) < closest.count))
			{
				closest = e;
				closest.count = vlen(e.origin - self.origin);
			}
		}
		e = find(e, classname, "player");
	}
	if(closest != world)
		closest.lastrazortargetdrop = 1;
	return closest;
};

void(entity p) StopDrop =
{
local entity e;
	p.lastrazortargetdrop = -1;
	e = find(world, classname, "razortarget");
	while(e != world)
	{
		if(e.owner == p)
			remove(e);
		e = find(e, classname, "razortarget");
	}
};

void() ChainThink =
{
local vector v, t;

	if((self.owner == world) || (self.ltime < time) || (!RSee(self.owner)) || (self.owner.stick) || ((self.enemy != world) && (self.enemy.health < 1))) 
	{
		if(self.enemy != world)
		{
			self.enemy.state = self.enemy.state - (self.enemy.state & S_CANT_MOVE);
			self.enemy.chained = 0;
		}
		if(self.nchain != world)
			self.nchain.chained = 0;
		if(self.owner != world)
			self.owner.count = self.owner.count - 1;
		remove(self);
		return;
	}

	if(self.enemy != world)
	{
		v = self.owner.origin - self.enemy.origin;
		if(vlen(v) > 50)
			v = self.enemy.origin;
		else
			v = '0 0 0';
	}
	else
		v = self.origin;

	if(v != '0 0 0')
	{
		t = self.owner.origin;
		WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
		WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
		WriteEntity (MSG_BROADCAST, self);
		WriteCoord (MSG_BROADCAST, t_x);
		WriteCoord (MSG_BROADCAST, t_y);
		WriteCoord (MSG_BROADCAST, t_z);
		WriteCoord (MSG_BROADCAST, v_x);
		WriteCoord (MSG_BROADCAST, v_y);
		WriteCoord (MSG_BROADCAST, v_z);
	}

	if(self.count)
	{
		if((self.enemy != world) && (vlen(self.origin - self.enemy.origin) > 50))
		{
			t = self.owner.origin - self.enemy.origin;
			self.enemy.velocity = normalize(t);
			self.enemy.velocity = self.enemy.velocity*(RAZOR_CHAINSPEED*(vlen(t)/100));
			if(vlen(self.enemy.velocity) > RAZOR_CHAINSPEED)
			{
				self.enemy.velocity = normalize(t);
				self.enemy.velocity = self.enemy.velocity*RAZOR_CHAINSPEED;
			}	
			if(!self.enemy.state & S_CANT_MOVE)
				self.enemy.state = self.enemy.state | S_CANT_MOVE;
		}
		else
		{
			t = self.owner.origin - self.origin;
			self.flags = self.flags - (self.flags & FL_ONGROUND);
			self.velocity = normalize(t);
			self.velocity = self.velocity*(RAZOR_CHAINSPEED*(vlen(t)/20));
			if(vlen(self.velocity) > RAZOR_CHAINSPEED)
			{
				self.velocity = normalize(t);
				self.velocity = self.velocity*RAZOR_CHAINSPEED;
			}	
			if(vlen(self.origin - self.owner.origin) < 32)
			{
				if(self.enemy != world)
				{
					self.enemy.state = self.enemy.state - (self.enemy.state & S_CANT_MOVE);
					self.enemy.chained = 0;
				}
				if(self.nchain != world)
				{
					self.nchain.chained = 0;	
				}
				if(self.owner != world)
					self.owner.count = self.owner.count - 1;
				remove(self);
				return;
			}
		}
	}
	self.nextthink = time + 0.05;
};

// Chain
// movetarget: Doesn't hurt this player
// nchain: the entity chain is trying to hit
// enemy: the entity chain has hit

void() ChainTouch =
{
	if((other.takedamage) && (other != self.movetarget))
	{
		self.enemy = other;
		T_Damage(other, self, self.owner.owner, RAZOR_CHAINDAMAGE, 0, "chain", "");
		if(other.health < 1)
			self.owner.randomf = time;
	}
	self.count = 1;
	self.origin = self.origin - 24*normalize(self.velocity);
};

void(entity ignore) FireChain =
{
local entity victim, found, rchain;

	victim = world;
	victim = findradius(self.origin, RAZOR_CHAINRADIUS);
	while(victim != world)
	{
		if((victim.takedamage) && (!victim.chained) && (victim.netname != ignore.netname))
			found = victim;
		victim = victim.chain;
	}
	if(found == world)
	{
		return;
	}

	found.chained = TRUE;

	self.count = self.count + 1;
	sound (self, CHAN_AUTO, "weapons/r_chain.wav", 1, ATTN_NORM);
	rchain = spawn();
	rchain.owner = self;
	rchain.enemy = world;
	rchain.nchain = found;
	rchain.movetarget = ignore;
	rchain.origin = self.origin;
	rchain.movetype = MOVETYPE_FLYMISSILE;
	rchain.solid = SOLID_TRIGGER;
	rchain.velocity = normalize(found.origin - self.origin);
	rchain.velocity = rchain.velocity * RAZOR_CHAINSPEED;
	rchain.touch = ChainTouch;
	rchain.think = ChainThink;
	rchain.count = 0;
	rchain.nextthink = time;
	rchain.ltime = time + 10;
};

// Razor
// count: chains currently out
// ltime: when razor returns
// stick: razor returns if stick == 1
// jumptime: next time to play razor flying sound
// randomf: time to change random velocity


void() RazorThink;
void() RazorReturn =
{
	centerprint(self.owner, "Samurai claw is coming back.");
	self.stick = time;
	self.think = RazorThink;
	self.nextthink = time;
};

void() RazorThink =
{	
        local vector dir, olddir, vtemp;
        local float d;

	if(self.jumptime < time)
	{
		sound (self, CHAN_VOICE, "weapons/r_fly.wav", 1, ATTN_NORM);
		self.jumptime = time + 0.486;
	}
	if(self.avelocity_y == 0)
		self.avelocity_y = 2000;
	if(self.stick)
	{
		if(RSee(self.owner))
		{
			self.flags = self.flags - (self.flags & FL_ONGROUND);
			vtemp = self.owner.origin - self.origin;
			self.velocity = normalize(vtemp);
			self.velocity = self.velocity*(RAZOR_RETURNSPEED*(vlen(vtemp)/100));
			if(vlen(self.velocity) > RAZOR_SPEED)
			{
				self.velocity = normalize(vtemp);
				self.velocity = self.velocity*RAZOR_RETURNSPEED;
			}	
			if(vlen(vtemp) < 20)
			{
				if(!self.owner.items & IT_LIGHTNING)
					self.owner.items = self.owner.items | IT_LIGHTNING;
				centerprint(self.owner, "Samurai claw has returned.");
				sound (self, CHAN_VOICE, "weapons/r_return.wav", 1, ATTN_NORM);
				remove(self);
			}
		}
		else
		{
			if(self.stick < (time - RAZOR_MAXRETURNTIME))
			{
				if(!self.owner.items & IT_LIGHTNING)
					self.owner.items = other.items | IT_LIGHTNING;
				centerprint(self.owner, "Samurai claw has returned.");
				sound (self, CHAN_VOICE, "weapons/r_return.wav", 1, ATTN_NORM);
				remove(self);
			}
			else if(self.randomf < time)
			{
				self.flags = self.flags - (self.flags & FL_ONGROUND);
				self.velocity_x = mrand();
				self.velocity_y = mrand();
				self.velocity_z = mrand();
				self.velocity = normalize(self.velocity);
				self.velocity = self.velocity * RAZOR_SPEED;
				self.randomf = time + random()*10 +2;
			}
		}
		self.nextthink = time + 0.1;
		return;
	}

	if (self.ltime < time)	
	{	
		if(self.enemy != world)
			StopDrop(self.enemy);
		RazorReturn();
		return;
	}

	self.nextthink = time + 0.1;

	if ((!self.enemy) || (self.enemy == world) || (self.enemy.health < 1) || (self.owner.health < 1))
	{
		if(self.owner.health < 1)
			remove(self);
		else if((self.enemy.health < 1) && (self.enemy != world))
			RazorReturn();
		else
	                self.enemy = ClosestTarget();
	}

	if(!RSee(self.enemy))
	{
		if(self.movetarget == world)
			self.movetarget = NextRazorTarget(0, self.enemy);
		else 
			self.movetarget = NextRazorTarget(self.movetarget.count, self.enemy);
	}
	else
	{
		if(self.count < RAZOR_MAXCHAINS)
			FireChain(self.owner);
		self.movetarget = self.enemy;
	}

	if(!RSee(self.movetarget))
	{
		if(self.enemy != world)
			StopDrop(self.enemy);
		self.movetarget = world;
		self.enemy = world;
		self.count = 0;
		if((self.randomf > 0) && (self.randomf < time))
		{
			self.flags = self.flags - (self.flags & FL_ONGROUND);
			self.velocity_x = mrand();
			self.velocity_y = mrand();
			self.velocity_z = mrand();
			self.velocity = normalize(self.velocity);
			self.velocity = self.velocity * RAZOR_SPEED;
			self.randomf = time + random()*10 +2;
		}
		return;
	}
        if (self.movetarget != world)
	{
		self.flags = self.flags - (self.flags & FL_ONGROUND);
		vtemp = self.movetarget.origin;
                olddir = normalize(self.velocity);
		dir = normalize(vtemp - self.origin);
                self.velocity = dir * RAZOR_SPEED;
	}
};

void(string gibname, float dm, vector org) ThrowGib;
void() T_RazorTouch =
{
local string g;
local entity stemp;

	if(other.takedamage == DAMAGE_AIM)
	{
		T_Damage(other, self, self.owner, RAZOR_DAMAGE, 0, "razor", "gib");
		if(self.chained < time)
		{
			spawn_touchblood(20);
			if(random() > 0.6)
				g = "progs/gib1.mdl";
			else if(random() > 0.3)
				g = "progs/gib2.mdl";
			else
				g = "progs/gib3.mdl";
			stemp = self;
			self = other;
			ThrowGib (g, -100, self.origin);
			self = stemp;
			self.chained = time + 0.2;
			if(other.classname == "player")
				NinjaPainSound(other);
		}
		if(other.health < 1)
			self.randomf = time;
	}
	else
	{
//		self.origin = self.origin - 24*normalize(self.velocity);
		if(self.enemy == world)
			self.randomf = time;
	}
};

void() FireRazor =
{
	local	entity razor;
	
	razor = find(world, classname, "razor");
	while(razor != world)
	{
		if(razor.owner == self)
		{
			razor.think = RazorReturn;
			razor.nextthink = time;
			return;
		}
		razor = find(razor, classname, "razor");
	}
	sound (self, CHAN_WEAPON, "weapons/r_fire.wav", 1, ATTN_NORM);

	self.punchangle_x = -2;

	razor = spawn ();
	razor.owner = self;
	razor.movetype = MOVETYPE_FLYMISSILE;
	razor.solid = SOLID_BBOX;
	razor.classname = "razor";
		
// set razor speed	

	makevectors (self.v_angle);
	razor.velocity = aim(self, 1000);
	razor.velocity = razor.velocity * RAZOR_SPEED;
	razor.avelocity_y = 1000;
	
	razor.touch = T_RazorTouch;
	
// set razor duration
	razor.nextthink = time;
	razor.think = RazorThink;
	razor.enemy = world;
	razor.movetarget = world;
	razor.ltime = time + RAZOR_TIME;
	razor.count = 0;
	razor.randomf = -1;

	setmodel (razor, "progs/katana.mdl");
	setsize (razor, '-2 -2 -2', '2 2 2');		
	setorigin (razor, self.origin + v_forward*8 + '0 0 16');
};

void() DropRazorTarget =
{
local entity t, e, smallest, last;
local float num_targets, highest;
	

	highest = 0;
	smallest = world;
	last = world;

	e = find(world, classname, "razortarget");
	while(e != world)
	{
		if(e.owner == self)
		{
			if((smallest == world) || (e.count > smallest.count))
				smallest = e;
			if((highest == 0) || (highest < e.count))
			{
				last = e;
				highest = e.count;
			}
			num_targets = num_targets + 1;
		}
		e = find(e, classname, "razortarget");
	}
	if((num_targets > MAXRAZORTARGETS) && (smallest != world))
		remove(smallest);

	if(last != world)
	{
		traceline(last.origin, self.origin, TRUE, self);
		self.lastseen = self.origin;
		self.lastseenoldvel = self.velocity;
		if(trace_fraction == 1)
			return;
	}
	t = spawn();
	if(self.lastseen == '0 0 0')
		t.origin = self.origin;
	else 
		t.origin = self.lastseen - 48*normalize(self.lastseenoldvel);
	t.movetype = MOVETYPE_NONE;
	t.classname = "razortarget";
	t.owner = self;
	t.count = highest + 1;
//	setmodel (t, "progs/grenade.mdl");

	//there is nothing following?
	e = world;
	e = find(world, classname, "razor");
	while(e != world)
	{
		if(e.enemy == self)
			return;
		e = find(e, classname, "razor");
	}
	if(e == world)
		StopDrop(self);
};

