/* Hack Hunter AMX MOD X Anti Cheat Plugin

*  Authors : 
- SAMURAI
- Anthrax
- DarkSnow
- EKS
 
* Version : 0.7

* It Detetects:

- Burst Scripts
- Fast Fire scripts
- forward backward 
- force move "right" "left"
- Anti Kick scripts
- Speed hack 75 %
- Aimbot 40 %
- No Recoil 55 %
- Spin Hack 80 %
- No Flashbang 80 %
- Winamp Scripts from OGC (not all versions)
- Winamp Scripts from Scorpion Hack
- Hud C4 Messages 
- Bot bone 25 %
- ECStatic Scripts


* Credits : 
  - AssKickr 
  - CheesyPeteza
  - Twinlight Suzuka
  - xeroblood 
     for some codes ...

* This plugin dont detect all cheats, 80 % of them

   ! Who can thanks for posibility to play CS at a high level :
   
    AMX MOD X TeaM :

- David Andersson aka BAILOPAN
- Christian Hammacher aka Basic Master
- DevconeS 
- Borja Ferrer 
- Orangutanz 
- Damaged Soul aka Scott Ehlert
- m0gely 
- SniperBeamer aka Felix Geyer
- Brad 
- Jonny Bergström aka Johnny got his gun 
- s p l i t 
- PM aka Pavol Marko
- DoubleDoom 
- SidLuke aka Lukasz Wlasinski


    AMX MOD TeaM :

- Aleksander Naszko aka OLO
- Julien Laurent aka KRoT@L 
- Split
- DoubleDoom
- ArtAttack
- KleeneX
- T(+)rget
- Jonny Bergström aka Johnny got his gun 
- Ludwig van
- JustinHoMi
- XAD
- Vapok
- Duca
- Manip
- f117bomb



    ADMINMOD TeaM :

- Alfred Reynolds 
- Florian Zschocke aka florian
- Jaguar
- Greg Hughes
- Will Day
- David Mart aka Wraith
- Falko Hartmann aka BlackKnight
- Bud-froggy
- Yensid

* Have a nice day now
*/

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

#pragma tabsize 0

//#define DEBUG

//constants
#define PS_VERSION "0.7"

#define MAXPLAYERS 32
#define MaxAngelChange 1500
#define MAX_DETECTIONS 25

#define MAX_FLASHZONES 40

#define PLAYER_LEFT 128
#define PLAYER_RIGHT 256

#define PLAYER_ATTACK 1
#define PLAYER_JUMP 2
#define PLAYER_DUCK 4
#define PLAYER_FORWARD 8
#define PLAYER_BACK 16
#define PLAYER_LEFT 128
#define PLAYER_RIGHT 256
#define PLAYER_STRAFELEFT 512
#define PLAYER_STRAFERIGHT 1024
#define PLAYER_ATTACK2 2048

#define BlockMovment 1
#define BlockDubbleAttack 2
#define BlockCVARS 4
#define PunsihPlayer 8

#define LogBeforeWrite 128

#define SPEEDHACK 0
#define SPINHACK 1
#define RAPIDFIRE 2
#define SHAKE 3
#define RECOIL 4
#define EXPLOIT 5

#define REMOTE_HOST "cstrike.ro"

#define SETTING_ENABLE 0
#define SETTING_RAPIDFIRE 1
#define SETTING_SPEEDHACK 2
#define SETTING_SPINHACK 3
#define SETTING_SHAKE 4
#define SETTING_MOVEKEY 5
#define SETTING_DOUBLEATTACK 6
#define SETTING_CVARS 7
#define SETTING_VERSION 8
#define SETTING_PASSIVE 9
#define SETTING_BAN 10
#define SETTING_SAFESPEED 11
#define SETTING_SILENT 12
#define SETTING_C4BEEP 13
#define SETTING_FLASHBUG 14

#define FALSE 0
#define TRUE 1

#define MAX_PLAYERS 32



       


new g_clist[MAX_PLAYERS]

new g_cstrlst[8][] =
{
	"EcstaticCheat",
	"TeKilla",
	"MicCheat",
	"AlphaCheat",
	"PimP",
	"LCD",
	"Chapman",
	"_PRJVDC"
}


#define SILENTPLANT_SOUND 0
#define SILENTPLANT_READY 1

//sockets
new sckversion
new sckaddtostatistics

//definitikons
new settings[15]


new Float:fShake[MAXPLAYERS+1][3]

new Float:gf_LastAng[MAXPLAYERS+1][3]

new Float:gf_TotalAng[MAXPLAYERS+1]

new Float:tmpVec[3]

new tmpVec2[3]

new Float:userAim[MAXPLAYERS+1][3]

new userOrg[MAXPLAYERS+1][3]

new userDetections[MAXPLAYERS+1][5]

new userWarnings[MAXPLAYERS+1]

new g_LastAttack[MAXPLAYERS+1]
new gs_Log[LogBeforeWrite+1][256]
new g_LogsWriten
new gs_LogFile[64]
new MapName[32]

new g_MaxPlayers
new is_current
new admin_online = FALSE





new Float:recoil_LastAng[MAXPLAYERS+1][3]
new g_nCurWeapon[MAXPLAYERS+1][2]

new bugfix[2]
new g_c4entity
new g_entillusionary
new g_classname
new gi_soundnum
new Float: gf_volume

new Float: gf_attenuation

new Float: gf_c4origin[3]

new Float: gf_entorigin[3]
new gi_flags

new gi_pitch


new fbFile[64]
new fz[MAX_FLASHZONES+1][4]

new cntVectors


new g_fb_model[] = "models/w_flashbang.mdl"

