/* AMX MOD X Plugin

This file is provided as is (no warranties)
*/

#include <amxmodx>
#include <amxmisc>
#include <cstrike>
#include <fakemeta>

#define PLUGIN "AFK Manager"
#define VERSION "1.2"
#define AUTHOR "Alka"

#define CHECK_ACTIV_FREQUENCY 1 //DON'T CHANGE
#define MIN_CHECK_TIME 10 //Just for safe
#define MAX_AFK_SPECTATORS 3

#define PLUGIN_TAG "AFK"
#define ADMIN_ACCES_FLAG ADMIN_MENU
#define ADMIN_IMMUNITY_FLAG ADMIN_KICK

enum Cvars {
	
	CVAR_AUTOCHECK = 0,
	CVAR_FASTMACHINE,
	CVAR_AC_TIME,
	CVAR_AC_IMMUNITY,
	CVAR_AC_MAXAFKTIME,
	CVAR_AC_BOMBTIME,
	CVAR_AC_PUNISH,
	CVAR_AFK_MENU,
	CVAR_UNASSIGNED_CHECK,
	CVAR_UNASSIGNED_TIME,
	CVAR_FS_KICK_SPEC
}

new lastactive[33], nextcheck[33];
new player_id[33], player_name[32][33];
new bomb_carrier;
new pcvar[Cvars];
new bool:user_recording_demo[33];

new const afk_kick_reason[] = "Afk:You have been kicked for beeing Afk too long!";

public plugin_init() {
	
	register_plugin(PLUGIN, VERSION, AUTHOR);
	
	register_dictionary("afk_manager.txt");
	
	register_forward(FM_CmdStart, "Fwd_CmdStart");
	register_logevent("bomb_events", 3, "1=triggered", "2=Spawned_With_The_Bomb", "2=Dropped_The_Bomb", "2=Got_The_Bomb", "2=Planted_The_Bomb");
	
	register_clcmd("say /afk", "AfkMenu");
	register_clcmd("say_team /afk", "AfkMenu");
	
	pcvar[CVAR_AUTOCHECK] = register_cvar("afk_autocheck", "1");
	pcvar[CVAR_FASTMACHINE] = register_cvar("afk_ac_fastmachine", "0");
	pcvar[CVAR_AC_TIME] = register_cvar("afk_ac_time", "20");
	pcvar[CVAR_AC_IMMUNITY] = register_cvar("afk_ac_immunity", "1");
	pcvar[CVAR_AC_MAXAFKTIME] = register_cvar("afk_ac_maxafktime", "80");
	pcvar[CVAR_AC_BOMBTIME] = register_cvar("afk_ac_bombtime", "20");
	pcvar[CVAR_AC_PUNISH] = register_cvar("afk_ac_punish_type", "1");
	pcvar[CVAR_AFK_MENU] = register_cvar("afk_menu", "1");
	pcvar[CVAR_UNASSIGNED_CHECK] = register_cvar("afk_unassigned_check", "1");
	pcvar[CVAR_UNASSIGNED_TIME] = register_cvar("afk_unassigned_time", "15");
	pcvar[CVAR_FS_KICK_SPEC] = register_cvar("afk_fs_kick_spec", "1");
	
	if(get_pcvar_num(pcvar[CVAR_AUTOCHECK]) && get_pcvar_num(pcvar[CVAR_FASTMACHINE]) && !get_pcvar_num(pcvar[CVAR_AC_TIME]))
	{
		set_task(1.0, "AutoCheck_Afk");
	}
	if(get_pcvar_num(pcvar[CVAR_AUTOCHECK]) && !get_pcvar_num(pcvar[CVAR_FASTMACHINE]) && get_pcvar_num(pcvar[CVAR_AC_TIME]) > MIN_CHECK_TIME)
	{
		set_task(get_pcvar_float(pcvar[CVAR_AC_TIME]), "AutoCheck_Afk");
	}
	AutoCheck_Afk_Bomb();
}

