Правила форума Гаранты форума
Размещение рекламы AMX-X компилятор

Здравствуйте, гость Вход | Регистрация

Наши новости:

14-дек
24-апр
10-апр
11-апр

> Правила форума

Этот раздел, как вы могли заметить по названию, предназначен для решения вопросов по поводу уже существующих модов и плагинов.
Пожалуйста, если у вас проблема с написанием плагина, не путайте этот раздел с разделом по скриптингу.
Для поиска плагинов и модов существует соответствующий раздел.

Название темы должно соответствовать содержанию. Темы с названием типа "Помогите", "Вопрос", "парни подскажите..." - будут удалены.
Все темы, не относящиеся к "Вопросам по модам и плагинам", будут удалены или перемещены в соответствующий раздел.

Правила оформления темы:
1. Помимо заголовка не забудьте верно сформулировать свой вопрос.
2. Выложите исходник (в тег кода + ) или ссылку на плагин который вызывает у вас вопросы.
3. Выложите лог с ошибками (если имеется) под спойлер

В Galileo не работает rtv

Simbo
сообщение 10.6.2012, 11:28
Сообщение #1
Стаж: 13 лет

Сообщений: 146
Благодарностей: 3
Полезность: 0

Поставил плагин галилео а rtv не работает, всё время пишет осталось 7 минут... что можно с этим сделать?

Конфиг
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Название: Galileo //
// Версия : 1.1.290 //
// Автор перевода: MastaMan //
// Код: Brad //
// Источник: amx-server.blogspot.com //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Galileo Файл Конфигурации
echo Executing Galileo (GAL) Configuration File


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Разрешает продление времени текущей карты, добавит пункт в голосовании //
// "Продлить карту". Если большинство проголосует за продление, будет увеличено //
// время игры на карте на определенное значение, что позволит игрокам оставатся //
// на данной карте дольше. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Максимальное кол-во минут для игры, если карта была
// продлена. Значение меньшее mp_timelimit не разрешит продлевать карту.

amx_extendmap_max 90


// Кол-во минут на котороые будет продлена карта.

amx_extendmap_step 30


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Две стандартные взаимосвязанные команды, //
// которые не могут нормально работать, когда используется плагин. //
// Для избежания ошибок при голосовании оставте значения по умолчанию. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Cтандартная команда "votemap".
// 0 - отключено (по умолчанию).
// 1 - включено.

gal_cmd_votemap 0

// Cтандартная команда "listmaps".
// 0 - отключено.
// 1 - включено.
// 2 - ведет себя так же как команда "gal_listmaps" (по умолчанию).

gal_cmd_listmaps 2


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Запрещение последних сыгранных карт означает что они не будут попадатся //
// в следующем голосовании, исключая многократную игру на одной карте. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


// *Кол-во самых последних карт, для исключения из голосования.
// Значение 0 отключит эту функцию.
// (по умолчанию 3)

gal_banrecent 0


// Стиль отображения последних карт, при
// использовании чат команды "recentmaps".
// 1 - все краты в одной строке (по умолчанию).
// 2 - каждая карта в отдельной строке.

gal_banrecentstyle 1


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Голосование за смену карты способ сообщить //
// о том, что игроки желают преждевременно сменить карту. //
// Если достаточное количество пожелало сменить карту, //
// начнется голосование. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Чат команды которые будут вызывать голосование.
// Использование флагов. Значение 0 отключает эту функцию.
// 1 - стандартная команда "rockthevote".
// 2 - сокращенная команда "rtv".
// 4 - динамическая "rockthe<любая>vote" команда (разрешает использовать
// любое слово (без пробелов) начиная с "rockthe" и заканчивая
// "vote". Пример: "rockthedamnvote",
// "rockthesillylittlevote", или "rockthefreakingvote". Общая длина
// слова не должна превышать 31 символ. В итоге
// остается 20 символов для творчества если не учитывать
// длину "rockthe" и "vote").

gal_rtv_commands 2


// Кол-во минут после начала карты,
// которые игроки должны ждать, прежде чем они могут
// вызывать голосование. Когда один игрок на сервере, он может
// вызывать голосование в любое время, вне зависимости от этого параметра.
// (по умолчанию 10)

gal_rtv_wait 7


// *Процент игроков необходимый для вызова голосования.
// Когда один игрок на серере, голосование начнется немедленно.
// (по умолчанию 0.60)

gal_rtv_ratio 0.65


// *Кол-во минут между напоминаниями о том сколько
// голосов необходимо, после последнего созданного голосования.
// Значение 0 отключает эту функцию.
// (по умолчанию 2)

gal_rtv_reminder 10


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Номинации разрешают игрокам назначать карты которые они хотели бы //
// включить в следующее голосование. //
// Не зависимо от того сколько карт было номинированно, не исключена //
// возможность что не все номинации попадут в следующее голосование. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Кол-во номинаций которые может иметь каждый игрок.
// Максимальное количество определено в параметре,
// MAX_NOMINATION_CNT, не больше 5 в SMA исходнике
// Вы можете изменить при надобности значение.
// Эта переменная должна быть меньше чем значение указанное в исходнике.
// Значение 0 отключает эту функцию.

gal_nom_playerallowance 1

// Файл со списком карт, кторые игроки могут номинировать.
// Используйте * для всех карт которые есть на сервере.

gal_nom_mapfile maps.ini


// Использовать prefixes.ini для проверки имен карт,
// если игрок не правильно набрал текст.

gal_nom_prefixes 1


// Кол-во номинаций которые будут учитыватся в
// голосовании за следующую карту.
// Значение 0 означает что учитыватся будут все номинации.

gal_nom_qtyused 0


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Если ни один из вариантов голосования не //
// получил более 50% голосов, два варианта с //
// с наивысшим кол-вом голосов будут выбиратся в дополнительном //
// голосовании. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Разрешить дополнительное голосование.
// 0 - отключиь.
// 1 - включить (по умолчанию).

gal_runoff_enabled 1

// Продолжение в секундах дополнительного голосования.

gal_runoff_duration 15


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Вес голоса, позволяет учитывать //
// голос администратора больше чем обычного игрока. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Сколько голосов считать за один голос администратора.
// Значения 0 или 1 отключают эту функцию.

gal_vote_weight 2

// *Флаги необходимые для голосования с большим весом.
// Вы можете использовать несколько флагов.
// (по умолчанию y)

gal_vote_weightflags h


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// По окончанию времени сменить карту //
// со следующего раунда или немедленно. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// По окончанию времени карты:
// 0 - сменить на следующую немедленно.
// 1 - сменить на следующую по окончанию раунда (по умолчанию).

gal_endonround 1


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Отображение процента голосов за каждую карту. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Когда прогресс голосования будет отображен игроку.
// Значение 0 отключает эту функцию.
// 0 - никогда.
// 1 - после голосования игрока (по умолчанию).
// 2 - по окончанию голосования.

gal_vote_showstatus 1

// Отображать прогресс:
// 1 - как количество.
// 2 - как процент проголосовавших (по умолчанию).

gal_vote_showstatustype 2


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// В зависимости от рестарта - по надобности //
// или от падения сервера, связанное с картой //
// вы можете определить следующее действие. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// *Действие при рестарте сервера:
// 0 - оставатся на той же карте с которой стартовал сервер (по умолчанию).
// 1 - сменить на карту которая была перед рестартом.
// 2 - сменить на следующую карту, которая была определена
// перед рестартом (если следующая карта не известна,
// будет так же как и п.3).
// 3 - начать голосование после первых двух минут.
// 4 - изменить произвольно карту из списка номинаций .
// (по умолчанию 0)

gal_srv_start 0


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Некоторые люди любят придерживатся своего //
// предопределенного цикла карт. Другим - нравится //
// что бы голосование было в конце карты, что бы решить какая //
// карта будет следующая. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Разрешить голосование в конце карты
// для определения следующей карты.
gal_endofmapvote 1


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Разбивание на страницы списка карт отображаемая //
// консольной командой gal_listmaps предотвращает //
// выкидывание игроков с сервера при просмотре большого //
// списка карт. При разбивании на страницы будет показана //
// только часть карт из общего списка. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Определяет кол-во карт на страницу при использовании
// команды gal_listmaps.
// Значение 0 отключает разбивку на страницы.
// Разбивка на страницы будет на подобии команды amx_help.

gal_listmaps_paginate 10


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Настройки голосования. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// *Кол-во карт которые игроки могут выбирать в списке карт.
// Число карт должно быть между 2 и 8.
// (по умолчанию 5)

gal_vote_mapchoices 8

// *Кол-во секунд продолжения голосования.
// (по умолчанию 15)

gal_vote_duration 20

// Определяет файл с названием карт, которые будут использоватся
// в голосовании или для определения кол-ва групп карт,
// для перменной gal_vote_mapfiletype.

gal_vote_mapfile mapcycle.txt

// Как добавляются карты после номинаций.
// Должны иметь уникальный префикс карты
// от тех которые уже в голосовании или нет.

gal_vote_uniqueprefixes 0


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Показывать таймер с обратным отсчетом, игрокам //
// которые не успели проголосвать, если остается 10 секунд до //
// окончания голосования. Таймер отсчитывает //
// время от 10 до 0, перд окончанием голосования. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Как показывать обратный отсчет.
// 0 - не показывать
// 1 - показывать (по умолчанию)

gal_vote_expirationcountdown 0


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Показывать в чате за что голосует каждый игрок //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Показывать всем выбор каждого игока.
// 0 - не показывать.
// 1 - показывать всем.

gal_vote_announcechoice 0


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Вы, возможно, имеете много карт но только, некотрые из них //
// привлекут большее количество игроков. Когда сервер пуст, поменять //
// на одну из этих карт. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Сколько минут ждать, когда сервер пустой, пред сменой
на альтернативный цикл карт для для пустого сервера.
// Значение 0 отключит эту функцию (по умолчанию).

gal_emptyserver_wait 2

// Файл содержащий список карт, на подобии
// mapcycle.txt, для использования цикла карт когда сервер пуст.

gal_emptyserver_mapfile emptycycle.txt

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Отключение произношения слов у разных событий до и во время голосования. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

// Укажите какие звуки необходимо отключить.
// Флаги аддитивны. Значение 0 оставляет все звуки.
// 1 - "get ready to choose a map"
// 2 - "7", "6", "5", "4", "3", "2", "1"
// 4 - "time to choose"
// 8 - "runoff voting is required"
gal_sounds_mute 0

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Название: Galileo //
// Версия : 1.1.290 //
// Автор перевода: MastaMan //
// Код: Brad //
// Источник: amx-server.blogspot.com //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


Исходник
new const PLUGIN_VERSION[] = "1.1 $Revision: 290 $"; // $Date: 2009-02-26 11:20:25 -0500 (Thu, 26 Feb 2009) $;

#include <amxmodx>
#include <amxmisc>

#pragma semicolon 1

#define TASKID_EMPTYSERVER 98176977
#define TASKID_REMINDER 52691153

#define RTV_CMD_STANDARD 1
#define RTV_CMD_SHORTHAND 2
#define RTV_CMD_DYNAMIC 4

#define SOUND_GETREADYTOCHOOSE 1
#define SOUND_COUNTDOWN 2
#define SOUND_TIMETOCHOOSE 4
#define SOUND_RUNOFFREQUIRED 8

#define MAPFILETYPE_SINGLE 1
#define MAPFILETYPE_GROUPS 2

#define SHOWSTATUS_VOTE 1
#define SHOWSTATUS_END 2

#define SHOWSTATUSTYPE_COUNT 1
#define SHOWSTATUSTYPE_PERCENTAGE 2

#define ANNOUNCECHOICE_PLAYERS 1
#define ANNOUNCECHOICE_ADMINS 2

#define MAX_NOMINATION_CNT 5

#define MAX_PREFIX_CNT 32
#define MAX_RECENT_MAP_CNT 16

#define MAX_PLAYER_CNT 32
#define MAX_STANDARD_MAP_CNT 25
#define MAX_MAPNAME_LEN 31
#define MAX_MAPS_IN_VOTE 8
#define MAX_NOM_MATCH_CNT 1000

#define VOTE_IN_PROGRESS 1
#define VOTE_FORCED 2
#define VOTE_IS_RUNOFF 4
#define VOTE_IS_OVER 8
#define VOTE_IS_EARLY 16
#define VOTE_HAS_EXPIRED 32

#define SRV_START_CURRENTMAP 1
#define SRV_START_NEXTMAP 2
#define SRV_START_MAPVOTE 3
#define SRV_START_RANDOMMAP 4

#define LISTMAPS_USERID 0
#define LISTMAPS_LAST 1

#define TIMELIMIT_NOT_SET -1.0

new MENU_CHOOSEMAP[] = "gal_menuChooseMap";

new DIR_CONFIGS[64];
new DIR_DATA[64];

new CLR_RED[3]; // \r
new CLR_WHITE[3]; // \w
new CLR_YELLOW[3]; // \y
new CLR_GREY[3]; // \d

new bool:g_wasLastRound = false;
new g_mapPrefix[MAX_PREFIX_CNT][16], g_mapPrefixCnt = 1;
new g_currentMap[MAX_MAPNAME_LEN+1], Float:g_originalTimelimit = TIMELIMIT_NOT_SET;

new g_nomination[MAX_PLAYER_CNT + 1][MAX_NOMINATION_CNT + 1], g_nominationCnt, g_nominationMatchesMenu[MAX_PLAYER_CNT];
//new g_nonOverlapHudSync;

new g_voteWeightFlags[32];

