#pragma semicolon 1

#include <amxmodx>
#include <xs>
#include <reapi>
#include <fakemeta>

#define PLUGIN_NAME		"THook"
#define PLUGIN_VERS		"1.0"
#define PLUGIN_AUTH		"Fax" // NOT ONLY FAX!!!!!!!

#define HOOK_YETKI		ADMIN_IMMUNITY


/* Eger Hook sesi istemiyorsaniz #define HOOK_SOUND onune // isaretini koyun. */
//#define HOOK_SOUND

/* Burada sadece ses dosyalarinin ismini degistirin. */
#if defined HOOK_SOUND
new const sesdosyalari[] = "weapons/xbow_hit2.wav";
#endif

enum (+= 1000)
{
	TASKID_HOOK = 1000,
	TASKID_GRAB,
	TASKID_ROPE,
	TASKID_POWER1
};

new bool:hook[MAX_CLIENTS + 1],
Float:hook_to[MAX_CLIENTS + 1][3],
Float:hook_speed,
hook_usage,
dot;

public plugin_init() {
	register_plugin(PLUGIN_NAME, PLUGIN_VERS, PLUGIN_AUTH);

	register_clcmd("+thook", "@hook_on");
	register_clcmd("-thook", "@hook_off");

	bind_pcvar_float(create_cvar("thook_speed", "8", _, _, true, 0.0, true, 20.0), hook_speed);

	bind_pcvar_num(create_cvar("thook_usage", "8", _, _, true, 0.0, true, 9.0), hook_usage);
	RegisterHookChain(RG_CBasePlayer_Spawn, "@CBasePlayer_Spawn", .post=false);
}

public plugin_precache()
{
	dot = precache_model("sprites/dot.spr");
#if defined HOOK_SOUND
	for(new i=0; i < sizeof(sesdosyalari); i++)
	{
		precache_sound(sesdosyalari[i]);
	}
#endif
}

@CBasePlayer_Spawn(const id)
{
	hook[id] = false; 
}