/*
System stuff
----------------------------------------------------------------------------------------------------
*/
public plugin_init()
{
	register_plugin("Hack Hunter", PS_VERSION ,"SAMURAI / DarkSnow / EKS / Anthrax")

	load_config()

	register_event("ResetHUD", "hook_hud", "be")
	
	register_event( "CurWeapon", "Event_ShotFired",  "b" )

	if (settings[SETTING_C4BEEP] == TRUE)
	{
		if ( engfunc ( EngFunc_FindEntityByString, -1, "classname", "func_bomb_target" ) )
		{
			register_logevent ( "fn_triggerplanted" , 3, "1=triggered", "2=Planted_The_Bomb" )
			register_logevent ( "fn_triggerroundstart" , 2, "1=Round_Start" )
			
			register_forward ( FM_EmitSound, "fn_soundcheck" )
		}
	}

	set_task(1.0, "cheatRapidFire",127,_,_,"b")
	set_task(1.0,"Task_ClearRecoil",128,_,_,"b")
	
	set_task(1.0,"Task_CheckSpinTotal",128,_,_,"b")
	
	set_task(0.5,"Task_CheckTravelDist",128,_,_,"b")
	set_task(120.0,"displayBanner",256,_,_,"b")

	get_mapname(MapName,31)
	get_localinfo("amxx_basedir",gs_LogFile,63)
	format(gs_LogFile,63,"%s/logs/hackhnuter.log",gs_LogFile)
	
	g_MaxPlayers = get_maxplayers()

	if (settings[SETTING_FLASHBUG] == TRUE)
	{
		get_localinfo("amxx_basedir",fbFile,63)
		format(fbFile, 63, "%s/hackhunter/flashbug/%s.ini", fbFile, MapName)
		if (file_exists(fbFile))
		{
			load_flashconfig()
			register_think("grenade","think_grenade");

			server_print("[Hack Hunter] Loaded config ^"%s^" (flashbug)", fbFile)
		}
	}

	if (lastUpdated() == TRUE)
		set_task(5.0,"connect_version")
		
	register_cvar ("hackhunter_ecban","0")
	register_cvar ("hackhunter_ecbantime","0")
	register_cvar ("hackhunter_echud","0")
	register_cvar ("hackhunter_ecadmins","1")
	register_concmd("hackhunter_eclist", "cmd_list", ADMIN_KICK, " list potential cheaters")
	
	
	
}

public plugin_end()
{
	if(g_LogsWriten !=0)
		WriteLogs2File()
}

public plugin_precache()

{
	precache_sound("hackhunter/spray.wav")
	
	precache_sound("hackhunter/warning.wav")
	
	return PLUGIN_CONTINUE
}

public client_connect(id)
{
	userDetections[id][SPINHACK] = 0
	
	userDetections[id][SPEEDHACK] = 0
	
	userDetections[id][RAPIDFIRE] = 0
	userDetections[id][SHAKE] = 0
	userDetections[id][RECOIL] = 0
	
	
	checkForAdmin()
	
	
	new plname[32]
	get_user_name(id,plname,31)
	new userid = get_user_userid(id)  
	
	
	
	if (is_user_connected(userid))
	
	{
	client_print(0,print_chat,"[Hack Hunter]%s CFG has been scaned succesfully",plname)
	
          }
}



public client_disconnect(id)
{
	checkForAdmin()
	
	g_clist[id] = FALSE
	
	
}

public hackhuntersettings()
{        
          new fileCFG[64]
	
	get_localinfo("amxx_basedir",fileCFG,63)
	
	format(fileCFG,63,"%s/hackhunter/hackhunter.cfg",fileCFG)

		if (file_exists(fileCFG))
		{
			server_print("Hack Hunter Settings Activated !")
			server_cmd("exec addons/amxmodx/hackhunter/hackhunter.cfg")
		    }

		else 
		{
			server_print("[Hack Hunter] Settings File not found !")
			server_print("[Hack Hunter] Check hackhunter folder from amxmodx\hackhunter")
			
		    }
  	
}

public pluginsloaded()
{
	if(is_plugin_loaded("war3ft.amxx") != -1 || is_plugin_loaded("uwc3.amxx") != 1)
	{
		server_print("===============================================================")
		server_print("===============================================================")
		server_print("==== Hack Hunter don't work in conjunction with Warcraft 3 ====")
		server_print("Server will be closed in 1 minute !")
		set_task(60.0,"serverclose")
	 }
}
		

public serverclose()
{
	
	server_cmd("quit")
	
}


public client_putinserver(id)
{
	new infoField[3]
	g_clist[id] = FALSE
	for (new i=0; i<8; i++)
	{
		get_user_info(id,g_cstrlst[i],infoField,2)
		
		if (strlen(infoField) > 0)
			ban_client(id, g_cstrlst[i])
	}
}

public dmsg(nmsg[])
{
	new msgt = get_cvar_num("hackhunter_echud")
	
	new oa = get_cvar_num("hackhunter_ecadmins")
	if (msgt == 0)
	{
		if (oa == 0)
		{
			format(nmsg, 127, "[Hack Hunter] %s", nmsg)
			client_print(0, print_chat, nmsg)
		}
		else
			for (new i=0; i<MAX_PLAYERS; i++)
				if (is_user_connected(i))
					if (access(i, ADMIN_KICK))
					{
						client_print(i, print_chat, nmsg)
						
						client_cmd(i, "spk ^"fvox/beep^"")
					}
	}
	else
	{
		if (oa == 0)
		{
			for (new i=0; i<MAX_PLAYERS; i++)
			{
				if (is_user_connected(i))
				{
					if (access(i, ADMIN_KICK))
					{
						client_cmd(i, "spk ^"fvox/beep^"")
						
						set_hudmessage(255, 0, 0, -1.0, -1.0, 0, 6.0, 7.0)
						
						show_hudmessage(i, nmsg)
					}
				}
			}
		}
		else
		{
			format(nmsg, 127, "[Hack Hunter] %s", nmsg)
			
			set_hudmessage(255, 0, 0, -1.0, -1.0, 0, 6.0, 7.0)
			show_hudmessage(0, nmsg)
		}
	}
}


