//------------------------------------------------------------------------------------
// GChain
//------------------------------------------------------------------------------------

void(vector org, vector ang, float tspeed) Trace =
{
	local	entity gchain;
	
	gchain = spawn ();
	gchain.owner = self;
	gchain.movetype = MOVETYPE_NOCLIP;
	gchain.solid = SOLID_NOT;
		
// set gchain speed	

	gchain.velocity = normalize(ang);
	gchain.velocity = gchain.velocity * tspeed;
	
	gchain.touch = SUB_Remove;
	
// set gchain duration
	gchain.nextthink = time + 10;
	gchain.think = SUB_Remove;

	setmodel (gchain, "progs/missile.mdl");
	setsize (gchain, '0 0 0', '0 0 0');		
	setorigin (gchain, org);
};

vector(float i, vector ang, vector org, float length) Index2Vector =
{
	local vector t, v;

	t = org;
	t_z = t_z - GRAPPLE_DEPTH;
	t = t + (ang * (i * GRAPPLE_POINTDIST));
	v = normalize(t - org);
	return (org + v * length);
};

void(entity hook, vector sorg) NextIndex =
{
	local float ri, i;
	local vector curtarget;

	i = 0;
	curtarget = Index2Vector(hook.stick, hook.angles, hook.origin, hook.jumpheight);

	hook.state = hook.nextstate;

	if(hook.stick > 0)
	{
		if(hook.state == 0)
		{
			hook.stick = hook.stick - 1;
			if(hook.stick == 0)
			{
				hook.gfrom = 1;
				hook.nextstate = 1;
			}
		}
		else
			hook.stick = hook.stick + 1;
	}
	else if(hook.stick < 0)
	{
		if(hook.state == 0)
		{
			hook.stick = hook.stick + 1;
			if(hook.stick == 0)
			{
				hook.gfrom = -1;
				hook.nextstate = 1;
			}
		}
		else
			hook.stick = hook.stick - 1;
	}
	else if(!hook.stick)
	{
		if(hook.gfrom < 0)
			hook.stick = 1;
		else
			hook.stick = -1;
	}
	curtarget = Index2Vector(hook.stick, hook.angles, hook.origin, hook.jumpheight);

	while((vlen(curtarget - sorg) <= GRAPPLE_TARGETMINDIST) && (hook.stick))
	{
		if(hook.stick > 0)
		{
			if(hook.state == 0)
			{
				hook.stick = hook.stick - 1;
				if(hook.stick == 0)
				{
					hook.gfrom = 1;
					hook.nextstate = 1;
				}
			}
			else
				hook.stick = hook.stick + 1;
		}
		else if(hook.stick < 0)
		{
			if(hook.state == 0)
			{
				hook.stick = hook.stick + 1;
				if(hook.stick == 0)
				{
					hook.gfrom = -1;
					hook.nextstate = 1;
				}
			}
			else
				hook.stick = hook.stick - 1;
		}
		else if(!hook.stick)
		{
			if(hook.gfrom < 0)
				hook.stick = 1;
			else
				hook.stick = -1;
		}
		curtarget = Index2Vector(hook.stick, hook.angles, hook.origin, hook.jumpheight);
		i = i + 1;
		if(i > 20)	//prevent loop errors
		{
//			bprint("loop error\n");
			return 0;
		}
	}
//	bprint("next index: ");
//	bprint(ftos(hook.stick));
//	bprint("\n");
};

float(entity p, vector v) PlayerTouchingSide =	//optimieren!!! nur in schwungrichtung prüfen!
{
local vector source, t;

	if(p.retesttouch > time)
		return FALSE;
	p.retesttouch = time + 2;
	source = p.origin + '0 0 -8';
	t = source;
	t_z = t_z + NINJA_CLIMB_RANGE;
	traceline (source, source + v*NINJA_CLIMB_RANGE, FALSE, p);
	if (trace_fraction == 1.0)
	{
		traceline (source, source - v*NINJA_CLIMB_RANGE, FALSE, p);
		if (trace_fraction == 1.0)
		{
			traceline (source, t, FALSE, p);
			if (trace_fraction == 1.0)
			{
				source = p.origin + p.mins;
				traceline (source, source + v*NINJA_CLIMB_RANGE, FALSE, p);
				if (trace_fraction == 1.0)
				{
					traceline (source, source - v*NINJA_CLIMB_RANGE, FALSE, p);
					if (trace_fraction == 1.0)
					{
						source = p.origin + p.maxs;
						traceline (source, source + v*NINJA_CLIMB_RANGE, FALSE, p);
						if (trace_fraction == 1.0)
						{
							traceline (source, source + v*NINJA_CLIMB_RANGE, FALSE, p);
							if (trace_fraction == 1.0)
							{
								traceline (p.origin, p.origin + '0 0 40', FALSE, p);
								if (pointcontents(trace_endpos) == CONTENT_SKY)
									return TRUE;
								else
									return FALSE;
							}
						}
					}
				}
			}
		}
	}
	return TRUE;
};