public Fwd_CmdStart(id, uc_handle, seed)
{	
	new systime = get_systime();
	
	if(nextcheck[id] < systime)
	{
		new button = get_uc(uc_handle, UC_Buttons);
		if(button != 0)
		{
			lastactive[id] = systime;
			nextcheck[id] = systime + CHECK_ACTIV_FREQUENCY;
		}
	}
	return FMRES_HANDLED;
}

public AfkMenu(id)
{
	if(!get_pcvar_num(pcvar[CVAR_AFK_MENU]))
	{
		client_print(id, print_chat, "%L", LANG_PLAYER, "AFK_MENU_DISABLED", PLUGIN_TAG);
		return 1;
	}
	if(get_pcvar_num(pcvar[CVAR_AFK_MENU]) == 2 && !is_user_admin(id))
	{
		client_print(id, print_chat, "%L", LANG_PLAYER, "AFK_MENU_DISABLED", PLUGIN_TAG);
		return 1;
	}
	
	new menu = menu_create("\yAfk Players Check:", "AfkMenu_Handler");
	
	new players[32], num, x, pos_id[4];
	get_players(players, num);
	
	new name[32];
	new actualtime, playertime, mins, secs;
	new Buffer[64];
	
	actualtime = get_systime();
	
	for(new i = 0 ; i < num ; i++)
	{
		x = players[i];
		
		formatex(pos_id, sizeof pos_id - 1, "%d", x);
		get_user_name(x, name, sizeof name - 1);
		
		playertime = actualtime - lastactive[x];
		
		if((playertime / 60) >= 1)
		{
			mins = playertime / 60;
			secs = playertime % 60;
		}
		else
		{
			mins = 0;
			secs = playertime;
		}
		if(is_user_admin(x))
		{
			formatex(Buffer, sizeof Buffer - 1, "\r* \w%s ^t^t \y(%s%d:%s%d)^t%s", name, mins < 10 ? "0" : "", mins, secs < 10 ? "0" : "", secs, is_user_alive(x) ? "" : "(Dead)");
		}
		else
		{
			formatex(Buffer, sizeof Buffer - 1, "\w%s ^t^t \y(%s%d:%s%d)^t%s", name, mins < 10 ? "0" : "", mins, secs < 10 ? "0" : "", secs, is_user_alive(x) ? "" : "(Dead)");
		}
		menu_additem(menu, Buffer, pos_id, 0);
	}
	menu_addblank(menu, 0);
	menu_setprop(menu, MPROP_EXIT, MEXIT_ALL);
	menu_display(id, menu, 0);
	
	return 0;
}

public AfkMenu_Handler(id, menu, item)
{
	if(item == MENU_EXIT)
	{
		menu_destroy(menu);
		return;
	}
	new data[6];
	new access, callback;
	menu_item_getinfo(menu, item, access, data, sizeof data - 1,_,_, callback);
	
	player_id[id] = str_to_num(data);
	get_user_name(player_id[id], player_name[id], sizeof player_name - 1);
	
	if((get_user_flags(id) & ADMIN_ACCES_FLAG))
	{
		ShowAfkSubMenu(id);
	}
	else
	{
		menu_display(id, menu, 0);
		return;
	}
}

public ShowAfkSubMenu(id)
{
	new Buffer[128];
	formatex(Buffer, sizeof Buffer - 1, "\wManage Afk player, \y%s:", player_name[id]);
	
	new menu = menu_create(Buffer, "AfkSubMenu_Handler");
	
	menu_additem(menu, "\wMove to Spectators", "1", 0);
	menu_additem(menu, "\wKick", "2", 0);
	
	menu_addblank(menu, 0);
	menu_setprop(menu, MPROP_EXIT, MEXIT_NORMAL);
	menu_display(id, menu, 0);
}

