Code:
#include <amxmodx>
#define DELAYED_START 5 // After how many you can change the card / vote. 0 - disable
#define MAX_NOMINATE_MAP 4 // Maximum number of cards in the nomination
#define INCLUDE_AMX_MAP // Add the command amx_map
// # define FORCE_CHANGELEVEL // Change immediately after selection (Actual for CSDM, GunGame and other noround servers)
// Comment out if you dont want the map to change at the beginning of the round
enum _:MENUS
{
CHANGEMAP,
VOTEMAP
}
enum _:st
{
None,
Select,
Voting,
Changelevel
}
new g_stMenus;
enum _:DATA { Menu, Pos, MenuId, MenuIdAccept, Insider, nNum, Votes[MAX_NOMINATE_MAP + 1], Nominated[MAX_NOMINATE_MAP + 1], NewMap[32] }
new g_iMapsMenu[DATA];
new Array:g_aMaps;
new g_iMapsCount;
#if DELAYED_START > 0
new g_iStartMap;
#endif
#if AMXX_VERSION_NUM < 183
#include <colorchat>
#define engine_changelevel(%0) server_cmd("changelevel %s", %0)
#endif
public plugin_init()
{
register_plugin("Maps Menu", "1", "unknown");
register_clcmd("amx_mapmenu", "CmdMapMenu", ADMIN_MAP);
register_clcmd("amx_votemapmenu", "CmdVoteMapMenu", ADMIN_VOTE);
register_concmd("amx_votemap", "CmdAmxVote", ADMIN_VOTE);
#if defined INCLUDE_AMX_MAP
register_concmd("amx_map", "CmdAmxMap", ADMIN_MAP);
#endif
g_iMapsMenu[MenuId] = register_menuid("Maps Menu");
g_iMapsMenu[MenuIdAccept] = register_menuid("Accept Menu");
register_menucmd(g_iMapsMenu[MenuId], 1023, "mapsmenu_handler");
register_menucmd(g_iMapsMenu[MenuIdAccept], MENU_KEY_1|MENU_KEY_2, "acceptmenu_handler");
register_menucmd(register_menuid("Vote Map"), (-1^(-1<<(MAX_NOMINATE_MAP+1))), "votemap_handler");
#if !defined FORCE_CHANGELEVEL
register_event("HLTV", "eRoundStart", "a", "1=0", "2=0");
#endif
#if DELAYED_START > 0
g_iStartMap = get_systime();
#endif
}
public plugin_cfg()
{
g_aMaps = ArrayCreate(32);
new fp = fopen("addons/amxmodx/configs/maps.ini", "rt");
if(!fp) set_fail_state("Map file not found!");
new szMapName[32], buff[32];
while(!feof(fp))
{
fgets(fp, buff, charsmax(buff));
remove_quotes(buff); trim(buff);
if(buff[0] && buff[0] != ';' && parse(buff, szMapName, charsmax(szMapName)) && is_map_valid(szMapName))
ArrayPushString(g_aMaps, szMapName);
}
fclose(fp);
g_iMapsCount = ArraySize(g_aMaps);
if(!g_iMapsCount)
set_fail_state("Maps not found");
}
public plugin_end()
ArrayDestroy(g_aMaps);
#if !defined FORCE_CHANGELEVEL
public eRoundStart()
if(g_stMenus == Changelevel && g_iMapsMenu[NewMap][0])
engine_changelevel(g_iMapsMenu[NewMap]);
#endif
public CmdMapMenu(id, flags)
return PreOpenMenu(id, flags, CHANGEMAP);
public CmdVoteMapMenu(id, flags)
return PreOpenMenu(id, flags, VOTEMAP);
public CmdAmxVote(id, flags)
{
if(id && !IsValidChange(id, flags, 1))
return PLUGIN_HANDLED;
if(read_argc() < 2)
{
console_print(id, "* Use o comando - amx_votemap <map1> [map2] [map3] [map4]");
return PLUGIN_HANDLED;
}
g_iMapsMenu[nNum] = 0;
for(new i, x, argvmap[32], map[32]; i < MAX_NOMINATE_MAP; i++)
{
read_argv(i+1, argvmap, charsmax(argvmap));
for(x = 0; x < g_iMapsCount; x++)
{
ArrayGetString(g_aMaps, x, map, charsmax(map));
if(!strcmp(map, argvmap) && !is_map_selected(x))
{
g_iMapsMenu[Nominated][g_iMapsMenu[nNum]] = x;
g_iMapsMenu[nNum]++;
break;
}
}
}
if(!g_iMapsMenu[nNum])
console_print(id, "* The maps you have selected are not available on the server!");
else
{
g_iMapsMenu[Insider] = (id == 0) ? 33 : id;
g_stMenus = Voting;
VoteMap();
WriteLogs(id, 6);
}
return PLUGIN_HANDLED;
}
#if defined INCLUDE_AMX_MAP
public CmdAmxMap(id, flags)
{
if(id && !IsValidChange(id, flags, 0))
return PLUGIN_HANDLED;
read_argv(1, g_iMapsMenu[NewMap], charsmax(g_iMapsMenu[NewMap]));
for(new x, map[32]; x < g_iMapsCount; x++)
{
ArrayGetString(g_aMaps, x, map, charsmax(map));
if(!strcmp(g_iMapsMenu[NewMap], map))
{
if(id) WriteLogs(id, 1);
#if defined FORCE_CHANGELEVEL
engine_changelevel(g_iMapsMenu[NewMap]);
#else
if(!id) engine_changelevel(g_iMapsMenu[NewMap]);
else g_stMenus = Changelevel;
#endif
return PLUGIN_HANDLED;
}
}
console_print(id, "* The map you selected is not on the server!");
return PLUGIN_HANDLED;
}
#endif
public mapsmenu_handler(id, key)
{
switch(key)
{
case 8: BuildMenu(id, ++g_iMapsMenu[Pos]);
case 9:
{
g_iMapsMenu[Pos]--;
if(g_iMapsMenu[Pos] < 0)
ClearData();
else BuildMenu(id, g_iMapsMenu[Pos]);
}
default:
{
switch(g_iMapsMenu[Menu])
{
case CHANGEMAP:
{
ArrayGetString(g_aMaps, g_iMapsMenu[Pos] * 8 + key, g_iMapsMenu[NewMap], charsmax(g_iMapsMenu[NewMap]));
#if !defined FORCE_CHANGELEVEL
new name[32]; get_user_name(id, name, charsmax(name));
client_print_color(0, print_team_default, "^1[^4Maps^1] ^4ADMIN ^3%s ^4Chose the following map ^3%s^4. The map ^3will change at the end of the round!", name, g_iMapsMenu[NewMap]);
#else
engine_changelevel(g_iMapsMenu[NewMap]);
#endif
WriteLogs(id, 1);
g_stMenus = Changelevel;
}
case VOTEMAP:
{
if(key == 7)
{
VoteMap();
g_stMenus = Voting;
WriteLogs(id, 2);
}
else
{
g_iMapsMenu[Nominated][g_iMapsMenu[nNum]] = g_iMapsMenu[Pos] * 7 + key;
g_iMapsMenu[nNum]++;
if(g_iMapsMenu[nNum] == MAX_NOMINATE_MAP)
{
VoteMap();
g_stMenus = Voting;
WriteLogs(id, 2);
}
else BuildMenu(id, g_iMapsMenu[Pos]);
}
}
}
}
}
}
public votemap_handler(id, key)
{
g_iMapsMenu[Votes][key]++;
return PLUGIN_HANDLED;
}
public acceptmenu_handler(id, key)
{
switch(key)
{
case 0:
{
#if !defined FORCE_CHANGELEVEL
client_print_color(0, print_team_default, "^1[^4Maps^1] ^4Selected map ^3%s^4. The map ^3will change at the end of the round!", g_iMapsMenu[NewMap]);
#else
engine_changelevel(g_iMapsMenu[NewMap]);
#endif
WriteLogs(0, 3);
g_stMenus = Changelevel;
}
case 1:
{
client_print_color(0, print_team_default, "^1[^4Maps^1] ^4The result is not accepted by the administrator!");
WriteLogs(id, 4);
ClearData();
}
}
return PLUGIN_HANDLED;
}
public CheckVotes()
{
new b;
for(new a; a < g_iMapsMenu[nNum]; a++)
{
if(g_iMapsMenu[Votes][b] < g_iMapsMenu[Votes][a])
b = a;
}
if(!g_iMapsMenu[Votes][b])
{
client_print_color(0, print_team_default, "^1[^4Maps^1] ^4Voting failed. No one voted for the change.");
WriteLogs(0, 5);
ClearData();
}
else
{
ArrayGetString(g_aMaps, g_iMapsMenu[Nominated][b], g_iMapsMenu[NewMap], charsmax(g_iMapsMenu[NewMap]));
if(g_iMapsMenu[Insider] == 33)
{
#if !defined FORCE_CHANGELEVEL
client_print_color(0, print_team_default, "^1[^4Maps^1] ^4Selected map ^3%s^4. The map ^3will change at the end of the round!", g_iMapsMenu[NewMap]);
#else
engine_changelevel(g_iMapsMenu[NewMap]);
#endif
WriteLogs(0, 3);
g_stMenus = Changelevel;
}
else
{
new menu[128];
formatex(menu, charsmax(menu), "\d[\rVoteMap\d] \ySelected map \r%s^n\wAccept the result?^n^n\r1. \yYes^n\r2. \rNo", g_iMapsMenu[NewMap]);
show_menu(g_iMapsMenu[Insider], MENU_KEY_1|MENU_KEY_2, menu, -1, "Accept Menu");
}
}
}
PreOpenMenu(id, flags, menu)
{
if(id && !IsValidChange(id, flags, menu == CHANGEMAP ? 0 : 1))
return PLUGIN_HANDLED;
switch(g_stMenus) // why not?! =)
{
case Select: CheckOpenMenus(id, g_iMapsMenu[Insider], g_iMapsMenu[MenuId]);
case Voting: CheckOpenMenus(id, g_iMapsMenu[Insider], g_iMapsMenu[MenuIdAccept]);
}
switch(g_stMenus)
{
case None:
{
g_iMapsMenu[Pos] = 0;
g_iMapsMenu[Menu] = menu;
g_iMapsMenu[Insider] = id;
g_stMenus = Select;
BuildMenu(id, g_iMapsMenu[Pos]);
}
case Select:
client_print_color(id, print_team_default, "^1[^4Maps^1] ^4ADMIN ^3already chose ^4%s!", menu == VOTEMAP ? "vote" : "change");
case Voting:
client_print_color(id, print_team_default, "^1[^4Maps^1] ^4There is a vote for the next map!");
case Changelevel:
client_print_color(id, print_team_default, "^1[^4Maps^1] ^4The next map ^3is defined^4! Changing ^3в at the beginning of the round^4!");
}
return PLUGIN_HANDLED;
}
BuildMenu(id, pos)
{
new szMenu[512];
new len;
new start, end;
new keys = MENU_KEY_0;
new pages;
if(g_iMapsMenu[Menu] == CHANGEMAP)
{
start = pos * 8;
end = start + 8;
pages = (g_iMapsCount / 8 + ((g_iMapsCount % 8) ? 1 : 0));
}
else
{
start = pos * 7;
end = start + 7;
pages = (g_iMapsCount / 7 + ((g_iMapsCount % 7) ? 1 : 0));
}
if(start >= g_iMapsCount)
start = g_iMapsMenu[Pos] = 0;
if(end > g_iMapsCount)
end = g_iMapsCount;
switch(g_iMapsMenu[Menu])
{
case CHANGEMAP: len = formatex(szMenu, charsmax(szMenu), "\d[\rMaps Menu\d] ");
case VOTEMAP: len = formatex(szMenu, charsmax(szMenu), "\d[\rVoteMap Menu\d] ");
}
len += formatex(szMenu[len], charsmax(szMenu) - len, "\yPlease Select the Map\w\R%d/%d^n^n", pos + 1, pages);
for(new i = start, a, map[32]; i < end; i++)
{
ArrayGetString(g_aMaps, i, map, charsmax(map));
switch(g_iMapsMenu[Menu])
{
case CHANGEMAP:
{
keys |= (1 << a++);
len += formatex(szMenu[len], charsmax(szMenu) - len, "\r%d. \w%s^n", a, map);
}
case VOTEMAP:
{
if(is_map_selected(i))
len += formatex(szMenu[len], charsmax(szMenu) - len, "\r# \d%s \d[\ySelected\d]^n", map);
else
{
keys |= (1 << a);
len += formatex(szMenu[len], charsmax(szMenu) - len, "\r%d. \w%s^n", a+1, map);
}
a++;
}
}
}
if(g_iMapsMenu[Menu] == VOTEMAP)
{
if(g_iMapsMenu[nNum])
{
len += formatex(szMenu[len], charsmax(szMenu) - len, "^n\r8. \yBegin \wVote^n");
keys |= MENU_KEY_8;
}
else len += formatex(szMenu[len], charsmax(szMenu) - len, "^n\r# \dStart voting^n");
}
if(end != g_iMapsCount)
{
formatex(szMenu[len], charsmax(szMenu) - len, "^n\r9. \yNext^n\r0. \r%s", pos ? "Back" : "Exit");
keys |= MENU_KEY_9;
}
else formatex(szMenu[len], charsmax(szMenu) - len, "^n\r0. \r%s", pos ? "Back" : "Exit");
show_menu(id, keys, szMenu, -1, "Maps Menu");
return PLUGIN_HANDLED;
}
ClearData()
{
g_stMenus = None;
g_iMapsMenu[nNum] = 0;
g_iMapsMenu[Insider] = 0;
g_iMapsMenu[NewMap][0] = 0;
arrayset(g_iMapsMenu[Nominated], 0, sizeof g_iMapsMenu[Nominated]);
}
VoteMap()
{
new menu[300];
new len;
new keys;
switch(g_iMapsMenu[nNum])
{
case 1:
{
ArrayGetString(g_aMaps, g_iMapsMenu[Nominated][0], g_iMapsMenu[NewMap], charsmax(g_iMapsMenu[NewMap]));
len = formatex(menu, charsmax(menu), "\d[\rVoteMap\d] \yChange map to \r%s \y?^n^n", g_iMapsMenu[NewMap]);
len += formatex(menu[len], charsmax(menu) - len, "\r1. \wYes^n\r2. \wNo");
keys = MENU_KEY_1|MENU_KEY_2;
}
default:
{
len = formatex(menu, charsmax(menu), "\d[\rVoteMap\d] \ySelect a map:^n^n");
for(new i, map[32]; i < g_iMapsMenu[nNum]; i++)
{
ArrayGetString(g_aMaps, g_iMapsMenu[Nominated][i], map, charsmax(map));
len += formatex(menu[len], charsmax(menu) - len, "\r%d. \w%s^n", i+1, map);
keys |= (1 << i);
}
}
}
show_menu(0, keys, menu, 15, "Vote Map");
set_task(15.0, "CheckVotes");
}
WriteLogs(id, log)
{
new name[32];
if(id)
get_user_name(id, name, charsmax(name));
else copy(name, charsmax(name), "Server Console");
switch(log)
{
case 1: log_amx("ADMIN %s Changed the map to %s", name, g_iMapsMenu[NewMap]);
case 2: log_amx("ADMIN %s Launched a vote for %s", name, g_iMapsMenu[nNum] == 1 ? "change" : "vote");
case 3: log_amx("Voting successfully! Next map %s", g_iMapsMenu[NewMap]);
case 4: log_amx("The result of voting was not accepted by the admin %s", name);
case 5: log_amx("Voting failed, no one voted for the change");
case 6:
{
new array[190];
new len;
len = formatex(array, charsmax(array), "ADMIN %s Nominated ", name);
for(new i, map[32]; i < g_iMapsMenu[nNum]; i++)
{
ArrayGetString(g_aMaps, g_iMapsMenu[Nominated][i], map, charsmax(map));
len += formatex(array[len], charsmax(array) - len, "%s, ", map);
}
array[len - 2] = EOS;
log_amx(array);
}
}
}
bool:IsValidChange(id, flags, vote)
{
if(~get_user_flags(id) & flags)
{
console_print(id, "* [%s] Insufficient privileges to use this command!", vote ? "VoteMap" : "ChangeMap");
return false;
}
#if DELAYED_START > 0
new time = (get_systime() - g_iStartMap) / 60;
if(DELAYED_START > time)
{
client_print_color(id, print_team_default, "^1[^4Maps^1] ^3%s ^4Voting will be available in ^3%d ^4minutes", vote ? "Vote" : "Change map", DELAYED_START - time);
console_print(id, "* %s Voting will be available in %d minutes!", vote ? "Vote" : "Change map", DELAYED_START - time);
return false;
}
#endif
return true;
}
stock bool:is_map_selected(map)
{
if(g_iMapsMenu[nNum] == 0) return false;
for(new i; i < g_iMapsMenu[nNum]; i++)
{
if(g_iMapsMenu[Nominated][i] == map)
return true;
}
return false;
}
stock CheckOpenMenus(id, insider, menu)
{
if(is_user_connected(insider))
{
new oldmenu, newmenu;
player_menu_info(insider, oldmenu, newmenu);
if(menu == oldmenu)
{
new szName[32];
get_user_name(insider, szName, charsmax(szName));
console_print(id, "* ADMIN %s is using the map menu!", szName);
}
else ClearData();
}
else ClearData();
}