float(vector fororg, vector gorg, vector gang, float length) FindNearestTargetvector =
{
	local vector t,v, besttarget, curtarget;
	local float i, found, besttargeti, besttargetdist, curtargetdist;
	//now find the closest target in the grapple's swing curve!
	//v and t are just temporary vectors

	i = GRAPPLE_MAXSTEPS;
	found = FALSE;
	curtarget = '0 0 0';
	besttarget = '0 0 0';
	besttargeti = -999;
	besttargetdist = -999;
	while((i > (GRAPPLE_MAXSTEPS * -1)) && (!found))
	{
		t = gorg;
		t_z = t_z - GRAPPLE_DEPTH;
		t = t + (gang * (i * GRAPPLE_POINTDIST));
		v = normalize(t - gorg);
		curtarget = gorg + v * length;
		curtargetdist = vlen(fororg - curtarget);
		traceline(fororg, curtarget, TRUE, world);

		if((curtargetdist > besttargetdist) && (besttargetdist != -999))
			found = TRUE;
		if(((besttargetdist > curtargetdist) || (besttargetdist == -999)) && (trace_fraction == 1.0) && i)
		{
			besttargetdist = curtargetdist;
			besttargeti = i;
			besttarget = curtarget;
		}
		i = i - 1;
	}
	return besttargeti;	//-999 if no target found!
};

void() GChainThink =
{
local vector t, v, curtarget;
local float mod, newtarg;

	if(self.enemy)
		self.origin = self.enemy.origin;
	v = self.origin;

	t = self.owner.origin + '0 0 28';
	WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
	WriteByte (MSG_BROADCAST, TE_LIGHTNING2);	//now a chain
	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);