new Array:g_emptyCycleMap, bool:g_isUsingEmptyCycle = false, g_emptyMapCnt = 0;

new Array:g_mapCycle;

new g_recentMap[MAX_RECENT_MAP_CNT][MAX_MAPNAME_LEN + 1], g_cntRecentMap;
new Array:g_nominationMap, g_nominationMapCnt;
new Array:g_fillerMap;
new Float:g_rtvWait;
new bool:g_rockedVote[MAX_PLAYER_CNT + 1], g_rockedVoteCnt;

new g_mapChoice[MAX_MAPS_IN_VOTE + 1][MAX_MAPNAME_LEN + 1], g_choiceCnt, g_choiceMax;
new bool:g_voted[MAX_PLAYER_CNT + 1] = {true, ...}, g_mapVote[MAX_MAPS_IN_VOTE + 1];
new g_voteStatus, g_voteDuration, g_votesCast;
new g_runoffChoice[2];
new g_vote[512];
new bool:g_handleMapChange = true;

new g_refreshVoteStatus = true, g_voteTallyType[3], g_snuffDisplay[MAX_PLAYER_CNT + 1];

new g_menuChooseMap;

new g_pauseMapEndVoteTask, g_pauseMapEndManagerTask;

new cvar_extendmapMax, cvar_extendmapStep;
new cvar_endOnRound, cvar_endOfMapVote;
new cvar_rtvWait, cvar_rtvRatio, cvar_rtvCommands;
new cvar_cmdVotemap, cvar_cmdListmaps, cvar_listmapsPaginate;
new cvar_banRecent, cvar_banRecentStyle, cvar_voteDuration;
new cvar_nomMapFile, cvar_nomPrefixes;
new cvar_nomQtyUsed, cvar_nomPlayerAllowance;
new cvar_voteExpCountdown, cvar_voteWeightFlags, cvar_voteWeight;
new cvar_voteMapChoiceCnt, cvar_voteAnnounceChoice, cvar_voteUniquePrefixes;
new cvar_voteMapFile, cvar_rtvReminder;
new cvar_srvStart;
new cvar_emptyWait, cvar_emptyMapFile, cvar_emptyCycle;
new cvar_runoffEnabled, cvar_runoffDuration;
new cvar_voteStatus, cvar_voteStatusType;
new cvar_soundsMute;

public plugin_init()
{
// build version information
new jnk[1], version[8], rev[8];
parse(PLUGIN_VERSION, version, sizeof(version)-1, jnk, sizeof(jnk)-1, rev, sizeof(rev)-1, jnk, sizeof(jnk)-1);
new pluginVersion[16];
formatex(pluginVersion, sizeof(pluginVersion)-1, "%s.%s", version, rev);

register_plugin("Galileo", pluginVersion, "Brad Jones");

register_cvar("gal_version", pluginVersion, FCVAR_SERVER|FCVAR_SPONLY);
set_cvar_string("gal_version", pluginVersion);

register_cvar("gal_server_starting", "1", FCVAR_SPONLY);
cvar_emptyCycle = register_cvar("gal_in_empty_cycle", "0", FCVAR_SPONLY);

register_cvar("gal_debug", "0");

register_dictionary("common.txt");
register_dictionary("nextmap.txt");
register_dictionary("galileo.txt");

if (module_exists("cstrike"))
{
register_event("HLTV", "event_round_start", "a", "1=0", "2=0");
}
else if (module_exists("dodx"))
{
register_event("RoundState", "event_round_start", "a", "1=1");
}

register_event("TextMsg", "event_game_commencing", "a", "2=#Game_Commencing", "2=#Game_will_restart_in");
register_event("30", "event_intermission", "a");

g_menuChooseMap = register_menuid(MENU_CHOOSEMAP);
register_menucmd(g_menuChooseMap, MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_4|MENU_KEY_5|MENU_KEY_6|MENU_KEY_7|MEN
U_KEY_8|MENU_KEY_9|MENU_KEY_0, "vote_handleChoice");

register_clcmd("say", "cmd_say", -1);
register_clcmd("say nextmap", "cmd_nextmap", 0, "- displays nextmap");
register_clcmd("say currentmap", "cmd_currentmap", 0, "- display current map");
register_clcmd("say ff", "cmd_ff", 0, "- display friendly fire status"); // grrface
register_clcmd("votemap", "cmd_HL1_votemap");
register_clcmd("listmaps", "cmd_HL1_listmaps");

register_concmd("gal_startvote", "cmd_startVote", ADMIN_MAP);
register_concmd("gal_createmapfile", "cmd_createMapFile", ADMIN_RCON);

register_cvar("amx_nextmap", "", FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_SPONLY);
cvar_extendmapMax = register_cvar("amx_extendmap_max", "90");
cvar_extendmapStep = register_cvar("amx_extendmap_step", "15");

cvar_cmdVotemap = register_cvar("gal_cmd_votemap", "0");
cvar_cmdListmaps = register_cvar("gal_cmd_listmaps", "2");

cvar_listmapsPaginate = register_cvar("gal_listmaps_paginate", "10");

cvar_banRecent = register_cvar("gal_banrecent", "3");
cvar_banRecentStyle = register_cvar("gal_banrecentstyle", "1");

cvar_endOnRound = register_cvar("gal_endonround", "1");
cvar_endOfMapVote = register_cvar("gal_endofmapvote", "1");

cvar_emptyWait = register_cvar("gal_emptyserver_wait", "0");
cvar_emptyMapFile = register_cvar("gal_emptyserver_mapfile", "");

cvar_srvStart = register_cvar("gal_srv_start", "0");

cvar_rtvCommands = register_cvar("gal_rtv_commands", "3");
cvar_rtvWait = register_cvar("gal_rtv_wait", "10");
cvar_rtvRatio = register_cvar("gal_rtv_ratio", "0.60");
cvar_rtvReminder = register_cvar("gal_rtv_reminder", "2");

cvar_nomPlayerAllowance = register_cvar("gal_nom_playerallowance", "2");
cvar_nomMapFile = register_cvar("gal_nom_mapfile", "mapcycle");
cvar_nomPrefixes = register_cvar("gal_nom_prefixes", "1");
cvar_nomQtyUsed = register_cvar("gal_nom_qtyused", "0");

cvar_voteWeight = register_cvar("gal_vote_weight", "2");
cvar_voteWeightFlags = register_cvar("gal_vote_weightflags", "y");
cvar_voteMapFile = register_cvar("gal_vote_mapfile", "mapcycle.txt");
cvar_voteDuration = register_cvar("gal_vote_duration", "15");
cvar_voteExpCountdown = register_cvar("gal_vote_expirationcountdown", "1");
cvar_voteMapChoiceCnt = register_cvar("gal_vote_mapchoices", "5");
cvar_voteAnnounceChoice = register_cvar("gal_vote_announcechoice", "1");
cvar_voteStatus = register_cvar("gal_vote_showstatus", "1");
cvar_voteStatusType = register_cvar("gal_vote_showstatustype", "2");
cvar_voteUniquePrefixes = register_cvar("gal_vote_uniqueprefixes", "0");

cvar_runoffEnabled = register_cvar("gal_runoff_enabled", "0");
cvar_runoffDuration = register_cvar("gal_runoff_duration", "10");

cvar_soundsMute = register_cvar("gal_sounds_mute", "0");

//set_task(1.0, "dbg_test",_,_,_,"a", 15);
}

public dbg_fakeVotes()
{
if (!(g_voteStatus & VOTE_IS_RUNOFF))
{
g_mapVote[0] += 2; // map 1
g_mapVote[1] += 0; // map 2
g_mapVote[2] += 6; // map 3
g_mapVote[3] += 0; // map 4
g_mapVote[4] += 0; // map 5
g_mapVote[5] += 4; // extend option

g_votesCast = g_mapVote[0] + g_mapVote[1] + g_mapVote[2] + g_mapVote[3] + g_mapVote[4] + g_mapVote[5];
}
else if (g_voteStatus & VOTE_IS_RUNOFF)
{
g_mapVote[0] += 1; // choice 1
g_mapVote[1] += 0; // choice 2

g_votesCast = g_mapVote[0] + g_mapVote[1];
}
}

public plugin_cfg()
{
formatex(DIR_CONFIGS[get_configsdir(DIR_CONFIGS, sizeof(DIR_CONFIGS)-1)], sizeof(DIR_CONFIGS)-1, "/galileo");
formatex(DIR_DATA[get_datadir(DIR_DATA, sizeof(DIR_DATA)-1)], sizeof(DIR_DATA)-1, "/galileo");

server_cmd("exec %s/galileo.cfg", DIR_CONFIGS);
server_exec();

if (colored_menus())
{
copy(CLR_RED, 2, "\r");
copy(CLR_WHITE, 2, "\w");
copy(CLR_YELLOW, 2, "\y");
}

g_rtvWait = get_pcvar_float(cvar_rtvWait);
get_pcvar_string(cvar_voteWeightFlags, g_voteWeightFlags, sizeof(g_voteWeightFlags)-1);
get_mapname(g_currentMap, sizeof(g_currentMap)-1);
g_choiceMax = max(min(MAX_MAPS_IN_VOTE, get_pcvar_num(cvar_voteMapChoiceCnt)), 2);
// g_nonOverlapHudSync = CreateHudSyncObj();
g_fillerMap = ArrayCreate(32);
g_nominationMap = ArrayCreate(32);

// initialize nominations table
nomination_clearAll();

if (get_pcvar_num(cvar_banRecent))
{
register_clcmd("say recentmaps", "cmd_listrecent", 0);

map_loadRecentList();

if (!(get_cvar_num("gal_server_starting") && get_pcvar_num(cvar_srvStart)))
{
map_writeRecentList();
}
}

if (get_pcvar_num(cvar_rtvCommands) & RTV_CMD_STANDARD)
{
register_clcmd("say rockthevote", "cmd_rockthevote", 0);
}

if (get_pcvar_num(cvar_nomPlayerAllowance))
{
register_concmd("gal_listmaps", "cmd_listmaps");
register_clcmd("say nominations", "cmd_nominations", 0, "- displays current nominations for next map");

if (get_pcvar_num(cvar_nomPrefixes))
{
map_loadPrefixList();
}
map_loadNominationList();
}

new mapName[32];
get_mapname(mapName, 31);
dbg_log(6, "[%s]", mapName);
dbg_log(6, "");

if (get_cvar_num("gal_server_starting"))
{
srv_handleStart();
}

set_task(10.0, "vote_setupEnd");

if (get_pcvar_num(cvar_emptyWait))
{
g_emptyCycleMap = ArrayCreate(32);
map_loadEmptyCycleList();
set_task(60.0, "srv_initEmptyCheck");
}
}

public plugin_end()
{
map_restoreOriginalTimeLimit();
}

public vote_setupEnd()
{
dbg_log(4, "%32s mp_timelimit: %f g_originalTimelimit: %f", "vote_setupEnd(in)", get_cvar_float("mp_timelimit"), g_originalTimelimit);

g_originalTimelimit = get_cvar_float("mp_timelimit");

new nextMap[32];
if (get_pcvar_num(cvar_endOfMapVote))
{
formatex(nextMap, sizeof(nextMap)-1, "%L", LANG_SERVER, "GAL_NEXTMAP_UNKNOWN");
}
else
{
g_mapCycle = ArrayCreate(32);
map_populateList(g_mapCycle, "mapcycle.txt");
map_getNext(g_mapCycle, g_currentMap, nextMap);
}
map_setNext(nextMap);

// as long as the time limit isn't set to 0, we can manage the end of the map automatically
if (g_originalTimelimit)
{
set_task(15.0, "vote_manageEnd", _, _, _, "b");
}

dbg_log(2, "%32s mp_timelimit: %f g_originalTimelimit: %f", "vote_setupEnd(out)", get_cvar_float("mp_timelimit"), g_originalTimelimit);
}

map_getNext(Array:mapArray, currentMap[], nextMap[32])
{
new thisMap[32], mapCnt = ArraySize(mapArray), nextmapIdx = 0, returnVal = -1;
for (new mapIdx = 0; mapIdx < mapCnt; mapIdx++)
{
ArrayGetString(mapArray, mapIdx, thisMap, sizeof(thisMap)-1);
if (equal(currentMap, thisMap))
{
nextmapIdx = (mapIdx == mapCnt - 1) ? 0 : mapIdx + 1;
returnVal = nextmapIdx;
break;
}
}
ArrayGetString(mapArray, nextmapIdx, nextMap, sizeof(nextMap)-1);

return returnVal;
}

public srv_handleStart()
{
// this is the key that tells us if this server has been restarted or not
set_cvar_num("gal_server_starting", 0);

// take the defined "server start" action
new startAction = get_pcvar_num(cvar_srvStart);
if (startAction)
{
new nextMap[32];

if (startAction == SRV_START_CURRENTMAP || startAction == SRV_START_NEXTMAP)
{
new filename[256];
formatex(filename, sizeof(filename)-1, "%s/info.dat", DIR_DATA);

new file = fopen(filename, "rt");
if (file) // !feof(file)
{
fgets(file, nextMap, sizeof(nextMap)-1);

if (startAction == SRV_START_NEXTMAP)
{
nextMap[0] = 0;
fgets(file, nextMap, sizeof(nextMap)-1);
}
}
fclose(file);
}
else if (startAction == SRV_START_RANDOMMAP)
{
// pick a random map from allowable nominations

// if noms aren't allowed, the nomination list hasn't already been loaded
if (get_pcvar_num(cvar_nomPlayerAllowance) == 0)
{
map_loadNominationList();
}

if (g_nominationMapCnt)
{
ArrayGetString(g_nominationMap, random_num(0, g_nominationMapCnt - 1), nextMap, sizeof(nextMap)-1);
}
}

trim(nextMap);

if (nextMap[0] && is_map_valid(nextMap))
{
server_cmd("changelevel %s", nextMap);
}
else
{
vote_manageEarlyStart();
}
}
}

