#include <amxmodx>

#if AMXX_VERSION_NUM < 183
	#include <colorchat>
#else
	#define DontChange print_team_default
	#define Blue print_team_blue
	#define Red print_team_red
	#define Grey print_team_grey
#endif

#define PLUGIN "Map Manager RU"
#define VERSION "1.2.2"
#define AUTHOR "Mistrick"

#pragma semicolon 1

#define SELECT_MAPS 5// MAX 8
#define VOTE_TIME 15
#define SOUND_TIME 10//MAX 10
#define NOMINATE_MAX 3
#define NOMINATE_PLAYER_MAX 3
#define MAP_BLOCK 5
#define HUD_RESULT_COLOR 0, 55, 255

#define TASK_CHECKTIMER 978662
#define TASK_CHANGELEVEL 978562
#define TASK_SHOWMENU 978262
#define TASK_SHOWTIMER 978362
#define TASK_TIMER 978462
#define TASK_VOTEMENU 978162

enum _:BLOCKED_DATA
{
	MAP[33], COUNT
}
enum _:NOMINATE_DATA
{
	MAP[33], PLAYER, ID
}

new const FILE_MAPS[] = "addons/amxmodx/configs/mapcycle.ini";
new const FILE_BLOCKEDMAPS[] = "addons/amxmodx/data/blockedmaps.ini";
new const TEMP_FILE[] = "addons/amxmodx/data/temp.ini";

new const PREFIX[] = "[MM]";

new Array:g_iMapsArray, Array:g_iNominateArray;

new g_pLoadMapsType, g_pChangeMap, g_pChangeMapRounds, g_pShowSelects, g_pShowResultAfterVote, g_pShowResultType;
new g_pDebug, g_pTimeStartVote, g_pTimeStartVoteBeforeEnd, g_pTimeLimit, g_pExendedMax, g_pExendedTime, g_pChatTime;
new g_pRockEnable, g_pRockChange, g_pRockPercent, g_pRockDelay, g_pRockShow, g_pNextMap, g_pFriendlyFire, g_pMenuStopVote;
new g_pRockEndBlock;

new bool:g_bBeInVote, bool:g_bVoteFinished, bool:g_bRockVote, bool:g_bHasVoted[33], bool:g_bRockVoted[33];

new g_iExtendedMax, g_iRound, g_iStartPlugin, g_iLoadMaps, g_iForwardStartVote, g_iForwardFinishVote;
new g_iInMenu[SELECT_MAPS], g_iVoteItem[SELECT_MAPS + 1], g_iTotal, g_iVoteTime, g_iRockVote;
new g_iNominatedMaps[33], g_iPage[33], g_iTimer;

new g_szInMenuMapName[SELECT_MAPS][33], g_BlockedMaps[MAP_BLOCK][BLOCKED_DATA], g_szCurrentMap[33];

new const g_szPrefixes[][] = {"deathrun_", "speedrun_", "de_"};
new const g_szSound[][] =
{
	"",	"fvox/one",	"fvox/two",	"fvox/three", "fvox/four", "fvox/five",
	"fvox/six", "fvox/seven", "fvox/eight",	"fvox/nine", "fvox/ten"
};

