/*
 *
 *             MMMMMMM               ,MMMMMMMMMMMMMMMMMMMMMMMM   MMMM             .aMMMMM               
 *          0MMMMMMMMMi              MMMMMMMMMMMMMMMMMMMMMMMM   MMMM            MMMMMr                 
 *          MMMMMMMMMM:              MMMM                       MMMM          MMMMMM                   
 *          7MMM2 MMMM               MMMM                       MMMM        .MMMMM.                    
 *         MMMMMM MMMMMM             MMMM                       MMMM       MMMMMM                      
 *         MMMM     MMMM             MMMM                       MMMM     rMMMMM                        
 *       .iMMMM    WMMMMr            MMMM                       MMMM   XMMMMM8                         
 *       rMMMM       MMMM            MMMM;WWWWWWWWWWWWWM0       MMMM  @MMMM.                           
 *      MMMMMM       MMMMMM          MMMMMMMMMMMMMMMMMMMM       MMMMZMMMMMM                            
 *      MMMM          SMMMM          MMMMMMMMMMMMMMMMMMMM       MMMMMMMMMMMM8                          
 *      MMMM,         MMMM2          MMMM                       MMMMMMM SMMMMM                         
 *    2MMMMa          ,ZMMMM         MMMM                       MMMMW     MMMMMM                       
 *    MMMM  irrrrrrr:  MMMM          MMMM                       MMMM       ;MMMMMi          7Zrrrrrrrr7
 *   BMMMMMMMMMMMMMMMMMMMMMM0r       MMMM                       MMMM          MMMMMX        MMMMMMMMMMM
 *   MMMMMMMMMMMMMMMMMMMMMMMM:       MMMM                       MMMM           @MMMMM                  
 *  MMMMM8               MMMMMM      MMMM                       MMMM             MMMMMZ                
 *  MMMM                   MMMM      MMMM                       MMMM              ZMMMMM               
 *  MMMM                  ;MMMM      MMMM                       MMMM                MMMMM@             
 * MMMZ2                   rMMMMZ   ,MMMM                       MMMM                  XMMMM
 *
 *
 *
 *
 * MMM           BMMMW    ;MMM       r @MMMMMMMMM0 .         . 0MMMMMMMMM@ r           2MMMMMMMMMM i   
 * MMM         MMMM0      ;MMM      MMMMMMMMMMMMMMMMM       MMMMMMMMMMMMMMMMM       MMMMMMMMMMMMMMMMM: 
 * MMM       WMMMW                 @MMMa         @MMMM     BMMMW         ZMMMM.    MMMMM         rMMMM 
 * MMM     rMMMM                  iMMM             MMMi    MMM             MMMa    MMM             MMMX
 * MMM    MMMMr            MZM    2MMM;                   .MMMS                    MMMZ                
 * MMM  MMMMM             rMMM      MMMM,                   MMMMS                   MMMMM              
 * MMM MMMM                MMM      @MMMMMMMM rrrX,         MMMMMMMMMrrrr77         BMMMMMMMMZ;rrr8    
 * MMMMMMMMMM              MMM         MMMMMMMMMMMMMM          MMMMMMMMMMMMMM          ZMMMMMMMMMMMMMi 
 * MMMMB  MMMMr            MMM              @ZZZSMMMMM              MZZZ20MMMM,             ZZZZa2MMMM.
 * MMM     ZMMMM           MMM                    iMMMM:                   MMMMX                   MMM0
 * MMM       WMMM@         MMM   .S,X               MMM:  2,7               MMMZ  Z,r               WMM
 * MMM         MMMM0       MMM   MMMMM              MMM: WMMMM              MMMZ XMMMM              @MM
 * MMM          SMMMM      MMM     MMM            XMMMM.   MMM            ,MMMMr   MMMi            MMMZ
 * MMM            BMMMM    MMM     rMMMMMMMMMMMMMMMMMM      MMMMMMMMMMMMMMMMMMi    iMMMMM@MMMMMMMMMMMM:
 * MMM              7MMM0 ,MMM       S MMMMMMMMMMMM S        i.BMMMMMMMMMMM 7         :aMMMMMMMMMMM 7
 *
 *
 *
 *
 *      Kick/Slay/Spec-Switcher for CS with bombdrop
 *	based on AFK-Kicker by Cheesy Peteza
 *      Slay ability and Bomb drop added by Isobold (www.clan-nva.de)
 *	Code revision and some nice hints by juKay
 *      
 *	Date:		            01-Jul-2005
 *
 *
 *	Description:	AFK Slay/Kicker for CS. Kicks after mp_afktime and slays player
 *                                  if last surviver and afk and minimum afk_minplayers.
 *                                  Textmessage elsewhere
 *                      Drops bomb after 25 sec afk
 *                      AFK-Count-Message at roundstart
 *                      AFK-Players are renamed and get their old name back when playing again or being switched spec 
 *                      (never the less their afk-name will show up during spectime)
  *                     Able to kick specs after a certain time
 *
 *	Cvars:
 *           afk_kicktime 150	 // Kick people AFK longer than this time
 *           afk_slaytime 60     // Slay people AFK longer than this time and last survivor
 *           afk_minplayers 8	 // Only kick AFKs when there is atleast this many players on the server
 *           afk_slayplayers 1   // Shall we slay or shall we not
 *           afk_adminimmunity 1 // Admins immun from slaying
 *                               // Will show message anyway!
 *           afk_adminkickimmunity 1 // Admins immun from kicking
 *           afk_options 1       // 1 - Kick player after kicktime, 0 - switch to spec after kicktime
 *           afk_rename 1        // Set to 1, it renames AFK players as described before
 * 
 *
 *
 *	Requirements:	AMXModX (cstrike and engine module)
 * 
 *   
 *
 *
 *	Need help with this?
 *
 *	http://www.amxmodx.org/forums/viewtopic.php?t=15163
 *
 *
 */

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