@hook_on(const id)
{
	if(!is_continue(id, hook_usage, HOOK_YETKI) || hook[id])
	{
		return PLUGIN_HANDLED;
	}
	if(useable(id)){
		client_print_color(id,id,"^4[THook] ^3Sadece ^1ustu kapali ^3alanlarda kullanabilirsin.");	
		return PLUGIN_HANDLED;
	}
	else {

		set_entvar(id, var_gravity, 0.0);
		set_task(0.1, "@hook_prethink", id + TASKID_HOOK, .flags = "b");
		hook[id] = true;
		hook_to[id][0] = 999999.0;
		@hook_prethink(id + TASKID_HOOK);
	#if defined HOOK_SOUND
		rh_emit_sound2(id, 0, CHAN_AUTO, sesdosyalari[0], VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
	#endif
		return PLUGIN_HANDLED;
	}
}

@hook_off(const id)
{
	if(!hook[id])
	{
		return PLUGIN_HANDLED;
	}

	if(is_user_alive(id))
	{
		set_entvar(id, var_gravity, 1.0);
	}
	hook[id] = false;
	return PLUGIN_HANDLED;
}

@hook_prethink(TaskId)
{
	new id = TaskId - TASKID_HOOK;

	if(!is_continue(id, hook_usage, HOOK_YETKI))
	{
		hook[id] = false;
	}

	if(useable(id) || !hook[id])
	{
		set_entvar(id, var_velocity, {0.0, 0.0, 0.0});

		remove_task(id + TASKID_HOOK);
		return;
	}

	if(hook_to[id][0] == 999999)
	{
		static origin2[3], Float:origin2_f[3];
		get_user_origin(id, origin2, 3);

		xs_vec_set_float(origin2, origin2_f);
		xs_vec_copy(origin2_f, hook_to[id]);
	}

	#if defined RENKLI_HOOK
	static rgb[3];
	choose_random(rgb);
	create_message(id, hook_to[id], rgb[0], rgb[1], rgb[2], true);
	#else
	create_message(id, hook_to[id], 255, 0, 0, true);
	#endif

	static Float:origin1_f[3];
	get_entvar(id, var_origin, origin1_f);

	static Float:velocity[3];
	xs_vec_sub_scaled_fix(hook_to[id], origin1_f, 3.0, velocity);

	static Float:y;
	y = velocity[0] * velocity[0] + velocity[1] * velocity[1] + velocity[2] * velocity[2];

	static Float:x;
	x = (hook_speed * 120.0)/ floatsqroot(y);
	xs_vec_mul_scalar(velocity, x, velocity);

	set_entvar(id, var_velocity, velocity);
}

#if defined RENKLI_HOOK
choose_random(rgb[3])
{
	rgb[0] = random(255);
	rgb[1] = random(255);
	rgb[2] = random(255);

	if(rgb[0] < 50 && rgb[1] < 50 && rgb[2] < 50)
	{
		rgb[random(2)] = random_num(150,255);
	}
}
#endif

bool:is_continue(const id, const usage, const flag)
{
	if(!is_user_alive(id))
	{
		return false;
	}

	switch(usage)
	{
		case 1: {
			return bool:(get_member(id, m_iTeam) == TEAM_CT);
		}
		case 2: {
			return bool:(get_member(id, m_iTeam) == TEAM_CT && get_entvar(id, var_takedamage) == DAMAGE_NO);
		}
		case 3: {
			return bool:((get_member(id, m_iTeam) == TEAM_CT || get_user_flags(id) & flag));
		}
		case 4: {
			return bool:((get_member(id, m_iTeam) == TEAM_CT && get_entvar(id, var_takedamage) == DAMAGE_NO) || get_user_flags(id) & flag);
		}
		case 5: {
			return bool:(get_member(id, m_iTeam) == TEAM_CT && get_user_flags(id) & flag);
		}
		case 6: {
			return bool:(get_member(id, m_iTeam) == TEAM_CT && get_entvar(id, var_takedamage) == DAMAGE_NO && get_user_flags(id) & flag);
		}
		case 7: {
			return bool:(get_entvar(id, var_takedamage) == DAMAGE_NO);
		}
		case 8: {
			return bool:(get_user_flags(id) & flag);
		}
		case 9: {
			return true;
		}
	}
	return false;
}

xs_vec_set_float(const in[], Float:out[])
{
	out[0] = float(in[0]);
	out[1] = float(in[1]);
	out[2] = float(in[2]);
}

xs_vec_sub_scaled_fix(const Float:in1[], const Float:in2[], Float:scalar, Float:out[])
{
	out[0] = (in1[0] - in2[0]) * scalar;
	out[1] = (in1[1] - in2[1]) * scalar;
	out[2] = (in1[2] - in2[2]) * scalar;
}

stock Float:useable(id)
{
	new Float:vOrigin[3], Float:fDist;
	get_entvar(id, var_origin, vOrigin);
	
	fDist = vOrigin[2];
	
	while(engfunc(EngFunc_PointContents, vOrigin) == CONTENTS_EMPTY) {	
		vOrigin[2] += 5.0;
	}
	if(engfunc(EngFunc_PointContents, vOrigin) == CONTENTS_SKY) {
		return (vOrigin[2] - fDist);
	}
	
	return 0.0;
} 

create_message(const id, const Float:coord[3], const R, const G, const B, bool:hook = false)
{
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
	write_byte(1);
	write_short(id);
	write_coord_f(coord[0]);
	write_coord_f(coord[1]);
	write_coord_f(coord[2]);
	write_short(dot);
	write_byte(1);
	write_byte(1);
	write_byte(hook ? 2 : 1);
	write_byte(5);
	write_byte(0);
	write_byte(R);
	write_byte(G);
	write_byte(B);
	write_byte(200);
	write_byte(0);
	message_end();
}
/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1055\\ f0\\ fs16 \n\\ par }
*/
