#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
#include <engine>

#define MAXPLAYERS					32
#define FLAGS_BUILD 					ADMIN_KICK

#define IsMovingEnt(%1)   	( entity_get_int( %1, EV_INT_iuser2 ) == 1 )
#define MovingEnt(%1)     	( entity_set_int( %1, EV_INT_iuser2,     1 ) )
#define UnmovingEnt(%1)   	( entity_set_int( %1, EV_INT_iuser2,     0 ) )

#define SetEntMover(%1,%2)  	( entity_set_int( %1, EV_INT_iuser3, %2 ) )
#define UnsetEntMover(%1)   	( entity_set_int( %1, EV_INT_iuser3, 0  ) )
#define SetLastMover(%1,%2)  	( entity_set_int( %1, EV_INT_iuser4, %2 ) )

#define GetEntMover(%1)   	( entity_get_int( %1, EV_INT_iuser3     ) )
#define GetLastMover(%1)  	( entity_get_int( %1, EV_INT_iuser4     ) )


#define OBJECT_PUSHPULLRATE 				6.0

//Building Stores
new Float:g_fOffset1[MAXPLAYERS+1], Float:g_fOffset2[MAXPLAYERS+1], Float:g_fOffset3[MAXPLAYERS+1]
new g_iOwnedEnt[MAXPLAYERS+1]
new Float:g_fEntDist[MAXPLAYERS+1]
new Float:g_fBuildDelay[MAXPLAYERS+1]
new Float:g_fEntMinDist = 32.0, Float: g_fEntSetDist = 64.0, Float:g_fEntMaxDist = 768.0
#define BUILD_DELAY 0.75


// Main 
new g_iEntBarrier, g_HudSync, cvar_activated, bool:g_boolCanBuild = true, Float:MAX_Z = 80.0, Float:MIN_Z = -10.0

public plugin_init()
{
	register_plugin("NRS : Survival Builder", "1.0", "Tirant")
	register_clcmd("say /builder", "NRS_Building_switch")
	register_clcmd("say rules", "Rules_SHOW")
	register_clcmd("say_team rules", "Rules_SHOW")
	register_clcmd("say_team /rules", "Rules_SHOW")
	register_clcmd("say /rules", "Rules_SHOW")
	
	g_iEntBarrier = find_ent_by_tname( -1, "gate" );
	
	register_forward(FM_CmdStart, 			"fw_CmdStart");
	register_forward(FM_PlayerPreThink, 		"fw_PlayerPreThink")
	register_forward(FM_TraceLine, 			"fw_Traceline", 1)

	register_dictionary("nrs_builder.txt");
	
	cvar_activated = register_cvar("nrs_builder", "0")
	g_HudSync = CreateHudSyncObj();
	
	/*new Float:serverOrigin[3], Float:serverAbsmin[3]
	pev(0, pev_origin, serverOrigin)
	pev(0, pev_absmin, serverOrigin)
	Z_DIST = fm_distance_to_floor(0, serverOrigin, serverAbsmin);*/
}


public Rules_SHOW(id)
{
	show_motd(id,"nrs_builder_rules.txt","The Last Stand : Rules.")
	return PLUGIN_HANDLED   
}


public client_disconnect(id)
{
	if (g_iOwnedEnt[id])
		cmdStopEnt(id)
}

public NRS_Building_switch(id)
{
	if ( g_boolCanBuild ) g_boolCanBuild = false
	else g_boolCanBuild = true
	client_print(id, print_center, "Building %s", g_boolCanBuild ? "activated!" : "disabled.")
}

public fw_CmdStart( id, uc_handle, randseed )
{
	if ( !is_user_alive(id) )
		return FMRES_IGNORED
	
	if ( !get_pcvar_num(cvar_activated) && !(access(id, FLAGS_BUILD) ) )
	{
		if (g_iOwnedEnt[id])
			cmdStopEnt(id)
		return FMRES_IGNORED
	}

	new button = get_uc( uc_handle , UC_Buttons );
	new oldbutton = pev(id, pev_oldbuttons)

	if( button & IN_USE && !(oldbutton & IN_USE) && !g_iOwnedEnt[id])
		cmdGrabEnt(id)
	else if( oldbutton & IN_USE && !(button & IN_USE) && g_iOwnedEnt[id])
		cmdStopEnt(id)

	return FMRES_IGNORED;
}