#define MIN_AFK_TIME 30		// I use this incase stupid admins accidentally set afk_kicktime to something silly.
#define WARNING_TIME 15		// Start warning the user this many seconds before they are about to be kicked.
#define CHECK_FREQ 5		// This is also the warning message frequency.
#define BOMB_DROP_TIME 25       // Time until bomb gets dropped, it is also afk recognition time
#define SHOW_FREQ 20            // Frequence of afk-count-messages, only needed if the CVAR afk_show_counter is set to 1
#define SPEC_ASK_TIME 30        // Time until demo-menu will pop up ...


new g_oldangles[33][3]
new g_spawnpos[33][3]
new g_afktime[33]
new g_spectime[33]
new st_afk_name[33][33]
new bool:g_spawned[33] = {true, ...}
new bool:g_demorec[33] = {false, ...}
new bool:g_afkname[33] = {false, ...}
new CsTeams:team
new AfkCT
new AfkT
new bombcarrier
new numCT
new numT

// At mapchange init this
public plugin_init() {
	register_plugin("AFK KiSSS","2.5.2","Isobold & Cheesy Peteza") 
	register_cvar("afkslay_version", "2.5.2", FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_SPONLY)

	register_cvar("afk_options", "1")		// Set to 0 will not kick player but switch him to spec-team
	register_cvar("afk_kicktime", "150")		// Kick people AFK longer than this time
	register_cvar("afk_slaytime", "60")     	// Slay people AFK and last survivor longer than this time
	register_cvar("afk_minplayers", "8")		// Only kick AFKs when there is at least this many players on the server
	register_cvar("afk_slayplayers", "1")   	// Shall we slay or shall we not
	register_cvar("afk_adminimmunity", "1")		// Honor the immunity flag or not
	register_cvar("afk_adminkickimmunity", "0")	// Honor the immunity flag or not
	register_cvar("afk_show_counter", "0")		// If set to one, plugin will show number of afk players every SHOW_FREQ seconds
	register_cvar("afk_rename", "0")		// Renames player for his afk-time, if set to one (triggers at afk_slaytime)
	register_cvar("afk_speckick", "0")		// Kicks players in spec not admin, not tacking demo after afk_speckkicktime
	register_cvar("afk_speckicktime", "300")	// Time to wait until afk_speckick, no effect if afk_speckick 0
	
	set_task(float(CHECK_FREQ),"checkPlayers",_,_,_,"b")
	register_event("ResetHUD", "playerSpawned", "be")
	register_dictionary("afkkicker.txt")
	register_logevent("event_RoundStart",2,"0=World triggered","1=Round_Start")
	register_logevent("bomb_events", 3, "1=triggered", "2=Spawned_With_The_Bomb", "2=Dropped_The_Bomb", "2=Got_The_Bomb", "2=Planted_The_Bomb")
	
	new keys = MENU_KEY_1|MENU_KEY_2
    	register_menucmd(register_menuid("Recording a demo?"), keys, "recDemo")
    	//register_menucmd(register_menuid("Recording a demo?"), 1023, "recDemo")
}


