/*
Anti Speedhack v2.2
Change:
switch(get_cvar_num("amx_sh_bantype"))
	{
		case 0:
		server_cmd("amx_ban #%d 20160 Speedhack", get_user_userid(id), get_cvar_num("anti_say_bantime"))		
		case 1:
		server_cmd("amx_banip 20160 #%d Speedhack", get_cvar_num("anti_say_bantime"), get_user_userid(id))		
		default:
		server_cmd("amx_ban 20160 #%d Speedhack", get_cvar_num("anti_say_bantime"), get_user_userid(id))		
	}
*/

#include <amxmodx>
#include <amxmisc>
#include <cstrike>
#include <engine>

#pragma tabsize 0

#define PLUGIN "Anti SpeedHack"
#define VERSION "2.2"
#define AUTHOR "dr.aft"

#define MAXPLAYERS 32
#define UseAMXBANS 0
#define DEBUG 0		//1 to activate debug mode
//Max offence is the max value of secdist+ before we can be 100% sure its speedhack
//Secdist is the distance between the intervals that is concidered maximum of normal travel speed,
//normaly you run just under 300 units, but counting in that you might jump we use about 350 just to be sure
#define MAXOFFENCE 680 //Sensitivity, may need to be adjusted
#define SECDIST 260	//Sensitivity, may need to be adjusted
new mSpeedhackaction // Menu
new mcbSpeedhackaction // Menu Callback
new suspect_id
new SusCNT[MAXPLAYERS+1] //Suspect Counter
new ShRoundCNT[MAXPLAYERS+1]
new SHWarningFlag = 0
new namekick[32]
new CheaterFrags
new CheaterDeaths
new CheatCount
new TotalPlayers = 0

new g_OldPos[3][MAXPLAYERS+1]
new g_MaxPlayers
new g_Detections[MAXPLAYERS+1] 
new g_Warning[MAXPLAYERS+1]


public plugin_init() {
	new mapname[64] 
	mSpeedhackaction = menu_create("Speedhack action", "mh_Speedhackaction")
	mcbSpeedhackaction = menu_makecallback("mcb_Speedhackaction")
	menu_additem(mSpeedhackaction, "Ban", "ma_Speedhackaction", ADMIN_BAN, mcbSpeedhackaction)
	menu_additem(mSpeedhackaction, "Spectate", "ma_Speedhackaction", ADMIN_BAN, mcbSpeedhackaction)
	/* Menu End */

	register_plugin(PLUGIN, VERSION, AUTHOR)
	
	get_mapname(mapname,63) 
	if (containi(mapname,"surf_")!=-1)
		return PLUGIN_HANDLED_MAIN
	if (containi(mapname,"kz_")!=-1)
		return PLUGIN_HANDLED_MAIN
	if (containi(mapname,"fy_")!=-1)
		return PLUGIN_HANDLED_MAIN

	if (contain(mapname, "aim_aztec")!=-1)
		return PLUGIN_HANDLED_MAIN
	if (contain(mapname, "aim_sk_awp")!=-1)
		return PLUGIN_HANDLED_MAIN

	if (contain(mapname, "awp_teamwave")!=-1)
		return PLUGIN_HANDLED_MAIN


	g_MaxPlayers = get_maxplayers()
	set_task(0.7, "checkSpeedHack",127,_,_,"b")
	register_logevent("clearAlertValue",2,"0=World triggered","1=Round_Start")
	register_logevent( "clearAlertValue",2,"0=World triggered","1=Round_End")
		
	register_cvar("amx_sh_bantype","1")
	register_cvar("amx_aim_zerofrags", "32")
	register_cvar("amx_aim_minplayers", "4")
	register_cvar("amx_aim_nonzerofrags", "48")
	register_cvar("amx_aim_frags_to_deaths", "7") 

	return PLUGIN_CONTINUE
}