public ban_client(id, cheat[])
{
	new name[32]
	new auth[32]
	
	new bantime = get_cvar_num("hackhunter_ecbantime")
	

	get_user_name(id,name,31)
	get_user_authid(id,auth,31)

	log_to_file("ec.log","Logged: ^"%s<%d><%s>^" (cheat ^"%s^")", name, get_user_userid(id), auth, cheat)

	if (get_cvar_num("hackhunter_ecban") == 5)
		return PLUGIN_CONTINUE

	if (get_cvar_num("hackhunter_ecban") == 0)
	{
		new nmsg[128]
		format(nmsg, 127, "%s is maybe using cheat: %s", name, cheat)
		dmsg(nmsg)
		g_clist[id] = TRUE
	}
	if (get_cvar_num("hackhunter_ecban") == 1)
	{
		server_cmd("kick #%d Banned (%s)",get_user_userid(id),cheat)
		server_cmd("banid 0.0 %s",auth)
		server_cmd("writeid")
	}
	else if (get_cvar_num("hackhunter_ecban") == 2)
	{
		server_cmd("amx_ban %i %s %s",bantime,auth,cheat)
	}
	else if (get_cvar_num("hackhunter_ecban") == 3)
	{
		server_cmd("amx_banip %i %s %s", bantime,auth,cheat)
	}
	else if (get_cvar_num("hackhunter_ecban") == 4)
	{
		server_cmd("kick #%d Kicked (%s)",get_user_userid(id),cheat)
	}

	if (get_cvar_num("hackhunter_ecban") != 0)
	{
		log_amx("[Hack Hunter]Player %s<%s> was Banned for %s",name,auth,cheat)
		client_print(0, print_chat, "[Hack Hunter] Player %s<%s> was Banned for %s",name,auth,cheat)
	}

	server_exec()
	return PLUGIN_CONTINUE
}

public cmd_list(id, level, cid)
{
	if (!cmd_access(id, level, cid, 1))
		return PLUGIN_CONTINUE
	new cnt = 0

	console_print(id, "Listing suspected clients")
	console_print(id, "=========================")
	for (new i=0; i<MAX_PLAYERS; i++)
	{
		if (is_user_connected(i))
		{
			if (g_clist[i] == TRUE)
			{
				new name[32]
				new auth[32]
				new ip[32]
				get_user_name(i, name, 31)
				get_user_authid(i, auth, 31)
				get_user_ip(i, ip, 31)
				console_print(id, "%s<%s> - %s", name, auth, ip)
				cnt++
			}
		}
	}
	if (cnt == 0)
		console_print(id, "None found")
	else
		console_print(id, "Total: %i clients", cnt)

	return PLUGIN_CONTINUE
}




public client_PreThink(id)
{
	if(!is_user_alive(id)) return PLUGIN_CONTINUE
	
	cheatScriptBlock_Pre(id)
	if ((is_user_admin(id)) && (is_current == 1))
	{
		if (settings[SETTING_SILENT] == FALSE)
		{
			set_hudmessage(60, 60, 60, -1.0, 0.02, 0, 6.0, 12.0,_,_, 3)
			show_hudmessage(id, "Download at: http://www.cstrike.ro/forum")
			set_hudmessage(60, 60, 60, -1.0, 0.00, 0, 6.0, 12.0,_,_, 4)
			show_hudmessage(id, "This Server is protected with Hack Hunter v0.7 by SAMURAI")
		}
		else
		{
			client_print(id,print_chat,"[Hack Hunter] This Server is protected with Hack Hunter v0.7 by SAMURAI")
			client_print(id,print_chat,"[Hack Hunter] Anti Cheat based on AMX MOD X")
			client_print(id,print_chat,"[Hack Hunter] See http://www.cstrike.ro/forum")
		}
	}
	
	return PLUGIN_CONTINUE
}
public client_PostThink(id)
{
	if(is_user_alive(id))
	{
		if (settings[SETTING_SPINHACK] == TRUE)
			cheatSpinHack_post(id)
		
		if (settings[SETTING_SHAKE] == TRUE)
			cheatShake(id)
	}
}