// made a chain

	if((self.ltime < time) || (self.owner.health < 1) || (!RSee(self.owner)))
	{
		self.owner.state = self.owner.state - (self.owner.state & S_NOGRAV);
		remove(self);
		return;
	}

	if((self.ltime < time) || (self.owner.button2) || ((self.enemy != world) && (self.enemy.health < 1)))
	{
		self.owner.state = self.owner.state - (self.owner.state & S_NOGRAV);
		self.movetype = MOVETYPE_NOCLIP;	//return to owner
		self.solid = SOLID_NOT;
		self.count = 3;
	}

	self.nextthink = time + 0.1;

	if(self.count == 1)	//grapple has hit something
	{
		if(self.enemy != world)
		{
			if((self.enemy.classname == "player") && self.enemy.button0 && (self.enemy.weapon == IT_ROCKET_LAUNCHER) && Infront(self.enemy, self.origin))
			{
				self.count = 3;		//chain was cut!
				centerprint(self.owner, "Chain was cut!\n");
			}
			SpawnSparks(self.enemy.origin, 70, 10, 8, 600);
			T_Damage(self.enemy, self, self.owner, GRAPPLE_DAMAGE, 0, "gchain", "");
			return;
		}
		else	//swing!
		{
			//jumpheight: 	ideal lenght of the chain
			//stick:  	position in the swing curve !! ? =)
			//state:  	1 = moving upwards; 0 = moving downwards
			//speed:  	current speed of player
			//attack_state: 1 = swinging; 0 = moving towards first swing point
			//gamps: 	how often the hook has changed direction (up/down)

			if(!self.owner.state & S_NOGRAV)
				self.owner.state = self.owner.state | S_NOGRAV;

			if(self.stick == -999)	//initialize grapple to swing
			{
				self.stick = GRAPPLE_MAXSTEPS;
				self.splish = GRAPPLE_MAXSTEPS;
				traceline(self.origin, self.origin - '0 0 2000', TRUE, self.owner);
				self.jumpheight = self.origin_z - self.owner.origin_z - 40;
				self.state = 0;

				//now calculate direction to swing to...
				t = self.owner.origin;
				t_z = 0;
				v = self.origin;
				v_z = 0;
				self.angles = normalize(t - v);	//angles pointing towards owner
				self.speed = GRAPPLE_DRAGSPEED;
				self.attack_state = 0;

				self.stick = FindNearestTargetvector(self.owner.origin, self.origin, self.angles, self.jumpheight);
//				bprint(ftos(self.stick));
//				bprint(" first target\n");
			}
/* length adjustment is buggy
			if(self.owner.grapple0)
			{
				self.jumpheight = self.jumpheight - GRAPPLE_ADJUSTLENGTHSTEP;
				if(self.jumpheight < 45)
					self.jumpheight = 45;
				self.stick = FindNearestTargetvector(self.owner.origin, self.origin, self.angles, self.jumpheight);
			}
*/
			if((self.owner.flags & FL_ONGROUND) && (vlen(self.owner.origin - self.origin) < self.jumpheight))
				return;	//cannot swing this way...

			curtarget = Index2Vector(self.stick, self.angles, self.origin, self.jumpheight);
	
			mod = fabs(self.stick);
			mod = mod / (GRAPPLE_MAXSTEPS*0.8);
			mod = mod + 0.5;
			if(mod > 1)
				mod = 1;
			self.owner.velocity_z = self.owner.velocity_z - cvar("sv_gravity") * frametime * mod;

			newtarg = FALSE;
			self.speed = vlen(self.owner.velocity);
			mod = vlen(curtarget - self.owner.origin);
			if(self.state)
			{
				if((fabs(self.owner.speed - self.owner.oldspeed) < 3) && (self.speed <= GRAPPLE_MINSPEED))
				{
//					bprint("now swinging downwards speed\n");
					self.nextstate = 0;
					self.gamps = self.gamps + 1;
					self.slowdown = 1;
					NextIndex(self, self.owner.origin);
					newtarg = TRUE;
				}
				else if (PlayerTouchingSide(self.owner, self.angles))
				{
//					bprint("now swinging downwards touch\n");
					self.nextstate = 0;
					self.gamps = self.gamps + 1;
					self.slowdown = 1;
					NextIndex(self, self.owner.origin);
					newtarg = TRUE;
				}
			}
			if((mod <= GRAPPLE_TARGETMINDIST) && !newtarg)
			{
				self.attack_state = 1;
				NextIndex(self, self.owner.origin);
			}
//			bprint(ftos(mod));
//			bprint(" : dist.\n");
			self.owner.oldspeed = floor(self.owner.speed);
	
//			bprint(ftos(self.speed));
//			bprint(" : speed.\n");
			t = curtarget - self.owner.origin;
			self.owner.velocity = normalize(t);

			if(!self.attack_state)
				self.owner.velocity = self.owner.velocity*GRAPPLE_DRAGSPEED;
			else if(self.gamps <= GRAPPLE_MAXAMPS)
			{
				if(!self.state)
					self.owner.velocity = self.owner.velocity*self.speed;
				else
				{
					if(self.slowdown)
					{
						mod = (GRAPPLE_MAXAMPS - self.gamps) / GRAPPLE_MAXAMPS;
						self.slowdown = 0;
					}
					else
						mod = 1;
					if(mod < 0)
						mod = 0;
//					bprint("mod: ");
//					bprint(ftos(mod));
//					bprint("\n");
					self.owner.velocity = self.owner.velocity*self.speed*mod;
				}
			}
			else
				self.owner.velocity = '0 0 0';
		}
	}
	else if (self.count == 2)	//grapple drags owner
	{
		if(!self.owner.state & S_NOGRAV)
			self.owner.state = self.owner.state | S_NOGRAV;

		if(self.enemy != world)
		{
			if((self.enemy.classname == "player") && self.enemy.button0 && (self.enemy.weapon == IT_ROCKET_LAUNCHER) && Infront(self.enemy, self.origin))
			{
				self.count = 3;		//chain was cut!
				sprint(self.owner, "Chain was cut!\n");
			}
			T_Damage(self.enemy, self, self.owner, GRAPPLE_DAMAGE, 0, "gchain", "");
			SpawnSparks(self.enemy.origin, 70, 10, 8, 600);
			curtarget = self.enemy.origin;
		}
		else
			curtarget = self.origin;
		if(vlen(curtarget - self.owner.origin) > 50)
		{
			t = curtarget - self.owner.origin;
			self.owner.velocity = normalize(t);
			self.owner.velocity = self.owner.velocity*(GRAPPLE_DRAGSPEED*(vlen(t)/100));
			if(vlen(self.owner.velocity) > GRAPPLE_DRAGSPEED)
			{
				self.owner.velocity = normalize(t);
				self.owner.velocity = self.owner.velocity*GRAPPLE_DRAGSPEED;
			}	
		}
		else if(self.enemy == world)	//we are near to a wall, now tie up
		{
			centerprint(self.owner, "You are grappled to the wall\n");
			self.owner.movetype = MOVETYPE_NONE;
			self.owner.state = self.state | S_TIEDUP;
			self.owner.velocity = '0 0 0';
			self.owner.state = self.owner.state - (self.owner.state & S_NOGRAV);
			remove(self);
		}
	}
	else if (self.count == 3)	//grapple returns
	{
		self.owner.state = self.owner.state - (self.owner.state & S_NOGRAV);
		if(!visible(self.owner))
		{
			remove(self);
			return;
		}
		self.flags = self.flags - (self.flags & FL_ONGROUND);
		curtarget = self.origin;
		if(vlen(self.owner.origin - curtarget) > 50)
		{
			t = self.owner.origin - curtarget;
			self.velocity = normalize(t);

			self.velocity = self.velocity*(GRAPPLE_RETURNSPEED*(vlen(t)/100));	//moves slower if distance (t) is < 100 units
			if(vlen(self.velocity) > GRAPPLE_RETURNSPEED)
			{
				self.velocity = normalize(t);
				self.velocity = self.velocity*GRAPPLE_RETURNSPEED;
			}	
		}
		else
			remove(self);
	}
};