//Clear all previous detections so the new player does not get booted if someone previously banned
//for speedhack hapened to have the same id
public client_connect(id)
{
	g_Detections[id] = 0
	g_Warning[id] = 0
	g_OldPos[0][id] = 0
	g_OldPos[1][id] = 0
	g_OldPos[2][id] = 0
	SusCNT[id] = 0
	ShRoundCNT[id] = 0

	return PLUGIN_CONTINUE
}

public client_putinserver ( id )
{
	clearSpecificAlertValue(id)
	SusCNT[id] = 0
	ShRoundCNT[id] = 0
	TotalPlayers++
	get_user_name(id, namekick, 32)

	// Just copy two strings below if you want to ban some names

	if(contain(namekick, "BOTUSAY") != -1)		
	server_cmd("amx_kick #%d Noob", get_user_userid(id))	

	if(contain(namekick, "FFX-user") != -1)		
	server_cmd("amx_kick #%d ^"Cheat: Fighter FX^"", get_user_userid(id))	

	if(contain(namekick, "-[pWneD]-") != -1)		
	server_cmd("amx_kick #%d ^"Cheat: Fighter FX^"", get_user_userid(id))	

	if(contain(namekick, "HeadShot@Machine") != -1)		
	server_cmd("amx_kick #%d ^"Cheat: Fighter FX^"", get_user_userid(id))	

	if(contain(namekick, "Kiss.my.Ass") != -1)		
	server_cmd("amx_kick #%d ^"Cheat: Fighter FX^"", get_user_userid(id))	

	if(contain(namekick, "n00b") != -1)		
	server_cmd("amx_kick #%d ^"Your nick is not allowed...^"", get_user_userid(id))	

	if(contain(namekick, "MoThErFuCkEr") != -1)		
	server_cmd("amx_kick #%d ^"Cheat: Fighter FX^"", get_user_userid(id))
		
	// =)	

	return PLUGIN_CONTINUE
}

public client_disconnect ( id )
{
	clearSpecificAlertValue(id)
	ShRoundCNT[id] = 0
	SusCNT[id] = 0
	TotalPlayers--
	return PLUGIN_CONTINUE
}



public checkSpeedHack()
{
	for(new i=1;i<=g_MaxPlayers;i++)
	{
		if(is_user_alive(i)) //rather pointless otherwise, dont you think?
		{
			new origin[3] 
			new oldorigin[3]
			new dist
			
			
			//Get origins
			get_user_origin(i, origin, 0)
			oldorigin[0] = g_OldPos[0][i]
			oldorigin[1] = g_OldPos[1][i]
			oldorigin[2] = g_OldPos[2][i]
			
			
			dist = get_distance(origin, oldorigin)
			if (dist > SECDIST)
				g_Detections[i] = g_Detections[i] + dist - SECDIST
			if (cs_get_user_buyzone(i))
				clearSpecificAlertValue(i)
			if (g_Detections[i] > SECDIST)
			{
				g_Warning[i]++
				if (g_Warning[i] > 5)
					if (g_Detections[i] > MAXOFFENCE)
					{
						SHWarningFlag++		// Flag to Register probable SH once a round
						suspect_id = i

						if (ShRoundCNT[suspect_id] > 1) // If sh warnings are continuing in more than 2 rounds - go for the ban
						RegisterOffense(i)
					}
			}
			
			g_OldPos[0][i] = origin[0]
			g_OldPos[1][i] = origin[1]
			g_OldPos[2][i] = origin[2]
		}
		else
		{
			clearSpecificAlertValue(i)
		}
	}
   
}