vote_manageEarlyStart()
{
g_voteStatus |= VOTE_IS_EARLY;

set_task(120.0, "vote_startDirector");
}

map_setNext(nextMap[])
{
// set the queryable cvar
set_cvar_string("amx_nextmap", nextMap);

// update our data file
new filename[256];
formatex(filename, sizeof(filename)-1, "%s/info.dat", DIR_DATA);

new file = fopen(filename, "wt");
if (file)
{
fprintf(file, "%s", g_currentMap);
fprintf(file, "^n%s", nextMap);
fclose(file);
}
else
{
//error
}
}

public vote_manageEnd()
{
new secondsLeft = get_timeleft();

// are we ready to start an "end of map" vote?
if (secondsLeft < 150 && secondsLeft > 90 && !g_pauseMapEndVoteTask && get_pcvar_num(cvar_endOfMapVote) && !get_pcvar_num(cvar_emptyCycle))
{
vote_startDirector(false);
}

// are we managing the end of the map?
if (secondsLeft < 20 && !g_pauseMapEndManagerTask)
{
map_manageEnd();
}
}

public map_loadRecentList()
{
new filename[256];
formatex(filename, sizeof(filename)-1, "%s/recentmaps.dat", DIR_DATA);

new file = fopen(filename, "rt");
if (file)
{
new buffer[32];

while (!feof(file))
{
fgets(file, buffer, sizeof(buffer)-1);
trim(buffer);

if (buffer[0])
{
if (g_cntRecentMap == get_pcvar_num(cvar_banRecent))
{
break;
}
copy(g_recentMap[g_cntRecentMap++], sizeof(buffer)-1, buffer);
}
}
fclose(file);
}
}

public map_writeRecentList()
{
new filename[256];
formatex(filename, sizeof(filename)-1, "%s/recentmaps.dat", DIR_DATA);

new file = fopen(filename, "wt");
if (file)
{
fprintf(file, "%s", g_currentMap);

for (new idxMap = 0; idxMap < get_pcvar_num(cvar_banRecent) - 1; ++idxMap)
{
fprintf(file, "^n%s", g_recentMap[idxMap]);
}

fclose(file);
}
}

public map_loadFillerList(filename[])
{
return map_populateList(g_fillerMap, filename);
}

public cmd_rockthevote(id)
{
client_print(id, print_chat, "%L", id, "GAL_CMD_RTV");
vote_rock(id);
return PLUGIN_CONTINUE;
}

public cmd_nominations(id)
{
client_print(id, print_chat, "%L", id, "GAL_CMD_NOMS");
nomination_list(id);
return PLUGIN_CONTINUE;
}

public cmd_nextmap(id)
{
new map[32];
get_cvar_string("amx_nextmap", map, sizeof(map)-1);
client_print(0, print_chat, "%L %s", LANG_PLAYER, "NEXT_MAP", map);
return PLUGIN_CONTINUE;
}

public cmd_currentmap(id)
{
client_print(0, print_chat, "%L: %s", LANG_PLAYER, "PLAYED_MAP", g_currentMap);
return PLUGIN_CONTINUE;
}

public cmd_listrecent(id)
{
switch (get_pcvar_num(cvar_banRecentStyle))
{
case 1:
{
new msg[101], msgIdx;
for (new idx = 0; idx < g_cntRecentMap; ++idx)
{
msgIdx += format(msg[msgIdx], sizeof(msg)-1-msgIdx, ", %s", g_recentMap[idx]);
}
client_print(0, print_chat, "%L: %s", LANG_PLAYER, "GAL_MAP_RECENTMAPS", msg[2]);
}
case 2:
{
for (new idx = 0; idx < g_cntRecentMap; ++idx)
{
client_print(0, print_chat, "%L (%i): %s", LANG_PLAYER, "GAL_MAP_RECENTMAP", idx+1, g_recentMap[idx]);
}
}
}

return PLUGIN_HANDLED;
}

public cmd_startVote(id, level, cid)
{
if (!cmd_access(id, level, cid, 1))
return PLUGIN_HANDLED;

if (g_voteStatus & VOTE_IN_PROGRESS)
{
client_print(id, print_chat, "%L", id, "GAL_VOTE_INPROGRESS");
}
else if (g_voteStatus & VOTE_IS_OVER)
{
client_print(id, print_chat, "%L", id, "GAL_VOTE_ENDED");
}
else
{
// we may not want to actually change the map after outcome of vote is determined
if (read_argc() == 2)
{
new arg[32];
read_args(arg, sizeof(arg)-1);

if (equali(arg, "-nochange"))
{
g_handleMapChange = false;
}
}

vote_startDirector(true);
}

return PLUGIN_HANDLED;
}

map_populateList(Array:mapArray, mapFilename[])
{
// clear the map array in case we're reusing it
ArrayClear(mapArray);

// load the array with maps
new mapCnt;

if (!equal(mapFilename, "*"))
{
new file = fopen(mapFilename, "rt");
if (file)
{
new buffer[32];

while (!feof(file))
{
fgets(file, buffer, sizeof(buffer)-1);
trim(buffer);

if (buffer[0] && !equal(buffer, "//", 2) && !equal(buffer, ";", 1) && is_map_valid(buffer))
{
ArrayPushString(mapArray, buffer);
++mapCnt;
}
}
fclose(file);
}
else
{
log_error(AMX_ERR_NOTFOUND, "%L", LANG_SERVER, "GAL_MAPS_FILEMISSING", mapFilename);
}
}
else
{
// no file provided, assuming contents of "maps" folder
new dir, mapName[32];
dir = open_dir("maps", mapName, sizeof(mapName)-1);

if (dir)
{
new lenMapName;

while (next_file(dir, mapName, sizeof(mapName)-1))
{
lenMapName = strlen(mapName);
if (lenMapName > 4 && equali(mapName[lenMapName - 4], ".bsp", 4))
{
mapName[lenMapName-4] = '^0';
if (is_map_valid(mapName))
{
ArrayPushString(mapArray, mapName);
++mapCnt;
}
}
}
close_dir(dir);
}
else
{
// directory not found, wtf?
log_error(AMX_ERR_NOTFOUND, "%L", LANG_SERVER, "GAL_MAPS_FOLDERMISSING");
}
}
return mapCnt;
}

public map_loadNominationList()
{
new filename[256];
get_pcvar_string(cvar_nomMapFile, filename, sizeof(filename)-1);

g_nominationMapCnt = map_populateList(g_nominationMap, filename);
}

// grrface, this has no place in a map choosing plugin. just replicating it because it's in AMXX's
public cmd_ff()
{
client_print(0, print_chat, "%L: %L", LANG_PLAYER, "FRIEND_FIRE", LANG_PLAYER, get_cvar_num("mp_friendlyfire") ? "ON" : "OFF");
return PLUGIN_CONTINUE;
}

public cmd_createMapFile(id, level, cid)
{
if (!cmd_access(id, level, cid, 1))
return PLUGIN_HANDLED;

new cntArg = read_argc() - 1;

switch (cntArg)
{
case 1:
{
new arg1[256];
read_argv(1, arg1, sizeof(arg1)-1);
remove_quotes(arg1);

new mapName[MAX_MAPNAME_LEN+5]; // map name is 31 (i.e. MAX_MAPNAME_LEN), ".bsp" is 4, string terminator is 1.
new dir, file, mapCnt, lenMapName;

dir = open_dir("maps", mapName, sizeof(mapName)-1);
if (dir)
{
new filename[256];
formatex(filename, sizeof(filename)-1, "%s/%s", DIR_CONFIGS, arg1);

file = fopen(filename, "wt");
if (file)
{
mapCnt = 0;
while (next_file(dir, mapName, sizeof(mapName)-1))
{
lenMapName = strlen(mapName);

if (lenMapName > 4 && equali(mapName[lenMapName - 4], ".bsp", 4))
{
mapName[lenMapName- 4] = '^0';
if (is_map_valid(mapName))
{
mapCnt++;
fprintf(file, "%s^n", mapName);
}
}
}
fclose(file);
con_print(id, "%L", LANG_SERVER, "GAL_CREATIONSUCCESS", filename, mapCnt);
}
else
{
con_print(id, "%L", LANG_SERVER, "GAL_CREATIONFAILED", filename);
}
close_dir(dir);
}
else
{
// directory not found, wtf?
con_print(id, "%L", LANG_SERVER, "GAL_MAPSFOLDERMISSING");
}
}
default:
{
// inform of correct usage
con_print(id, "%L", id, "GAL_CMD_CREATEFILE_USAGE1");
con_print(id, "%L", id, "GAL_CMD_CREATEFILE_USAGE2");
}
}
return PLUGIN_HANDLED;
}

public map_loadPrefixList()
{
new filename[256];
formatex(filename, sizeof(filename)-1, "%s/prefixes.ini", DIR_CONFIGS);

new file = fopen(filename, "rt");
if (file)
{
new buffer[16];
while (!feof(file))
{
fgets(file, buffer, sizeof(buffer)-1);
if (buffer[0] && !equal(buffer, "//", 2))
{
if (g_mapPrefixCnt <= MAX_PREFIX_CNT)
{
trim(buffer);
copy(g_mapPrefix[g_mapPrefixCnt++], sizeof(buffer)-1, buffer);
}
else
{
log_error(AMX_ERR_BOUNDS, "%L", LANG_SERVER, "GAL_PREFIXES_TOOMANY", MAX_PREFIX_CNT, filename);
break;
}
}
}
fclose(file);
}
else
{
log_error(AMX_ERR_NOTFOUND, "%L", LANG_SERVER, "GAL_PREFIXES_NOTFOUND", filename);
}
return PLUGIN_HANDLED;
}

map_loadEmptyCycleList()
{
new filename[256];
get_pcvar_string(cvar_emptyMapFile, filename, sizeof(filename)-1);

g_emptyMapCnt = map_populateList(g_emptyCycleMap, filename);
}

public map_manageEnd()
{
dbg_log(2, "%32s mp_timelimit: %f", "map_manageEnd(in)", get_cvar_float("mp_timelimit"));

g_pauseMapEndManagerTask = true;

if (get_realplayersnum() <= 1)
{
// at most there is only one player on the server, so no need to stay around
map_change();
}
else
{
if (get_pcvar_num(cvar_endOnRound) && g_wasLastRound == false)
{
// let the server know it's the last round
g_wasLastRound = true;

// let the players know it's the last round
if (g_voteStatus & VOTE_FORCED)
{
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_CHANGE_NEXTROUND");
}
else
{
client_print(0, print_chat, "%L %L", LANG_PLAYER, "GAL_CHANGE_TIMEEXPIRED", LANG_PLAYER, "GAL_CHANGE_NEXTROUND");
}

// prevent the map from ending automatically
server_cmd("mp_timelimit 0");
}
else
{
// freeze the game and show the scoreboard
message_begin(MSG_ALL, SVC_INTERMISSION);
message_end();

//new chatTime = floatround(get_cvar_float("mp_chattime"), floatround_floor);

// display intermission expiration countdown
//set_task(1.0, "intermission_displayTimer", chatTime, _, _, "a", chatTime);

// change the map after "chattime" is over
set_task(floatmax(get_cvar_float("mp_chattime"), 2.0), "map_change");
}

new map[MAX_MAPNAME_LEN + 1];
get_cvar_string("amx_nextmap", map, sizeof(map)-1);
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_NEXTMAP", map);
}

dbg_log(2, "%32s mp_timelimit: %f", "map_manageEnd(out)", get_cvar_float("mp_timelimit"));
}

/*
public intermission_displayTimer(originalChatTime)
{
static secondsLeft = -1;
if (secondsLeft == -1)
{
secondsLeft = originalChatTime;
}
secondsLeft--;

client_print(0, print_center, "Intermission ends in %i seconds.", secondsLeft);
client_print(0, print_chat, "%i seconds", secondsLeft);

set_hudmessage(255, 0, 90, 0.80, 0.20, 0, 1.0, 2.0, 0.1, 0.1, -1);
// set_hudmessage(0, 222, 50, -1.0, 0.13, 0, 1.0, 0.94, 0.0, 0.0, -1);
show_hudmessage(0, "Intermission ends in %i seconds.", secondsLeft);
// use audio since visual doesn't seem to work
// something like "map will change in 2 seconds"

}
*/

public event_round_start()
{
if (g_wasLastRound)
{
map_manageEnd();
}
}

public event_game_commencing()
{
// make sure the reset time is the original time limit
// (can be skewed if map was previously extended)
map_restoreOriginalTimeLimit();
}

public event_intermission()
{
// don't let the normal end interfere
g_pauseMapEndManagerTask = true;

// change the map after "chattime" is over
set_task(floatmax(get_cvar_float("mp_chattime"), 2.0), "map_change");

return PLUGIN_CONTINUE;
}

map_getIdx(text[])
{
new map[MAX_MAPNAME_LEN + 1];
new mapIdx;
new nominationMap[32];

for (new prefixIdx = 0; prefixIdx < g_mapPrefixCnt; ++prefixIdx)
{
formatex(map, sizeof(map)-1, "%s%s", g_mapPrefix[prefixIdx], text);

for (mapIdx = 0; mapIdx < g_nominationMapCnt; ++mapIdx)
{
ArrayGetString(g_nominationMap, mapIdx, nominationMap, sizeof(nominationMap)-1);

if (equal(map, nominationMap))
{
return mapIdx;
}
}
}
return -1;
}