// Check wether one or more players is/are afk
public checkPlayers() {
	new playerCount, i, cplayer
	new cplayers[32] 
	get_players(cplayers, playerCount, "ac")
	get_alive_nums()

	for (i=0; i<playerCount; i++) {
		cplayer = cplayers[i]

        	if (is_user_connected(cplayer) && !is_user_bot(cplayer) && !is_user_hltv(cplayer) && is_user_alive(cplayer) && g_spawned[cplayer]) {
        		new newangle[3]
        		g_demorec[cplayer] = false
        		get_user_origin(cplayer, newangle)
        		if ( newangle[0] == g_spawnpos[cplayer][0] && newangle[1] == g_spawnpos[cplayer][1] && newangle[2] == g_spawnpos[cplayer][2] ) {
        			g_afktime[cplayer] += CHECK_FREQ
				check_afktime(cplayer)
				if(get_cvar_num("afk_rename") && get_cvar_num("afk_slaytime") && !(g_afkname[cplayer])) {
					new AFKName[32]
					get_user_name(cplayer, st_afk_name[cplayer], 31)
					format(AFKName, 31, "[AFK] %s", st_afk_name[cplayer])
					set_user_info(cplayer, "name", AFKName)
					g_afkname[cplayer] = true
				}
				if(get_cvar_num("afk_slayplayers"))
					check_team(cplayer)
			} else {	
				get_user_origin(cplayer, newangle, 3)
				if ( newangle[0] == g_oldangles[cplayer][0] && newangle[1] == g_oldangles[cplayer][1] && newangle[2] == g_oldangles[cplayer][2] ) {
					g_afktime[cplayer] += CHECK_FREQ
					check_afktime(cplayer)
					if(get_cvar_num("afk_rename") && get_cvar_num("afk_slaytime") && !(g_afkname[cplayer])) {
						new AFKName[32]
						get_user_name(cplayer, st_afk_name[cplayer], 31)
						format(AFKName, 31, "[AFK] %s", st_afk_name[cplayer])
						set_user_info(cplayer, "name", AFKName)
						g_afkname[cplayer] = true
					}
					if(get_cvar_num("afk_slayplayers"))
						check_team(cplayer)
				} else {
					g_oldangles[cplayer][0] = newangle[0]
					g_oldangles[cplayer][1] = newangle[1]
					g_oldangles[cplayer][2] = newangle[2]
					if(g_afkname[cplayer]) {
						new AFKName[32]
						format(AFKName, 31, "%s", st_afk_name[cplayer])
						set_user_info(cplayer, "name", AFKName)
						g_afkname[cplayer] = false
					}
					g_afktime[cplayer] = 0
				}
			}
			if(g_afktime[cplayer] > BOMB_DROP_TIME && cplayer == bombcarrier) {
				client_cmd(cplayer,"use weapon_c4")
				client_cmd(cplayer,"drop")
				client_print(0, print_chat, "[AFK KiSSS] - Bomb Drop")
			} 
        	} else {
        		if (is_user_connected(cplayer) && !is_user_bot(cplayer) && !is_user_hltv(cplayer))
        			checkspec(cplayer)
        	}
	}
	return PLUGIN_HANDLED
}

// All players in your team afk or not?
check_team(id) {
	if(g_afktime[id] < get_cvar_num("afk_slaytime")) {
	} else {
		team = cs_get_user_team(id)
		if((team == CS_TEAM_T && numT > 0) || (team == CS_TEAM_CT && numCT > 0)) {
		} else {		
			if(get_playersnum() < get_cvar_num("afk_minplayers") || (get_user_flags(id)&ADMIN_IMMUNITY && get_cvar_num("afk_adminimmunity"))) {
		 		client_print(0, print_chat, "[AFK KiSSS]: %L", LANG_PLAYER, "AFK_INFO_MSG")
			} else {
				new sid[1]
				sid[0] = id
				delayed_wc3_slay(sid)
				new pname[32]
				get_user_name(id, pname, 31)
				client_print(0, print_chat, "[AFK KiSSS]: %L", LANG_PLAYER, "AFK_KILL_MSG", pname)
			}
		}
	}
}