public plugin_init()
{
	register_plugin(PLUGIN, VERSION, AUTHOR);
	
	g_pLoadMapsType = register_cvar("mm_loadmapstype", "1");//0 - load all maps from maps folder, 1 - load maps from file
	g_pChangeMap = register_cvar("mm_changemap", "1");//0 - after end vote, 1 - in round end, 2 - after end map
	g_pChangeMapRounds = register_cvar("mm_changemap_rounds", "0");// 0 - disable
	g_pTimeStartVoteBeforeEnd = register_cvar("mm_timestartvote_before_end", "2");//minutes
	g_pTimeStartVote = register_cvar("mm_timestartvote", "20");//if timelimit == 0
	g_pShowSelects = register_cvar("mm_showselects", "0");//0 - disable, 1 - all, 2 - self
	g_pShowResultAfterVote = register_cvar("mm_show_result_aftervote", "1");//0 - disable, 1 - enable
	g_pShowResultType = register_cvar("mm_showresulttype", "0");//0 - menu, 1 - hud
	g_pExendedTime = register_cvar("mm_extendedtime", "15");//minutes
	g_pExendedMax = register_cvar("mm_extendedmap_max", "3");
	g_pMenuStopVote = register_cvar("mm_menustopvote", "0");
	
	g_pNextMap = register_cvar("amx_nextmap", "");
	
	g_pRockEnable = register_cvar("mm_rtv_enable", "1");//0 - disable, 1 - enable
	g_pRockPercent = register_cvar("mm_rtv_percent", "60");
	g_pRockChange = register_cvar("mm_rtv_change", "0");//0 - after vote, 1 - in round end
	g_pRockDelay = register_cvar("mm_rtv_delay", "0");//minutes
	g_pRockEndBlock = register_cvar("mm_rtv_beforeendblock", "0");//minutes
	g_pRockShow = register_cvar("mm_rtv_show", "1");//0 - all, 1 - self
	
	g_pChatTime = get_cvar_pointer("mp_chattime");
	g_pTimeLimit = get_cvar_pointer("mp_timelimit");
	g_pFriendlyFire = get_cvar_pointer("mp_friendlyfire");
	
	g_pDebug = register_cvar("mm_debug", "0");
	
	register_concmd("mm_startvote", "Command_StartVote", ADMIN_MAP);
	register_concmd("mm_stopvote", "Command_StopVote", ADMIN_MAP);
	register_clcmd("votemap", "Command_Votemap");
	register_clcmd("say ff", "Command_FriendlyFire");
	register_clcmd("say maps", "Command_MapsList");
	register_clcmd("say /maps", "Command_MapsList");
	register_clcmd("say rtv", "Command_RTV");
	register_clcmd("say /rtv", "Command_RTV");
	register_clcmd("say rockthevote", "Command_RTV");
	register_clcmd("say nextmap", "Command_Nextmap");
	register_clcmd("say timeleft", "Command_Timeleft");
	register_clcmd("say currentmap", "Command_CurrentMap");
	register_clcmd("say", "Command_Say");
	register_clcmd("say_team", "Command_Say");
	
	register_event("SendAudio", "Event_RoundEnd", "a", "2=%!MRAD_terwin", "2=%!MRAD_ctwin", "2=%!MRAD_rounddraw");
	register_event("TextMsg", "Event_GameRestart", "a", "2=#Game_Commencing", "2=#Game_will_restart_in");
	register_event("30", "Event_MapEnd", "a");
	
	register_menucmd(register_menuid("Vote_Menu"), 1023, "VoteMenu_Handler");
	register_menucmd(register_menuid("MapsList_Menu"), 1023, "MapsListMenu_Handler");
	
	g_iNominateArray = ArrayCreate(NOMINATE_DATA);
	g_iStartPlugin = get_systime();
	g_iForwardStartVote = CreateMultiForward("mapmanager_startvote", ET_IGNORE);
	g_iForwardFinishVote = CreateMultiForward("mapmanager_finishvote", ET_IGNORE);
		
	set_task(5.0, "CheckTime", TASK_CHECKTIMER, .flags = "b");
	set_task(11.0, "SoundTimer", .flags = "d");
	
	set_cvar_string("mapcyclefile", FILE_MAPS);
	get_mapname(g_szCurrentMap, charsmax(g_szCurrentMap));
	
	if(get_pcvar_num(g_pDebug))
	{
		log_to_file("mapmanager_debug.log", "PLUGIN_INIT: %s", g_szCurrentMap);
	}
	
	Load_BlockedMaps();
	Load_MapList();
}
public plugin_end()
{
	if(g_iExtendedMax)
	{
		set_pcvar_num(g_pTimeLimit, get_pcvar_num(g_pTimeLimit) - g_iExtendedMax * get_pcvar_num(g_pExendedTime));
	}
	
	set_pcvar_num(g_pChatTime, get_pcvar_num(g_pChatTime) - 6);
	
	new iVar = MAP_BLOCK;
	if(iVar < 2) return;
	
	new iTemp = fopen(TEMP_FILE, "wt");
	
	if(iTemp)
	{
		for(new i = 0; i < MAP_BLOCK; i++)
		{
			if(g_BlockedMaps[i][COUNT])
			{
				fprintf(iTemp, "^"%s^" ^"%d^"^n", g_BlockedMaps[i][MAP], g_BlockedMaps[i][COUNT]);
			}
		}	
		
		fprintf(iTemp, "^"%s^" ^"%d^"^n", g_szCurrentMap, MAP_BLOCK);	
		fclose(iTemp);
		
		delete_file(FILE_BLOCKEDMAPS);
		new iRename = rename_file(TEMP_FILE, FILE_BLOCKEDMAPS, 1);
		if(get_pcvar_num(g_pDebug))
		{
			log_to_file("mapmanager_debug.log", "PLUGIN_END: File Renamed ? %d", iRename);
		}
	}
	else if(get_pcvar_num(g_pDebug))
	{
		log_to_file("mapmanager_debug.log", "PLUGIN_END: Can't write file");
	}
}
//*****  *****//
Load_BlockedMaps()
{	
	if(!file_exists(FILE_BLOCKEDMAPS) || MAP_BLOCK < 2) return PLUGIN_CONTINUE;
		
	new iFile = fopen(FILE_BLOCKEDMAPS, "rt");
	new iTemp = fopen(TEMP_FILE, "wt");
	
	new szBuffer[64], szMap[33], szCount[8], iCount, i = 0;
	
	while(!feof(iFile))
	{
		fgets(iFile, szBuffer, charsmax(szBuffer));
		parse(szBuffer, szMap, charsmax(szMap), szCount, charsmax(szCount));
		
		if(get_blocked_map_count(szMap) || !is_map_valid(szMap) || equali(szMap, g_szCurrentMap)) continue;
		
		iCount = str_to_num(szCount) - 1;
		
		if(!iCount) continue;
		
		if(iCount > MAP_BLOCK)
		{
			fprintf(iTemp, "^"%s^" ^"%d^"^n", szMap, MAP_BLOCK);
			iCount = MAP_BLOCK;
		}
		else
		{
			fprintf(iTemp, "^"%s^" ^"%d^"^n", szMap, iCount);
		}
		
		formatex(g_BlockedMaps[i][MAP], charsmax(g_BlockedMaps[][MAP]), szMap);
		g_BlockedMaps[i++][COUNT] = iCount;
		
		if(i >= MAP_BLOCK) break;
	}
	
	fclose(iFile);
	fclose(iTemp);
	
	delete_file(FILE_BLOCKEDMAPS);
	new iRename = rename_file(TEMP_FILE, FILE_BLOCKEDMAPS, 1);
	
	if(get_pcvar_num(g_pDebug))
	{
		log_to_file("mapmanager_debug.log", "LOAD_BLOCKEDMAPS: File Renamed? %d; Blocked ? %d", iRename, i);
	}
	
	return PLUGIN_CONTINUE;
}
Load_MapList()
{
	g_iLoadMaps = 0;
	g_iMapsArray = ArrayCreate(33);
	
	if(file_exists(FILE_MAPS) && get_pcvar_num(g_pLoadMapsType))
	{		
		new szMapName[33];
		
		new f = fopen(FILE_MAPS, "rt");
		
		if(f)
		{
			while(!feof(f))
			{
				fgets(f, szMapName, charsmax(szMapName));
				trim(szMapName);
				remove_quotes(szMapName);
				
				if(!szMapName[0] || szMapName[0] == ';' || szMapName[0] == '/' && szMapName[1] == '/'
					|| !valid_map(szMapName) || in_maps_array(szMapName) || equali(szMapName, g_szCurrentMap))
					continue;
				
				g_iLoadMaps++;
				
				ArrayPushString(g_iMapsArray, szMapName);
			}		
			fclose(f);
		}
	}
	else
	{
		new iDir, iLen, szFileName[64];
		new DirName[] = "maps";
		iDir = open_dir(DirName, szFileName, charsmax(szFileName));
		
		if(iDir)
		{
			while(next_file(iDir, szFileName, charsmax(szFileName)))
			{
				iLen = strlen(szFileName) - 4;
				
				if(iLen < 0) continue;
				
				if(equali(szFileName[iLen], ".bsp") && !equali(szFileName, g_szCurrentMap))
				{
					szFileName[iLen] = '^0';
					
					g_iLoadMaps++;
					
					ArrayPushString(g_iMapsArray, szFileName);
				}
			}
			close_dir(iDir);
		}
	}
	
	if(!g_iLoadMaps)
	{
		if(get_pcvar_num(g_pDebug))
		{
			log_to_file("mapmanager_debug.log", "LOAD_MAPS: Nothing loaded");
		}
		set_fail_state("LOAD_MAPS: Nothing loaded");
		return;
	}
	
	if(g_iLoadMaps - get_blocked_maps() <= 0)
	{
		clear_blocked_maps();
	}
	
	new szMap[33];	
	do
	{
		ArrayGetString(g_iMapsArray, random_num(0, g_iLoadMaps - 1), szMap, charsmax(szMap));
	} while(get_blocked_map_count(szMap));
	
	set_pcvar_string(g_pNextMap, szMap);
	
	if(get_pcvar_num(g_pDebug))
	{
		log_to_file("mapmanager_debug.log", "LOAD_MAPS: Loaded Maps ? %d", g_iLoadMaps);
	}
}
//*****  *****//
public client_disconnect(id)
{
	if(task_exists(id + TASK_VOTEMENU)) remove_task(id + TASK_VOTEMENU);
	if(g_bRockVoted[id])
	{
		g_bRockVoted[id] = false;
		g_iRockVote--;
	}
	if(g_iNominatedMaps[id])
	{
		clear_nominated_maps(id);		
	}
}
//***** Commands *****//
public Command_Votemap(id)
{
	return PLUGIN_HANDLED;
}
public Command_StartVote(id, flag)
{
	return ~get_user_flags(id) & flag ? PLUGIN_HANDLED : StartVote(id);
}
public Command_StopVote(id, flag)
{
	if(~get_user_flags(id) & flag) return PLUGIN_HANDLED;
	
	if(g_bBeInVote)
	{
		g_bBeInVote = false;
		g_bRockVote = false;
		g_iRockVote = 0;
		arrayset(g_bRockVoted, false, 33);
		
		if(task_exists(TASK_SHOWMENU)) remove_task(TASK_SHOWMENU);
		if(task_exists(TASK_SHOWTIMER)) remove_task(TASK_SHOWTIMER);
		if(task_exists(TASK_TIMER)) remove_task(TASK_TIMER);
		for(new id = 1; id <= 32; id++)
		{
			if(task_exists(TASK_VOTEMENU + id)) remove_task(TASK_VOTEMENU + id);
		}
		show_menu(0, 0, "^n", 1);
		new szName[32]; get_user_name(id, szName, charsmax(szName));
		client_print_color(0, DontChange, "^4%s^3 %s^1 отменил голосование.", PREFIX, szName);
	}
	
	return PLUGIN_HANDLED;
}
public Command_FriendlyFire(id)
{
	client_print_color(0, DontChange, "^4%s^1 На сервере^3 %s^1 огонь по своим.", PREFIX, get_pcvar_num(g_pFriendlyFire) ? "разрешен" : "запрещен");
}
public Command_MapsList(id)
{
	Show_MapsListMenu(id, g_iPage[id] = 0);
}
public Show_MapsListMenu(id, iPage)
{
	if(iPage < 0) return PLUGIN_HANDLED;
	
	new iMax = ArraySize(g_iMapsArray);
	new i = min(iPage * 8, iMax);
	new iStart = i - (i % 8);
	new iEnd = min(iStart + 8, iMax);
	
	iPage = iStart / 8;
	g_iPage[id] = iPage;
	
	new szMenu[512], iLen = 0, szMapName[33];
	
	iLen = formatex(szMenu, charsmax(szMenu), "\yСписок карт \w[%d/%d]:^n", iPage + 1, ((iMax - 1) / 8) + 1);
	
	new Keys, Item, iBlock, iNominator;
	
	for (i = iStart; i < iEnd; i++)
	{
		ArrayGetString(g_iMapsArray, i, szMapName, charsmax(szMapName));
		iBlock = get_blocked_map_count(szMapName);
		iNominator = is_map_nominated(szMapName);
		if(iBlock)
		{
			iLen += formatex(szMenu[iLen], charsmax(szMenu) - iLen, "^n\r%d.\d %s[\r%d\d]", ++Item, szMapName, iBlock);
		}
		else if(iNominator)
		{
			if(iNominator == id)
			{
				Keys |= (1 << Item);
				iLen += formatex(szMenu[iLen], charsmax(szMenu) - iLen, "^n\r%d.\w %s[\y*\w]", ++Item, szMapName);
				
			}
			else
			{
				iLen += formatex(szMenu[iLen], charsmax(szMenu) - iLen, "^n\r%d.\d %s[\y*\d]", ++Item, szMapName);
			}
		}
		else
		{
			Keys |= (1 << Item);
			iLen += formatex(szMenu[iLen], charsmax(szMenu) - iLen, "^n\r%d.\w %s", ++Item, szMapName);
		}
	}
	while(Item <= 8)
	{
		Item++;
		iLen += formatex(szMenu[iLen], charsmax(szMenu) - iLen, "^n");
	}
	if (iEnd < iMax)
	{
		Keys |= (1 << 8)|(1 << 9);		
		formatex(szMenu[iLen], charsmax(szMenu) - iLen, "^n\r9.\w Вперед^n\r0.\w %s", iPage ? "Назад" : "Выход");
	}
	else
	{
		Keys |= (1 << 9);
		formatex(szMenu[iLen], charsmax(szMenu) - iLen, "^n^n\r0.\w %s", iPage ? "Назад" : "Выход");
	}
	show_menu(id, Keys, szMenu, -1, "MapsList_Menu");
	return PLUGIN_HANDLED;
}
public MapsListMenu_Handler(id, key)
{
	switch (key)
	{
		case 8: Show_MapsListMenu(id, ++g_iPage[id]);
		case 9: Show_MapsListMenu(id, --g_iPage[id]);
		default:
		{			
			new szMapName[33]; ArrayGetString(g_iMapsArray, key + g_iPage[id] * 8, szMapName, charsmax(szMapName));
			if(g_iNominatedMaps[id] && is_map_nominated(szMapName))
			{
				remove_nominated_map(id, szMapName);
			}
			else
			{
				NominateMap(id, szMapName);
			}
		}
	}
	return PLUGIN_HANDLED;
}
public Command_RTV(id)
{
	if(g_bVoteFinished || g_bBeInVote) return PLUGIN_HANDLED;
	
	if(!get_pcvar_num(g_pRockEnable)) return PLUGIN_CONTINUE;
	
	if(get_timeleft() / 60 < get_pcvar_num(g_pRockEndBlock))
	{
		client_print_color(id, DontChange, "^4%s^1 Слишком поздно для досрочного голосования.", PREFIX);
		return PLUGIN_HANDLED;
	}
	
	new iTime = get_systime();
	if(iTime - g_iStartPlugin < get_pcvar_num(g_pRockDelay) * 60)
	{
		new iMin = 1 + (get_pcvar_num(g_pRockDelay) * 60 - (iTime - g_iStartPlugin)) / 60;
		new szMin[16]; get_ending(iMin, "минут", "минута", "минуты", szMin, charsmax(szMin));
				
		client_print_color(id, DontChange, "^4%s^1 Вы не можете голосовать за досрочную смену карты. Осталось:^3 %d^1 %s.", PREFIX, iMin, szMin);
		return PLUGIN_HANDLED;
	}
	
	if(!g_bRockVoted[id])
	{
		g_bRockVoted[id] = true;
		g_iRockVote++;
		
		new iVote = floatround(get_players_num() * get_pcvar_num(g_pRockPercent) / 100.0, floatround_ceil) - g_iRockVote;
		
		if(iVote > 0)
		{
			new szVote[16];	get_ending(iVote, "голосов", "голос", "голоса", szVote, charsmax(szVote));
			
			switch(get_pcvar_num(g_pRockShow))
			{
				case 0:
				{
					new szName[33];
					get_user_name(id, szName, charsmax(szName));
					client_print_color(0, DontChange, "^4%s^3 %s^1 проголосовал за смену карты. Осталось:^3 %d^1 %s.", PREFIX, szName, iVote, szVote);
				}
				case 1: client_print_color(id, DontChange, "^4%s^1 Ваш голос учтен. Осталось:^3 %d^1 %s.", PREFIX, iVote, szVote);
			}
		}
		else
		{
			g_bRockVote = true;
			StartVote(0);
			client_print_color(0, DontChange, "^4%s^1 Начинаем досрочное голосование.", PREFIX);
		}
	}
	else
	{
		new iVote = floatround(get_players_num() * get_pcvar_num(g_pRockPercent) / 100.0, floatround_ceil) - g_iRockVote;
		new szVote[16];	get_ending(iVote, "голосов", "голос", "голоса", szVote, charsmax(szVote));
		client_print_color(id, DontChange, "^4%s^1 Вы уже голосовали. Осталось:^3 %d^1 %s.", PREFIX, iVote, szVote);
	}
	
	return PLUGIN_HANDLED;
}
public Command_Nextmap(id)
{
	new szMap[33]; get_pcvar_string(g_pNextMap, szMap, charsmax(szMap));
	client_print_color(0, Blue, "^4%s^1 Следующая карта: ^3%s^1.", PREFIX, szMap);
}
public Command_Timeleft(id)
{
	if (get_pcvar_num(g_pTimeLimit))
	{
		new a = get_timeleft();
		client_print_color(0, Blue, "^4%s^1 До конца карты осталось:^3 %d:%02d", PREFIX, (a / 60), (a % 60));
	}
	else
	{
		client_print_color(0, DontChange, "^4%s^1 Карта не ограничена по времени.", PREFIX);
	}
}
public Command_CurrentMap(id)
{
	client_print_color(0, Blue, "^4%s^1 Текущая карта:^3 %s^1.", PREFIX, g_szCurrentMap);
}
public Command_Say(id)
{
	if(g_bVoteFinished || g_bBeInVote) return;
	
	new szText[33];	read_args(szText, charsmax(szText));
	remove_quotes(szText);
	trim(szText);
	strtolower(szText);
	if(in_maps_array(szText))
	{
		if(g_iNominatedMaps[id] && is_map_nominated(szText))
		{
			remove_nominated_map(id, szText);
		}
		else
		{
			NominateMap(id, szText);
		}
	}
	else
	{
		for(new i = 0; i < sizeof(g_szPrefixes); i++)
		{
			new szFormat[33]; formatex(szFormat, charsmax(szFormat), "%s%s", g_szPrefixes[i], szText);
			if(in_maps_array(szFormat))
			{
				if(g_iNominatedMaps[id] && is_map_nominated(szFormat))
				{
					remove_nominated_map(id, szFormat);
				}
				else
				{
					NominateMap(id, szFormat);
				}
				break;
			}
		}
	}
}
NominateMap(id, map[33])
{	
	if(g_iNominatedMaps[id] == NOMINATE_PLAYER_MAX)
	{
		client_print_color(id, DontChange, "^4%s^1 Вы не можете больше номинировать карты.", PREFIX);
		return PLUGIN_HANDLED;
	}
	if(get_blocked_map_count(map))
	{
		client_print_color(id, DontChange, "^4%s^1 Эта карта недоступна для номинации.", PREFIX);
		return PLUGIN_HANDLED;
	}
	if(is_map_nominated(map))
	{
		client_print_color(id, DontChange, "^4%s^1 Эта карта уже номинирована.", PREFIX);
		return PLUGIN_HANDLED;
	}	
	
	new szMap[33], i;
	for(i = 0; i < g_iLoadMaps; i++)
	{
		ArrayGetString(g_iMapsArray, i, szMap, charsmax(szMap));
		if(equali(map, szMap)) break;
	}
		
	new Data[NOMINATE_DATA];
	Data[MAP] = map;
	Data[PLAYER] = id;
	Data[ID] = i;
	ArrayPushArray(g_iNominateArray, Data);
	
	g_iNominatedMaps[id]++;
	new szName[33];	get_user_name(id, szName, charsmax(szName));
	client_print_color(0, id, "^4%s^3 %s^1 номинировал на голосование^3 %s^1.", PREFIX, szName, map);

	return PLUGIN_HANDLED;
}
//***** Events *****//
public Event_RoundEnd()
{
	g_iRound++;
	new iCvar = get_pcvar_num(g_pChangeMapRounds);
	if(iCvar && g_iRound >= iCvar)
	{
		StartVote(0);
	}
	if(g_bVoteFinished && (get_pcvar_num(g_pChangeMap) == 1 || g_bRockVote && get_pcvar_num(g_pRockChange) == 1))
	{
		set_task(5.0, "ChangeLevel", TASK_CHANGELEVEL);
		if(get_pcvar_num(g_pDebug))
		{
			log_to_file("mapmanager_debug.log", "EVENT_ROUNDEND: ChangeLevel");
		}
	}
}
public Event_GameRestart()
{
	g_iRound = 0;
	g_iStartPlugin = get_systime();
}
public Event_MapEnd()
{
	set_pcvar_num(g_pChatTime, get_pcvar_num(g_pChatTime) + 6);
	set_task(5.0, "ChangeLevel", TASK_CHANGELEVEL);
	if(get_pcvar_num(g_pDebug))
	{
		log_to_file("mapmanager_debug.log", "EVENT_MAPEND: ChangeLevel");
	}
}
//*****  *****//
public CheckTime()
{
	if(g_bVoteFinished || g_bBeInVote) return PLUGIN_CONTINUE;
	
	static iTimeLimit; iTimeLimit = get_pcvar_num(g_pTimeLimit);
	
	if(iTimeLimit > 2)
	{
		if(get_systime() - g_iStartPlugin >= (iTimeLimit - get_pcvar_num(g_pTimeStartVoteBeforeEnd)) * 60)
		{
			StartVote(0);
		}
	}
	else if(iTimeLimit == 0)
	{
		if(get_systime() - g_iStartPlugin >= get_pcvar_num(g_pTimeStartVote) * 60)
		{
			StartVote(0);
		}
	}
	
	return PLUGIN_CONTINUE;
}
public StartVote(id)
{
	if(g_bBeInVote)
	{
		if(id) client_print_color(id, DontChange, "^4%s^1 Голосование запущено.", PREFIX);
		return PLUGIN_HANDLED;
	}
	
	g_bBeInVote = true;
	g_iTotal = 0;
	
	arrayset(g_iVoteItem, 0, SELECT_MAPS + 1);
	arrayset(g_iInMenu, -1, SELECT_MAPS);
	arrayset(g_bHasVoted, false, 33);	
	
	new Num,  NomInMenu = 0, Data[NOMINATE_DATA];
	new iMax = 8, Limits[2];
	
	Limits[0] = SELECT_MAPS;
	Limits[1] = g_iLoadMaps - get_blocked_maps();
	
	for(new i = 0; i < sizeof(Limits); i++)
	{
		if(iMax > Limits[i]) iMax = Limits[i];
	}
	
	new iNomMax, iNomNum = ArraySize(g_iNominateArray);
	iNomMax = iNomNum > NOMINATE_MAX ? NOMINATE_MAX : iNomNum;
	
	for(new i = 0; i < iMax; i++)
	{		
		if(NomInMenu < iNomMax)
		{
			Num = random_num(0, ArraySize(g_iNominateArray) - 1);
			
			ArrayGetArray(g_iNominateArray, Num, Data);
			
			formatex(g_szInMenuMapName[i], 32, Data[MAP]);
			g_iInMenu[i] = Data[ID];
			NomInMenu++;
			
			ArrayDeleteItem(g_iNominateArray, Num);
			g_iNominatedMaps[Data[PLAYER]]--;
		}
		else
		{
			do Num = random_num(0, g_iLoadMaps - 1);
			while(in_menu(Num) || is_blocked(Num));
			
			g_iInMenu[i] = Num;
			ArrayGetString(g_iMapsArray, Num, g_szInMenuMapName[i], 32);
		}		
	}
	
	g_iTimer = SOUND_TIME; if(g_iTimer > 10) g_iTimer = 10;
	set_task(1.0, "Show_Timer", TASK_SHOWTIMER, _, _, "a", g_iTimer);
	set_task(float(g_iTimer) + 1.0, "Show_Menu", TASK_SHOWMENU);
	
	new iRet;
	ExecuteForward(g_iForwardStartVote, iRet);
	
	if(get_pcvar_num(g_pDebug))
	{
		log_to_file("mapmanager_debug.log", "START_VOTE: RTV ? %d", g_bRockVote ? 1 : 0);
	}
	
	return PLUGIN_HANDLED;
}
public Show_Timer()
{
	new szSec[16]; get_ending(g_iTimer, "секунд", "секунда", "секунды", szSec, charsmax(szSec));
	
	for(new i = 1; i <= 32; i++)
	{
		if(!is_user_connected(i)) continue;
		set_hudmessage(50, 255, 50, -1.0, is_user_alive(i) ? 0.9 : 0.3, 0, 0.0, 1.0, 0.0, 0.0, 1);
		show_hudmessage(i, "До голосования осталось %d %s!", g_iTimer, szSec);
	}
	
	client_cmd(0, "spk %s", g_szSound[g_iTimer--]);
}
public Show_Menu()
{
	new Players[32], pNum, iPlayer; get_players(Players, pNum, "ch");
	
	g_iVoteTime = VOTE_TIME;
		
	for(new i = 0; i < pNum; i++)
	{
		iPlayer = Players[i];
		VoteMenu(iPlayer + TASK_VOTEMENU);
		set_task(1.0, "VoteMenu", iPlayer + TASK_VOTEMENU, _, _, "a", VOTE_TIME);
	}
	set_task(1.0, "Timer", TASK_TIMER, _, _, "a", VOTE_TIME+1);
	
	client_cmd(0, "spk Gman/Gman_Choose2");	
}
public VoteMenu(id)
{
	id -= TASK_VOTEMENU;
		
	if(g_iVoteTime == 0)
	{
		show_menu(id, 0, "^n", 1);		
		if(task_exists(id+TASK_VOTEMENU)) remove_task(id+TASK_VOTEMENU);
		return PLUGIN_HANDLED;
	}
	
	new szMenu[512], len = 0;
	
	len = formatex(szMenu[len], charsmax(szMenu) - len, "\y%s:^n^n", g_bHasVoted[id] ? "Результаты голосования" : "Выберите карту");
	
	new Key, iPercent, i, iMax = maps_in_menu();
	
	for(i = 0; i < iMax; i++)
	{		
		iPercent = 0;
		if(g_iTotal)
		{
			iPercent = floatround(g_iVoteItem[i]*100.0/g_iTotal);
		}
		
		if(!g_bHasVoted[id])
		{
			len += formatex(szMenu[len], charsmax(szMenu) - len, "\r%d.\w %s\d[\r%d%%\d]^n", i + 1, g_szInMenuMapName[i], iPercent);	
			Key |= (1 << i);		
		}
		else
		{
			len += formatex(szMenu[len], charsmax(szMenu) - len, "\d%s[\r%d%%\d]^n", g_szInMenuMapName[i], iPercent);
		}		
	}
	
	if(!g_bRockVote && get_pcvar_num(g_pTimeLimit) != 0 && g_iExtendedMax < get_pcvar_num(g_pExendedMax))
	{
		iPercent = 0;
		if(g_iTotal)
		{
			iPercent = floatround(g_iVoteItem[i]*100.0/g_iTotal);
		}
		
		if(!g_bHasVoted[id])
		{
			len += formatex(szMenu[len], charsmax(szMenu) - len, "^n\r%d.\w %s\d[\r%d%%\d]\y[Продлить]^n", i + 1, g_szCurrentMap, iPercent);	
			Key |= (1 << i);		
		}
		else
		{
			len += formatex(szMenu[len], charsmax(szMenu) - len, "^n\d%s[\r%d%%\d]\y[Продлить]^n", g_szCurrentMap, iPercent);
		}
	}
	
	if(get_pcvar_num(g_pMenuStopVote) && get_user_flags(id) & ADMIN_MAP)
	{
		i++;
		len += formatex(szMenu[len], charsmax(szMenu) - len, "^n\r%d. Отменить голосование^n", i + 1 == 10 ? 0 : i + 1);
		Key |= (1 << i);
	}
	
	new szSec[16]; get_ending(g_iVoteTime, "секунд", "секунда", "секунды", szSec, charsmax(szSec));
	len += formatex(szMenu[len], charsmax(szMenu) - len, "^n\dОсталось \r%d\d %s", g_iVoteTime, szSec);
	
	if(!Key) Key |= (1 << 9);
	
	if(g_bHasVoted[id] && get_pcvar_num(g_pShowResultType) == 1)
	{
		while(replace(szMenu, charsmax(szMenu), "\r", "")){}
		while(replace(szMenu, charsmax(szMenu), "\d", "")){}
		while(replace(szMenu, charsmax(szMenu), "\w", "")){}
		while(replace(szMenu, charsmax(szMenu), "\y", "")){}
		
		set_hudmessage(HUD_RESULT_COLOR, 0.02, -1.0, 0, 6.0, 1.0, 0.1, 0.2, 4);
		show_hudmessage(id, "%s", szMenu);
	}
	else
	{
		show_menu(id, Key, szMenu, -1, "Vote_Menu");
	}
	
	return PLUGIN_HANDLED;
}
public VoteMenu_Handler(id, key)
{
	if(g_bHasVoted[id])
	{
		VoteMenu(id + TASK_VOTEMENU);
		return PLUGIN_HANDLED;
	}	
	if(get_pcvar_num(g_pMenuStopVote) && key == maps_in_menu() + 1)
	{
		Command_StopVote(id, ADMIN_MAP);
		return PLUGIN_HANDLED;
	}
	
	g_iVoteItem[key]++;
	g_iTotal++;
	
	g_bHasVoted[id] = true;
	
	new iCvar = get_pcvar_num(g_pShowSelects);
	if(iCvar)
	{
		new szName[32];
		get_user_name(id, szName, charsmax(szName));
		if(key == maps_in_menu())
		{
			switch(iCvar)
			{
				case 1:	client_print_color(0, id, "^4%s^1 ^3%s^1 выбрал продление карты.", PREFIX, szName);
				case 2: client_print_color(id, DontChange, "^4%s^1 Вы выбрали продление карты.", PREFIX);
			}
		}
		else
		{
			switch(iCvar)
			{
				case 1:	client_print_color(0, id, "^4%s^3 %s^1 выбрал^3 %s^1.", PREFIX, szName, g_szInMenuMapName[key]);
				case 2: client_print_color(id, DontChange, "^4%s^1 Вы выбрали^3 %s^1.", PREFIX, g_szInMenuMapName[key]);
			}
		}
	}

	if(get_pcvar_num(g_pShowResultAfterVote))
	{
		VoteMenu(id + TASK_VOTEMENU);
	}
	else
	{
		if(task_exists(id + TASK_VOTEMENU)) remove_task(id + TASK_VOTEMENU);
	}

	return PLUGIN_HANDLED;
}
public Timer()
{
	if(--g_iVoteTime == 0)
	{
		FinishVote();
		show_menu(0, 0, "^n", 1);		
		if(task_exists(TASK_TIMER)) remove_task(TASK_TIMER);
	}
}
FinishVote()
{
	new MaxVote = 0, iInMenu = maps_in_menu(), iRandom;
	new iMax = g_bRockVote ? iInMenu : iInMenu + 1;
	for(new i = 1; i < iMax ; i++)
	{
		iRandom = random_num(0, 1);
		switch(iRandom)
		{
			case 0: if(g_iVoteItem[MaxVote] < g_iVoteItem[i]) MaxVote = i;
			case 1: if(g_iVoteItem[MaxVote] <= g_iVoteItem[i]) MaxVote = i;
		}
	}
	
	g_bBeInVote = false;
	g_bVoteFinished = true;
	
	if(!g_iTotal || (MaxVote != iInMenu))
	{
		if(g_iTotal)
		{
			client_print_color(0, Blue, "^4%s^1 Следующая карта:^3 %s^1.", PREFIX, g_szInMenuMapName[MaxVote]);
		}
		else
		{
			MaxVote = random_num(0, iInMenu - 1);
			client_print_color(0, Blue, "^4%s^1 Никто не голосовал. Следуйщей будет^3 %s^1.", PREFIX, g_szInMenuMapName[MaxVote]);
		}
	
		set_pcvar_string(g_pNextMap, g_szInMenuMapName[MaxVote]);
		
		if(g_bRockVote && get_pcvar_num(g_pRockChange) == 0 || get_pcvar_num(g_pChangeMap) == 0)
		{
			client_print_color(0, DontChange, "^4%s^1 Карта сменится через^3 10^1 секунд.", PREFIX);
			set_task(10.0, "ChangeLevel", TASK_CHANGELEVEL);
			if(get_pcvar_num(g_pDebug))
			{
				log_to_file("mapmanager_debug.log", "FINISH_VOTE: ChangeLevel");
			}
		}
		else if(g_bRockVote && get_pcvar_num(g_pRockChange) == 1 || get_pcvar_num(g_pChangeMap) == 1)
		{
			client_print_color(0, DontChange, "^4%s^1 Карта сменится в следующем раунде.", PREFIX);
		}
	}
	else
	{
		g_bVoteFinished = false;
		g_iExtendedMax++;
		new iMin = get_pcvar_num(g_pExendedTime);
		new szMin[16]; get_ending(iMin, "минут", "минута", "минуты", szMin, charsmax(szMin));
		
		client_print_color(0, DontChange, "^4%s^1 Текущая карта продлена на^3 %d^1 %s.", PREFIX, iMin, szMin);
		set_cvar_num("mp_timelimit", get_pcvar_num(g_pTimeLimit) + iMin);
	}
	
	new iRet;
	ExecuteForward(g_iForwardFinishVote, iRet);
}
public ChangeLevel()
{
	new szMap[33]; get_pcvar_string(g_pNextMap, szMap, charsmax(szMap));
	server_cmd("changelevel %s", szMap);
}
public SoundTimer()
{
	set_task(1.0, "Show_Timer2", TASK_SHOWTIMER, _, _, "a", 10);
}
public Show_Timer2()
{
	static iTimer; if(iTimer == 0) iTimer = 10;
	
	new szSec[16]; get_ending(iTimer, "секунд", "секунда", "секунды", szSec, charsmax(szSec));
	
	for(new i = 1; i <= 32; i++)
	{
		if(!is_user_connected(i)) continue;
		set_hudmessage(50, 255, 50, -1.0, is_user_alive(i) ? 0.9 : 0.3, 0, 0.0, 1.0, 0.0, 0.0, 1);
		show_hudmessage(i, "До смены карты осталось %d %s!", iTimer, szSec);
	}
	
	client_cmd(0, "spk %s", g_szSound[iTimer--]);
}
//*****  *****//
bool:valid_map(map[])
{
	if(is_map_valid(map)) return true;
	
	new len = strlen(map) - 4;
	
	if(len < 0) return false;
	
	if(equali(map[len], ".bsp"))
	{
		map[len] = '^0';		
		if(is_map_valid(map)) return true;
	}
	
	return false;
}
bool:in_maps_array(map[])
{
	new szMap[33], iMax = ArraySize(g_iMapsArray);
	for(new i = 0; i < iMax; i++)
	{
		ArrayGetString(g_iMapsArray, i, szMap, charsmax(szMap));
		if(equali(szMap, map))
		{
			return true;
		}
	}
	return false;
}
get_blocked_maps()
{
	new iCount = 0;
	for(new i = 0; i < MAP_BLOCK; i++)
	{
		if(g_BlockedMaps[i][COUNT]) iCount++;
	}
	return iCount;
}
clear_blocked_maps()
{
	for(new i = 0; i < MAP_BLOCK; i++)
	{
		g_BlockedMaps[i][MAP] = "";
		g_BlockedMaps[i][COUNT] = 0;
	}
	delete_file(FILE_BLOCKEDMAPS);
}
get_blocked_map_count(map[])
{
	for(new i = 0; i < MAP_BLOCK; i++)
	{
		if(equali(g_BlockedMaps[i][MAP], map)) return g_BlockedMaps[i][COUNT];
	}
	return 0;
}
clear_nominated_maps(id)
{
	new Data[NOMINATE_DATA];
	for(new i = 0; i < ArraySize(g_iNominateArray); i++)
	{
		ArrayGetArray(g_iNominateArray, i, Data);
		if(Data[PLAYER] == id)
		{
			ArrayDeleteItem(g_iNominateArray, i--);	
			if(!--g_iNominatedMaps[id]) break;
		}
	}
}
remove_nominated_map(id, map[])
{
	new Data[NOMINATE_DATA], iMax = ArraySize(g_iNominateArray);
	for(new i = 0; i < iMax; i++)
	{
		ArrayGetArray(g_iNominateArray, i, Data);
		if(Data[PLAYER] == id && equali(Data[MAP], map))
		{
			new szName[32]; get_user_name(id, szName, charsmax(szName));
			g_iNominatedMaps[id]--;
			ArrayDeleteItem(g_iNominateArray, i);
			client_print_color(0, Blue, "^4%s^3 %s^1 убрал номинацию с карты^3 %s^1.", PREFIX, szName, map);
			break;
		}
	}	
}
is_map_nominated(map[])
{
	new Data[NOMINATE_DATA], iMax = ArraySize(g_iNominateArray);
	for(new i = 0; i < iMax; i++)
	{
		ArrayGetArray(g_iNominateArray, i, Data);
		if(equali(Data[MAP], map)) return Data[PLAYER];
	}			
	return 0;
}
bool:in_menu(num)
{
	for(new i = 0; i < SELECT_MAPS && i < 8; i++)
	{
		if(num == g_iInMenu[i]) return true;
	}
	return false;
}
bool:is_blocked(num)
{
	new szMap[33]; ArrayGetString(g_iMapsArray, num, szMap, charsmax(szMap));	
	for(new i = 0; i < MAP_BLOCK; i++)
	{
		if(equali(g_BlockedMaps[i][MAP], szMap)) return true;
	}
	return false;
}
maps_in_menu()
{
	new map;
	for(new i = 0; i < SELECT_MAPS; i++)
	{
		if(g_iInMenu[i] != -1) map++;
	}
	return map;
}
stock get_players_num()
{
	new iPlayers = 0, iMax = get_maxplayers();
	for(new id = 1; id < iMax; id++)
	{
		if(is_user_connected(id) && !is_user_bot(id) && !is_user_hltv(id)) iPlayers++;
	}
	return iPlayers;
}
stock get_ending(num, const a[], const b[], const c[], output[], lenght)
{
	new num100 = num % 100, num10 = num % 10;
	if(num100 >=5 && num100 <= 20 || num10 == 0 || num10 >= 5 && num10 <= 9) format(output, lenght, "%s", a);
	else if(num10 == 1) format(output, lenght, "%s", b);
	else if(num10 >= 2 && num10 <= 4) format(output, lenght, "%s", c);
}