#include <amxmodx>
#include <fakemeta>

#define SINE_STEP 0.01
#define SINE_FACTOR_X 0.9
#define SINE_FACTOR_Y 0.9

#define GetPlayerFOV(%1) get_pdata_int(%1, 363 /* m_iFOV */)

#define FOV_NORMAL 90

new taskid[33], c_realsnipe, c_fade, c_shake, c_sinus, c_unscope

public plugin_init()
{
	register_plugin ("Real Snipe", "1.33", "se7h")

	register_event("SetFOV", "scope_func", "be", "1<90")
	register_event("SetFOV", "unscope_func", "be", "1=90")
	register_event("HLTV", "event_startround", "a", "1=0", "2=0")

	register_forward(FM_PlayerPreThink, "playerposthink", true)

	c_realsnipe = register_cvar("amx_real_snipe", "1")		// 0 - disable, 1 - enable with only sniper rifles, 2 - enable all guns with scopes
	c_fade = register_cvar("rs_enabled_fade", "1")		// 0/1 dis/en fades
	c_shake = register_cvar("rs_enabled_shake", "1")		// 0/1 dis/en shake
	c_sinus = register_cvar("rs_enabled_sinus", "1")		// 0/1 dis/en sinus
	c_unscope = register_cvar("rs_enabled_unscope", "1")		// 0/1 dis/en unscope when player not an a ground
}

public playerposthink(id)
{
	if(!get_pcvar_num(c_realsnipe) || !get_pcvar_num(c_sinus) || is_user_bot(id))
		return FMRES_IGNORED

	static Float:Vel[3]
	pev(id, pev_velocity, Vel)

	if(!(vector_length(Vel)) && !(pev(id, pev_button) & IN_DUCK))
	{
		static a, b
		switch(get_user_weapon(id, a, b))
		{
			case 3,13,18,24:
			{
				static FovOld[33], Fov
				static Float:State, Float:Sign
				static Float:States[33] = {0.0, ...}
				static Float:Signs[33] = {1.0, ...}
				static Float:Increment0[33] = {0.0, ...}
				static Float:Increment1[33] = {0.0, ...}
				static Float:oldAngles[3]
				static Float:newAngles[3]
	
				pev(id, pev_v_angle, newAngles)
	
				if(oldAngles[0] == newAngles[0] && oldAngles[1] == newAngles[1])
				{
					Fov = GetPlayerFOV(id)
					if (!(0 < Fov <= FovOld[id]))
					{
						States[id] = 0.0
						Signs[id] = 1.0
						Increment0[id] = 0.0
						Increment1[id] = 0.0
					}
		
					FovOld[id] = Fov
	
					if (!(0 < Fov < FOV_NORMAL))
						return FMRES_IGNORED
	
					State = States[id]
					Sign = Signs[id]
	
					static Float:Angles[3]
					pev(id, pev_v_angle, Angles)
	
					Angles[0] += Increment0[id]
					Angles[1] += Increment1[id]
	
					State += SINE_STEP * Sign
					if (State > M_PI || State < -M_PI)
					{
						State = M_PI * Sign
						Sign = -Sign
					}
	
					Angles[0] -= (Increment0[id] = floatsin(State) * Sign * SINE_FACTOR_Y)
					Angles[1] -= (Increment1[id] = State * SINE_FACTOR_X)
	
					set_pev(id, pev_v_angle, Angles)
					set_pev(id, pev_angles, Angles)
					set_pev(id, pev_fixangle, true)
	
					States[id] = State
					Signs[id] = Sign
				}
	
				oldAngles = newAngles
			}
		}
	}

	return FMRES_IGNORED
}

public event_startround(id)
{
	if(!is_user_bot(id))
		client_cmd(0, "weapon_knife; lastinv")
}

public scope_func(id)
{
	if(get_pcvar_num(c_realsnipe) && !is_user_bot(id))
	{
		static bool:DoStuff
		static a, b, weapon
		weapon = get_user_weapon(id, a, b)
	
		DoStuff = false
	
		switch(get_pcvar_num(c_realsnipe))
		{
			case 1:
			{
				switch(weapon)
				{
					case 3,13,18,24:
						DoStuff=true
				}
			}
			case 2:
			{
				switch(weapon)
				{
					case 3,13,18,24,8,27:
						DoStuff=true
				}
			}
		}
	
		if(DoStuff)
		{
			if(get_pcvar_num(c_fade))
			{
				message_begin(MSG_ONE, 98, {0,0,0}, id)
				write_short(1<<10)
				write_short(1<<16)
				write_short(1<<1)
				write_byte(0)
				write_byte(0)
				write_byte(0)
				write_byte(255)
				message_end()
			}

			if(!taskid[id])
			{
				static playerid[1]
				playerid[0] = id
				taskid[id] = get_user_userid(id)
				set_task(0.1, "check_movement", taskid[id], playerid[0], 1, "b")
			}
		}
	}
}

public unscope_func(id)
{
	if(!is_user_bot(id))
	{
		remove_task(taskid[id])
		taskid[id] = 0
	}
}

public check_movement(playerid[])
{ 
	static id
	id = playerid[0]

	if(!is_user_bot(id))
	{
		if(get_pcvar_num(c_unscope) && !(pev(id, pev_flags) & FL_ONGROUND))
		{
			if(!task_exists(524104+id))
				set_task(0.7, "check", 524104+id)
		}
	
		if(get_pcvar_num(c_shake))
		{
			static Float:Vel[3]
			pev(id, pev_velocity, Vel)
		
			switch(floatround(vector_length(Vel)))
			{
				case 1..60:
				{
					message_begin(MSG_ONE, 97, {0,0,0}, id)
					write_short(1<<10)
					write_short(1<<10)
					write_short(1<<10)
					message_end()
				}
				case 61..120:
				{
					message_begin(MSG_ONE, 97, {0,0,0}, id)
					write_short(1<<11)
					write_short(1<<10)
					write_short(1<<11)
					message_end()
				}
				case 121..180:
				{
					message_begin(MSG_ONE, 97, {0,0,0}, id)
					write_short(1<<12)
					write_short(1<<10)
					write_short(1<<12)
					message_end()
				}
				case 181..240:
				{
					message_begin(MSG_ONE, 97, {0,0,0}, id)
					write_short(1<<13)
					write_short(1<<10)
					write_short(1<<13)
					message_end()
				}
				case 241..320:
				{
					message_begin(MSG_ONE, 97, {0,0,0}, id)
					write_short(1<<14)
					write_short(1<<10)
					write_short(1<<14)
					message_end()
				}
			}
		}
	}
}

public check(checkid)
{
	static id
	id = checkid-524104

	if(!(pev(id, pev_flags) & FL_ONGROUND))
	{
		engclient_cmd(id,"lastinv")
		engclient_cmd(id,"lastinv")
		unscope_func(id)
	}
}