public cmd_say(id)
{
//-----
// generic say handler to determine if we need to act on what was said
//-----

static text[70], arg1[32], arg2[32], arg3[2];
read_args(text, sizeof(text)-1);
remove_quotes(text);
arg1[0] = '^0';
arg2[0] = '^0';
arg3[0] = '^0';
parse(text, arg1, sizeof(arg1)-1, arg2, sizeof(arg2)-1, arg3, sizeof(arg3)-1);

// if the chat line has more than 2 words, we're not interested at all
if (arg3[0] == 0)
{
new idxMap;

// if the chat line contains 1 word, it could be a map or a one-word command
if (arg2[0] == 0) // "say [rtv|rockthe<anything>vote]"
{
if ((get_pcvar_num(cvar_rtvCommands) & RTV_CMD_SHORTHAND && equali(arg1, "rtv")) || ((get_pcvar_num(cvar_rtvCommands) & RTV_CMD_DYNAMIC && equali(arg1, "rockthe", 7) && equali(arg1[strlen(arg1)-4], "vote"))))
{
vote_rock(id);
return PLUGIN_HANDLED;
}
else if (get_pcvar_num(cvar_nomPlayerAllowance))
{
if (equali(arg1, "noms"))
{
nomination_list(id);
return PLUGIN_HANDLED;
}
else
{
idxMap = map_getIdx(arg1);
if (idxMap >= 0)
{
nomination_toggle(id, idxMap);
return PLUGIN_HANDLED;
}
}
}
}
else if (get_pcvar_num(cvar_nomPlayerAllowance)) // "say <nominate|nom|cancel> <map>"
{
if (equali(arg1, "nominate") || equali(arg1, "nom"))
{
nomination_attempt(id, arg2);
return PLUGIN_HANDLED;
}
else if (equali(arg1, "cancel"))
{
// bpj -- allow ambiguous cancel in which case a menu of their nominations is shown
idxMap = map_getIdx(arg2);
if (idxMap >= 0)
{
nomination_cancel(id, idxMap);
return PLUGIN_HANDLED;
}
}
}
}
return PLUGIN_CONTINUE;
}

nomination_attempt(id, nomination[]) // (playerName[], &phraseIdx, matchingSegment[])
{
// all map names are stored as lowercase, so normalize the nomination
strtolower(nomination);

// assume there'll be more than one match (because we're lazy) and starting building the match menu
//menu_destroy(g_nominationMatchesMenu[id]);
g_nominationMatchesMenu[id] = menu_create("Номинировать карту", "nomination_handleMatchChoice");

// gather all maps that match the nomination
new mapIdx, nominationMap[32], matchCnt = 0, matchIdx = -1, info[1], choice[64], disabledReason[16];
for (mapIdx = 0; mapIdx < g_nominationMapCnt && matchCnt <= MAX_NOM_MATCH_CNT; ++mapIdx)
{
ArrayGetString(g_nominationMap, mapIdx, nominationMap, sizeof(nominationMap)-1);

if (contain(nominationMap, nomination) > -1)
{
matchCnt++;
matchIdx = mapIdx; // store in case this is the only match

// there may be a much better way of doing this, but I didn't feel like
// storing the matches and mapIdx's only to loop through them again
info[0] = mapIdx;

// in most cases, the map will be available for selection, so assume that's the case here
disabledReason[0] = 0;

// disable if the map has already been nominated
if (nomination_getPlayer(mapIdx))
{
formatex(disabledReason, sizeof(disabledReason)-1, "%L", id, "GAL_MATCH_NOMINATED");
}
// disable if the map is too recent
else if (map_isTooRecent(nominationMap))
{
formatex(disabledReason, sizeof(disabledReason)-1, "%L", id, "GAL_MATCH_TOORECENT");
}
else if (equal(g_currentMap, nominationMap))
{
formatex(disabledReason, sizeof(disabledReason)-1, "%L", id, "GAL_MATCH_CURRENTMAP");
}

formatex(choice, sizeof(choice)-1, "%s %s", nominationMap, disabledReason);
menu_additem(g_nominationMatchesMenu[id], choice, info, (disabledReason[0] == 0) ? 0 : (1<<26));
}
}

// handle the number of matches
switch (matchCnt)
{
case 0:
{
// no matches; pity the poor fool
client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_NOMATCHES", nomination);
}
case 1:
{
// one match?! omg, this is just like awesome
map_nominate(id, matchIdx);

}
default:
{
// this is kinda sexy; we put up a menu of the matches for them to pick the right one
client_print(id, print_chat, "%L", id, "GAL_NOM_MATCHES", nomination);
if (matchCnt == MAX_NOM_MATCH_CNT)
{
client_print(id, print_chat, "%L", id, "GAL_NOM_MATCHES_MAX", MAX_NOM_MATCH_CNT, MAX_NOM_MATCH_CNT);
}
menu_display(id, g_nominationMatchesMenu[id]);
}
}
}

public nomination_handleMatchChoice(id, menu, item)
{
if( item < 0 ) return PLUGIN_CONTINUE;

// Get item info
new mapIdx, info[1];
new access, callback;

menu_item_getinfo(g_nominationMatchesMenu[id], item, access, info, 1, _, _, callback);

mapIdx = info[0];
map_nominate(id, mapIdx);

return PLUGIN_HANDLED;
}

nomination_getPlayer(idxMap)
{
// check if the map has already been nominated
new idxNomination;
new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);

for (new idPlayer = 1; idPlayer <= MAX_PLAYER_CNT; ++idPlayer)
{
for (idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
{
if (idxMap == g_nomination[idPlayer][idxNomination])
{
return idPlayer;
}
}
}
return 0;
}

nomination_toggle(id, idxMap)
{
new idNominator = nomination_getPlayer(idxMap);
if (idNominator == id)
{
nomination_cancel(id, idxMap);
}
else
{
map_nominate(id, idxMap, idNominator);
}
}

nomination_cancel(id, idxMap)
{
// cancellations can only be made if a vote isn't already in progress
if (g_voteStatus & VOTE_IN_PROGRESS)
{
client_print(id, print_chat, "%L", id, "GAL_CANCEL_FAIL_INPROGRESS");
return;
}
// and if the outcome of the vote hasn't already been determined
else if (g_voteStatus & VOTE_IS_OVER)
{
client_print(id, print_chat, "%L", id, "GAL_CANCEL_FAIL_VOTEOVER");
return;
}

new bool:nominationFound, idxNomination;
new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);

for (idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
{
if (g_nomination[id][idxNomination] == idxMap)
{
nominationFound = true;
break;
}
}

new mapName[32];
ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);

if (nominationFound)
{
g_nomination[id][idxNomination] = -1;
g_nominationCnt--;

nomination_announceCancellation(mapName);
}
else
{
new idNominator = nomination_getPlayer(idxMap);
if (idNominator)
{
new name[32];
get_user_name(idNominator, name, 31);

client_print(id, print_chat, "%L", id, "GAL_CANCEL_FAIL_SOMEONEELSE", mapName, name);
}
else
{
client_print(id, print_chat, "%L", id, "GAL_CANCEL_FAIL_WASNOTYOU", mapName);
}
}
}

map_nominate(id, idxMap, idNominator = -1)
{
// nominations can only be made if a vote isn't already in progress
if (g_voteStatus & VOTE_IN_PROGRESS)
{
client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_INPROGRESS");
return;
}
// and if the outcome of the vote hasn't already been determined
else if (g_voteStatus & VOTE_IS_OVER)
{
client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_VOTEOVER");
return;
}

new mapName[32];
ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);

// players can not nominate the current map
if (equal(g_currentMap, mapName))
{
client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_CURRENTMAP", g_currentMap);
return;
}

// players may not be able to nominate recently played maps
if (map_isTooRecent(mapName))
{
client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_TOORECENT", mapName);
client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_TOORECENT_HLP");
return;
}

// check if the map has already been nominated
if (idNominator == -1)
{
idNominator = nomination_getPlayer(idxMap);
}

if (idNominator == 0)
{
// determine the number of nominations the player already made
// and grab an open slot with the presumption that the player can make the nomination
new nominationCnt = 0, idxNominationOpen, idxNomination;
new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);

for (idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
{
if (g_nomination[id][idxNomination] >= 0)
{
nominationCnt++;
}
else
{
idxNominationOpen = idxNomination;
}
}

if (nominationCnt == playerNominationMax)
{
new nominatedMaps[256], buffer[32];
for (idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
{
idxMap = g_nomination[id][idxNomination];
ArrayGetString(g_nominationMap, idxMap, buffer, sizeof(buffer)-1);
format(nominatedMaps, sizeof(nominatedMaps)-1, "%s%s%s", nominatedMaps, (idxNomination == 1) ? "" : ", ", buffer);
}

client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_TOOMANY", playerNominationMax, nominatedMaps);
client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_TOOMANY_HLP");
}
else
{
// otherwise, allow the nomination
g_nomination[id][idxNominationOpen] = idxMap;
g_nominationCnt++;
map_announceNomination(id, mapName);
client_print(id, print_chat, "%L", id, "GAL_NOM_GOOD_HLP");
}
}
else if (idNominator == id)
{
client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_ALREADY", mapName);
}
else
{
new name[32];
get_user_name(idNominator, name, 31);

client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_SOMEONEELSE", mapName, name);
client_print(id, print_chat, "%L", id, "GAL_NOM_FAIL_SOMEONEELSE_HLP");
}
}

public nomination_list(id)
{
new idxNomination, idxMap; //, hudMessage[512];
new msg[101], mapCnt;
new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);
new mapName[32];

for (new idPlayer = 1; idPlayer <= MAX_PLAYER_CNT; ++idPlayer)
{
for (idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
{
idxMap = g_nomination[idPlayer][idxNomination];
if (idxMap >= 0)
{
ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);
format(msg, sizeof(msg)-1, "%s, %s", msg, mapName);

if (++mapCnt == 4) // list 4 maps per chat line
{
client_print(0, print_chat, "%L: %s", LANG_PLAYER, "GAL_NOMINATIONS", msg[2]);
mapCnt = 0;
msg[0] = 0;
}
// construct the HUD message
// format(hudMessage, sizeof(hudMessage)-1, "%s^n%s", hudMessage, mapName);

// construct the console message
}
}
}
if (msg[0])
{
client_print(0, print_chat, "%L: %s", LANG_PLAYER, "GAL_NOMINATIONS", msg[2]);
}
else
{
client_print(0, print_chat, "%L: %L", LANG_PLAYER, "GAL_NOMINATIONS", LANG_PLAYER, "NONE");
}

// set_hudmessage(255, 0, 90, 0.80, 0.20, 0, 1.0, 12.0, 0.1, 0.1, -1);
// ShowSyncHudMsg(id, g_nonOverlapHudSync, hudMessage);
}

public vote_startDirector(bool:forced)
{
new choicesLoaded, voteDuration;

if (g_voteStatus & VOTE_IS_RUNOFF)
{
choicesLoaded = vote_loadRunoffChoices();
voteDuration = get_pcvar_num(cvar_runoffDuration);

if (get_realplayersnum())
{
dbg_log(4, " [RUNOFF VOTE CHOICES (%i)]", choicesLoaded);
}
}
else
{
// make it known that a vote is in progress
g_voteStatus |= VOTE_IN_PROGRESS;

// stop RTV reminders
remove_task(TASKID_REMINDER);

// set nextmap to "voting"
if (forced || get_pcvar_num(cvar_endOfMapVote))
{
new nextMap[32];
formatex(nextMap, sizeof(nextMap)-1, "%L", LANG_SERVER, "GAL_NEXTMAP_VOTING");
map_setNext(nextMap);
}

// pause the "end of map" tasks so they don't interfere
g_pauseMapEndVoteTask = true;
g_pauseMapEndManagerTask = true;

if (forced)
{
g_voteStatus |= VOTE_FORCED;
}

choicesLoaded = vote_loadChoices();
voteDuration = get_pcvar_num(cvar_voteDuration);

if (get_realplayersnum())
{
dbg_log(4, " [PRIMARY VOTE CHOICES (%i)]", choicesLoaded);
}

if (choicesLoaded)
{
// clear all nominations
nomination_clearAll();
}
}

if (choicesLoaded)
{
// alphabetize the maps
SortCustom2D(g_mapChoice, choicesLoaded, "sort_stringsi");

// dbg code ----
if (get_realplayersnum())
{
for (new dbgChoice = 0; dbgChoice < choicesLoaded; dbgChoice++)
{
dbg_log(4, " %i. %s", dbgChoice+1, g_mapChoice[dbgChoice]);
}
}
//--------------

// mark the players who are in this vote for use later
new player[32], playerCnt;
get_players(player, playerCnt, "ch"); // skip bots and hltv
for (new idxPlayer = 0; idxPlayer < playerCnt; ++idxPlayer)
{
g_voted[player[idxPlayer]] = false;
}

// make perfunctory announcement: "get ready to choose a map"
if (!(get_pcvar_num(cvar_soundsMute) & SOUND_GETREADYTOCHOOSE))
{
client_cmd(0, "spk ^"get red(e80) ninety(s45) to check(e20) use bay(s18) mass(e42) cap(s50)^"");
}

// announce the pending vote countdown from 7 to 1
set_task(1.0, "vote_countdownPendingVote", _, _, _, "a", 7);

// display the map choices
set_task(8.5, "vote_handleDisplay");

// display the vote outcome
if (get_pcvar_num(cvar_voteStatus))
{
new arg[3] = {-1, -1, false}; // indicates it's the end of vote display
set_task(8.5 + float(voteDuration) + 1.0, "vote_display", _, arg, 3);
set_task(8.5 + float(voteDuration) + 6.0, "vote_expire");
}
else
{
set_task(8.5 + float(voteDuration) + 3.0, "vote_expire");
}
}
else
{
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_VOTE_NOMAPS");
}
if (get_realplayersnum())
{
dbg_log(4, "");
dbg_log(4, " [PLAYER CHOICES]");
}
}