/*
Cheat detection stuff
----------------------------------------------------------------------------------------------------
*/
// Cheat: Shake (aimbot) //
public cheatShake (id)
{
	if ((settings[SETTING_PASSIVE] == TRUE) && (admin_online == TRUE))
		return PLUGIN_CONTINUE

	if (is_user_bot(id))
		return PLUGIN_CONTINUE

	new Float:aim[3]
	entity_get_vector(id,EV_VEC_angles,aim)

	if ((aim[0] == fShake[id][0]) && (aim[1] == fShake[id][1]))
	{
		userDetections[id][SHAKE] = userDetections[id][SHAKE] - 12
	}
	else
	{
		userDetections[id][SHAKE]++
	}

	if (userDetections[id][SHAKE] < 0)
		userDetections[id][SHAKE] = 0
		
	if (userDetections[id][SHAKE] > 450)
	{
		announce(id, "Shake warning! (rest mouse a second)")
		userWarnings[id]++
		playsound(id, "warning")
	}
	if (userDetections[id][SHAKE] > 650)
		cheatDetected(id,SHAKE)
			
	CopyVector(aim,fShake[id])

	return PLUGIN_CONTINUE
}
public cheatSpinHack_post(id)
{
	if ((settings[SETTING_PASSIVE] == TRUE) && (admin_online == TRUE))
		return PLUGIN_CONTINUE

	new Float:Angel[3]
	entity_get_vector(id,EV_VEC_angles,Angel)
				
	gf_TotalAng[id] += vector_distance(gf_LastAng[id],Angel)
	CopyVector(Angel,gf_LastAng[id])
		
	new flags = entity_get_int(id,EV_INT_button)

	if (settings[SETTING_MOVEKEY] == FALSE)
		if(flags & PLAYER_LEFT || flags & PLAYER_RIGHT)
			userDetections[id][SPINHACK] = 0

	return PLUGIN_CONTINUE
}
public hook_hud(id)
{
	if ((settings[SETTING_PASSIVE] == TRUE) && (admin_online == TRUE))
		return PLUGIN_CONTINUE

	if (settings[SETTING_SPEEDHACK] == TRUE)
		cheatSpeedHack_Hud(id)
		
	attach_view(id,id) //bugfix

	return PLUGIN_CONTINUE
}
public Event_ShotFired(id) 
{
	if ((settings[SETTING_PASSIVE] == TRUE) && (admin_online == TRUE))
		return PLUGIN_CONTINUE

	if (settings[SETTING_RAPIDFIRE] == FALSE)
		return PLUGIN_CONTINUE

	new Float:aim[3]
	new weaponID = read_data( 2 ) 
	new wAmmo = read_data( 3 ) 

	entity_get_vector(id,EV_VEC_angles,aim)
	
	if( g_nCurWeapon[id-1][0] != weaponID ) // User Changed Weapons.. 
	{ 
		g_nCurWeapon[id-1][0] = weaponID 
		g_nCurWeapon[id-1][1] = wAmmo 
		return PLUGIN_CONTINUE 
	} 
	if( g_nCurWeapon[id-1][1] < wAmmo ) // User Reloaded.. 
	{ 
		g_nCurWeapon[id-1][1] = wAmmo 
		return PLUGIN_CONTINUE 
	} 
	if( g_nCurWeapon[id-1][1] == wAmmo ) // User did something else, but didn't shoot.. 
		return PLUGIN_CONTINUE 
	g_nCurWeapon[id-1][1] = wAmmo 
	g_nCurWeapon[id-1][0] = weaponID 


	if (weaponID == CSW_HEGRENADE 
	|| weaponID == CSW_SMOKEGRENADE 
	|| weaponID == CSW_FLASHBANG 
	|| weaponID == CSW_KNIFE 
	|| weaponID == CSW_C4
	|| weaponID == CSW_GLOCK18) { 
		return PLUGIN_HANDLED 
	}else{
		userDetections[id][RAPIDFIRE]++ //Counting the bullets, one by one, all day long :)
		
		if((aim[0]==recoil_LastAng[id][0] && recoil_LastAng[id][0]!=0))
		{
			userDetections[id][RECOIL]++
		}else{
			userDetections[id][RECOIL]--
		}
		recoil_LastAng[id][0]=aim[0]
		
		
		if (userDetections[id][RECOIL] > 6)
		{
			announce(id, "Low-recoil warning!")
			userWarnings[id]++
			playsound(id, "warning")
		}
		if (userDetections[id][RECOIL] > 10)
			cheatDetected(id,RECOIL)

		//client_print(0,print_chat,"%i",userDetections[id][RECOIL])
	}
	
	return PLUGIN_CONTINUE 
}  

public Task_ClearRecoil()
{
	
	for(new i=0;i<=g_MaxPlayers;i++)
	
	{
		userDetections[i][RECOIL] = userDetections[i][RECOIL] - 10

		if (userDetections[i][RECOIL] < 0)
		
			userDetections[i][RECOIL] = 0
	}
	
}



// Cheat: Speed Hack //
public Task_CheckTravelDist()
{
	
	if ((settings[SETTING_PASSIVE] == TRUE) && (admin_online == TRUE))
		return PLUGIN_CONTINUE

		
	if (settings[SETTING_SPEEDHACK] == FALSE)
		return PLUGIN_CONTINUE
	
	
	for(new i=1;i<=g_MaxPlayers;i++)
	{
		if(is_user_alive(i))
		{
			new origin[3] 
			
			new oldorigin[3]
			
			new dist
			//new flags = entity_get_int(i,EV_INT_flags)
			
			//Get origins
			
			get_user_origin(i, origin, 0)
			
			oldorigin[0] = userOrg[i][0]
			
			oldorigin[1] = userOrg[i][1]
			
			oldorigin[2] = userOrg[i][2]
			
			if (settings[SETTING_SAFESPEED] == TRUE)
			{
				origin[2] = 0
				oldorigin[2] = 0
			}
			
			dist = get_distance(origin, oldorigin)
			
			
			if (userDetections[i][SPEEDHACK] >= 3)
			userDetections[i][SPEEDHACK]--
			
			if (userDetections[i][SPEEDHACK] < 0)
				userDetections[i][SPEEDHACK] = 0
			
			if (dist >= 240)
				userDetections[i][SPEEDHACK] = userDetections[i][SPEEDHACK] + 3
			
			if (userDetections[i][SPEEDHACK] >= 6)
			{
				announce(i, "[Hack Hunter] Speedhack warning!")
				userWarnings[i]++
				playsound(i, "warning")
			}

			if (userDetections[i][SPEEDHACK] >= 8)
				cheatDetected(i,SPEEDHACK)
			
			userOrg[i][0] = origin[0]
			userOrg[i][1] = origin[1]
			userOrg[i][2] = origin[2]
		}
	}
	return PLUGIN_CONTINUE
}



public cheatSpeedHack_Hud(id)
{
	if ((settings[SETTING_PASSIVE] == TRUE) && (admin_online == TRUE))
		return PLUGIN_CONTINUE

	if (settings[SETTING_SPEEDHACK] == FALSE)
		return PLUGIN_CONTINUE

	get_user_origin(id, tmpVec2, 0)
	userOrg[id][0] = tmpVec2[0]
	
	userOrg[id][1] = tmpVec2[1]
	
	
	userOrg[id][2] = tmpVec2[2]

	return PLUGIN_CONTINUE
}




// Cheat: Spinhack //
public Task_CheckSpinTotal()
{
	if ((settings[SETTING_PASSIVE] == TRUE) && (admin_online == TRUE))
		return PLUGIN_CONTINUE

	if (settings[SETTING_SPINHACK] == FALSE)
		return PLUGIN_CONTINUE

	for(new i=1;i<=g_MaxPlayers;i++)
	{
		if(is_user_alive(i))
		{
			if(gf_TotalAng[i] >= MaxAngelChange)
			{
				if(userDetections[i][SPINHACK] >= MAX_DETECTIONS)
				{
					
					cheatDetected(i,SPINHACK)
					
				}
				
				if(userDetections[i][SPINHACK] >= MAX_DETECTIONS / 3)
				{
					announce(i, "[Hack Hunter] Spinhack warning!")
					
					userWarnings[i]++
					playsound(i, "warning")
					
				}
				
				userDetections[i][SPINHACK]++
			}
			else
				userDetections[i][SPINHACK] = 0
	
			gf_TotalAng[i] = 0.0
		}
	}

	return PLUGIN_CONTINUE
}



