Код:
/* neygomon created ^_^ | http://www.neugomon.ru Original Code: AMXX Dev Team */ #include <amxmodx> #define SELECTMAPS 5 // Количество карт в голосовании. Не ставить больше 8! #define BLOCK_MAPS 10 // Количество последних сыгранных карт, которые не будут выставлены на голосование. #define MAX_NUMEXTEND 3 // Максимальное число продлений #define STEP_EXTEND 15 // Время продления [В минутах] #define VOTETIME 10 // Время голосования. #define RTV_FUNC // Функция досрочного голосования. Закоментируйте, если не требуется;) #if defined RTV_FUNC #define RTV_DELAY 180 // Через какое время от начала карты можно пользоваться функцией rtv. [В секундах... 60 = 1 минута] #define RTV_PERCENT 60 // Сколько процентов надо набрать, чтобы запустить досрочную смену карты. #endif //#define NOMINATE_FUNC // Функция номинации карт. Раскомментируйте если требуется;) #if defined NOMINATE_FUNC #define MAX_NOMINATE 3 // Максимум карт для номинации #define MAX_NOMINATE_PL 1 // Максимум карт для номинации ОДНИМ игроком //#define MAPSMENU // Команда /maps в чате. Работает только при #define NOMINATE_FUNC #endif //#define NOROUND // Поддержка бесконечных раундов. Аля CSDM, GunGame сервера //#define AMXRTV // Включает команду amx_rtv #define SCREENFADE // Затемнять экран на время голосование(плавно :D) #define MAP_ON_PLAYERS // Показывать карты в зависимости от онлайна #define MAX_MAPS 1024 // Максимум карт. Если надо, укажите больше. Но я б не стал... #if defined NOMINATE_FUNC new g_iNomMap[33], g_iIdMapNom[MAX_NOMINATE+1], g_iCountNom; new g_sNomMap[MAX_NOMINATE+1][32]; #endif #if defined MAPSMENU new g_iMapsMenu; #endif new g_sVoteMap[SELECTMAPS+2][32], g_iMapInMenu[SELECTMAPS+1], g_iVoteCount[SELECTMAPS + 2]; new g_sLastMap[BLOCK_MAPS+1][32], g_iLastMap = 1; new g_sMap[MAX_MAPS][32]; #if defined MAP_ON_PLAYERS new g_MapPlayerData[MAX_MAPS][3]; #endif new g_iVoteMapNum, g_iMapCount; new g_NextMap[32], g_sCurMap[32]; new bool:g_bVoteStarted, bool:g_bBeInVote, bool:g_bBlockExtended; new g_pTimeLimit, g_oldTimeLimit, g_iTempTimelimit; new g_pMaxSpeed, g_oldMaxSpeed; #if !defined NOROUND new g_pRoundTime, g_pC4Timer; #endif new g_iStartMap; #if defined RTV_FUNC new bool:g_bRockVoted[33], g_iRockVote; #endif new const g_szSound[][] = { "", "fvox/one", "fvox/two", "fvox/three" }; #define IsMapValidOnPlayers(%0,%1) (g_MapPlayerData[%0][1] <= %1 <= g_MapPlayerData[%0][2]) public plugin_init() { #define VERSION "2.6" register_plugin("Lite MapChooser", VERSION, "neygomon"); register_cvar("lite_chooser", VERSION, FCVAR_SERVER | FCVAR_SPONLY); register_menucmd(register_menuid("MapChoose"), (-1^(-1<<(SELECTMAPS+2))), "votemenu_handler") #if !defined NOROUND register_event("HLTV", "eRoundStart", "a", "1=0", "2=0"); #endif #if defined RTV_FUNC register_clcmd("say rtv", "clcmd_RockVote"); register_clcmd("say /rtv", "clcmd_RockVote"); #endif #if defined MAPSMENU register_clcmd("say /maps", "clcmd_Maps"); register_clcmd("say_team /maps", "clcmd_Maps"); #endif #if defined NOMINATE_FUNC register_clcmd("say", "clcmd_Say"); #endif #if defined AMXRTV register_concmd("amx_rtv", "concmd_StartVote", ADMIN_VOTE); #endif register_clcmd("say ff", "clcmd_FF"); register_clcmd("say nextmap", "clcmd_NextMap"); register_clcmd("say timeleft", "clcmd_TimeLeft"); register_clcmd("say thetime", "clcmd_TheTime"); g_pTimeLimit = get_cvar_pointer("mp_timelimit"); g_pMaxSpeed = get_cvar_pointer("sv_maxspeed"); #if !defined NOROUND g_pRoundTime = get_cvar_pointer("mp_roundtime"); g_pC4Timer = get_cvar_pointer("mp_c4timer"); #endif g_iStartMap = get_systime(); } public plugin_end() { if(g_oldTimeLimit) set_pcvar_num(g_pTimeLimit, g_oldTimeLimit); } public plugin_cfg() { #if defined MAPSMENU g_iMapsMenu = menu_create("\d[\rNominate\d] \yВыберите карту\w", "mapsmenu_handler"); menu_setprop(g_iMapsMenu, MPROP_EXITNAME, "Выход"); menu_setprop(g_iMapsMenu, MPROP_NEXTNAME, "Далее"); menu_setprop(g_iMapsMenu, MPROP_BACKNAME, "Назад"); #endif get_mapname(g_sCurMap, charsmax(g_sCurMap)); LoadBlockMaps(); LoadMaps(); // грузим мапы. set_task(15.0, "CheckTime", .flags="b"); } #if defined RTV_FUNC public client_disconnect(id) { if(!g_bRockVoted[id]) return; g_bRockVoted[id] = false; g_iRockVote--; } #endif #if defined AMXRTV public concmd_StartVote(id, flag) { if(id) { if(!IsValidRtv(id)) return PLUGIN_HANDLED; if(~get_user_flags(id) & flag) return console_print(id, "У вас недостаточно прав для использования этой команды!"); } if(g_bVoteStarted) return console_print(id, "[MM] VoteMap has already started"); console_print(id, "[MM] VoteMap started in new round!"); new name[32]; get_user_name(id, name, charsmax(name)); ChatColor(0, "^1[^4MM^1] ^4Администратор ^3%s ^4запустил ^3досрочное ^4голосование!", name); log_amx("Администратор %s запустил досрочное голосование", name); #if defined NOROUND StartVoteMap(); g_bBlockExtended = true; #else g_bVoteStarted = g_bBlockExtended = true; hud_lastround(); #endif return PLUGIN_HANDLED; } #endif public clcmd_FF(id) { ChatColor(id, "^1[^4MM^1] ^4На сервере ^3%s ^4огонь по своим.", get_cvar_num("mp_friendlyfire") ? "разрешен" : "запрещен"); return PLUGIN_HANDLED; } public clcmd_TheTime(id) { static time[64]; get_time ("%Y/%m/%d - %H:%M:%S", time, charsmax(time)); ChatColor(id, "^1[^4MM^1] ^4Текущее время: ^3 %s", time); return PLUGIN_HANDLED; } public clcmd_NextMap(id) { ChatColor(id, "^1[^4MM^1] ^4Следующая карта еще ^3не определена ^1:("); return PLUGIN_HANDLED; } public clcmd_TimeLeft(id) { static a; a = get_timeleft(); if(a > 0) ChatColor(id, "^1[^4MM^1] ^4До конца карты осталось: ^3%d:%02d", (a / 60), (a % 60)); else ChatColor(id, "^1[^4MM^1] ^4Карта ^3не ограничена ^4по времени."); return PLUGIN_HANDLED; } #if defined RTV_FUNC public clcmd_RockVote(id) { if(g_bVoteStarted || g_bBeInVote || !IsValidRtv(id)) return PLUGIN_HANDLED; static iVote; if(!g_bRockVoted[id]) { g_bRockVoted[id] = true; if((iVote = floatround(get_playersnum() * RTV_PERCENT / 100.0, floatround_round) - ++g_iRockVote) > 0) { static szName[32]; get_user_name(id, szName, charsmax(szName)); ChatColor(0, "^1[^4MM^1] ^3%s ^4проголосовал за смену карты. Осталось голосов: ^3%d", szName, iVote); log_amx("%s проголосовал за смену карты. Осталось: %d голосов.", szName, iVote); } else { #if defined NOROUND StartVoteMap(); g_bBlockExtended = true; #else g_bVoteStarted = g_bBlockExtended = true; hud_lastround(); #endif ChatColor(0, "^1[^4MM^1] ^4Все голоса за досрочную смену карты набраны."); } } else ChatColor(id, "^1[^4MM^1] ^4Вы уже голосовали!"); return PLUGIN_HANDLED; } #endif #if defined NOMINATE_FUNC public clcmd_Say(id) { if(g_bVoteStarted || g_bBeInVote) return PLUGIN_CONTINUE; static szMessage[36]; read_args(szMessage, charsmax(szMessage)); remove_quotes(szMessage); return CheckValidMap(id, szMessage); } #if defined MAPSMENU public clcmd_Maps(id) { if(!g_bVoteStarted && !g_bBeInVote) menu_display(id, g_iMapsMenu, 0); return PLUGIN_HANDLED; } public mapsmenu_handler(id, menu, item) { if(item == MENU_EXIT) return PLUGIN_HANDLED; new _access, item_data[1], item_name[32], callback; menu_item_getinfo(menu, item, _access, item_data, charsmax(item_data), item_name, charsmax(item_name), callback); CheckValidMap(id, item_name); return PLUGIN_HANDLED; } #endif CheckValidMap(id, map[]) { static i; if(_is_map_blocked(map)) return ChatColor(id, "^1[^4MM^1] ^4Эту карту ^3недавно ^4играли!"); else if(_is_map_nominated(map)) return ChatColor(id, "^1[^4MM^1] ^4Эта карта уже номинирована!"); else if((i = _is_map_loaded(map)) != -1) { if(g_iNomMap[id] == MAX_NOMINATE_PL) return ChatColor(id, "^1[^4MM^1] ^4Вы больше ^3не можете ^4номинировать карт!"); else if(g_iCountNom == MAX_NOMINATE) return ChatColor(id, "^1[^4MM^1] ^4Уже номинировано ^3максимальное ^4число карт!"); #if defined MAP_ON_PLAYERS else if(!IsMapValidOnPlayers(i, get_playersnum())) return ChatColor(id, "^1[^4MM^1] ^4Карта ^3не подходит ^4для текущего онлайна!"); #endif else { g_iIdMapNom[g_iCountNom] = i; copy(g_sNomMap[g_iCountNom], charsmax(g_sNomMap[]), map); g_iNomMap[id]++; g_iCountNom++; static szName[32]; get_user_name(id, szName, charsmax(szName)); return ChatColor(0, "^1[^4MM^1] ^3%s ^4номинировал на голосование^3 %s^1.", szName, map); } } return PLUGIN_CONTINUE; } #endif #if !defined NOROUND public eRoundStart() { if(!g_bVoteStarted) return; g_bVoteStarted = false; StartVoteMap(); } #endif StartVoteMap() { if(!g_oldMaxSpeed) g_oldMaxSpeed = get_pcvar_num(g_pMaxSpeed); set_pcvar_num(g_pMaxSpeed, 0); #if defined SCREENFADE ScreenFade(1); #endif set_task(1.0, "ShowTimer", _, _ , _, "a", 3); set_task(4.0, "voteNextMap"); } public CheckTime() { if(g_bVoteStarted || g_bBeInVote) return; static iTimeLeft, iTimeLimit; iTimeLeft = get_timeleft(); iTimeLimit = get_pcvar_num(g_pTimeLimit); if(iTimeLeft < 30 && iTimeLimit) { g_iTempTimelimit = iTimeLimit; #if defined NOROUND StartVoteMap(); #else g_bVoteStarted = true; if(!g_oldTimeLimit) g_oldTimeLimit = iTimeLimit; set_pcvar_num(g_pTimeLimit, iTimeLimit + get_pcvar_num(g_pRoundTime) + get_pcvar_num(g_pC4Timer)); hud_lastround(); #endif } } public ShowTimer() { static iTimer; if(!iTimer) iTimer = 3; set_hudmessage(50, 255, 50, -1.0, 0.6, 0, 0.0, 1.0, 0.0, 0.0, 1); show_hudmessage(0, "До голосования осталось %d сек!", iTimer); client_cmd(0, "spk %s", g_szSound[iTimer--]); } public voteNextMap() { g_bBeInVote = true; static szMenu[256], iLen, iKeys, a, iMaxMaps, iTempMapTime; if(!iTempMapTime) iTempMapTime = g_iTempTimelimit + MAX_NUMEXTEND * STEP_EXTEND; if(!iMaxMaps) iMaxMaps = (g_iMapCount - 1 < SELECTMAPS) ? g_iMapCount - 1 : SELECTMAPS; iLen = formatex(szMenu, charsmax(szMenu), "\d[\rMap to Choose\d] \yВыберите карту^n^n"); #if defined MAP_ON_PLAYERS new x, players = get_playersnum(); #endif g_iVoteMapNum = iKeys = 0; while(g_iVoteMapNum < iMaxMaps) { #if defined NOMINATE_FUNC if(g_iVoteMapNum < g_iCountNom) { g_iMapInMenu[g_iVoteMapNum] = g_iIdMapNom[g_iVoteMapNum]; copy(g_sVoteMap[g_iVoteMapNum], charsmax(g_sVoteMap[]), g_sMap[g_iIdMapNom[g_iVoteMapNum]]); iLen += formatex(szMenu[iLen], charsmax(szMenu) - iLen, "\r%d. \w%s^n", g_iVoteMapNum+1, g_sVoteMap[g_iVoteMapNum]); iKeys |= (1<<g_iVoteMapNum++); continue; } #endif do a = random(g_iMapCount - 1); while(_is_map_in_menu(a)); g_iMapInMenu[g_iVoteMapNum] = a; #if defined MAP_ON_PLAYERS if(!IsMapValidOnPlayers(a, players)) { if(++x < g_iMapCount) continue; else break; } #endif copy(g_sVoteMap[g_iVoteMapNum], charsmax(g_sVoteMap[]), g_sMap[a]); iLen += formatex(szMenu[iLen], charsmax(szMenu) - iLen, "\r%d. \w%s^n", g_iVoteMapNum+1, g_sVoteMap[g_iVoteMapNum]); iKeys |= (1<<g_iVoteMapNum++); } if(g_iTempTimelimit < iTempMapTime && !g_bBlockExtended) { formatex(szMenu[iLen], charsmax(szMenu) - iLen, "^n\r%d. \w%s \d[\rПродлить\d]", g_iVoteMapNum+1, g_sCurMap); iKeys |= (1<<g_iVoteMapNum); } show_menu(0, iKeys, szMenu, VOTETIME, "MapChoose"); set_task(float(VOTETIME), "checkVotes"); client_cmd(0, "spk Gman/Gman_Choose2"); log_amx("Vote: Voting for the nextmap started"); return PLUGIN_HANDLED; } public votemenu_handler(id, iKey) { static szName[32]; get_user_name(id, szName, charsmax(szName)); if(iKey == g_iVoteMapNum) ChatColor(0, "^1[^4MM^1] ^4Игрок ^3%s ^4выбрал ^3продление карты", szName); else ChatColor(0, "^1[^4MM^1] ^4Игрок ^3%s ^4выбрал карту ^3%s", szName, g_sVoteMap[iKey]); return g_iVoteCount[iKey]++; } public checkVotes() { new b; for(new a; a < SELECTMAPS+1; a++) if(g_iVoteCount[b] < g_iVoteCount[a]) b = a; if(!g_iVoteCount[b]) { new map = random(g_iVoteMapNum-1); ChatColor(0, "^1[^4MM^1] ^4Никто ^3не проголосовал! ^4Cлучайная карта ^3%s", g_sVoteMap[map]); log_amx("[End VoteMap] Nobody voted for the nextmap. Random map %s", g_sVoteMap[map]); copy(g_NextMap, charsmax(g_NextMap), g_sVoteMap[map]); ChangeLevel(); } else if(g_iVoteCount[b] == g_iVoteCount[g_iVoteMapNum]) { set_pcvar_num(g_pTimeLimit, g_iTempTimelimit + STEP_EXTEND); ChatColor(0, "^1[^4MM^1] ^4Голосование ^3завершено! ^4Карта продлена на ^3%d ^4минут.", STEP_EXTEND); log_amx("[End VoteMap] Voting for the nextmap finished. Map %s extended by %d minutes", g_sCurMap, STEP_EXTEND); g_bBeInVote = false; arrayset(g_iVoteCount, 0, SELECTMAPS + 2); #if defined NOMINATE_FUNC g_iCountNom = 0; arrayset(g_iNomMap, 0, 33); arrayset(g_iIdMapNom, 0, MAX_NOMINATE+1); for(new i; i < MAX_NOMINATE+1; i++) g_sNomMap[i][0] = 0; #endif #if defined SCREENFADE ScreenFade(0); #endif } else { ChatColor(0, "^1[^4MM^1] ^4Голосование ^3завершено! ^4Cледующая карта: ^3%s", g_sVoteMap[b]); log_amx("[End VoteMap] Voting for the nextmap finished. The nextmap will be %s", g_sVoteMap[b]); copy(g_NextMap, charsmax(g_NextMap), g_sVoteMap[b]); ChangeLevel(); } set_pcvar_num(g_pMaxSpeed, g_oldMaxSpeed); } #define FILE_BLOCKEDMAPS "addons/amxmodx/data/mm_last.ini" LoadBlockMaps() { copy(g_sLastMap[0], charsmax(g_sLastMap[]), g_sCurMap); if(file_exists(FILE_BLOCKEDMAPS)) { new buff[256], fp = fopen(FILE_BLOCKEDMAPS, "rt"); while(g_iLastMap < BLOCK_MAPS && !feof(fp)) { fgets(fp, buff, charsmax(buff)); if(buff[0] != ';' && parse(buff, g_sLastMap[g_iLastMap], charsmax(g_sLastMap[]))) g_iLastMap++; } fclose(fp); unlink(FILE_BLOCKEDMAPS); } if(write_file(FILE_BLOCKEDMAPS, "; File generated by Lite Mapchooser. Do not modify!")) for(new i; i < g_iLastMap; i++) write_file(FILE_BLOCKEDMAPS, g_sLastMap[i]); } LoadMaps() { new buff[256], fp = fopen("addons/amxmodx/configs/maps.ini", "rt"); if(!fp) set_fail_state("File ^"addons/amxmodx/configs/maps.ini^" not found"); #if defined MAP_ON_PLAYERS new minpl[3], maxpl[3]; #endif while(!feof(fp) && g_iMapCount < MAX_MAPS) { fgets(fp, buff, charsmax(buff)); trim(buff); remove_quotes(buff); if(!buff[0] || buff[0] == ';') continue; #if defined MAP_ON_PLAYERS if(parse(buff, g_sMap[g_iMapCount], charsmax(g_sMap[]), minpl, charsmax(minpl), maxpl, charsmax(maxpl))) #else if(parse(buff, g_sMap[g_iMapCount], charsmax(g_sMap[]))) #endif { if(!is_map_valid(g_sMap[g_iMapCount]) || _is_map_blocked(g_sMap[g_iMapCount]) || !strcmp(g_sMap[g_iMapCount], g_sCurMap)) continue; #if defined MAP_ON_PLAYERS g_MapPlayerData[g_iMapCount][1] = str_to_num(minpl); g_MapPlayerData[g_iMapCount][2] = str_to_num(maxpl); #endif #if defined MAPSMENU menu_additem(g_iMapsMenu, g_sMap[g_iMapCount]); #endif g_iMapCount++; } } fclose(fp); if(!g_iMapCount) set_fail_state("[Load Maps] Nothing loaded. Plugin stopped!"); else if(g_iMapCount == 1) set_fail_state("[Load Maps] Critical loaded maps. Add maps in ^"addons/amxmodx/configs/maps.ini^". Plugin stopped!"); else if(g_iMapCount < SELECTMAPS) log_to_file("lite_mapchooser.log", "[Load Maps] WARNING! Too little maps for voting! [Load: %d / Min: %d]", g_iMapCount, SELECTMAPS); } bool:_is_map_in_menu(MapId) { for(new i; i < g_iVoteMapNum; i++) if(g_iMapInMenu[i] == MapId) return true; return false; } bool:_is_map_blocked(map[]) { for(new i; i < g_iLastMap; i++) if(!strcmp(g_sLastMap[i], map)) return true; return false; } #if defined NOMINATE_FUNC bool:_is_map_nominated(map[]) { for(new i; i < g_iCountNom; i++) if(!strcmp(g_sNomMap[i], map)) return true; return false; } _is_map_loaded(map[]) { for(new i; i < g_iMapCount; i++) if(!strcmp(g_sMap[i], map)) return i; return -1; } #endif ChangeLevel() { message_begin(MSG_ALL, SVC_INTERMISSION); message_end(); set_task(3.0, "NextMap"); } public NextMap() server_cmd("changelevel %s", g_NextMap); #if defined SCREENFADE public ScreenFade(fade) { static time, hold, flags, mScreenFade; if(!mScreenFade) mScreenFade = get_user_msgid("ScreenFade"); time = (0 <= fade <= 1) ? 4096 : 1; hold = (0 <= fade <= 1) ? 1024 : 1; switch(fade) { case 0: { flags = 2; set_msg_block(mScreenFade, BLOCK_NOT); } case 1: { flags = 1; set_task(1.0, "ScreenFade", 2); } case 2: { flags = 4; set_msg_block(mScreenFade, BLOCK_SET); } } message_begin(MSG_BROADCAST, mScreenFade); write_short(time); write_short(hold); write_short(flags); write_byte(0); write_byte(0); write_byte(0); write_byte(255); message_end(); } #endif stock hud_lastround() { set_hudmessage(127, 127, 127, 0.02, 0.21, 0, 30.0, 30.0, 0.0, 0.5, 3); show_hudmessage(0, "Последний раунд"); } stock IsValidRtv(const id) { static estimated_time; estimated_time = (get_systime() - g_iStartMap); if(RTV_DELAY > estimated_time) { static frmt[129], temp, _time; _time = (temp = ((RTV_DELAY - estimated_time) / 60)) < 1 ? 0 : temp; if(!_time) formatex(frmt, charsmax(frmt), "^4Досрочная смена карты будет доступна менее, чем через ^3минуту!"); else formatex(frmt, charsmax(frmt), "^4Досрочная смена карты будет доступна через ^3%d ^4мин!", _time); ChatColor(id, "^1[^4MM^1] %s", frmt); return 0; } return 1; } stock ChatColor(const id, const szMessage[], any:...) { static pnum, players[32], szMsg[190], IdMsg; vformat(szMsg, charsmax(szMsg), szMessage, 3); if(!IdMsg) IdMsg = get_user_msgid("SayText"); if(id) { if(!is_user_connected(id)) return 0; players[0] = id; pnum = 1; } else get_players(players, pnum, "ch"); for(new i; i < pnum; i++) { message_begin(MSG_ONE, IdMsg, .player = players[i]); write_byte(players[i]); write_string(szMsg); message_end(); } return 1; }