// Check what to do when afk
check_afktime(id) {
	new numplayers = get_playersnum()
	new minplayers = get_cvar_num("afk_minplayers")
	
	if(!(get_user_flags(id)&ADMIN_IMMUNITY && get_cvar_num("afk_adminkickimmunity")))
	{
		if (numplayers >= minplayers) {
			new maxafktime = get_cvar_num("afk_kicktime")
			if (maxafktime < MIN_AFK_TIME) {
				log_amx("cvar afk_kicktime %i is too low. Minimum value is %i.", maxafktime, MIN_AFK_TIME)
				maxafktime = MIN_AFK_TIME
				set_cvar_num("afk_kicktime", MIN_AFK_TIME)
			}
			new name[32]
			get_user_name(id, name, 31)
			if(get_cvar_num("afk_options")==1) {
				if ( maxafktime-WARNING_TIME <= g_afktime[id] < maxafktime) {
					new timeleft = maxafktime - g_afktime[id]
					client_print(id, print_chat, "[AFK KiSSS] %L", id, "AFK_TIMELEFT", timeleft)
				} else if (g_afktime[id] > maxafktime) {
					client_print(0, print_chat, "[AFK KiSSS]: %L", LANG_PLAYER, "AFK_KICKED", name, maxafktime)
					log_amx("%s was kicked for being AFK longer than %i seconds", name, maxafktime)
					server_cmd("kick #%d ^"You were kicked for being AFK longer than %i seconds^"", get_user_userid(id), maxafktime)
				}
			} else {
				if ( maxafktime-WARNING_TIME <= g_afktime[id] < maxafktime) {
					new timeleft = maxafktime - g_afktime[id]
					client_print(id, print_chat, "[AFK KiSSS] %L", id, "AFK_STIME", timeleft)
				} else if (g_afktime[id] > maxafktime) {
					log_amx("%s was switched to spec for being AFK longer than %i seconds", name, maxafktime)
					client_cmd(id,"kill")
					cs_set_user_team(id, CS_TEAM_SPECTATOR)
					client_print(0, print_chat, "[AFK KiSSS] - Spec Switch")
					g_afktime[id] = 0
					g_spectime[id] = 0
					new sid[1]
					sid[0] = id
					set_task(0.5,"delayed_wc3_slay",_,sid)
					if(get_cvar_num("afk_rename") && g_afkname[id]) {
						new AFKName[32]
						format(AFKName, 31, "%s", st_afk_name[id])
						set_user_info(id, "name", AFKName)
						g_afkname[id] = false
					}
				}
			}
		}
	}
}

checkspec(cplayer) {
	log_amx("Checkspec for id: %i", cplayer)
	if(get_cvar_num("afk_speckick") == 1 && cs_get_user_team(cplayer) == CS_TEAM_SPECTATOR && g_demorec[cplayer] == false) {
        	if(!(get_user_flags(cplayer)&ADMIN_IMMUNITY && get_cvar_num("afk_adminkickimmunity"))) {
        		// Spectatorbehandlung hier rein
        		new maxspectime = get_cvar_num("afk_speckicktime")
			new sname[32]
			get_user_name(cplayer, sname, 31)
			if(g_spectime[cplayer] > SPEC_ASK_TIME) {
			    log_amx("Showing demo menu to %s - id: %i", sname, cplayer)
			    ShowDemoMenu(cplayer)
			}
			g_spectime[cplayer] += CHECK_FREQ
			if(g_spectime[cplayer] > maxspectime) {
				client_print(0, print_chat, "[AFK KiSSS]: %L", LANG_PLAYER, "AFK_KICKED", sname, maxspectime)
				log_amx("%s was kicked for being spec longer than %i seconds", sname, maxspectime)
				server_cmd("kick #%d ^"You were kicked for being spec longer than %i seconds^"", cplayer, maxspectime)
			}
        	}
        }
}

// just connected you are not afk for shure ;)
public client_connect(id) {
	g_afktime[id]  = 0
	g_spectime[id] = 0
	g_demorec[id]  = false
	g_afkname[id]  = false
	get_user_name(id, st_afk_name[id], 31)
	return PLUGIN_HANDLED
}