// Cheat: Rapid fire
public cheatRapidFire()
{
	if ((settings[SETTING_PASSIVE] == TRUE) && (admin_online == TRUE))
		return PLUGIN_CONTINUE

	if (settings[SETTING_RAPIDFIRE] == FALSE)
		return PLUGIN_CONTINUE

	for(new i=1;i<=g_MaxPlayers;i++)
	{
		if(is_user_alive(i))
		{
			if (userDetections[i][RAPIDFIRE] > 19)
				cheatDetected(i,RAPIDFIRE)
		}
		userDetections[i][RAPIDFIRE] = 0
	}

	return PLUGIN_CONTINUE
}


// Cheat: Scripting//
public cheatScriptBlock_Pre(id)
{
	if ((settings[SETTING_PASSIVE] == TRUE) && (admin_online == TRUE))
		return PLUGIN_CONTINUE

	entity_get_vector(id, EV_VEC_angles, tmpVec);
	userAim[id][0] = tmpVec[0]
	userAim[id][1] = tmpVec[1]
	userAim[id][2] = tmpVec[2]
	
	new flags = entity_get_int(id,EV_INT_button)
	
	if (settings[SETTING_MOVEKEY] == TRUE)
	{
		if(flags & PLAYER_LEFT)
		{
			client_cmd(id, "-left")
			tmpVec[0] = userAim[id][0]
			tmpVec[1] = userAim[id][1]
			tmpVec[2] = userAim[id][2]
			entity_set_vector(id, EV_VEC_angles, tmpVec)
			entity_set_int(id, EV_INT_fixangle, 1 )
			Write2Log(id,"has used +left")
			announce(id, "Left and Right keys are disabled!")
			}
		else if(flags & PLAYER_RIGHT)
		{
			client_cmd(id, "-right")
			tmpVec[0] = userAim[id][0]
			tmpVec[1] = userAim[id][1]
			tmpVec[2] = userAim[id][2]
			entity_set_vector(id, EV_VEC_angles, tmpVec)
			entity_set_int(id, EV_INT_fixangle, 1 )			
			Write2Log(id,"has used +right")
			announce(id, "Left and Right keys are disabled!")
		}
	}
	if (settings[SETTING_DOUBLEATTACK] == TRUE)
	{
		if(flags & PLAYER_ATTACK && flags & PLAYER_ATTACK2) // If the user is holding down both attack buttons we remove the last one pressed
		{
			if(g_LastAttack[id] == 0) // This means the player
				entity_set_int(id,EV_INT_button,(flags-PLAYER_ATTACK2))
			else if(g_LastAttack[id] == PLAYER_ATTACK)
			{
				entity_set_int(id,EV_INT_button,(flags-PLAYER_ATTACK2))
				announce(id, "Dual attack binding is not allowed!")
			}
			else if(g_LastAttack[id] == PLAYER_ATTACK2)
			{
				entity_set_int(id,EV_INT_button,(flags-PLAYER_ATTACK))
				entity_set_int(id,EV_INT_button,(flags-PLAYER_ATTACK2))
				announce(id, "Dual attack binding is not allowed!")
			}
		}
		else if(flags & PLAYER_ATTACK || flags & PLAYER_ATTACK2) // used to save
		{
			if(g_LastAttack[id] & PLAYER_ATTACK)
				g_LastAttack[id] = PLAYER_ATTACK
			else 
				g_LastAttack[id] = PLAYER_ATTACK2
		}
		else g_LastAttack[id] = 0 // This means the user is NOT holding down attack so we clear the array holding the last attack
	}

	return PLUGIN_CONTINUE
}

/*
Bugfix stuff
----------------------------------------------------------------------------------------------------
*/



public think_grenade(ent)
{
	new Float:org1[3]
	new org2[3]
	new hackzone[3]
	new model[32];
	
	entity_get_string(ent,EV_SZ_model,model,31);
	if (equal(model, g_fb_model))
	{
		new id = entity_get_edict(ent, EV_ENT_owner)
		entity_get_vector(ent,EV_VEC_origin,org1)

		org2[0] = floatround( org1[0] )
		org2[1] = floatround( org1[1] )
		org2[2] = floatround( org1[2] ) 

#if defined DEBUG //use to determine flashbug zones
		client_print(0,print_chat, "%ix %iy %iz", org2[0],org2[1],org2[2])
#endif

		for (new i=0;i<cntVectors;i++)
		{
			hackzone[0] = fz[i][0]
			hackzone[1] = fz[i][1]
			hackzone[2] = fz[i][2]

			if (get_distance(org2, hackzone) < fz[i][3])
			{
				new strMes[64]
				client_print(0, print_chat, "[Hack Hunter] Removed a flashbang (%ix %iy %iz)", org2[0],org2[1],org2[2])
				playsound(id, "warning")
				remove_entity( ent )
				userWarnings[id]++
				format(strMes, 63, "Illegal map exploit (Ban warning #%i)", userWarnings[id])
				announce(id, strMes)
				user_slap(id, (get_user_health (id) / 3))
				break
			}
		}
	}
}
public load_flashconfig()
{
	new line = 0, textline[256], len, i=0
	const SIZE = 63
	new line_x[SIZE + 1], line_y[SIZE + 1], line_z[SIZE + 1], line_proximity[SIZE + 1], parsedParams
	
	while ((line = read_file(fbFile, line, textline, 255, len)))
	{
		if (len == 0 || textline[0] == ';')
			continue // comment line
		
		parsedParams = parse(textline, line_x, SIZE, line_y, SIZE, line_z, SIZE, line_proximity, SIZE)
		
		if (parsedParams != 4)
		{
			server_print("[Hack Hunter] Error/warning in config (%s)", fbFile)
			continue
		}
		
		fz[i][0] = str_to_num(line_x)
		fz[i][1] = str_to_num(line_y)
		fz[i][2] = str_to_num(line_z)
		fz[i][3] = str_to_num(line_proximity)
		i++
	}
	
	cntVectors = i
	server_print("[Hack Hunter] Loaded %i vector(s) for this map", cntVectors)
	return PLUGIN_CONTINUE
}
public fn_triggerplanted ()
{
	bugfix[SILENTPLANT_SOUND] = TRUE
}