void() T_GChainTouch =
{
	if(other == self.owner)
		return;

	if(other.classname == "sworddamage")
		self.count = 3;		//chain was cut!
	if((other.classname == "player") && other.button0 && (other.weapon == IT_ROCKET_LAUNCHER) && Infront(other, self.origin))
		self.count = 3;		//chain was cut!

	if(!self.count)
	{
		if(self.origin_z < self.owner.origin_z)
			self.count = 2;
		else
			self.count = 1;
	}
	else if(self.count == 4)
		self.count = 2;
	if(other.takedamage)
	{
		self.enemy = other;
		self.count = 2;
	}
	else
	{
		sound (self, CHAN_WEAPON, "weapons/ghitwall.wav", 1, ATTN_NORM);
		self.oldvel = self.origin;
	}
	self.velocity = '0 0 0';
};

//count:
//1: grapple touched something
//2: grapple drags owner to anchor
//3: grapple returns to owner

void() W_FireGrapple =
{
	local	entity gchain;
	
	if(self.state & S_TIEDUP)
	{
		self.movetype = MOVETYPE_WALK;
		self.state = self.state - (self.state & S_TIEDUP);
		return;
	}
	gchain = find(world, classname, "gchain");
	while(gchain != world)
	{
		if(gchain.owner == self)
		{
			if(gchain.count == 0)
			{
				gchain.count = 4;
				centerprint(self, "Drag mode");
			}
			else if(gchain.count == 1)
			{
				gchain.count = 2;
				centerprint(self, "Drag mode");
			}
			else if(gchain.count == 2)
			{
				self.movetype = MOVETYPE_WALK;
				self.state = self.state - (self.state & S_TIEDUP);
				gchain.count = 3;
				centerprint(self, "Grapple returning");
			}
			gchain.nextthink = time;
			return;
		}
		gchain = find(gchain, classname, "gchain");
	}
	centerprint(self, "Swing mode");
//	sound (self, CHAN_WEAPON, "weapons/gfire.wav", 1, ATTN_NORM);

	self.punchangle_x = -2;

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

	makevectors (self.v_angle);
	gchain.velocity = aim(self, 1000);
	gchain.velocity = gchain.velocity * GRAPPLE_SPEED;
	
	gchain.touch = T_GChainTouch;
	
// set gchain duration
	gchain.nextthink = time;
	gchain.think = GChainThink;
	gchain.ltime = time + GRAPPLE_TIME;
	gchain.enemy = world;
	gchain.stick = -999;
	gchain.gamps = 1;

//	setmodel (gchain, "progs/missile.mdl");
	setsize (gchain, '0 0 0', '0 0 0');		
	setorigin (gchain, self.origin + v_forward*8);
};