public vote_countdownPendingVote()
{
static countdown = 7;

// visual countdown
set_hudmessage(0, 222, 50, -1.0, 0.13, 0, 1.0, 0.94, 0.0, 0.0, -1);
show_hudmessage(0, "%L", LANG_PLAYER, "GAL_VOTE_COUNTDOWN", countdown);

// audio countdown
if (!(get_pcvar_num(cvar_soundsMute) & SOUND_COUNTDOWN))
{
new word[6];
num_to_word(countdown, word, 5);

client_cmd(0, "spk ^"fvox/%s^"", word);
}

// decrement the countdown
countdown--;

if (countdown == 0)
{
countdown = 7;
}
}

vote_addNominations()
{
// dbg code ----
if (get_realplayersnum())
{
dbg_log(4, " [NOMINATIONS (%i)]", g_nominationCnt);
}
//--------------

if (g_nominationCnt)
{
// set how many total nominations we can use in this vote
new maxNominations = get_pcvar_num(cvar_nomQtyUsed);
new slotsAvailable = g_choiceMax - g_choiceCnt;
new voteNominationMax = (maxNominations) ? min(maxNominations, slotsAvailable) : slotsAvailable;

// set how many total nominations each player is allowed
new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);

// add as many nominations as we can
// [TODO: develop a better method of determining which nominations make the cut; either FIFO or random]
new idxMap, id, mapName[32];

// dbg code ----
if (get_realplayersnum())
{
new nominator_id, playerName[32];
for (new idxNomination = playerNominationMax; idxNomination >= 1; --idxNomination)
{
for (id = 1; id <= MAX_PLAYER_CNT; ++id)
{
idxMap = g_nomination[id][idxNomination];
if (idxMap >= 0)
{
ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);
nominator_id = nomination_getPlayer(idxMap);
get_user_name(nominator_id, playerName, sizeof(playerName)-1);

dbg_log(4, " %-32s %s", mapName, playerName);
}
}
}
dbg_log(4, "");
}
//--------------

for (new idxNomination = playerNominationMax; idxNomination >= 1; --idxNomination)
{
for (id = 1; id <= MAX_PLAYER_CNT; ++id)
{
idxMap = g_nomination[id][idxNomination];
if (idxMap >= 0)
{
ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);
copy(g_mapChoice[g_choiceCnt++], sizeof(g_mapChoice[])-1, mapName);

if (g_choiceCnt == voteNominationMax)
{
break;
}
}
}
if (g_choiceCnt == voteNominationMax)
{
break;
}
}
}
}

vote_addFiller()
{
if (g_choiceCnt == g_choiceMax)
{
return;
}

// grab the name of the filler file
new filename[256];
get_pcvar_string(cvar_voteMapFile, filename, sizeof(filename)-1);

// create an array of files that will be pulled from
new fillerFile[8][256];
new mapsPerGroup[8], groupCnt;

if (!equal(filename, "*"))
{
// determine what kind of file it's being used as
new file = fopen(filename, "rt");
if (file)
{
new buffer[16];
fgets(file, buffer, sizeof(buffer)-1);
trim(buffer);
fclose(file);

if (equali(buffer, "[groups]"))
{
dbg_log(8, " ");
dbg_log(8, "this is a [groups] file");
// read the filler file to determine how many groups there are (max of 8)
new groupIdx;

file = fopen(filename, "rt");

while (!feof(file))
{
fgets(file, buffer, sizeof(buffer)-1);
trim(buffer);
// dbg_log(8, "buffer: %s isdigit: %i groupCnt: %i ", buffer, isdigit(buffer[0]), groupCnt);

if (isdigit(buffer[0]))
{
if (groupCnt < 8)
{
groupIdx = groupCnt++;
mapsPerGroup[groupIdx] = str_to_num(buffer);
formatex(fillerFile[groupIdx], sizeof(fillerFile[])-1, "%s/%i.ini", DIR_CONFIGS, groupCnt);
// dbg_log(8, "fillerFile: %s", fillerFile[groupIdx]);
}
else
{
log_error(AMX_ERR_BOUNDS, "%L", LANG_SERVER, "GAL_GRP_FAIL_TOOMANY", filename);
break;
}
}
}

fclose(file);

if (groupCnt == 0)
{
log_error(AMX_ERR_GENERAL, "%L", LANG_SERVER, "GAL_GRP_FAIL_NOCOUNTS", filename);
return;
}
}
else
{
// we presume it's a listing of maps, ala mapcycle.txt
copy(fillerFile[0], sizeof(filename)-1, filename);
mapsPerGroup[0] = 8;
groupCnt = 1;
}
}
else
{
log_error(AMX_ERR_NOTFOUND, "%L", LANG_SERVER, "GAL_FILLER_NOTFOUND", fillerFile);
}
}
else
{
// we'll be loading all maps in the /maps folder
copy(fillerFile[0], sizeof(filename)-1, filename);
mapsPerGroup[0] = 8;
groupCnt = 1;
}

// fill remaining slots with random maps from each filler file, as much as possible
new mapCnt, mapKey, allowedCnt, unsuccessfulCnt, choiceIdx, mapName[32];

for (new groupIdx = 0; groupIdx < groupCnt; ++groupIdx)
{
mapCnt = map_loadFillerList(fillerFile[groupIdx]);
dbg_log(8, "[%i] groupCnt:%i mapCnt: %i g_choiceCnt: %i g_choiceMax: %i fillerFile: %s", groupIdx, groupCnt, mapCnt, g_choiceCnt, g_choiceMax, fillerFile[groupIdx]);

if (g_choiceCnt < g_choiceMax && mapCnt)
{
unsuccessfulCnt = 0;
allowedCnt = min(min(mapsPerGroup[groupIdx], g_choiceMax - g_choiceCnt), mapCnt);
dbg_log(8, "[%i] allowedCnt: %i mapsPerGroup: %i Max-Cnt: %i", groupIdx, allowedCnt, mapsPerGroup[groupIdx], g_choiceMax - g_choiceCnt);

for (choiceIdx = 0; choiceIdx < allowedCnt; ++choiceIdx)
{
mapKey = random_num(0, mapCnt - 1);
ArrayGetString(g_fillerMap, mapKey, mapName, sizeof(mapName)-1);
dbg_log(8, "[%i] choiceIdx: %i allowedCnt: %i mapKey: %i mapName: %s", groupIdx, choiceIdx, allowedCnt, mapKey, mapName);
unsuccessfulCnt = 0;

while ((map_isInMenu(mapName) || equal(g_currentMap, mapName) || map_isTooRecent(mapName) || prefix_isInMenu(mapName)) && unsuccessfulCnt < mapCnt)
{
unsuccessfulCnt++;
if (++mapKey == mapCnt)
{
mapKey = 0;
}
ArrayGetString(g_fillerMap, mapKey, mapName, sizeof(mapName)-1);
}

if (unsuccessfulCnt == mapCnt)
{
//client_print(0, print_chat, "unsuccessfulCnt: %i mapCnt: %i", unsuccessfulCnt, mapCnt);
// there aren't enough maps in this filler file to continue adding anymore
break;
}

//client_print(0, print_chat, "mapIdx: %i map: %s", mapIdx, mapName);
copy(g_mapChoice[g_choiceCnt++], sizeof(g_mapChoice[])-1, mapName);
dbg_log(8, "[%i] mapName: %s unsuccessfulCnt: %i mapCnt: %i g_choiceCnt: %i", groupIdx, mapName, unsuccessfulCnt, mapCnt, g_choiceCnt);
}
}
}
}

vote_loadChoices()
{
vote_addNominations();
vote_addFiller();

return g_choiceCnt;
}

vote_loadRunoffChoices()
{
new choiceCnt;

new runoffChoice[2][MAX_MAPNAME_LEN+1];
copy(runoffChoice[0], sizeof(runoffChoice[])-1, g_mapChoice[g_runoffChoice[0]]);
copy(runoffChoice[1], sizeof(runoffChoice[])-1, g_mapChoice[g_runoffChoice[1]]);

new mapIdx;
if (g_runoffChoice[0] != g_choiceCnt)
{
copy(g_mapChoice[mapIdx++], sizeof(g_mapChoice[])-1, runoffChoice[0]);
choiceCnt++;
}
if (g_runoffChoice[1] != g_choiceCnt)
{
choiceCnt++;
}
copy(g_mapChoice[mapIdx], sizeof(g_mapChoice[])-1, runoffChoice[1]);

g_choiceCnt = choiceCnt;

return choiceCnt;
}

public vote_handleDisplay()
{
// announce: "time to choose"
if (!(get_pcvar_num(cvar_soundsMute) & SOUND_TIMETOCHOOSE))
{
client_cmd(0, "spk Gman/Gman_Choose%i", random_num(1, 2));
}

if (g_voteStatus & VOTE_IS_RUNOFF)
{
g_voteDuration = get_pcvar_num(cvar_runoffDuration);
}
else
{
g_voteDuration = get_pcvar_num(cvar_voteDuration);
}

if (get_pcvar_num(cvar_voteStatus) && get_pcvar_num(cvar_voteStatusType) == SHOWSTATUSTYPE_PERCENTAGE)
{
copy(g_voteTallyType, sizeof(g_voteTallyType)-1, "%");
}

if (get_cvar_num("gal_debug") & 4)
{
set_task(2.0, "dbg_fakeVotes");
}

// make sure the display is contructed from scratch
g_refreshVoteStatus = true;

// ensure the vote status doesn't indicate expired
g_voteStatus &= ~VOTE_HAS_EXPIRED;

new arg[3];
arg[0] = true;
arg[1] = 0;
arg[2] = false;

if (get_pcvar_num(cvar_voteStatus) == SHOWSTATUS_VOTE)
{
set_task(1.0, "vote_display", _, arg, sizeof(arg), "a", g_voteDuration);
}
else
{
set_task(1.0, "vote_display", _, arg, sizeof(arg));
}
}