public fn_triggerroundstart ()
{
	bugfix[SILENTPLANT_SOUND] = FALSE
	
	bugfix[SILENTPLANT_READY] = FALSE
	

	if ( pev_valid ( g_entillusionary ) )
	{
		engfunc ( EngFunc_RemoveEntity, g_entillusionary )
	}
}

new g_sounds[5][] =
{
	"weapons/c4_beep1.wav",
	"weapons/c4_beep2.wav",
	
	"weapons/c4_beep3.wav",
	
	"weapons/c4_beep4.wav",
	
	"weapons/c4_beep5.wav"
	
}

public fn_createentity ()
{
	g_c4entity = engfunc ( EngFunc_FindEntityByString, -1, "model", "models/w_c4.mdl" )
	pev ( g_c4entity, pev_origin, gf_c4origin )
	
	g_classname = engfunc ( EngFunc_AllocString, "func_illusionary" )
	
	g_entillusionary = engfunc ( EngFunc_CreateNamedEntity, g_classname )
	
	gf_entorigin = gf_c4origin
	engfunc ( EngFunc_SetOrigin, g_entillusionary, gf_entorigin )
	
	bugfix[SILENTPLANT_READY] = TRUE
	
	fn_emitsound ()
}

public fn_emitsound ()
{
	emit_sound ( g_entillusionary, 0, g_sounds[gi_soundnum], gf_volume, gf_attenuation, gi_flags, gi_pitch )
}

/*
Misc stuff
----------------------------------------------------------------------------------------------------
*/
public checkForAdmin()
{
	for (new i=0;i<=MAXPLAYERS;i++)
		if ((is_user_alive(i)) && (is_user_admin(i)))
			if (settings[SETTING_PASSIVE] == TRUE)
				admin_online = TRUE
}
public load_config()
{
	new fileCFG[64]
	
	get_localinfo("amxx_basedir",fileCFG,63)
	format(fileCFG,63,"%s/hackhunter/settings.cfg",fileCFG)
	
	//default settings - is overrided by config values
	settings[SETTING_ENABLE] = TRUE
	settings[SETTING_VERSION] = TRUE
	settings[SETTING_SILENT] = FALSE
	settings[SETTING_SAFESPEED] = TRUE
	
	settings[SETTING_BAN] = TRUE
	
	settings[SETTING_PASSIVE] = FALSE
	
	settings[SETTING_RAPIDFIRE] = TRUE
	
	settings[SETTING_SPINHACK] = TRUE
	
	
	settings[SETTING_SPEEDHACK] = TRUE
	settings[SETTING_SHAKE] = TRUE
	settings[SETTING_MOVEKEY] = FALSE
	
	settings[SETTING_DOUBLEATTACK] = FALSE
	
	settings[SETTING_C4BEEP] = TRUE
	
	settings[SETTING_FLASHBUG] = TRUE
	
	new line = 0, textline[256], len
	while ((line = read_file(fileCFG, line, textline, 255, len)))
	{
		if (len == 0 || equal(textline, ";", 1))
			continue // comment line

		if (strfind(textline, "enabled=", 0, 0) != -1)
		{
			if (strfind(textline,"=true",0,0) != -1)
			{
				settings[SETTING_ENABLE] = TRUE
			}
			else
			{
				settings[SETTING_ENABLE] = FALSE
				server_print("Plugin disabled - shutting down Hack Hunter...")
				pause("ac","hack_hunter.amxx")
				return PLUGIN_HANDLED_MAIN
			}
		}
		if (strfind(textline, "check_for_updates=", 0, 0) != -1)
		{
			if (strfind(textline,"=true",0,0) != -1)
			{
				settings[SETTING_VERSION] = TRUE
			}
			else
			{
				settings[SETTING_VERSION] = FALSE
			}
		}
		if (strfind(textline, "fix_flashbug=", 0, 0) != -1)
		{
			if (strfind(textline,"=true",0,0) != -1)
			{
				settings[SETTING_FLASHBUG] = TRUE
			}
			else
			{
				settings[SETTING_FLASHBUG] = FALSE
			}
		}
		if (strfind(textline, "fix_c4beep=", 0, 0) != -1)
		{
			if (strfind(textline,"=true",0,0) != -1)
			{
				settings[SETTING_C4BEEP] = TRUE
			}
			else
			{
				settings[SETTING_C4BEEP] = FALSE
			}
		}
		if (strfind(textline, "silent_mode=", 0, 0) != -1)
		{
			if (strfind(textline,"=enabled",0,0) != -1)
			{
				settings[SETTING_SILENT] = TRUE
			}
			else
			{
				settings[SETTING_SILENT] = FALSE
			}
		}
		if (strfind(textline, "speedhack_secure=", 0, 0) != -1)
		{
			if (strfind(textline,"=true",0,0) != -1)
			{
				settings[SETTING_SAFESPEED] = TRUE
			}
			else
			{
				settings[SETTING_SAFESPEED] = FALSE
			}
		}
		if (strfind(textline, "use_ban=", 0, 0) != -1)
		{
			if (strfind(textline,"=true",0,0) != -1)
			{
				settings[SETTING_BAN] = TRUE
			}
			else
			{
				settings[SETTING_BAN] = FALSE
			}
		}
		if (strfind(textline, "passive_mode=", 0, 0) != -1)
		{
			if (strfind(textline,"=enabled",0,0) != -1)
			{
				settings[SETTING_PASSIVE] = TRUE
			}
			else
			{
				settings[SETTING_PASSIVE] = FALSE
			}
		}
		if (strfind(textline, "rapidfire=", 0, 0) != -1)
		{
			if (strfind(textline,"=enabled",0,0) != -1)
			{
				settings[SETTING_RAPIDFIRE] = TRUE
			}
			else
			{
				settings[SETTING_RAPIDFIRE] = FALSE
			}
		}
		if (strfind(textline, "spinhack=", 0, 0) != -1)
		{
			if (strfind(textline,"=enabled",0,0) != -1)
			{
				settings[SETTING_SPINHACK] = TRUE
			}
			else
			{
				settings[SETTING_SPINHACK] = FALSE
			}
		}
		if (strfind(textline, "speedhack=", 0, 0) != -1)
		{
			if (strfind(textline,"=enabled",0,0) != -1)
			{
				settings[SETTING_SPEEDHACK] = TRUE
			}
			else
			{
				settings[SETTING_SPEEDHACK] = FALSE
			}
		}
		if (strfind(textline, "shake=", 0, 0) != -1)
		{
			if (strfind(textline,"=enabled",0,0) != -1)
			{
				settings[SETTING_SHAKE] = TRUE
			}
			else
			{
				settings[SETTING_SHAKE] = FALSE
			}
		}
		if (strfind(textline, "movekey=", 0, 0) != -1)
		{
			if (strfind(textline,"=enabled",0,0) != -1)
			{
				settings[SETTING_MOVEKEY] = TRUE
			}
			else
			{
				settings[SETTING_MOVEKEY] = FALSE
			}
		}
		if (strfind(textline, "doubleattack=", 0, 0) != -1)
		{
			if (strfind(textline,"=enabled",0,0) != -1)
			{
				settings[SETTING_DOUBLEATTACK] = TRUE
			}
			else
			{
				settings[SETTING_DOUBLEATTACK] = FALSE
			}
		}
	}
	return PLUGIN_CONTINUE
}