/* old version
void() GChainThink =
{
local vector t, v, targ, curtarget, besttarget;
local entity stemp, test;
local float clength, besttargeti, i, found, curtargetdist, besttargetdist, temp;

	if(self.enemy)
		v = self.enemy.origin;
	else if(self.count)
		v = self.oldvel;
	else
		v = self.origin;

	t = self.owner.origin;
	WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
	WriteByte (MSG_BROADCAST, TE_LIGHTNING2);	//now a chain
	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);
// made a chain

	if((self.ltime < time) || (self.owner.health < 1) || (!RSee(self.owner)))
	{
		self.owner.state = self.owner.state - (self.owner.state & S_NOGRAV);
		remove(self);
		return;
	}

	if((self.ltime < time) || (self.owner.button2) || ((self.enemy != world) && (self.enemy.health < 1)))
	{
		self.owner.state = self.owner.state - (self.owner.state & S_NOGRAV);
		self.movetype = MOVETYPE_NOCLIP;	//return to owner
		self.solid = SOLID_NOT;
		self.count = 3;
	}

	self.nextthink = time + 0.1;

	if(self.count == 1)	//grapple has hit something
	{
		if(self.enemy != world)
		{
			T_Damage(self.enemy, self, self.owner, GRAPPLE_DAMAGE, 0, "gchain", "");
			return;
		}
		else	//swing!
		{
			//jumpheight: ideal lenght of the chain
			//stick: position in the swing curve !! ? =)
			//splish: position to swing to. decreases from swing to swing... =)
			//state: 1 = moving upwards; 0 = moving downwards
//			if(!self.owner.state & S_NOGRAV)
//				self.owner.state = self.owner.state | S_NOGRAV;

			if(self.stick == -999)	//initialize grapple to swing
			{
				self.stick = GRAPPLE_MAXSTEPS;
				self.splish = GRAPPLE_MAXSTEPS;
				traceline(self.origin, self.origin - '0 0 2000', TRUE, self.owner);
				self.jumpheight = self.origin_z - self.owner.origin_z - 40;
//				self.jumpheight = 2000 * trace_fraction - 40;	//player should swing close over the ground
				self.state = 0;

				//now calculate direction to swing to...
				t = self.owner.origin;
				t_z = 0;
				v = self.origin;
				v_z = 0;
				self.angles = normalize(t - v);	//angles pointing towards owner

				self.stick = FindNearestTargetvector(self.owner.origin, self.origin, self.angles, self.jumpheight);
//				self.splish = self.stick;
			}
			if(self.owner.grapple0)
			{
				self.jumpheight = self.jumpheight - GRAPPLE_ADJUSTLENGTHSTEP;
				if(self.jumpheight < 45)
					self.jumpheight = 45;
				self.stick = FindNearestTargetvector(self.owner.origin, self.origin, self.angles, self.jumpheight);
			}
			if((self.owner.flags & FL_ONGROUND) && (vlen(self.owner.origin - self.origin) < self.jumpheight))
				return;	//cannot swing this way...

			if(self.retouch_time < time)
			{
				if((PlayerTouchingSide(self.owner)) && self.state)
				{
//					bprint("playertouching\n");
					self.stick = FindNearestTargetvector(self.owner.origin, self.origin, self.angles, self.jumpheight);
					self.state = !self.state;
				}
				self.retouch_time = time + 1;
			}

			if(((self.stick >= self.splish) || (self.stick <= (self.splish * -1))) && (self.state == 1))
			{
//				bprint("reached top of curve\n");
				self.state = 0;
				self.splish = self.splish - GRAPPLE_LOSESTEPS;
				if(self.splish < 0)
				{
					self.splish = 0;
					self.stick = 0;
				}
			}

			curtarget = Index2Vector(self.stick, self.angles, self.origin, self.jumpheight);

			i = 0;
			while((vlen(curtarget - self.owner.origin) <= 40) && (self.stick))
			{
//				bprint("next index: ");
				if(self.stick > 0)
				{
					if(self.state == 0)
					{
						self.stick = self.stick - 1;
						if(self.stick == 0)
						{
							self.stick = -1;
							self.state = 1;
						}
					}
					else
						self.stick = self.stick + 1;
				}
				else if(self.stick < 0)
				{
					if(self.state == 0)
					{
						self.stick = self.stick + 1;
						if(self.stick == 0)
						{
							self.stick = 1;
							self.state = 1;
						}
					}
					else
						self.stick = self.stick - 1;
				}
//				bprint(ftos(self.stick));
//				bprint("\n");
				curtarget = Index2Vector(self.stick, self.angles, self.origin, self.jumpheight);
				i = i + 1;
				if(i > 20)	//prevent loop errors
					self.stick = 0;
			}

			t = curtarget - self.owner.origin;
			self.owner.velocity = normalize(t);

			if(self.c_mode)
			{
				temp = self.stick * self.stick;
				temp = 1 - (temp / (GRAPPLE_MAXSTEPS * GRAPPLE_MAXSTEPS));
				if(temp <= 0)
					temp = 0.1;
			}
			else
				temp = 1;

			if((self.stick == 0) && (self.stick != self.oldtargi))
			{
				self.owner.velocity = self.owner.velocity*(GRAPPLE_DRAGSPEED*(vlen(t)/100));
				if(vlen(self.owner.velocity) > GRAPPLE_DRAGSPEED)
				{
					self.owner.velocity = normalize(t);
					self.owner.velocity = self.owner.velocity*GRAPPLE_DRAGSPEED;
				}
				self.c_mode = 1;
				self.oldtargi = self.stick;
			}
			else
				self.owner.velocity = self.owner.velocity*GRAPPLE_DRAGSPEED*temp;
		}
	}
	else if (self.count == 2)	//grapple drags owner
	{
		if(!self.owner.state & S_NOGRAV)
			self.owner.state = self.owner.state | S_NOGRAV;

		if(self.enemy != world)
		{
			T_Damage(self.enemy, self, self.owner, GRAPPLE_DAMAGE, 0, "gchain", "");
			targ = self.enemy.origin;
		}
		else
			targ = self.oldvel;
		if(vlen(targ - self.owner.origin) > 50)
		{
			t = targ - self.owner.origin;
			self.owner.velocity = normalize(t);
			self.owner.velocity = self.owner.velocity*(GRAPPLE_DRAGSPEED*(vlen(t)/100));
			if(vlen(self.owner.velocity) > GRAPPLE_DRAGSPEED)
			{
				self.owner.velocity = normalize(t);
				self.owner.velocity = self.owner.velocity*GRAPPLE_DRAGSPEED;
			}	
		}
		else	//we are near to a wall, now try to tie up
		{
			stemp = self;
			self = self.owner;
			TieUp();
			self = stemp;
			self.owner.state = self.owner.state - (self.owner.state & S_NOGRAV);
			remove(self);
		}
	}
	else if (self.count >= 3)	//grapple returns
	{
		self.owner.state = self.owner.state - (self.owner.state & S_NOGRAV);
		if(!visible(self.owner))
		{
			remove(self);
			return;
		}
		self.flags = self.flags - (self.flags & FL_ONGROUND);
		targ = self.origin;
		if(vlen(self.owner.origin - targ) > 50)
		{
			t = self.owner.origin - targ;
			self.velocity = normalize(t);

			self.velocity = self.velocity*(GRAPPLE_RETURNSPEED*(vlen(t)/100));	//moves slower if distance (t) is < 100 units
			if(vlen(self.velocity) > GRAPPLE_RETURNSPEED)
			{
				self.velocity = normalize(t);
				self.velocity = self.velocity*GRAPPLE_RETURNSPEED;
			}	
		}
		else
			remove(self);
	}
};
*/