public cmdGrabEnt(id)
{
	if (g_fBuildDelay[id] + BUILD_DELAY > get_gametime())
	{
		g_fBuildDelay[id] = get_gametime()
		client_print (id, print_center, "%L", LANG_SERVER, "BUILD_SPAM")
		return PLUGIN_HANDLED
	}
	else
		g_fBuildDelay[id] = get_gametime()
		
	if ( !g_boolCanBuild )
	{
		client_print (id, print_center, "%L", LANG_SERVER, "BUILD_NOTIME")
		return PLUGIN_HANDLED
	}
	
	if (g_iOwnedEnt[id] && pev_valid(g_iOwnedEnt[id])) 
		cmdStopEnt(id)
	
	new ent, bodypart
	get_user_aiming (id,ent,bodypart)
	
	if (ent == g_iEntBarrier || !pev_valid(ent)  || is_user_alive(ent) || IsMovingEnt(ent))
		return PLUGIN_HANDLED;
	
	
	new szClass[10], szTarget[7];
	entity_get_string(ent, EV_SZ_classname, szClass, 9);
	entity_get_string(ent, EV_SZ_targetname, szTarget, 6);
	if (!equal(szClass, "func_wall") || equal(szTarget, "ignore"))
		return PLUGIN_HANDLED;
		

	new Float:fOrigin[3], iAiming[3], Float:fAiming[3]
	
	get_user_origin(id, iAiming, 3);
	IVecFVec(iAiming, fAiming);
	entity_get_vector(ent, EV_VEC_origin, fOrigin);

	g_fOffset1[id] = fOrigin[0] - fAiming[0];
	g_fOffset2[id] = fOrigin[1] - fAiming[1];
	g_fOffset3[id] = fOrigin[2] - fAiming[2];
	
	g_fEntDist[id] = get_user_aiming(id, ent, bodypart);
		
	if (g_fEntMinDist)
	{
		if (g_fEntDist[id] < g_fEntMinDist)
			g_fEntDist[id] = g_fEntSetDist;
	}
	else if (g_fEntMaxDist)
	{
		if (g_fEntDist[id] > g_fEntMaxDist)
			return PLUGIN_HANDLED
	}

	set_pev(ent,pev_rendermode,kRenderTransColor)
	set_pev(ent,pev_rendercolor, {146.0, 110.0, 174.0} )
	set_pev(ent,pev_renderamt, 175.0 )
	
	MovingEnt(ent);
	SetEntMover(ent, id);
	g_iOwnedEnt[id] = ent
	
	return PLUGIN_HANDLED
}



public cmdStopEnt(id)
{
	if ( !g_iOwnedEnt[id] || !pev_valid(g_iOwnedEnt[id]) )
		return PLUGIN_HANDLED;
	
	new ent = g_iOwnedEnt[id]
	
	set_pev(ent,pev_rendermode,kRenderNormal)	
	
	UnsetEntMover(ent);
	SetLastMover(ent,id);
	g_iOwnedEnt[id] = 0;
	UnmovingEnt(ent);
	//remove_entity(ent)
	
	//client_cmd(id, "spk %s", GRAB_STOP);
	
	return PLUGIN_HANDLED;
}


public fw_PlayerPreThink(id)
{
	if ( !get_pcvar_num(cvar_activated)  )
	{
		if ( is_user_connected(id) )
			if ( !(access(id, FLAGS_BUILD) ) )
		return PLUGIN_CONTINUE
	}
		
	if (!is_user_connected(id))
	{
		cmdStopEnt(id)
		return PLUGIN_HANDLED
	}
	
	
	if (!g_iOwnedEnt[id] || !pev_valid(g_iOwnedEnt[id]))
		return FMRES_HANDLED
		
		
	new buttons = pev(id, pev_button)
	if (buttons & IN_ATTACK)
	{
		g_fEntDist[id] += OBJECT_PUSHPULLRATE;
		
		if (g_fEntDist[id] > g_fEntMaxDist)
		{
			g_fEntDist[id] = g_fEntMaxDist
			client_print(id, print_center, "%L", LANG_SERVER, "OBJECT_MAX")
		}
		else
			client_print(id, print_center, "%L", LANG_SERVER, "OBJECT_PUSH")
	}
	else if (buttons & IN_ATTACK2)
	{
		g_fEntDist[id] -= OBJECT_PUSHPULLRATE;
			
		if (g_fEntDist[id] < g_fEntSetDist)
		{
			g_fEntDist[id] = g_fEntSetDist
			client_print(id, print_center, "%L", LANG_SERVER, "OBJECT_MIN")
		}
		else
			client_print(id, print_center, "%L", LANG_SERVER, "OBJECT_PULL")
	}
	
	new iOrigin[3], iLook[3], /*Float:absmin[3], Float: distance_2_floor, */Float:fOrigin[3], Float:fLook[3], Float:vMoveTo[3], Float:fLength
	    
	get_user_origin(id, iOrigin, 1);
	IVecFVec(iOrigin, fOrigin);
	get_user_origin(id, iLook, 3);
	IVecFVec(iLook, fLook);
	    
	fLength = get_distance_f(fLook, fOrigin);
	if (fLength == 0.0) fLength = 1.0;

	vMoveTo[0] = (fOrigin[0] + (fLook[0] - fOrigin[0]) * g_fEntDist[id] / fLength) + g_fOffset1[id];
	vMoveTo[1] = (fOrigin[1] + (fLook[1] - fOrigin[1]) * g_fEntDist[id] / fLength) + g_fOffset2[id];
	vMoveTo[2] = (fOrigin[2] + (fLook[2] - fOrigin[2]) * g_fEntDist[id] / fLength) + g_fOffset3[id];
	vMoveTo[2] = float(floatround(vMoveTo[2], floatround_floor));
	
	//pev(g_iOwnedEnt[id], pev_absmin, absmin);
	//distance_2_floor = fm_distance_to_floor( g_iOwnedEnt[id], vMoveTo, absmin )
	
	//if ( distance_2_floor > Z_DIST )
	//{
		//vMoveTo[2] = 500.0
	//}
	
	//client_print(id, print_center, "%L", LANG_SERVER, "OBJECT_MAX_Z", floatround(vMoveTo[2]))
	if ( vMoveTo[2] >= MAX_Z )
	{
		client_print(id, print_center, "%L", LANG_SERVER, "OBJECT_MAX_Z")
		vMoveTo[2] = MAX_Z
	}
	
	if ( vMoveTo[2] <= MIN_Z )
	{
		client_print(id, print_center, "%L", LANG_SERVER, "OBJECT_MIN_Z")
		vMoveTo[2] = MIN_Z
	}


	entity_set_origin(g_iOwnedEnt[id], vMoveTo);
	
	
	return FMRES_HANDLED
}