stock cheaterCount()
{
	new cnt, fileCounter[64]
	
	new line = 0, textline[256], len
	
	
	get_localinfo("amxx_basedir",fileCounter,63)
	
	format(fileCounter,63,"%s/hackhunter/cnt.log",fileCounter)
	

	line = read_file(fileCounter, line, textline, 255, len)
	cnt = str_to_num(textline)
	
	
	cnt++
	num_to_str(cnt,textline,255)
	
	write_file(fileCounter,textline,0)
	return cnt
}


stock CopyVector(Float:Vec1[3],Float:Vec2[3])
{
	Vec2[0] = Vec1[0]

	Vec2[1] = Vec1[1]

	Vec2[2] = Vec1[2]
}
stock playsound(id, sound[32])
{

	client_cmd(id, "speak hackhunter/%s.wav", sound)

}
stock WriteLogs2File()
{
	for(new b=0;b<=g_LogsWriten;b++)
	
	{
		
		write_file(gs_LogFile,gs_Log[b],-1)
		
	}
	g_LogsWriten = 0		
}

stock Write2Log(id,Text[256])
{

	if(g_LogsWriten == LogBeforeWrite) WriteLogs2File()
	
	new CurrentTime[9],Name[32],Auth[35]
	
	get_user_name(id,Name,31)
	
	get_user_authid(id,Auth,35)
	
		
	get_time("%H:%M:%S",CurrentTime,8)
	
	format(gs_Log[g_LogsWriten],255,"%s (%s) <-> %s<%s> %s",CurrentTime,MapName,Name,Auth,Text)
	g_LogsWriten++
	return PLUGIN_CONTINUE

}
public announce(id, message[])
{
	if (settings[SETTING_SILENT] == FALSE)
	{
		set_hudmessage(255, 0, 0, -1.0, -1.0, 0, 6.0, 6.0, 0.3, 0.5, 3)

		show_hudmessage(id, "%s", message)

		set_hudmessage(255, 0, 0, 0.15, 0.05, 0, 6.0, 6.0, 0.3, 0.5, 4)

		show_hudmessage(id, "Hack Hunter Anti Cheat:")
	}
}
public cheatDetected(id, rcode)
{
	new auth[35],name[32],reason[64],cnt

	new CurrentTime[29],Map[32],ping,loss,Message[256]

	get_user_name(id,name,31)

	get_user_authid(id,auth,35)

	
	if (rcode==RAPIDFIRE)
		reason = "rapidfire"
	if (rcode==SHAKE)
		reason = "aimbot"
	if (rcode==SPEEDHACK)
		reason = "speedhack"
	if (rcode==SPINHACK)
		reason = "spinhack"
	if (rcode==RAPIDFIRE)
		reason = "rapidfire"
	if (rcode==RECOIL)
		reason = "low-recoil"
	if (rcode==EXPLOIT)
		reason = "illegal exploit"
	
	cnt = cheaterCount();
	
	if (settings[SETTING_SILENT] == FALSE)
	{
		set_hudmessage(255, 0, 0, -1.0, 0.91, 0, 6.0, 5.0, 0.3, 0.5, 2)
		if (settings[SETTING_BAN] == TRUE)
			show_hudmessage(0, "%s is #%i to be banned by Hack Hunter from this server, for using %s!",name,cnt,reason)
		else
			show_hudmessage(0, "%s is #%i to be kicked by Hack Hunter from this server, for using %s!",name,cnt,reason)
	}

	get_user_ping(id,ping,loss)
	get_time("%d/%m-%Y - %H:%M:%S",CurrentTime,29)
					
	if (settings[SETTING_BAN] == TRUE)
		format(Message,255,"[Hack Hunter %s - %s] %s<%s> banned for using: %s (Ping: %d )",CurrentTime,MapName,name,auth,reason,ping)
	else
		format(Message,255,"[Hack Hunter %s - %s] %s<%s> kicked for using: %s (Ping: %d )",CurrentTime,Map,name,auth,reason,ping)
	log_amx(Message)

	if (settings[SETTING_BAN] == TRUE)
	{
		client_print(0, print_chat, "[Hack Hunter] %s banned for cheating (%s)",name,reason)
		server_cmd("kick #%d Banned by Hack Hunter (%s)",get_user_userid(id),reason)
		server_cmd("banid 0.0 %s",auth)
		server_cmd("writeid")
	}
	else
	{
		client_print(0, print_chat, "[Hack Hunter] %s kicked for cheating (%s)",name,reason)
		server_cmd("kick #%d Kicked by Hack Hunter (%s)",get_user_userid(id),reason)
	}
	
	playsound(0, "spray")
	
}
public displayBanner()
{
	if (settings[SETTING_SILENT] == TRUE)
		return PLUGIN_CONTINUE

	for(new i=1;i<=g_MaxPlayers;i++)
	{
		if(is_user_alive(i))
		{
			set_hudmessage(42, 0, 255, -1.0, 0.03, 0, 6.0, 6.0, 0.3, 0.5, 3)
			show_hudmessage(i, "This server is secured with Hack Hunter v0.7 by SAMURAI")
			set_hudmessage(42, 0, 255, -1.0, 0.05, 0, 6.0, 6.0, 0.3, 0.5, 4)
			show_hudmessage(i, "http://www.cstrike.ro/forum")
		}
	}
	
	return PLUGIN_CONTINUE
}
stock lastUpdated()
{
	//limmit connections to once every month - thats 12 update checks per year, i dont
	//think there will be more releases then that, and theres no need to overload the server more
	//then necisary
	new fileCFG[64]
	
	new currentDate[6] 
	
	new line = 2, textline[256], len
	
	get_time("%m",currentDate,5)
	
	get_localinfo("amxx_basedir",fileCFG,63)
	
	format(fileCFG,63,"%s/hackhunter/auto.cfg",fileCFG)
	
	
	read_file(fileCFG, line, textline, 255, len)
	
	if (equal(textline, currentDate))
		return FALSE
	else
		write_file(fileCFG, currentDate, 2)
	return TRUE
}