public AfkSubMenu_Handler(id, menu, item)
{
	if(item == MENU_EXIT)
	{
		menu_destroy(menu);
		return;
	}
	new data[6];
	new access, callback;
	menu_item_getinfo(menu, item, access, data, 2,_,_, callback);
	
	new key = str_to_num(data);
	
	switch(key)
	{
		case 1:
		{
			if(is_user_connected(player_id[id]) && cs_get_user_team(player_id[id]) != CS_TEAM_SPECTATOR)
			{
				user_silentkill(player_id[id]);
				cs_set_user_team(player_id[id], CS_TEAM_SPECTATOR);
				
				Check_Spec_Slots();
			}
		}
		case 2:
		{
			server_cmd("kick #%i ^"%s^"", get_user_userid(player_id[id]), afk_kick_reason);
		}
	}
}

public AutoCheck_Afk()
{
	if(!get_pcvar_num(pcvar[CVAR_AUTOCHECK]))
		return;
	
	new players[32], num, x;
	get_players(players, num);
	
	new actualtime = get_systime();
	new playertime;
	
	for(new i = 0 ; i < num ; i++)
	{
		x = players[i];
		
		if(!is_user_connected(x))
			return;
		
		if(get_pcvar_num(pcvar[CVAR_AC_IMMUNITY]))
		{
			if((get_user_flags(x) & ADMIN_IMMUNITY_FLAG))
				continue;
		}
		
		playertime = actualtime - lastactive[x];
		
		new name[32];
		get_user_name(x, name, sizeof name - 1);
		
		if(playertime >= get_pcvar_num(pcvar[CVAR_AC_MAXAFKTIME]) && cs_get_user_team(x) == CS_TEAM_CT || cs_get_user_team(x) == CS_TEAM_T)
		{
			switch(get_pcvar_num(pcvar[CVAR_AC_PUNISH]))
			{
				case 1:
				{
					user_silentkill(x);
					cs_set_user_team(x, CS_TEAM_SPECTATOR);
					
					client_print(0, print_chat, "%L", LANG_PLAYER, "AFK_SPEC", PLUGIN_TAG, name, get_pcvar_num(pcvar[CVAR_AC_MAXAFKTIME]));
					
					Check_Spec_Slots();
				}
				case 2:
				{
					server_cmd("kick #%i ^"%s^"", get_user_userid(x), afk_kick_reason);
					
					client_print(0, print_chat, "%L", LANG_PLAYER, "AFK_KICK", PLUGIN_TAG, name, get_pcvar_num(pcvar[CVAR_AC_MAXAFKTIME]));
				}
			}
		}
	}
}

public AutoCheck_Afk_Bomb()
{
	new players[32], num, x;
	get_players(players, num, "a");
	
	new actualtime = get_systime();
	new playertime;
	
	for(new i = 0 ; i < num ; i++)
	{
		x = players[i];
		
		if(!is_user_connected(x))
			return;
		
		playertime = actualtime - lastactive[x];
		
		new name[32];
		get_user_name(x, name, sizeof name - 1);
		
		if(playertime >= get_pcvar_num(pcvar[CVAR_AC_BOMBTIME]) && x == bomb_carrier)
		{
			engclient_cmd(x, "drop", "weapon_c4");
			
			if(num < 2)
				return;
			
			new c4 = engfunc(EngFunc_FindEntityByString, -1, "classname", "weapon_c4");
			if(!c4)
				return;
			
			new c4_backpack = pev(c4, pev_owner);
			if(!c4_backpack)
				return;
			
			new target = random_t_player();
			
			set_pev(c4_backpack, pev_flags, pev(c4_backpack, pev_flags) | FL_ONGROUND);
			dllfunc(DLLFunc_Touch, c4_backpack, target);
			
			client_print(0, print_chat, "%L", LANG_PLAYER, "AFK_BOMB_TRANSFER", PLUGIN_TAG, name);
		}
		
	}
	set_task(1.0, "AutoCheck_Afk_Bomb");
}