/*stock Float:fm_distance_to_floor(ent, Float:fOrigin[3], Float:absmin[3], ignoremonsters = 1) 
{
	new Float:dest[3], Float:end[3];
	dest[0] = fOrigin[0];
	dest[1] = fOrigin[1];
	dest[2] = -8191.0;

	engfunc(EngFunc_TraceLine, fOrigin, dest, ignoremonsters, ent, 0);
	get_tr2(0, TR_vecEndPos, end);

	//pev(index, pev_absmin, fOrigin);
	new Float:ret = absmin[2] - end[2];

	return ret > 0 ? ret : 0.0;
}  */

public fw_Traceline(Float:start[3], Float:end[3], conditions, id, trace)
{	
	if (!is_user_alive(id))
		return PLUGIN_HANDLED
		
	new bool:bool_show_tips = false
	if ( get_pcvar_num(cvar_activated) || (access(id, FLAGS_BUILD) ) )
		bool_show_tips = true
		
	new ent = get_tr2(trace, TR_pHit)
	
	if (pev_valid(ent))
	{
		new ent,body
		get_user_aiming(id,ent,body)
		
		new szClass[10], szTarget[7];
		entity_get_string(ent, EV_SZ_classname, szClass, 9);
		entity_get_string(ent, EV_SZ_targetname, szTarget, 6);
		if (equal(szClass, "func_wall") && !equal(szTarget, "ignore") && ent != g_iEntBarrier)
		{
			if (g_boolCanBuild || bool_show_tips)
			{
				set_hudmessage(0, 50, 255, -1.0, 0.55, 1, 0.01, 3.0, 0.01, 0.01);
				new szCurMover[32], szLastMover[32], hudtext[500]
				if (GetEntMover(ent))
				{
					get_user_name(GetEntMover(ent),szCurMover,31)
					if (!GetLastMover(ent))
						formatex(hudtext, 499, "%L", LANG_SERVER, "MOVING_ISSURE", szCurMover, "NONE");
				}
				if (GetLastMover(ent))
				{
					get_user_name(GetLastMover(ent),szLastMover,31)
					if (!GetEntMover(ent))
						formatex(hudtext, 499, "%L", LANG_SERVER, "MOVING_ISSURE", "NONE", szLastMover);
				}
				if (GetEntMover(ent) && GetLastMover(ent))
					formatex(hudtext, 499, "%L", LANG_SERVER, "MOVING_ISSURE", szCurMover, szLastMover);
				else if (!GetEntMover(ent) && !GetLastMover(ent))
					formatex(hudtext, 499, "%L", LANG_SERVER, "MOVING_NOT")
				
				ShowSyncHudMsg(id, g_HudSync, hudtext);
			}
			
			new szENV_HEALTH[4]
			pev(ent, pev_targetname, szENV_HEALTH, 3)
			client_print(id, print_center, "%L", LANG_SERVER, "OBJECT_HEALTH", szENV_HEALTH);
			
		}
	}else if ( bool_show_tips ) ClearSyncHud(id, g_HudSync);
	
	
	return PLUGIN_HANDLED
}