// just connected you are not afk for shure ;)
public client_putinserver(id) {
	g_afktime[id]  = 0
	g_spectime[id] = 0
	g_demorec[id]  = false
	g_afkname[id]  = false
	get_user_name(id, st_afk_name[id], 31)
	return PLUGIN_HANDLED
}

// get player position after spawn
public playerSpawned(id) {
	g_spawned[id] = false
	g_demorec[id] = false
	new sid[1]
	sid[0] = id
	set_task(0.75, "delayedSpawn",_, sid, 1)	// Give the player time to drop to the floor when spawning
	return PLUGIN_HANDLED
}

// Used to get playerposition after spawn and drop
public delayedSpawn(sid[]) {
	get_user_origin(sid[0], g_oldangles[sid[0]], 3)
	get_user_origin(sid[0], g_spawnpos[sid[0]])
	g_spawned[sid[0]] = true
	return PLUGIN_HANDLED
}

public event_RoundStart() {
	new playerCount, Players[32], l
	if(task_exists (95729,0)) remove_task (95729,0)
	get_players(Players, playerCount, "ac")
	for(l=0;l<32;l++) {
		if(task_exists (2945 + l,0)) remove_task (2945 + l,0)
	}
	set_task(2.0, "afk_rs_msg")
	if(get_cvar_num("afk_show_counter") == 1) set_task(float(SHOW_FREQ),"afk_rs_msg",95729,_,_,"b")
	return PLUGIN_HANDLED
}

// Collect and displays informations about number and team of afk-players
public afk_rs_msg() {
	new playerCount, i, player
	new Players[32] 
	get_players(Players, playerCount, "ac")
	AfkT  = 0
	AfkCT = 0 

	for (i=0; i<playerCount; i++) {
		player = Players[i]
		if(g_afktime[player] > BOMB_DROP_TIME) {
			if(cs_get_user_team(player) == CS_TEAM_T)
				AfkT++
			if(cs_get_user_team(player) == CS_TEAM_CT)
				AfkCT++
		}
	}
	if(AfkT > 0 || AfkCT > 0) client_print(0, print_chat, "[AFK KiSSS]: %i T AFK - %i CT AFK", AfkT, AfkCT)
	return PLUGIN_HANDLED
}

// Tracks the bombholder
public bomb_events() {

        new arg0[64], action[64], name[33], userid, id; 

        // Read the log data that we need 
        read_logargv(0,arg0,63) 
        read_logargv(2,action,63) 

        // Find the id of the player that triggered the log 
        parse_loguser(arg0,name,32,userid) 
        id = find_player("k",userid) 

        // Find out what action it was 
        if (equal(action,"Spawned_With_The_Bomb")) { 
                bombcarrier = id; 
        } else if (equal(action,"Dropped_The_Bomb")) { 
                bombcarrier = 0; 
        } else if (equal(action,"Got_The_Bomb")) { 
                bombcarrier = id; 
        } else if (equal(action, "Planted_The_Bomb")) { 
                bombcarrier = 0; 
        } 

        return PLUGIN_HANDLED

}

// Retrieves the number of non-afk alive players
get_alive_nums() {
	new playerCount, i, gplayer
	new Players[32] 
	get_players(Players, playerCount, "ac")
	numCT = 0
	numT  = 0

	for (i=0; i<playerCount; i++) {
		gplayer = Players[i]
		if(cs_get_user_team(gplayer) == CS_TEAM_T && g_afktime[gplayer] < BOMB_DROP_TIME)
			numT++
		if(cs_get_user_team(gplayer) == CS_TEAM_CT && g_afktime[gplayer] < BOMB_DROP_TIME)
			numCT++
	}
}


public delayed_wc3_slay(sid[]) {
	new id
	id = sid[0]
	log_amx("Trying to wc3-slay %i",id)
	if(is_user_alive(id)) {
		client_cmd(id,"kill")
		set_task(2.0,"delayed_wc3_slay",2945 + id,sid)	
	}
}


public ShowDemoMenu(specid)
{ 
    new menu[192] 
    new keys = MENU_KEY_1|MENU_KEY_2
     
    format(menu, 191, "Recording a demo?^n^n1. Yes^n2. No") 
    show_menu(specid, keys, menu) 
} 

public recDemo(specid, key) 
{ 
    // if they pressed yes... 
    if ( key == 0 ) 
        g_demorec[specid] = true // If recording a demo, don't bother him anymore, only kick real afk-specs
}