public Check_Spec_Slots()
{
	new players[32], num, x;
	get_players(players, num);
	
	new SpecNum;
	
	new actualtime = get_systime();
	new playertime;
	
	for(new i = 0 ; i < num ; i++)
	{
		x = players[i];
		
		if(!is_user_connected(x))
			continue;
		
		if(get_pcvar_num(pcvar[CVAR_AC_IMMUNITY]))
		{
			if((get_user_flags(x) & ADMIN_IMMUNITY_FLAG))
				continue;
		}
		
		if(user_recording_demo[x])
			continue;
		
		playertime = actualtime - lastactive[x];
		
		if(cs_get_user_team(x) == CS_TEAM_SPECTATOR && playertime >= get_pcvar_num(pcvar[CVAR_AC_MAXAFKTIME]))
			++SpecNum;
	}
	if(SpecNum > MAX_AFK_SPECTATORS)
	{
		new rnd_player = random_afk_spec_player();
		
		server_cmd("kick #%i ^"%s^"", get_user_userid(rnd_player), afk_kick_reason);
		
		client_print(0, print_chat, "%L", LANG_PLAYER, "AFK_KICK_RND", PLUGIN_TAG);
	}
}

public bomb_events()
{
    new arg[64], message[64], name[32], userid, id; 
    
    read_logargv(0, arg, sizeof arg - 1) ;
    read_logargv(2, message, sizeof message - 1) ;
    
    parse_loguser(arg, name, sizeof name - 1, userid);
    id = find_player("k", userid);
    
    if(equali(message,"Spawned_With_The_Bomb") || equali(message,"Got_The_Bomb"))
    {
        bomb_carrier = id; 
    }
    else if(equali(message, "Planted_The_Bomb") || equali(message,"Dropped_The_Bomb"))
    {
        bomb_carrier = 0;
    }
    
    return 1;
}

public random_t_player()
{
	new players[32], num;
	get_players(players, num, "ae", "TERRORIST");
	
	return players[random_num(0, num)];
}

public random_afk_spec_player()
{
	new players[32], num, player, who, shortest = 999999;
	get_players(players, num, "e", "SPECTATORS");
	
	new actualtime = get_systime();
	new playertime;
	
	for(new i = 0 ; i < num ; i++)
	{
		player = players[i];
		
		if(!is_user_connected(player))
			continue;
		
		if(user_recording_demo[player])
			continue;
		
		playertime = actualtime - lastactive[player];
		
		if(shortest > playertime)
		{
			shortest = playertime;
			who = player;
		}
	}
	return who;
}

public client_command(id)
{
	new arg[13];
	read_argv(0, arg , sizeof arg - 1);
	
	if(equali(arg, "record"))
		user_recording_demo[id] = true;
	
	else if(equali(arg, "stopdemo"))
		user_recording_demo[id] = false;
}

public client_disconnect(id)
	user_recording_demo[id] = false;

public client_connect(id)
{
	if(!get_pcvar_num(pcvar[CVAR_FS_KICK_SPEC]))
		return;
	
	if(get_maxplayers() == get_playersnum(0))
	{
		new players[32], num
		get_players(players, num, "e", "SPECTATORS");
		
		if(num > 1)
		{
			new rnd_player = random_afk_spec_player();
			
			server_cmd("kick #%i ^"%s^"", get_user_userid(rnd_player), afk_kick_reason);
		}
	}
	player_id[id] = 0;
}
public client_putinserver(id)
{
	if(!get_pcvar_num(pcvar[CVAR_UNASSIGNED_CHECK]))
		return;
	
	set_task(get_pcvar_float(pcvar[CVAR_UNASSIGNED_TIME]), "UnassignedPlayer_Check", id);
}

public UnassignedPlayer_Check(id)
{
	if(!is_user_connected(id))
		return;
	
	if(cs_get_user_team(id) == CS_TEAM_UNASSIGNED)
	{
		server_cmd("kick #%i ^"%s^"", get_user_userid(id), afk_kick_reason);
	}
}