public vote_display(arg[3])
{
static allKeys = MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_4|MENU_KEY_5|MENU_KEY_6|MENU_KEY_7|MEN
U_KEY_8|MENU_KEY_9|MENU_KEY_0;
static keys, voteStatus[512], voteTally[16];

new updateTimeRemaining = arg[0];
new id = arg[1];

// dbg code ----
if (get_realplayersnum())
{
new snuff = (id > 0) ? g_snuffDisplay[id] : -1;
dbg_log(4, " [votedisplay()] id: %i updateTimeRemaining: %i unsnuffDisplay: %i g_snuffDisplay: %i g_refreshVoteStatus: %i g_choiceCnt: %i len(g_vote): %i len(voteStatus): %i", arg[1], arg[0], arg[2], snuff, g_refreshVoteStatus, g_choiceCnt, strlen(g_vote), strlen(voteStatus));
}

if (id > 0 && g_snuffDisplay[id])
{
new unsnuffDisplay = arg[2];
if (unsnuffDisplay)
{
g_snuffDisplay[id] = false;
}
else
{
return;
}
}

new isVoteOver = (updateTimeRemaining == -1 && id == -1);
new charCnt;

if (g_refreshVoteStatus || isVoteOver)
{
// wipe the previous vote status clean
voteStatus[0] = 0;
keys = MENU_KEY_0;

new voteCnt;

new allowStay = (g_voteStatus & VOTE_IS_EARLY);

new isRunoff = (g_voteStatus & VOTE_IS_RUNOFF);
new bool:allowExtend = !allowStay && ((isRunoff && g_choiceCnt == 1) || (!(g_voteStatus & VOTE_FORCED) && !isRunoff && get_cvar_float("mp_timelimit") < get_pcvar_float(cvar_extendmapMax)));
if (get_cvar_num("gal_debug") & 4)
{
allowExtend = !allowStay && ((isRunoff && g_choiceCnt == 1) || (!isRunoff && get_cvar_float("mp_timelimit") < get_pcvar_float(cvar_extendmapMax)));
}

// add the header
if (isVoteOver)
{
charCnt = formatex(voteStatus, sizeof(voteStatus)-1, "%s%L^n", CLR_YELLOW, LANG_SERVER, "GAL_RESULT");
}
else
{
charCnt = formatex(voteStatus, sizeof(voteStatus)-1, "%s%L^n", CLR_YELLOW, LANG_SERVER, "GAL_CHOOSE");
}

// add maps to the menu
for (new choiceIdx = 0; choiceIdx < g_choiceCnt; ++choiceIdx)
{
voteCnt = g_mapVote[choiceIdx];
vote_getTallyStr(voteTally, sizeof(voteTally)-1, voteCnt);

charCnt += formatex(voteStatus[charCnt], sizeof(voteStatus)-1-charCnt, "^n%s%i. %s%s%s", CLR_RED, choiceIdx+1, CLR_WHITE, g_mapChoice[choiceIdx], voteTally);
keys |= (1<<choiceIdx);
}

// add optional menu item
if (allowExtend || allowStay)
{
// if it's not a runoff vote, add a space between the maps and the additional option
if (g_voteStatus & VOTE_IS_RUNOFF == 0)
{
charCnt += formatex(voteStatus[charCnt], sizeof(voteStatus)-1-charCnt, "^n");
}

vote_getTallyStr(voteTally, sizeof(voteTally)-1, g_mapVote[g_choiceCnt]);

if (allowExtend)
{
// add the "Extend Map" menu item.
charCnt += formatex(voteStatus[charCnt], sizeof(voteStatus)-1-charCnt, "^n%s%i. %s%L%s", CLR_RED, g_choiceCnt+1, CLR_WHITE, LANG_SERVER, "GAL_OPTION_EXTEND", g_currentMap, floatround(get_pcvar_float(cvar_extendmapStep)), voteTally);
}
else
{
// add the "Stay Here" menu item
charCnt += formatex(voteStatus[charCnt], sizeof(voteStatus)-1-charCnt, "^n%s%i. %s%L%s", CLR_RED, g_choiceCnt+1, CLR_WHITE, LANG_SERVER, "GAL_OPTION_STAY", voteTally);
}

keys |= (1<<g_choiceCnt);
}

// make a copy of the virgin menu
if (g_vote[0] == 0)
{
new cleanCharCnt = copy(g_vote, sizeof(g_vote)-1, voteStatus);

// append a "None" option on for people to choose if they don't like any other choice
formatex(g_vote[cleanCharCnt], sizeof(g_vote)-1-cleanCharCnt, "^n^n%s0. %s%L", CLR_RED, CLR_WHITE, LANG_SERVER, "GAL_OPTION_NONE");
}

charCnt += formatex(voteStatus[charCnt], sizeof(voteStatus)-1-charCnt, "^n^n");

g_refreshVoteStatus = false;
}

static voteFooter[32];
if (updateTimeRemaining && get_pcvar_num(cvar_voteExpCountdown))
{
charCnt = copy(voteFooter, sizeof(voteFooter)-1, "^n^n");

if (--g_voteDuration <= 10)
{
formatex(voteFooter[charCnt], sizeof(voteFooter)-1-charCnt, "%s%L: %s%i", CLR_GREY, LANG_SERVER, "GAL_TIMELEFT", CLR_RED, g_voteDuration);
}
}

// create the different displays
static menuClean[512], menuDirty[512];
menuClean[0] = 0;
menuDirty[0] = 0;

formatex(menuClean, sizeof(menuClean)-1, "%s%s", g_vote, voteFooter);
if (!isVoteOver)
{
formatex(menuDirty, sizeof(menuDirty)-1, "%s%s", voteStatus, voteFooter);
}
else
{
formatex(menuDirty, sizeof(menuDirty)-1, "%s^n^n%s%L", voteStatus, CLR_YELLOW, LANG_SERVER, "GAL_VOTE_ENDED");
}

new menuid, menukeys;

// display the vote
new showStatus = get_pcvar_num(cvar_voteStatus);
if (id > 0)
{
// optionally display to single player that just voted
if (showStatus == SHOWSTATUS_VOTE)
{
// dbg code ----
new name[32];
get_user_name(id, name, 31);

dbg_log(4, " [%s (dirty, just voted)]", name);
dbg_log(4, " %s", menuDirty);
//--------------

get_user_menu(id, menuid, menukeys);
if (menuid == 0 || menuid == g_menuChooseMap)
{
show_menu(id, allKeys, menuDirty, max(1, g_voteDuration), MENU_CHOOSEMAP);
}
}
}
else
{
// display to everyone
new players[32], playerCnt;
get_players(players, playerCnt, "ch"); // skip bots and hltv

for (new playerIdx = 0; playerIdx < playerCnt; ++playerIdx)
{
id = players[playerIdx];

if (g_voted[id] == false && !isVoteOver)
{
// dbg code ----
if (playerIdx == 0)
{
new name[32];
get_user_name(id, name, 31);

dbg_log(4, " [%s (clean)]", name);
dbg_log(4, " %s", menuClean);
}
//--------------

get_user_menu(id, menuid, menukeys);
if (menuid == 0 || menuid == g_menuChooseMap)
{
show_menu(id, keys, menuClean, g_voteDuration, MENU_CHOOSEMAP);
}
}
else
{
if ((isVoteOver && showStatus) || (showStatus == SHOWSTATUS_VOTE && g_voted[id]))
{
// dbg code ----
if (playerIdx == 0)
{
new name[32];
get_user_name(id, name, 31);

dbg_log(4, " [%s (dirty)]", name);
dbg_log(4, " %s", menuDirty);
}
//--------------

get_user_menu(id, menuid, menukeys);
if (menuid == 0 || menuid == g_menuChooseMap)
{
show_menu(id, allKeys, menuDirty, (isVoteOver) ? 5 : max(1, g_voteDuration), MENU_CHOOSEMAP);
}
}
}
// dbg code ----
if (id == 1)
{
dbg_log(4, "");
}
//--------------
}
}
}

vote_getTallyStr(voteTally[], voteTallyLen, voteCnt)
{
if (voteCnt && get_pcvar_num(cvar_voteStatusType) == SHOWSTATUSTYPE_PERCENTAGE)
{
voteCnt = percent(voteCnt, g_votesCast);
}

if (get_pcvar_num(cvar_voteStatus) && voteCnt)
{
formatex(voteTally, voteTallyLen, " %s(%i%s)", CLR_GREY, voteCnt, g_voteTallyType);
}
else
{
voteTally[0] = 0;
}
}

public vote_expire()
{
g_voteStatus |= VOTE_HAS_EXPIRED;

// dbg code ----
if (get_realplayersnum())
{
dbg_log(4, "");
dbg_log(4, " [VOTE RESULT]");
new voteTally[16];
for (new idxChoice = 0; idxChoice <= g_choiceCnt; ++idxChoice)
{
vote_getTallyStr(voteTally, sizeof(voteTally)-1, g_mapVote[idxChoice]);
dbg_log(4, " %2i/%3i %i. %s", g_mapVote[idxChoice], voteTally, idxChoice, g_mapChoice[idxChoice]);
}
dbg_log(4, "");
}
//--------------

g_vote[0] = 0;

// determine the number of votes for 1st and 2nd place
new firstPlaceVoteCnt, secondPlaceVoteCnt, totalVotes;
for (new idxChoice = 0; idxChoice <= g_choiceCnt; ++idxChoice)
{
totalVotes += g_mapVote[idxChoice];

if (firstPlaceVoteCnt < g_mapVote[idxChoice])
{
secondPlaceVoteCnt = firstPlaceVoteCnt;
firstPlaceVoteCnt = g_mapVote[idxChoice];
}
else if (secondPlaceVoteCnt < g_mapVote[idxChoice])
{
secondPlaceVoteCnt = g_mapVote[idxChoice];
}
}

// determine which maps are in 1st and 2nd place
new firstPlace[MAX_MAPS_IN_VOTE + 1], firstPlaceCnt;
new secondPlace[MAX_MAPS_IN_VOTE + 1], secondPlaceCnt;

for (new idxChoice = 0; idxChoice <= g_choiceCnt; ++idxChoice)
{
if (g_mapVote[idxChoice] == firstPlaceVoteCnt)
{
firstPlace[firstPlaceCnt++] = idxChoice;
}
else if (g_mapVote[idxChoice] == secondPlaceVoteCnt)
{
secondPlace[secondPlaceCnt++] = idxChoice;
}
}

// announce the outcome
new idxWinner;
if (firstPlaceVoteCnt)
{
// start a runoff vote, if needed
if (get_pcvar_num(cvar_runoffEnabled) && !(g_voteStatus & VOTE_IS_RUNOFF))
{
// if the top vote getting map didn't receive over 50% of the votes cast, start runoff vote
if (firstPlaceVoteCnt <= totalVotes / 2)
{
// announce runoff voting requirement
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_RUNOFF_REQUIRED");
if (!(get_pcvar_num(cvar_soundsMute) & SOUND_RUNOFFREQUIRED))
{
client_cmd(0, "spk ^"run officer(e40) voltage(e30) accelerating(s70) is required^"");
}

// let the server know the next vote will be a runoff
g_voteStatus |= VOTE_IS_RUNOFF;

// determine the two choices that will be facing off
new choice1Idx, choice2Idx;
if (firstPlaceCnt > 2)
{
choice1Idx = random_num(0, firstPlaceCnt - 1);
choice2Idx = random_num(0, firstPlaceCnt - 1);

if (choice2Idx == choice1Idx)
{
choice2Idx = (choice2Idx == firstPlaceCnt - 1) ? 0 : ++choice2Idx;
}

g_runoffChoice[0] = firstPlace[choice1Idx];
g_runoffChoice[1] = firstPlace[choice2Idx];

client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_RESULT_TIED1", firstPlaceCnt);
}
else if (firstPlaceCnt == 2)
{
g_runoffChoice[0] = firstPlace[0];
g_runoffChoice[1] = firstPlace[1];
}
else if (secondPlaceCnt == 1)
{
g_runoffChoice[0] = firstPlace[0];
g_runoffChoice[1] = secondPlace[0];
}
else
{
g_runoffChoice[0] = firstPlace[0];
g_runoffChoice[1] = secondPlace[random_num(0, secondPlaceCnt - 1)];

client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_RESULT_TIED2", secondPlaceCnt);
}

/*
// dbg
new dbg1 = g_runoffChoice[0];
new dbg2 = g_runoffChoice[1];
client_print(0, print_chat, "%s, %s", g_mapChoice[dbg1], g_mapChoice[dbg2]);
*/

// clear all the votes
vote_resetStats();

// start the runoff vote
set_task(5.0, "vote_startDirector");

return;
}
}

// if there is a tie for 1st, randomly select one as the winner
if (firstPlaceCnt > 1)
{
idxWinner = firstPlace[random_num(0, firstPlaceCnt - 1)];
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_WINNER_TIED", firstPlaceCnt);
}
else
{
idxWinner = firstPlace[0];
}

if (idxWinner == g_choiceCnt)
{
if (get_pcvar_num(cvar_endOfMapVote))
{
new nextMap[32];
formatex(nextMap, sizeof(nextMap)-1, "%L", LANG_SERVER, "GAL_NEXTMAP_UNKNOWN");
map_setNext(nextMap);
}

// restart map end vote task
g_pauseMapEndVoteTask = false;

if (g_voteStatus & VOTE_IS_EARLY)
{
// "stay here" won
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_WINNER_STAY");

// clear all the votes
vote_resetStats();

// no longer is an early vote
g_voteStatus &= ~VOTE_IS_EARLY;
}
else
{
// "extend map" won
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_WINNER_EXTEND", floatround(get_pcvar_float(cvar_extendmapStep)));
map_extend();
}
}
else
{
map_setNext(g_mapChoice[idxWinner]);
server_exec();

client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_NEXTMAP", g_mapChoice[idxWinner]);

g_voteStatus |= VOTE_IS_OVER;
}
}
else
{
// nobody voted. pick a random map from the choices provided.
idxWinner = random_num(0, g_choiceCnt - 1);
map_setNext(g_mapChoice[idxWinner]);

client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_WINNER_RANDOM", g_mapChoice[idxWinner]);

g_voteStatus |= VOTE_IS_OVER;
}

g_refreshVoteStatus = true;

new playerCnt = get_realplayersnum();

// vote is no longer in progress
g_voteStatus &= ~VOTE_IN_PROGRESS;

if (g_handleMapChange)
{
if ((g_voteStatus & VOTE_FORCED || (playerCnt == 1 && idxWinner < g_choiceCnt) || playerCnt == 0) && !(get_cvar_num("gal_debug") & 4))
{
// tell the map we need to finish up
set_task(2.0, "map_manageEnd");
}
else
{
// restart map end task
g_pauseMapEndManagerTask = false;
}
}
}

map_extend()
{
dbg_log(2, "%32s mp_timelimit: %f g_rtvWait: %f extendmapStep: %f", "map_extend(in)", get_cvar_float("mp_timelimit"), g_rtvWait, get_pcvar_float(cvar_extendmapStep));

// reset the "rtv wait" time, taking into consideration the map extension
if (g_rtvWait)
{
g_rtvWait = get_cvar_float("mp_timelimit") + g_rtvWait;
}

// do that actual map extension
set_cvar_float("mp_timelimit", get_cvar_float("mp_timelimit") + get_pcvar_float(cvar_extendmapStep));
server_exec();

// clear vote stats
vote_resetStats();

// if we were in a runoff mode, get out of it
g_voteStatus &= ~VOTE_IS_RUNOFF;

dbg_log(2, "%32s mp_timelimit: %f g_rtvWait: %f extendmapStep: %f", "map_extend(out)", get_cvar_float("mp_timelimit"), g_rtvWait, get_pcvar_float(cvar_extendmapStep));
}

vote_resetStats()
{
// g_vote[0] = 0;
g_votesCast = 0;
arrayset(g_mapVote, 0, MAX_MAPS_IN_VOTE + 1);
// reset everyones' rocks
arrayset(g_rockedVote, false, sizeof(g_rockedVote));
g_rockedVoteCnt = 0;
// reset everyones' votes
// arrayset(g_voted, false, sizeof(g_voted));
}

map_isInMenu(map[])
{
for (new idxChoice = 0; idxChoice < g_choiceCnt; ++idxChoice)
{
if (equal(map, g_mapChoice[idxChoice]))
{
return true;
}
}
return false;
}