//Clear on each round and connect so people dont get booted for spawning
// ... since when you spawn you teleports whitch the script may otherwise enterprate as speedhack
public clearAlertValue()
{
	for(new i=1;i<=g_MaxPlayers;i++)
	{		
		g_Detections[i] = 0
		g_Warning[i] = 0
		SusCNT[i] = 0
		get_user_name(i,namekick,31)		
		if(get_user_frags(i) > get_cvar_num("amx_aim_zerofrags") && get_user_deaths(i) == 0)
		{
		get_user_name(i,namekick,31)
		client_print(0, print_chat, "[ANTICHEAT] Checking player %s",namekick)		
		client_print(0, print_chat, "[ANTICHEAT] Player '%s' - Cheat 'WallHack' - Punishment: ban 1 day",namekick)		
		switch(get_cvar_num("amx_sh_bantype"))
			{
			case 0:
			server_cmd("amx_ban #%d 1440 Wallhack (0 deaths)", get_user_userid(i), get_cvar_num("anti_say_bantime"))		
			case 1:
			server_cmd("amx_banip 1440 #%d Wallhack (0 deaths)", get_cvar_num("anti_say_bantime"), get_user_userid(i))		
			default:
			server_cmd("amx_ban 1440 #%d Wallhack (0 deaths)", get_cvar_num("anti_say_bantime"), get_user_userid(i))		
			}					
		}
		if(TotalPlayers > get_cvar_num("amx_aim_minplayers")) {
		if(get_user_frags(i) > get_cvar_num("amx_aim_nonzerofrags"))
		{
			get_user_name(i,namekick,31)
			client_print(0, print_chat, "[ANTICHEAT] Checking player '%s'",namekick)
			CheaterFrags = get_user_frags(i)
			CheaterDeaths = get_user_deaths(i)			
			CheatCount = CheaterFrags / CheaterDeaths
			client_print(0, print_chat, "[ANTICHEAT] Player '%s' - AimValueCheck = '%d'",namekick,CheatCount)			
			if(CheatCount > get_cvar_num("amx_aim_frags_to_death"))	// 42 frags / 7 deaths > 5		
			{
			client_print(0, print_chat, "[ANTICHEAT] Player '%s' - Cheat 'Wallhack' - Punishment: 1 day ban",namekick)
			switch(get_cvar_num("amx_sh_bantype"))
			{
			case 0:
			server_cmd("amx_ban #%d 1440 Wallhack (Stat: %d %d) ", get_user_userid(i), get_cvar_num("anti_say_bantime"), CheaterFrags, CheaterDeaths)		
			case 1:
			server_cmd("amx_banip 1440 #%d Wallhack (Stat: %d %d)", get_cvar_num("anti_say_bantime"), get_user_userid(i), CheaterFrags, CheaterDeaths)		
			default:
			server_cmd("amx_ban 1440 #%d Wallhack (Stat: %d %d)", get_cvar_num("anti_say_bantime"), get_user_userid(i), CheaterFrags, CheaterDeaths)		
			}
			}
		}
		}
	}
	if (SHWarningFlag > 0)
	{
		ShRoundCNT[suspect_id]++
		SHWarningFlag = 0
	}
	
}

public clearSpecificAlertValue(id)
{
	g_Detections[id] = 0
	g_Warning[id] = 0
}

/*
public client_putinserver ( id )
{
	clearSpecificAlertValue(id)
	SusCNT[id] = 0
	return PLUGIN_CONTINUE
}

public client_disconnect ( id )
{
	clearSpecificAlertValue(id)
	SusCNT[id] = 0
	return PLUGIN_CONTINUE
}
*/