stock ExplodeString( p_szOutput[][], p_nMax, p_nSize, p_szInput[], p_szDelimiter ) { // Function by xeroblood
	new nIdx = 0, l = strlen(p_szInput)
	new nLen = (1 + copyc( p_szOutput[nIdx], p_nSize, p_szInput, p_szDelimiter ))
	while( (nLen < l) && (++nIdx < p_nMax) )
		nLen += (1 + copyc( p_szOutput[nIdx], p_nSize, p_szInput[nLen], p_szDelimiter ))
	return nIdx
}


/*
Socket stuff
----------------------------------------------------------------------------------------------------
*/
public connect_version() {
	new error = 0
	new constring[512]
	
	if (settings[SETTING_VERSION] == FALSE)
		return PLUGIN_CONTINUE
	
	sckversion = socket_open(REMOTE_HOST, 80, SOCKET_TCP, error)
	if (sckversion > 0) {
		server_print("Socket_version: Connected to remote host")
		format(constring,511,"GET /ps/parser.php?request=version HTTP/1.1^nHost: %s^n^n",REMOTE_HOST)
		write_version(constring)
		read_version()
	}
	else {
		switch (error) {
			case 1: { server_print("Socket_version: Error creating socket"); }
			case 2: { server_print("Socket_version: Could not resolve hostname"); }
			case 3: { server_print("Socket_version: Could not connect to host"); }
		}
	}

	return PLUGIN_CONTINUE
}

public read_version() {
	new found = 0
	if (socket_change(sckversion, 100)) {
		new buf[512], lines[30][100], count = 0
		socket_recv(sckversion, buf, 511)
		count = ExplodeString(lines, 50, 119, buf, 13)
		for(new i=0;i<count;i++) {
			if (found == 1)
			{
				if (equal(lines[i],PS_VERSION))
				{
					is_current = 2 //is current version
				}
				else
				{
					is_current = 1
					server_print("Socket_version: A revised version is detected")
					//connect_update() //fixme - automatic download new version
				}
			}
			
			if (strfind(lines[i], "retval:version",0,0) != -1)
				found = 1
		}
	}
	
	if (sckversion != 0)
		set_task(0.5, "read_version")
	else {
		disconnect_version()
	}
}

public write_version(text[512]) {
	socket_send(sckversion, text, 511)
}

public disconnect_version() {
	server_print("Socket_version: Disconnected")
}


public connect_addtostatistics() {
	new error = 0
	sckaddtostatistics = socket_open("127.0.0.1", 80, SOCKET_TCP, error)
	if (sckaddtostatistics > 0) {
		server_print("Add to statistics: For more information please consult the readme file")
		server_print("Socket_addtostatistics: Connected to remote host")
		read_addtostatistics()
	}
	else {
		switch (error) {
			case 1: { server_print("Socket_addtostatistics: Error creating socket"); }
			case 2: { server_print("Socket_addtostatistics: Could not resolve hostname"); }
			case 3: { server_print("Socket_addtostatistics: Could not connect to host"); }
		}
	}
}



public read_addtostatistics() {
	if (socket_change(sckaddtostatistics, 100)) {
		new buf[512], lines[30][100], count = 0
		
		socket_recv(sckaddtostatistics, buf, 511)
		
		count = ExplodeString(lines, 50, 119, buf, 13)
		
		for(new i=0;i<count;i++) {
			/* Process items here */
		}
	}
	
	if (sckaddtostatistics != 0)
		set_task(0.5, "read_addtostatistics")
	else {
		disconnect_addtostatistics()
	}
}



public write_addtostatistics(text[512]) 
{
	socket_send(sckaddtostatistics, text, 511)
	
}


public disconnect_addtostatistics() {
	/* Disconnected */
}



/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1033\\ f0\\ fs16 \n\\ par }
*/