prefix_isInMenu(map[])
{
if (get_pcvar_num(cvar_voteUniquePrefixes))
{
new tentativePrefix[8], existingPrefix[8], junk[8];

strtok(map, tentativePrefix, sizeof(tentativePrefix)-1, junk, sizeof(junk)-1, '_', 1);

for (new idxChoice = 0; idxChoice < g_choiceCnt; ++idxChoice)
{
strtok(g_mapChoice[idxChoice], existingPrefix, sizeof(existingPrefix)-1, junk, sizeof(junk)-1, '_', 1);

if (equal(tentativePrefix, existingPrefix))
{
return true;
}
}
}
return false;
}

map_isTooRecent(map[])
{
if (get_pcvar_num(cvar_banRecent))
{
for (new idxBannedMap = 0; idxBannedMap < g_cntRecentMap; ++idxBannedMap)
{
if (equal(map, g_recentMap[idxBannedMap]))
{
return true;
}
}
}
return false;
}

public vote_handleChoice(id, key)
{
if (g_voteStatus & VOTE_HAS_EXPIRED)
{
client_cmd(id, "^"slot%i^"", key + 1);
return;
}

g_snuffDisplay[id] = true;

if (g_voted[id] == false)
{
new name[32];
if (get_pcvar_num(cvar_voteAnnounceChoice))
{
get_user_name(id, name, sizeof(name)-1);
}

// dbg code ----
get_user_name(id, name, sizeof(name)-1);
//--------------

// confirm the player's choice
if (key == 9)
{
dbg_log(4, " %-32s (none)", name);

if (get_pcvar_num(cvar_voteAnnounceChoice))
{
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_CHOICE_NONE_ALL", name);
}
else
{
client_print(id, print_chat, "%L", id, "GAL_CHOICE_NONE");
}
}
else
{
// increment votes cast count
g_votesCast++;

if (key == g_choiceCnt)
{
// only display the "none" vote if we haven't already voted (we can make it here from the vote status menu too)
if (g_voted[id] == false)
{
dbg_log(4, " %-32s (extend)", name);

if (get_pcvar_num(cvar_voteAnnounceChoice))
{
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_CHOICE_EXTEND_ALL", name);
}
else
{
client_print(id, print_chat, "%L", id, "GAL_CHOICE_EXTEND");
}
}
}
else
{
dbg_log(4, " %-32s %s", name, g_mapChoice[key]);

if (get_pcvar_num(cvar_voteAnnounceChoice))
{
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_CHOICE_MAP_ALL", name, g_mapChoice[key]);
}
else
{
client_print(id, print_chat, "%L", id, "GAL_CHOICE_MAP", g_mapChoice[key]);
}
}

// register the player's choice giving extra weight to admin votes
new voteWeight = get_pcvar_num(cvar_voteWeight);
if (voteWeight > 1 && has_flag(id, g_voteWeightFlags))
{
g_mapVote[key] += voteWeight;
g_votesCast += (voteWeight - 1);
client_print(id, print_chat, "%L", id, "GAL_VOTE_WEIGHTED", voteWeight);
}
else
{
g_mapVote[key]++;
}
}

g_voted[id] = true;
g_refreshVoteStatus = true;
}
else
{
client_cmd(id, "^"slot%i^"", key + 1);
}

// display the vote again, with status
if (get_pcvar_num(cvar_voteStatus) == SHOWSTATUS_VOTE)
{
new arg[3];
arg[0] = false;
arg[1] = id;
arg[2] = true;

set_task(0.1, "vote_display", _, arg, sizeof(arg));
//vote_display(arg);
}
}

public map_change()
{
// restore the map's timelimit, just in case we had changed it
map_restoreOriginalTimeLimit();

// grab the name of the map we're changing to
new map[MAX_MAPNAME_LEN + 1];
get_cvar_string("amx_nextmap", map, sizeof(map)-1);

// verify we're changing to a valid map
if (!is_map_valid(map))
{
// probably admin did something dumb like changed the map time limit below
// the time remaining in the map, thus making the map over immediately.
// since the next map is unknown, just restart the current map.
copy(map, sizeof(map)-1, g_currentMap);
}

// change to the map
server_cmd("changelevel %s", map);
}

Float:map_getMinutesElapsed()
{
dbg_log(2, "%32s mp_timelimit: %f", "map_getMinutesElapsed(in/out)", get_cvar_float("mp_timelimit"));
return get_cvar_float("mp_timelimit") - (float(get_timeleft()) / 60.0);
}

public vote_rock(id)
{
// if an early vote is pending, don't allow any rocks
if (g_voteStatus & VOTE_IS_EARLY)
{
client_print(id, print_chat, "%L", id, "GAL_ROCK_FAIL_PENDINGVOTE");
return;
}

new Float:minutesElapsed = map_getMinutesElapsed();

// if the player is the only one on the server, bring up the vote immediately
if (get_realplayersnum() == 1 && minutesElapsed > floatmin(2.0, g_rtvWait))
{
vote_startDirector(true);
return;
}

// make sure enough time has gone by on the current map
if (g_rtvWait)
{
if (minutesElapsed < g_rtvWait)
{
client_print(id, print_chat, "%L", id, "GAL_ROCK_FAIL_TOOSOON", floatround(g_rtvWait - minutesElapsed, floatround_ceil));
return;
}
}

// rocks can only be made if a vote isn't already in progress
if (g_voteStatus & VOTE_IN_PROGRESS)
{
client_print(id, print_chat, "%L", id, "GAL_ROCK_FAIL_INPROGRESS");
return;
}
// and if the outcome of the vote hasn't already been determined
else if (g_voteStatus & VOTE_IS_OVER)
{
client_print(id, print_chat, "%L", id, "GAL_ROCK_FAIL_VOTEOVER");
return;
}

// determine how many total rocks are needed
new rocksNeeded = vote_getRocksNeeded();

// make sure player hasn't already rocked the vote
if (g_rockedVote[id])
{
client_print(id, print_chat, "%L", id, "GAL_ROCK_FAIL_ALREADY", rocksNeeded - g_rockedVoteCnt);
rtv_remind(TASKID_REMINDER + id);
return;
}

// allow the player to rock the vote
g_rockedVote[id] = true;
client_print(id, print_chat, "%L", id, "GAL_ROCK_SUCCESS");

// make sure the rtv reminder timer has stopped
if (task_exists(TASKID_REMINDER))
{
remove_task(TASKID_REMINDER);
}

// determine if there have been enough rocks for a vote yet
if (++g_rockedVoteCnt >= rocksNeeded)
{
// announce that the vote has been rocked
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_ROCK_ENOUGH");

// start up the vote director
vote_startDirector(true);
}
else
{
// let the players know how many more rocks are needed
rtv_remind(TASKID_REMINDER);

if (get_pcvar_num(cvar_rtvReminder))
{
// initialize the rtv reminder timer to repeat how many rocks are still needed, at regular intervals
set_task(get_pcvar_float(cvar_rtvReminder) * 60.0, "rtv_remind", TASKID_REMINDER, _, _, "b");
}
}
}

vote_unrock(id)
{
if (g_rockedVote[id])
{
g_rockedVote[id] = false;
g_rockedVoteCnt--;
// and such
}
}

vote_getRocksNeeded()
{
return floatround(get_pcvar_float(cvar_rtvRatio) * float(get_realplayersnum()), floatround_ceil);
}

public rtv_remind(param)
{
new who = param - TASKID_REMINDER;

// let the players know how many more rocks are needed
client_print(who, print_chat, "%L", LANG_PLAYER, "GAL_ROCK_NEEDMORE", vote_getRocksNeeded() - g_rockedVoteCnt);
}

public cmd_listmaps(id)
{
// new arg1[8];
// new start = read_argv(1, arg1, 7) ? str_to_num(arg1) : 1;

map_listAll(id);

return PLUGIN_HANDLED;
}

public cmd_HL1_votemap(id)
{
if (get_pcvar_num(cvar_cmdVotemap) == 0)
{
con_print(id, "%L", id, "GAL_DISABLED");
return PLUGIN_HANDLED;
}
return PLUGIN_CONTINUE;
}

public cmd_HL1_listmaps(id)
{
switch (get_pcvar_num(cvar_cmdListmaps))
{
case 0:
{
con_print(id, "%L", id, "GAL_DISABLED");
}
case 2:
{
map_listAll(id);
}
default:
{
return PLUGIN_CONTINUE;
}
}
return PLUGIN_HANDLED;
}

map_listAll(id)
{
static lastMapDisplayed[MAX_PLAYER_CNT + 1][2];

// determine if the player has requested a listing before
new userid = get_user_userid(id);
if (userid != lastMapDisplayed[id][LISTMAPS_USERID])
{
lastMapDisplayed[id][LISTMAPS_USERID] = 0;
}

new command[32];
read_argv(0, command, sizeof(command)-1);

new arg1[8], start;
new mapCount = get_pcvar_num(cvar_listmapsPaginate);

if (mapCount)
{
if (read_argv(1, arg1, sizeof(arg1)-1))
{
if (arg1[0] == '*')
{
// if the last map previously displayed belongs to the current user,
// start them off there, otherwise, start them at 1
if (lastMapDisplayed[id][LISTMAPS_USERID])
{
start = lastMapDisplayed[id][LISTMAPS_LAST] + 1;
}
else
{
start = 1;
}
}
else
{
start = str_to_num(arg1);
}
}
else
{
start = 1;
}

if (id == 0 && read_argc() == 3 && read_argv(2, arg1, sizeof(arg1)-1))
{
mapCount = str_to_num(arg1);
}
}

if (start < 1)
{
start = 1;
}

if (start >= g_nominationMapCnt)
{
start = g_nominationMapCnt - 1;
}

new end = mapCount ? start + mapCount - 1 : g_nominationMapCnt;

if (end > g_nominationMapCnt)
{
end = g_nominationMapCnt;
}

// this enables us to use 'command *' to get the next group of maps, when paginated
lastMapDisplayed[id][LISTMAPS_USERID] = userid;
lastMapDisplayed[id][LISTMAPS_LAST] = end - 1;

con_print(id, "^n----- %L -----", id, "GAL_LISTMAPS_TITLE", g_nominationMapCnt);

new nominated[64], nominator_id, name[32], mapName[32], idx;
for (idx = start - 1; idx < end; idx++)
{
nominator_id = nomination_getPlayer(idx);
if (nominator_id)
{
get_user_name(nominator_id, name, sizeof(name)-1);
formatex(nominated, sizeof(nominated)-1, "%L", id, "GAL_NOMINATEDBY", name);
}
else
{
nominated[0] = 0;
}
ArrayGetString(g_nominationMap, idx, mapName, sizeof(mapName)-1);
con_print(id, "%3i: %s %s", idx + 1, mapName, nominated);
}

if (mapCount && mapCount < g_nominationMapCnt)
{
con_print(id, "----- %L -----", id, "GAL_LISTMAPS_SHOWING", start, idx, g_nominationMapCnt);

if (end < g_nominationMapCnt)
{
con_print(id, "----- %L -----", id, "GAL_LISTMAPS_MORE", command, end + 1, command);
}
}
}

/*
map_listMatches(id, match[])
{
strtolower(match);
con_print(id, "%L", id, "GAL_MATCHING", match);
con_print(id, "------------------------------------------");

new mapName[32], matchCnt;
new nominated[64], nominator_id, name[32];

for (new idx = 1; idx <= g_nominationMapCnt; ++idx)
{
copy(mapName, sizeof(mapName)-1, g_nominationMap[idx]);
strtolower(mapName);

if (containi(mapName, match) > -1)
{
nominator_id = nomination_getPlayer(idx);
if (nominator_id)
{
get_user_name(nominator_id, name, sizeof(name)-1);
formatex(nominated, sizeof(nominated)-1, "(nominated by %s)", name);
}
else
{
nominated[0] = 0;
}
con_print(id, "%3i: %s %s", ++matchCnt, g_nominationMap[idx], nominated);
}
}
}
*/

con_print(id, message[], {Float,Sql,Result,_}:...)
{
new consoleMessage[256];
vformat(consoleMessage, sizeof(consoleMessage)-1, message, 3);

if (id)
{
new authid[32];
get_user_authid(id, authid, 31);

if (!equal(authid, "STEAM_ID_LAN"))
{
console_print(id, consoleMessage);
return;
}
}

server_print(consoleMessage);
}

public client_disconnect(id)
{
g_voted[id] = false;

// un-rock the vote
vote_unrock(id);

// cancel player's nominations
new playerNominationMax = min(get_pcvar_num(cvar_nomPlayerAllowance), MAX_NOMINATION_CNT);
new nominatedMaps[256], nominationCnt, idxMap, mapName[32];
for (new idxNomination = 1; idxNomination <= playerNominationMax; ++idxNomination)
{
idxMap = g_nomination[id][idxNomination];
if (idxMap >= 0)
{
ArrayGetString(g_nominationMap, idxMap, mapName, sizeof(mapName)-1);
nominationCnt++;
format(nominatedMaps, sizeof(nominatedMaps)-1, "%s%s, ", nominatedMaps, mapName);
g_nomination[id][idxNomination] = -1;
}
}
if (nominationCnt)
{
// strip the extraneous ", " from the string
nominatedMaps[strlen(nominatedMaps) - 2] = 0;

// inform the masses that the maps are no longer nominated
nomination_announceCancellation(nominatedMaps);
}

new dbg_playerCnt = get_realplayersnum()-1;
dbg_log(2, "%32s dbg_playerCnt:%i", "client_disconnect()", dbg_playerCnt);

if (dbg_playerCnt == 0)
{
srv_handleEmpty();
}
}

