/* AMX Mod X script. 
* 
* (c) 2003, OLO 
* This file is provided as is (no warranties). 
* 
* Set you server max_players to 1 above the desirered value (ie. 21 or 33). 
* Query programs will see max_players -1 as max. Admins with reservation 
* can connect when there is 20/20 and player with worst ping or least play time
* will be kicked.
* 
* Cvar: 
* amx_reservation <value> 
* 1 - Kicks the Player with shortest playing time when an admin connects to a full server.
* 2 - Kick the Player with the highest ping when an admin connects to a full server. 
*/ 

#include <amxmodx> 
#include <amxmisc> 

// Comment if you don't want to hide true max_players  
#define HIDE_RESERVEDSLOTS 

public plugin_init() 
{ 
	register_plugin("Slots Reservation","0.9.7","f117bomb") 
	register_cvar("amx_reserv","1") 
	
	#if defined HIDE_RESERVEDSLOTS 
	set_cvar_num( "sv_visiblemaxplayers" , get_maxplayers() - 1 ) 
	#endif 
	
} 

public client_authorized(id) {

	new maxplayers = get_maxplayers()
	new players = get_playersnum( 1 ) 
	new limit = maxplayers - 1
	new resType = get_cvar_num( "amx_reserv" ) 
	new who
	
	if ( players > limit ) //21/20
	{ 
		if ( get_user_flags(id) & ADMIN_RESERVATION ) 
		{ 
			switch(resType) {     
				case 1: 
					who = kickFresh()
				case 2: 
					who = kickLag()
			}
			if(who)  {
				new name[32]
   				get_user_name( who, name , 31 )
   				client_cmd(id,"echo ^"* %s was kicked to free this slot^"" ,name )
   			}
			return PLUGIN_CONTINUE 
		} 

		if ( is_user_bot(id) ) 
			server_cmd("kick #%d", get_user_userid(id)  ) 
		else 
			client_cmd(id,"echo ^"Server is Full.^";disconnect")
			
		return PLUGIN_HANDLED // block connect in other plugins (especially in consgreet)	 
	} 
	return PLUGIN_CONTINUE 
} 

kickLag() {
	new who = 0, ping, loss, worst = -1
	new maxplayers = get_maxplayers()
	for(new i = 1; i <= maxplayers; ++i) {
		if ( !is_user_connected(i) && !is_user_connecting(i) ) 
			continue // not used slot  
		if (get_user_flags(i)&ADMIN_RESERVATION) 
			continue // has reservation, skip him
		get_user_ping(i,ping,loss) // get ping
		if ( ping > worst ) {
			worst = ping
			who = i
		}
	}
	if(who) 
		if ( is_user_bot(who) ) 
			server_cmd("kick #%d", get_user_userid(who)  ) 
		else 
			client_cmd(who,"echo ^"Dropped due to high ping to free slot for an admin^";disconnect")
	return who  
}

kickFresh() {
	new who = 0, itime, shortest = 0x7fffffff
	new maxplayers = get_maxplayers()
	for(new i = 1; i <= maxplayers; ++i){
		if ( !is_user_connected(i) && !is_user_connecting(i) )
			continue // not used slot
		if (get_user_flags(i)&ADMIN_RESERVATION)
			continue // has reservation, skip him
		itime = get_user_time(i) // get user playing time with connection duration  
		if ( shortest > itime ) {
			shortest = itime
			who = i
		}
	}
	if(who) 
		if ( is_user_bot(who) ) 
			server_cmd("kick #%d", get_user_userid(who)  ) 
		else 
			client_cmd(who,"echo ^"Dropped due to shortest playing time to free slot for an admin^";disconnect")
	return who
}
