418 lines
12 KiB
Plaintext
418 lines
12 KiB
Plaintext
|
/* Todo:
|
||
|
* countdown
|
||
|
*/
|
||
|
#include <amxmodx>
|
||
|
#include <amxmisc>
|
||
|
|
||
|
#define MAX_NOMINATIONS 4
|
||
|
#define MAX_MAPS_IN_VOTE 6
|
||
|
#define ID_EXTEND MAX_MAPS_IN_VOTE
|
||
|
|
||
|
#define TASK_VOTE 0
|
||
|
|
||
|
new Array:g_mapName;
|
||
|
new g_mapCount;
|
||
|
|
||
|
new g_voting;
|
||
|
new Float:g_lastVoteTime;
|
||
|
|
||
|
new g_mapChoices[MAX_MAPS_IN_VOTE + 1];
|
||
|
new g_mapVoteCount[MAX_MAPS_IN_VOTE + 1];
|
||
|
new g_numChoices;
|
||
|
|
||
|
new g_countDown;
|
||
|
new g_numPlayersVoted;
|
||
|
new g_maxClients;
|
||
|
|
||
|
new const g_prefix[] = "^1[^4f0.gg^1]";
|
||
|
|
||
|
new g_nextmap[32];
|
||
|
|
||
|
new g_nomination[33] = {-1, ...};
|
||
|
new bool:g_voted[33];
|
||
|
new bool:g_rocked[33];
|
||
|
|
||
|
new CvarExtendMax, CvarExtendStep;
|
||
|
new CvarRtvWait, CvarRtvRatio;
|
||
|
new CvarTimeLimit;
|
||
|
|
||
|
public plugin_init() {
|
||
|
register_plugin("rtv", "0.1", "Flummi");
|
||
|
register_menucmd(register_menuid("MapVoteMenu"), 1023, "CountMapVote");
|
||
|
register_clcmd("say", "CmdSay");
|
||
|
CvarExtendStep = register_cvar("mapvote_extend_step", "15");
|
||
|
CvarExtendMax = register_cvar("mapvote_extend_max", "90");
|
||
|
CvarRtvWait = register_cvar("mapvote_rtv_wait", "15");
|
||
|
CvarRtvRatio = register_cvar("mapvote_rtv_ratio", "0.7");
|
||
|
CvarTimeLimit = get_cvar_pointer("mp_timelimit");
|
||
|
g_maxClients = get_maxplayers() - 1;
|
||
|
g_mapName = ArrayCreate(32);
|
||
|
g_lastVoteTime = get_gametime() - 1000;
|
||
|
loadConfigs();
|
||
|
set_task(10.0, "CheckEndOfMap", 1337, _, _, "b");
|
||
|
pause("ac", "mapchooser.amxx");
|
||
|
}
|
||
|
|
||
|
public client_disconnected(id) {
|
||
|
g_rocked[id] = false;
|
||
|
g_voted[id] = false;
|
||
|
g_nomination[id] = -1;
|
||
|
}
|
||
|
|
||
|
public CmdSay(id) {
|
||
|
new arg[72];
|
||
|
read_args(arg, charsmax(arg));
|
||
|
remove_quotes(arg);
|
||
|
|
||
|
new arg1[32], arg2[32];
|
||
|
parse(arg, arg1, charsmax(arg1), arg2, charsmax(arg2));
|
||
|
|
||
|
new mapId = arrayFindString(g_mapName, arg1);
|
||
|
if(mapId != -1) {
|
||
|
nominateMap(id, mapId);
|
||
|
return PLUGIN_HANDLED;
|
||
|
}
|
||
|
else if(equal(arg1, "/nom") || equal(arg1, "/nominate")) {
|
||
|
ShowNominationMenu(id, arg2);
|
||
|
return PLUGIN_HANDLED;
|
||
|
}
|
||
|
else if(equal(arg1, "rtv") || equal(arg1, "rockthevote")) {
|
||
|
rockTheVote(id);
|
||
|
return PLUGIN_HANDLED;
|
||
|
}
|
||
|
return PLUGIN_CONTINUE;
|
||
|
}
|
||
|
|
||
|
public ShowNominationMenu(id, const match[]) {
|
||
|
new buffer[64];
|
||
|
formatex(buffer, charsmax(buffer), "Nomination \w(search: %s)\y", match);
|
||
|
new menu = menu_create(buffer, "HandleMenuNomination");
|
||
|
for(new mapId = 0; mapId < g_mapCount; mapId++) {
|
||
|
static mapName[32];
|
||
|
ArrayGetString(g_mapName, mapId, mapName, charsmax(mapName));
|
||
|
if(contain(mapName, match) > -1 || !match[0]) {
|
||
|
static info[2];
|
||
|
formatex(buffer, charsmax(buffer), mapName);
|
||
|
if(isMapNominated(mapId))
|
||
|
add(buffer, charsmax(buffer), "\r (nominated)");
|
||
|
info[0] = mapId;
|
||
|
menu_additem(menu, buffer, info);
|
||
|
}
|
||
|
}
|
||
|
menu_setprop(menu, MPROP_NUMBER_COLOR, "\y");
|
||
|
menu_display(id, menu);
|
||
|
}
|
||
|
|
||
|
public HandleMenuNomination(id, menu, item) {
|
||
|
if(item == MENU_EXIT) {
|
||
|
menu_destroy(menu);
|
||
|
return;
|
||
|
}
|
||
|
new dummy, info[2], tmpname[32];
|
||
|
menu_item_getinfo(menu, item, dummy, info, charsmax(info), tmpname, charsmax(tmpname), dummy);
|
||
|
new mapId = info[0]
|
||
|
if(!nominateMap(id, mapId))
|
||
|
client_print_color(id, print_chat, "%s Map ^"^4%s^1^" has already been nominated.", g_prefix, tmpname);
|
||
|
menu_destroy(menu);
|
||
|
}
|
||
|
|
||
|
public CheckEndOfMap() {
|
||
|
if(g_voting)
|
||
|
return;
|
||
|
if(get_timeleft() < 130)
|
||
|
MakeMapVote();
|
||
|
}
|
||
|
|
||
|
public MakeMapVote() {
|
||
|
g_voting = 1;
|
||
|
g_lastVoteTime = get_gametime();
|
||
|
g_numChoices = 0;
|
||
|
new nomination[32], numNominations = 0;
|
||
|
for(new i = 1; i <= g_maxClients; i++)
|
||
|
if(g_nomination[i] != -1)
|
||
|
nomination[numNominations++] = g_nomination[i];
|
||
|
new maxChoices = min(g_mapCount, MAX_MAPS_IN_VOTE);
|
||
|
new maxNomination = min(numNominations, MAX_NOMINATIONS);
|
||
|
while(g_numChoices < maxChoices) {
|
||
|
static map;
|
||
|
if(g_numChoices < maxNomination) {
|
||
|
new i = random(numNominations);
|
||
|
while(isMapInMenu((map = nomination[i])))
|
||
|
if(++i >= numNominations)
|
||
|
i = 0;
|
||
|
}
|
||
|
else { // Add random maps
|
||
|
map = random(g_mapCount);
|
||
|
while(isMapInMenu(map))
|
||
|
if(++map >= g_mapCount)
|
||
|
map = 0;
|
||
|
}
|
||
|
g_mapChoices[g_numChoices++] = map;
|
||
|
}
|
||
|
|
||
|
g_mapChoices[ID_EXTEND] = (get_pcvar_float(CvarTimeLimit) < get_pcvar_float(CvarExtendMax));
|
||
|
|
||
|
arrayset(g_mapVoteCount, 0, sizeof g_mapVoteCount);
|
||
|
arrayset(g_voted, false, sizeof g_voted);
|
||
|
remove_task(TASK_VOTE);
|
||
|
set_task(1.0, "ShowMapVote", TASK_VOTE, _, _, "a", 7);
|
||
|
set_task(6.0, "CheckMapVotes", TASK_VOTE);
|
||
|
g_countDown = 5;
|
||
|
g_numPlayersVoted = 0;
|
||
|
}
|
||
|
|
||
|
public ShowMapVote() {
|
||
|
new numPlayers = countRealPlayers();
|
||
|
static menu[512], len, keys;
|
||
|
for(new player = 1; player <= g_maxClients; player++) {
|
||
|
if(!is_user_connected(player) || is_user_bot(player))
|
||
|
continue;
|
||
|
if(g_voting == 1)
|
||
|
len = formatex(menu, charsmax(menu), "\yvoting will start soon...^n^n");
|
||
|
else if(g_voting == 2)
|
||
|
len = formatex(menu, charsmax(menu), "\yvote for the next map^n^n");
|
||
|
else
|
||
|
len = formatex(menu, charsmax(menu), "\yvoting results^n^n");
|
||
|
|
||
|
keys = 0;
|
||
|
len += formatex(menu[len], 511-len, "\r1. \wCheckpoint^n");
|
||
|
keys |= (1 << 0);
|
||
|
len += formatex(menu[len], 511-len, "\r2. \wGocheck^n^n");
|
||
|
keys |= (1 << 1);
|
||
|
|
||
|
for(new i = 2; i < (g_numChoices + 2); i++) {
|
||
|
new map = g_mapChoices[i-2];
|
||
|
if(g_voting != 2)
|
||
|
len += formatex(menu[len], 511-len, "\y%d. \w%a", i+1, ArrayGetStringHandle(g_mapName, map));
|
||
|
else
|
||
|
len += formatex(menu[len], 511-len, "\r%d. \w%a", i+1, ArrayGetStringHandle(g_mapName, map));
|
||
|
if(g_voting == 3 || (g_voted[player] && g_mapVoteCount[i - 2]))
|
||
|
len += formatex(menu[len], 511-len, " \y(%d%%)", (g_mapVoteCount[i - 2] * 100 / (numPlayers | 1)));
|
||
|
menu[len++] = '^n';
|
||
|
keys |= (1 << i);
|
||
|
}
|
||
|
|
||
|
new i = ID_EXTEND;
|
||
|
if(g_voting != 1 && g_mapChoices[i]) {
|
||
|
static mapName[32];
|
||
|
get_mapname(mapName, charsmax(mapName));
|
||
|
len += formatex(menu[len], 511-len, "^n%s9. \wextend %s", g_voting == 2 ? "\r" : "\y", mapName);
|
||
|
if(g_voting == 3 || (g_voted[player] && g_mapVoteCount[i]))
|
||
|
len += formatex(menu[len], 511-len, " \y(%d%%)", (g_mapVoteCount[i] * 100 / (numPlayers | 1)));
|
||
|
keys |= MENU_KEY_9;
|
||
|
}
|
||
|
if(g_voting != 3 && g_countDown <= 10)
|
||
|
len += formatex(menu[len], 511-len, "^n^n\wremaining time: %d", max(0, g_countDown));
|
||
|
show_menu(player, keys, menu, 5, "MapVoteMenu");
|
||
|
}
|
||
|
g_countDown--;
|
||
|
}
|
||
|
|
||
|
public CountMapVote(id, key) {
|
||
|
if(key == 0) {
|
||
|
client_cmd(id, "say /cp");
|
||
|
ShowMapVote();
|
||
|
return;
|
||
|
}
|
||
|
else if(key == 1) {
|
||
|
client_cmd(id, "say /gc");
|
||
|
ShowMapVote();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(g_voting == 2 && !g_voted[id]) {
|
||
|
new username[32];
|
||
|
get_user_name(id, username, charsmax(username));
|
||
|
new tmpmap[32];
|
||
|
ArrayGetString(g_mapName, g_mapChoices[key - 2], tmpmap, charsmax(tmpmap));
|
||
|
|
||
|
if((key + 1) == 9) {
|
||
|
g_mapVoteCount[ID_EXTEND]++;
|
||
|
g_numPlayersVoted++;
|
||
|
g_voted[id] = true;
|
||
|
client_print_color(0, print_chat, "%s %s chose map extending", g_prefix, username);
|
||
|
}
|
||
|
else {
|
||
|
g_mapVoteCount[key - 2]++;
|
||
|
g_numPlayersVoted++;
|
||
|
g_voted[id] = true;
|
||
|
client_print_color(0, print_chat, "%s %s chose %s", g_prefix, username, tmpmap);
|
||
|
}
|
||
|
}
|
||
|
ShowMapVote();
|
||
|
}
|
||
|
|
||
|
public CheckMapVotes() {
|
||
|
if(g_voting == 1) {
|
||
|
g_voting = 2;
|
||
|
client_cmd(0, "spk Gman/Gman_Choose%d", random_num(1, 2));
|
||
|
remove_task(TASK_VOTE);
|
||
|
set_task(1.0, "ShowMapVote", TASK_VOTE, _, _, "a", 15);
|
||
|
set_task(16.0, "CheckMapVotes", TASK_VOTE);
|
||
|
g_countDown = 15;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
new numPlayers = countRealPlayers();
|
||
|
g_voting = 3;
|
||
|
ShowMapVote();
|
||
|
|
||
|
new best;
|
||
|
for(new i = 0; i <= MAX_MAPS_IN_VOTE; i++)
|
||
|
if(g_mapVoteCount[i] > g_mapVoteCount[best])
|
||
|
best = i;
|
||
|
|
||
|
new sameVotes[MAX_MAPS_IN_VOTE + 1], num = 0;
|
||
|
for(new i = 0; i <= MAX_MAPS_IN_VOTE; i++)
|
||
|
if(g_mapVoteCount[i] > 0 && g_mapVoteCount[i] == g_mapVoteCount[best])
|
||
|
sameVotes[num++] = i;
|
||
|
|
||
|
if(num > 1) {
|
||
|
best = sameVotes[random(num)];
|
||
|
client_print_color(0, print_chat, "%s since there are %d results that are the same, one of them is randomly selected.", g_prefix, num);
|
||
|
}
|
||
|
|
||
|
new mapName[32];
|
||
|
|
||
|
if(best == ID_EXTEND || (g_numPlayersVoted == 0 && numPlayers != 0)) { // extend map
|
||
|
g_voting = 0;
|
||
|
get_mapname(mapName, charsmax(mapName));
|
||
|
|
||
|
if(get_timeleft() < 130)
|
||
|
set_cvar_float("mp_timelimit", get_cvar_float("mp_timelimit") + get_pcvar_float(CvarExtendStep));
|
||
|
|
||
|
client_print_color(0, print_chat, "%s voting is over. %s will be extended by %d minutes.", g_prefix, mapName, get_pcvar_num(CvarExtendStep));
|
||
|
}
|
||
|
else {
|
||
|
ArrayGetString(g_mapName, g_mapChoices[best], g_nextmap, charsmax(g_nextmap));
|
||
|
server_print("(after vote) g_nextmap: %s", g_nextmap);
|
||
|
set_cvar_string("amx_nextmap", g_nextmap);
|
||
|
set_task(10.0, "changeLevel", TASK_VOTE);
|
||
|
message_begin(MSG_ALL, SVC_INTERMISSION);
|
||
|
message_end();
|
||
|
client_print_color(0, print_chat, "%s voting is over. the next map will be %s.", g_prefix, g_nextmap);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public changeLevel() {
|
||
|
server_print("(changeLevel) g_nextmap: %s", g_nextmap);
|
||
|
client_print_color(0, print_chat, "%s changing map to %s...", g_prefix, g_nextmap);
|
||
|
server_cmd("changelevel ^"%s^"", g_nextmap);
|
||
|
}
|
||
|
|
||
|
loadConfigs() {
|
||
|
new currentMap[32];
|
||
|
get_mapname(currentMap, charsmax(currentMap));
|
||
|
|
||
|
new filePath[100];
|
||
|
get_configsdir(filePath, charsmax(filePath));
|
||
|
add(filePath, charsmax(filePath), "/maps.ini");
|
||
|
|
||
|
new file = fopen(filePath, "r");
|
||
|
if(file) {
|
||
|
while(!feof(file)) {
|
||
|
static data[64];
|
||
|
fgets(file, data, charsmax(data));
|
||
|
|
||
|
static mapName[32];
|
||
|
parse(data, mapName, charsmax(mapName));
|
||
|
|
||
|
if(is_map_valid(mapName) && !equal(currentMap, mapName) && !isMapExists(mapName)) {
|
||
|
ArrayPushString(g_mapName, mapName);
|
||
|
g_mapCount++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fclose(file);
|
||
|
}
|
||
|
|
||
|
if(!g_mapCount)
|
||
|
set_fail_state("Could not load any map.");
|
||
|
}
|
||
|
|
||
|
rockTheVote(id) {
|
||
|
if(g_voting) {
|
||
|
client_print_color(id, print_chat, "%s voting is in progress", g_prefix);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
new Float:timeWait = g_lastVoteTime + get_pcvar_float(CvarRtvWait) - get_gametime();
|
||
|
if(timeWait > 0.0) {
|
||
|
client_print_color(id, print_chat, "%s next vote in (%.f seconds)", g_prefix, timeWait);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(g_rocked[id]) {
|
||
|
g_rocked[id] = false;
|
||
|
client_print_color(id, print_chat, "%s you canceled the vote to change the map.", g_prefix);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
g_rocked[id] = true;
|
||
|
|
||
|
new maxVotes = floatround(get_pcvar_float(CvarRtvRatio) * countRealPlayers());
|
||
|
new numVotes = countRocked();
|
||
|
|
||
|
if(numVotes >= maxVotes) {
|
||
|
arrayset(g_rocked, false, sizeof g_rocked);
|
||
|
MakeMapVote();
|
||
|
|
||
|
client_print_color(0, print_chat, "%s %n voted to change the map.", g_prefix, id);
|
||
|
}
|
||
|
else
|
||
|
client_print_color(0, print_chat, "%s %n rocked the vote (%d players are needed).", g_prefix, id, maxVotes - numVotes);
|
||
|
}
|
||
|
|
||
|
bool:nominateMap(id, map) {
|
||
|
if(isMapNominated(map))
|
||
|
return false;
|
||
|
g_nomination[id] = map;
|
||
|
client_print_color(0, print_chat, "%s %n nominated the map %a.", g_prefix, id, ArrayGetStringHandle(g_mapName, map));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
stock bool:isMapInMenu(map) {
|
||
|
for(new i = 0; i < g_numChoices; i++)
|
||
|
if(g_mapChoices[i] == map)
|
||
|
return true
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
stock bool:isMapExists(const map[]) {
|
||
|
return (arrayFindString(g_mapName, map) != -1);
|
||
|
}
|
||
|
|
||
|
stock arrayFindString(Array:which, const string[]) {
|
||
|
new size = ArraySize(which);
|
||
|
for(new i = 0; i < size; i++) {
|
||
|
static buffer[128];
|
||
|
ArrayGetString(g_mapName, i, buffer, charsmax(buffer));
|
||
|
if(equal(string, buffer))
|
||
|
return i;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
stock bool:isMapNominated(map) {
|
||
|
for(new i = 1; i <= g_maxClients; i++)
|
||
|
if(g_nomination[i] == map)
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
stock countRocked() {
|
||
|
new count = 0;
|
||
|
for(new i = 1; i <= g_maxClients; i++)
|
||
|
if(g_rocked[i])
|
||
|
count++;
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
stock countRealPlayers() {
|
||
|
new count = 0;
|
||
|
for(new i = 1; i <= g_maxClients; i++)
|
||
|
if(is_user_connected(i) && !is_user_bot(i))
|
||
|
count++;
|
||
|
return count;
|
||
|
}
|