public client_connect(id)
{
set_pcvar_num(cvar_emptyCycle, 0);

vote_unrock(id);
}

public client_putinserver(id)
{
if ((g_voteStatus & VOTE_IS_EARLY) && !is_user_bot(id) && !is_user_hltv(id))
{
set_task(20.0, "srv_announceEarlyVote", id);
}
}

srv_handleEmpty()
{
dbg_log(2, "%32s mp_timelimit: %f g_originalTimelimit: %f", "srv_handleEmpty(in)", get_cvar_float("mp_timelimit"), g_originalTimelimit);

if (g_originalTimelimit != get_cvar_float("mp_timelimit"))
{
// it's possible that the map has been extended at least once. that
// means that if someone comes into the server, the time limit will
// be the extended time limit rather than the normal time limit. bad.
// reset the original time limit
map_restoreOriginalTimeLimit();
}

// might be utilizing "empty server" feature
if (g_isUsingEmptyCycle && g_emptyMapCnt)
{
srv_startEmptyCountdown();
}

dbg_log(2, "%32s mp_timelimit: %f g_originalTimelimit: %f", "srv_handleEmpty(out)", get_cvar_float("mp_timelimit"), g_originalTimelimit);
}

public srv_announceEarlyVote(id)
{
if (is_user_connected(id))
{
//client_print(id, print_chat, "%L", id, "GAL_VOTE_EARLY");
new text[101];
formatex(text, sizeof(text)-1, "^x04%L", id, "GAL_VOTE_EARLY");
print_color(id, text);
}
}

public srv_initEmptyCheck()
{
if (get_pcvar_num(cvar_emptyWait))
{
if ((get_realplayersnum()) == 0 && !get_pcvar_num(cvar_emptyCycle))
{
srv_startEmptyCountdown();
}
g_isUsingEmptyCycle = true;
}
}

srv_startEmptyCountdown()
{
new waitMinutes = get_pcvar_num(cvar_emptyWait);
if (waitMinutes)
{
set_task(float(waitMinutes * 60), "srv_startEmptyCycle", TASKID_EMPTYSERVER);
}
}

public srv_startEmptyCycle()
{
set_pcvar_num(cvar_emptyCycle, 1);

// set the next map from the empty cycle list,
// or the first one, if the current map isn't part of the cycle
new nextMap[32], mapIdx;
mapIdx = map_getNext(g_emptyCycleMap, g_currentMap, nextMap);
map_setNext(nextMap);

// if the current map isn't part of the empty cycle,
// immediately change to next map that is
if (mapIdx == -1)
{
map_change();
}
}

nomination_announceCancellation(nominations[])
{
client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_CANCEL_SUCCESS", nominations);
}

nomination_clearAll()
{
for (new idxPlayer = 1; idxPlayer <= MAX_PLAYER_CNT; idxPlayer++)
{
for (new idxNomination = 1; idxNomination <= MAX_NOMINATION_CNT; idxNomination++)
{
g_nomination[idxPlayer][idxNomination] = -1;
}
}
g_nominationCnt = 0;
}

map_announceNomination(id, map[])
{
new name[32];
get_user_name(id, name, sizeof(name)-1);

client_print(0, print_chat, "%L", LANG_PLAYER, "GAL_NOM_SUCCESS", name, map);
}

#if AMXX_VERSION_NUM < 180
has_flag(id, flags[])
{
return (get_user_flags(id) & read_flags(flags));
}
#endif

public sort_stringsi(const elem1[], const elem2[], const array[], data[], data_size)
{
return strcmp(elem1, elem2, 1);
}

stock get_realplayersnum()
{
new players[32], playerCnt;
get_players(players, playerCnt, "ch");

return playerCnt;
}

stock percent(is, of)
{
return (of != 0) ? floatround(floatmul(float(is)/float(of), 100.0)) : 0;
}

print_color(id, text[])
{
message_begin(MSG_ONE, get_user_msgid("SayText"), {0, 0, 0}, id);
write_byte(id);
write_string(text);
message_end();
}

map_restoreOriginalTimeLimit()
{
dbg_log(2, "%32s mp_timelimit: %f g_originalTimelimit: %f", "map_restoreOriginalTimeLimit(in)", get_cvar_float("mp_timelimit"), g_originalTimelimit);
if (g_originalTimelimit != TIMELIMIT_NOT_SET)
{
server_cmd("mp_timelimit %f", g_originalTimelimit);
server_exec();
}
dbg_log(2, "%32s mp_timelimit: %f g_originalTimelimit: %f", "map_restoreOriginalTimeLimit(out)", get_cvar_float("mp_timelimit"), g_originalTimelimit);
}

dbg_log(const mode, const text[] = "", {Float,Sql,Result,_}:...)
{
new dbg = get_cvar_num("gal_debug");
if (mode & dbg)
{
// format the text as needed
new formattedText[1024];
format_args(formattedText, 1023, 1);
// grab the current game time
new Float:gameTime = get_gametime();
// log text to file
log_to_file("_galileo.log", "{%3.4f} %s", gameTime, formattedText);

if (dbg & 1 && formattedText[0])
{
// make quotes in log text palatable to 3rd party chat log viewers
new isFound = 1;
while (isFound) isFound = replace(formattedText, 1023, "^"", "'");
// print to the server log so as to be picked up by programs such as HLSW
log_message("^"<><><>^" triggered ^"amx_chat^" (text ^"[GAL] %s^")", formattedText);
}
}
// not needed but gets rid of stupid compiler error
if (text[0] == 0) return;
}
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   Цитировать сообщение
Статус пользователя Fred Perry
сообщение 10.6.2012, 11:49
Сообщение #2


Иконка группы

Стаж: 16 лет

Сообщений: 6594
Благодарностей: 2370
Полезность: 813

Может быть конфликтует с другими плагинами?


You become responsible, forever, for what you have tamed
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
Поблагодарили 1 раз
   + Цитировать сообщение
Статус пользователя C1_
сообщение 10.6.2012, 15:51
Сообщение #3


Стаж: 18 лет

Сообщений: 978
Благодарностей: 401
Полезность: 830

Цитата
// Кол-во минут после начала карты,
// которые игроки должны ждать, прежде чем они могут
// вызывать голосование. Когда один игрок на сервере, он может
// вызывать голосование в любое время, вне зависимости от этого параметра.
// (по умолчанию 10)

gal_rtv_wait 7


и поставь нормальный galileo
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
Поблагодарили 1 раз
   + Цитировать сообщение
Simbo
сообщение 10.6.2012, 16:32
Сообщение #4
Стаж: 13 лет

Сообщений: 146
Благодарностей: 3
Полезность: 0

Что ещё может с ним конфликтовать?
Скрытый текст
csf_opengl32.amxx
csf_anticheat.amxx
amxbans_core.amxx
amxbans_main.amxx
admin.amxx
adminchat.amxx
admincmd.amxx
adminhelp.amxx
adminvote.amxx
amxbans_ssban.amxx
antiflood.amxx
cmdmenu.amxx
imessage.amxx
;mapchooser.amxx
mapsmenu.amxx
multilingual.amxx
nextmap.amxx
pausecfg.amxx
restmenu.amxx
scrollmsg.amxx
stats_logging.amxx
statscfg.amxx
telemenu.amxx
timeleft.amxx
pluginmenu.amxx
amxmod_compat.amxx
admin_sql.amxx
antireconnect.amxx
ad_manager.amxx
;lastround.amxx
;rockthevote_custom.amxx
info_rank.amxx
admin_check.amxx
killa_hp.amxx
weaponmenu.amxx
resetscore.amxx
admin_freelook.amxx
realnadedrops.amxx
info_rank.amxx
hl_ultimate_gore_upd.amxx
IP.amxx
menufront.amxx
plmenu.amxx
anti_autobuy_bug.amxx
c4cdvoice.amxx
bcd_hudtimer.amxx
players_with_steam.amxx
endroundmusic.amxx
a_ultimate_sounds_male.amxx
blue.amxx
damager.amxx
instant_autoteambalance.amxx
deagle_sniper.amxx
descriptive_fire_in_the_hole.amxx
gememenu.amxx
umm_autorestart.amxx
admin_chat_colors.amxx
say_admin.amxx
parachute.amxx
say_vip.amxx
vo_menu1.amxx
vip_weapon.amxx
amx_hpk.amxx
myadmin_models.amxx
admin_spec_esp.amxx
gag.amxx
voteban.amxx
statsx_gui.amxx
galileo.amxx
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   + Цитировать сообщение
Статус пользователя Fred Perry
сообщение 10.6.2012, 16:59
Сообщение #5


Иконка группы

Стаж: 16 лет

Сообщений: 6594
Благодарностей: 2370
Полезность: 813

umm_autorestart.amxx Это убери

ЗЫ Сам складывал сервер?


You become responsible, forever, for what you have tamed
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   + Цитировать сообщение
Simbo
сообщение 10.6.2012, 17:12
Сообщение #6
Стаж: 13 лет

Сообщений: 146
Благодарностей: 3
Полезность: 0

Fred Perry,
Конечно сам, свои плагины... но не пойму чем umm_autorestart.amxx тебе не нравится, это ведь лиш рестарт с задержкой 40 сек после смены карты...

я думал мб там плагины типо:
mapsmenu.amxx
timeleft.amm
nextmap.amxx
не в них проблема?

Отредактировал: Simbo, - 10.6.2012, 17:12
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   + Цитировать сообщение
Статус пользователя Fred Perry
сообщение 10.6.2012, 17:20
Сообщение #7


Иконка группы

Стаж: 16 лет

Сообщений: 6594
Благодарностей: 2370
Полезность: 813

Цитата(Simbo @ 10.6.2012, 18:12) *
Fred Perry,
Конечно сам, свои плагины... но не пойму чем umm_autorestart.amxx тебе не нравится, это ведь лиш рестарт с задержкой 40 сек после смены карты...

я думал мб там плагины типо:
mapsmenu.amxx
timeleft.amm
nextmap.amxx
не в них проблема?

Во-первых это приватный плагин
Во-вторых, у него есть свой Plugins.ini откуда он загружается.


You become responsible, forever, for what you have tamed
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   + Цитировать сообщение
Simbo
сообщение 10.6.2012, 19:14
Сообщение #8
Стаж: 13 лет

Сообщений: 146
Благодарностей: 3
Полезность: 0

Отключил, всё ровни пишет 7 минут бесконечно...
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   + Цитировать сообщение
Статус пользователя Fred Perry
сообщение 10.6.2012, 21:58
Сообщение #9


Иконка группы

Стаж: 16 лет

Сообщений: 6594
Благодарностей: 2370
Полезность: 813

Цитата(Simbo @ 10.6.2012, 19:14) *
Отключил, всё ровни пишет 7 минут бесконечно...

Чесно говоря, я бы отключил все плагины кроме дефолтных, а там далее смотрел как и что.
А то так смотреть, это как искать иголку в сене


You become responsible, forever, for what you have tamed
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   + Цитировать сообщение
Статус пользователя STILL47DEATH
сообщение 10.6.2012, 23:31
Сообщение #10


Стаж: 18 лет

Сообщений: 662
Благодарностей: 83
Полезность: 150

а что в галилео вообще что-то нормально работает? ахах
сам когда-то юзал, до того как umm поставил, это галилео такое уг, постоянно от фанаря карты менялись после голосования...
снеси, уж лучше дигл мап менеджер поставь
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   + Цитировать сообщение
Статус пользователя Fred Perry
сообщение 10.6.2012, 23:37
Сообщение #11


Иконка группы

Стаж: 16 лет

Сообщений: 6594
Благодарностей: 2370
Полезность: 813

Цитата(STILL47DEATH @ 11.6.2012, 0:31) *
а что в галилео вообще что-то нормально работает? ахах
сам когда-то юзал, до того как umm поставил, это галилео такое уг, постоянно от фанаря карты менялись после голосования...
снеси, уж лучше дигл мап менеджер поставь

Ну это правда.


You become responsible, forever, for what you have tamed
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   + Цитировать сообщение
Simbo
сообщение 11.6.2012, 14:26
Сообщение #12
Стаж: 13 лет

Сообщений: 146
Благодарностей: 3
Полезность: 0

umm стал моей любовью, ни лагов ни багов всё шикарно* Всем советую=)
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
   + Цитировать сообщение
Статус пользователя nekrasoff
сообщение 11.6.2012, 17:03
Сообщение #13


Стаж: 14 лет

Сообщений: 48
Благодарностей: 3
Полезность: < 0

Не советую вообще ставить Galileo. Он недоработан. Много лишнего в нём и есть моменты, из-за которых плагин отказывается работать. Galileo - пародия UMM (UFPS MAP MANEGER). Советую использовать UMM и не париться.
Плюсы UMM:
- Легко настраиваемый, по сравнению с галилео
- Не имеет левых настроек
- Из-за него сервер никогда не упадет
- Не конфликтует ни с какими нормальными плагинами (если конечно сами плагины не кривые)

p.s Будут вопросы, обращайся, помогу в настройке и установке. Пиши в личку.

Galileo можно использовать только на GunGame, т.к UMM не очень подходит для него =( и то, предварительно отключив много левого в нём.

Отредактировал: nekrasoff, - 11.6.2012, 17:05
Перейти в начало страницы         Просмотр профиля    Отправить личное сообщение
Поблагодарили 1 раз
   + Цитировать сообщение
  Тема закрытаНачать новую тему
 
0 пользователей и 2 гостей читают эту тему: