
public Action:Command_Grab(client, args)
{  
	// if an object is being held, go to UnGrab
	if (g_HeldEnt[client]>0)
		return Command_UnGrab(client, args);
	
	// make sure client is not spectating
	if (!IsPlayerAlive(client))
		return Plugin_Handled;
	
	// find entity
	new ent = TraceToEntity(client);
	if (ent==-1)
		return Plugin_Handled;
	
	// leave mah chippy alone - although it is frozen with spawn flag, it leads to bouncy shiat if you ever grab it so don't
	if (ent==g_ChippyEnt)
		return Plugin_Handled;
		
	if (ent==g_ChippyWindowsEnt)
		return Plugin_Handled;
	
	// only grab physics entities
	new String:edictname[128];
	GetEdictClassname(ent, edictname, 128);
	if (strncmp("prop_", edictname, 5, false)==0)
	{
		// check if another player is holding it
		new j;
		for (j=1; j<=MaxClients; j++)
		{
			if (g_HeldEnt[j]==ent)
			{
				if (GetConVarInt(cvSteal)==1)
				{
					// steal from other player
					Command_UnGrab(j, args);
				}
				else
				{
					// already being held - stealing not allowed
					return Plugin_Handled;
				}
			}
		}
		
		// grab entity
		g_HeldEnt[client] = ent;
		
		// whose head and if so set the last holder
		for (new i = 1; i <= MaxClients; i++)
		{
			if (g_HeadEnt[i] > 0)
			{
				if(ent == g_HeadEnt[i])
					g_HeadLastHolder[i] = client;
			}
		}
		
		g_ThrowCharge[client] = 0.0;
		EmitSoundToAll(g_HoldSound, client);
	}
	
	return Plugin_Handled;
}

public Action:Command_UnGrab(client, args)
{  
	// make sure client is not spectating
	if (!IsPlayerAlive(client))
		return Plugin_Handled;
	
	StopSound(client, SNDCHAN_AUTO, g_HoldSound);
	
	if (g_ThrowCharge[client]>0.0)
		PrintHintText(client, "");
	
	g_ThrowCharge[client] = 0.0;
	g_HeldEnt[client] = -1;
	
	new Float:Client_Origin[3];
	GetClientAbsOrigin(client,Client_Origin);
	
	g_ThrowPosValid[client] = true;
	g_ThrowPosX[client] = Client_Origin[0];
	g_ThrowPosY[client] = Client_Origin[1];
	g_ThrowPosZ[client] = Client_Origin[2];
	
	return Plugin_Handled;
}

public Action:Command_Throw(client, args)
{
	// make sure client is not spectating
	if (!IsPlayerAlive(client))
		return Plugin_Handled;
	// has an object?
	if (g_HeldEnt[client]<1)
		return Plugin_Handled;
	
	// start throw timer
	g_ThrowCharge[client] = GetEngineTime();
	
	return Plugin_Handled;
}

public Action:Command_UnGrab2(client, args)
{
	// changed so Commmand_Ungrab is called from Command_Grab if an object is already held
	// so we need to handle -grab with this function
	return Plugin_Handled;
}

public Action:Command_UnThrow(client, args)
{
	// make sure client is not spectating
	if (!IsPlayerAlive(client))
		return Plugin_Handled;
	// has an object?
	if (g_HeldEnt[client]<1)
		return Plugin_Handled;
	
	// record pos
	new Float:Client_Origin[3];
	GetClientAbsOrigin(client,Client_Origin);
	
	g_ThrowPosValid[client] = true;
	g_ThrowPosX[client] = Client_Origin[0];
	g_ThrowPosY[client] = Client_Origin[1];
	g_ThrowPosZ[client] = Client_Origin[2];
	
	// throw object
	new Float:throwtime = GetConVarFloat(cvThrowTime);
	new Float:throwspeed = GetConVarFloat(cvThrowSpeed);
	new Float:time = GetEngineTime();
	new Float:percent;
	
	time=time-g_ThrowCharge[client];
	if (time>throwtime)
	{
		percent = 1.0;
	}
	else
	{
		percent = time/throwtime;
	}
	throwspeed*=percent;
	
	new Float:start[3];
	GetClientEyePosition(client, start);
	new Float:angle[3];
	new Float:speed[3];
	GetClientEyeAngles(client, angle);
	GetAngleVectors(angle, speed, NULL_VECTOR, NULL_VECTOR);
	speed[0]*=throwspeed; speed[1]*=throwspeed; speed[2]*=throwspeed;
	
	TeleportEntity(g_HeldEnt[client], NULL_VECTOR, NULL_VECTOR, speed);
	
	// cleanup
	Command_UnGrab(client, args);
	PrintHintText(client, "");  
	
	return Plugin_Handled;
}


public Action:UpdateObjects(Handle:timer)
{
	new Float:vecDir[3], Float:vecPos[3], Float:vecVel[3];      // vectors
	new Float:viewang[3];                                       // angles
	new i;
	new Float:speed = GetConVarFloat(cvSpeed);
	new Float:distance = GetConVarFloat(cvDistance);
	new Float:throwtime = GetConVarFloat(cvThrowTime);
	new Float:time = GetEngineTime();
	new bool:DropInJump = false;
	for (i=0; i<=MaxClients; i++)
	{
		if (g_HeldEnt[i]>0)
		{
			if (GetConVarBool(cvDropOnJump))
			{
				DropInJump = GetClientButtons(i) & IN_JUMP ? true : false;
			}
			if (IsValidEdict(g_HeldEnt[i]) && IsValidEntity(g_HeldEnt[i]) && !DropInJump )
			{
				// get client info
				GetClientEyeAngles(i, viewang);
				GetAngleVectors(viewang, vecDir, NULL_VECTOR, NULL_VECTOR);
				GetClientEyePosition(i, vecPos);
				
				// update object 
				vecPos[0]+=vecDir[0]*distance;
				vecPos[1]+=vecDir[1]*distance;
				vecPos[2]+=vecDir[2]*distance;

				GetEntPropVector(g_HeldEnt[i], Prop_Send, "m_vecOrigin", vecDir);
				
				SubtractVectors(vecPos, vecDir, vecVel);
				
				ScaleVector(vecVel, speed);
				
				if(GetVectorDistance(vecPos, vecDir) < 150.0)
				{
				    TeleportEntity(g_HeldEnt[i], NULL_VECTOR, NULL_VECTOR, vecVel);
				
				    // update throw time
				    if (g_ThrowCharge[i]>0.0)
				    {
				    	ShowBar(i, time-g_ThrowCharge[i], throwtime);
				    }
				}
				else
				{
				    Command_UnGrab(i, 0);
				}
			}
			else
			{
				Command_UnGrab(i, 0);
				//g_HeldEnt[i]=-1;
			}
			
		}
	}
	
	return Plugin_Continue;
}

public TraceToEntity(client)
{
	new Float:vecClientEyePos[3], Float:vecClientEyeAng[3];
	GetClientEyePosition(client, vecClientEyePos); // Get the position of the player's eyes
	GetClientEyeAngles(client, vecClientEyeAng); // Get the angle the player is looking    
	
	//Check for colliding entities
	TR_TraceRayFilter(vecClientEyePos, vecClientEyeAng, MASK_SOLID, RayType_Infinite, TraceRayDontHitSelf, client);
	
	if (TR_DidHit(INVALID_HANDLE))
	{
		new TRIndex = TR_GetEntityIndex(INVALID_HANDLE);
		
		// check max distance
		new Float:pos[3];
		GetEntPropVector(TRIndex, Prop_Send, "m_vecOrigin", pos);
		if (GetVectorDistance(vecClientEyePos, pos)>GetConVarFloat(cvMaxDistance))
		{
			return -1;
		}
		else
		{
			return TRIndex;
		}
	}
	
	return -1;
}

public bool:TraceRayDontHitSelf(entity, mask, any:data)
{
	if(entity == data) // Check if the TraceRay hit the itself.
	{
		return false; // Don't let the entity be hit
	}
	return true; // It didn't hit itself
}


// show a progres bar via hint text
ShowBar(client, Float:curTime, Float:totTime)
{
	new i;
	new String:output[128];
	
	if (curTime>totTime)
	{
		Format(output, sizeof(output), "[XXXXXXXXXXXXXXXXXXXX]");
	}
	else
	{
		new Float:fl = 1.0;
		output[0]='[';
		for (i=1;i<21;i++)
		{
			if (fl/20.0 > curTime/totTime)
			{
				output[i]='-';
			}
			else
			{
				output[i]='X';
			}
			fl+=1.0;
		}
		output[21]=']';
		output[22]='\0';
	}
	
	PrintHintText(client, output);
}