//Boot the bugger from the server
public RegisterOffense(id)
{
	new admCnt=0

	new Authid[35],Name[32],CurrentTime[29],Map[32],ping,loss,Message[256]
	suspect_id = id
	get_user_name(id,Name,31)
	get_user_authid(id,Authid,34)
	get_mapname(Map,31)
	get_user_ping(id,ping,loss)
	get_time("%d/%m-%Y - %H:%M:%S",CurrentTime,29)

#if DEBUG == 1
	client_print(0, print_chat, "%i detections, %i warnings",g_Detections[id],g_Warning[id])
#endif
	clearSpecificAlertValue(id)

	if (cs_get_user_buyzone(id))
	{
	client_print(0, print_chat, "[ANTICHEAT] Checking...")
	return PLUGIN_CONTINUE
	}
	else	
	{
	for(new i=1;i<=g_MaxPlayers;i++)
	{
		if (is_user_admin(i))
		{
				
			format(Message,255,"[Anti Speed Hack %s - %s] %s<%s> is suspected of using speedhack or high ping (Ping: %d )",CurrentTime,Map,Name,Authid,ping)
			
			client_print(i, print_chat, "[ANTICHEAT] Player '%s' - Cheat 'SPEEDHACK'!",Name)
			log_amx(Message)
			menu_display(i, mSpeedhackaction, 0)
			admCnt++
			
		}
	}

	//No admins online?
	if (admCnt == 0)
	{	
		if (get_cvar_num("amx_sh_bantype") == 1)
		{
			SusCNT[id]++
		}	
	}
	if (SusCNT[id] > 0)
	{
		if(get_user_ping(id,ping,loss) > 90)
		{
		format(Message,255,"[Anti Speed Hack %s - %s] %s<%s> suspected of high ping (Ping: %d ) - No admin online, banned from server",CurrentTime,Map,Name,Authid,ping)		
		client_print(0, print_chat, "[ANTICHEAT] Player %s - Too high ping - Punishment: 10 hours ban...",Name)
		log_amx(Message)
		switch(get_cvar_num("amx_sh_bantype"))
		{
		case 0:
		server_cmd("amx_ban #%d 600 Too high ping", get_user_userid(id), get_cvar_num("anti_say_bantime"))		
		case 1:
		server_cmd("amx_banip 600 #%d Too high ping", get_cvar_num("anti_say_bantime"), get_user_userid(id))		
		default:
		server_cmd("amx_ban 600 #%d Too high ping", get_cvar_num("anti_say_bantime"), get_user_userid(id))		
		}
		}
		else
		{
		format(Message,255,"[Anti Speed Hack %s - %s] %s<%s> suspected of using speedhack (Ping: %d ) - No admin online, banned from server",CurrentTime,Map,Name,Authid,ping)		
		client_print(0, print_chat, "[ANTICHEAT] Player %s - Cheat 'SPEEDHACK' - Punishment: 2 weeks ban...",Name)
		log_amx(Message)
		switch(get_cvar_num("amx_sh_bantype"))
		{
		case 0:
		server_cmd("amx_ban #%d 20160 Speedhack", get_user_userid(id), get_cvar_num("anti_say_bantime"))		
		case 1:
		server_cmd("amx_banip 20160 #%d Speedhack", get_cvar_num("anti_say_bantime"), get_user_userid(id))		
		default:
		server_cmd("amx_ban 20160 #%d Speedhack", get_cvar_num("anti_say_bantime"), get_user_userid(id))		
		}
		}
	}
	}
	
	return PLUGIN_CONTINUE
}


/* Menu Speedhack action */

public mh_Speedhackaction(id, menu, item) {
	/* This event is called when someone presses a key on this menu */
	new Authid[35],Name[32],CurrentTime[29],Map[32],AdminName[32]
	get_user_name(suspect_id,Name,31)
	get_user_name(id,AdminName,31)
	get_user_authid(suspect_id,Authid,34)
	get_mapname(Map,31)
	get_time("%d/%m-%Y - %H:%M:%S",CurrentTime,29)

	if (item == 0)
	{
		new Message[256]
		switch(get_cvar_num("amx_sh_bantype"))
		{
		case 0:
		server_cmd("amx_ban #%d 20160 Speedhack", get_user_userid(id), get_cvar_num("anti_say_bantime"))		
		case 1:
		server_cmd("amx_banip 20160 #%d Speedhack", get_cvar_num("anti_say_bantime"), get_user_userid(id))		
		default:
		server_cmd("amx_ban 20160 #%d Speedhack", get_cvar_num("anti_say_bantime"), get_user_userid(id))		
		}

		format(Message,255,"[Anti Speed Hack %s - %s] %s<%s> Banned by admin %s - Speedhack",CurrentTime,Map,Name,Authid,AdminName)
		log_amx(Message)

	}
	if (item == 1)
	{
		cs_set_user_team(id, 3)
		user_silentkill(id)
	}
		
}

