ferret99gt@1440: /** ferret99gt@1440: * vim: set ts=4 : ferret99gt@1440: * ============================================================================= ferret99gt@1440: * SourceMod Mapchooser Plugin ferret99gt@1440: * Creates a map vote at appropriate times, setting sm_nextmap to the winning ferret99gt@1440: * vote ferret99gt@1440: * pred@2032: * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. ferret99gt@1440: * ============================================================================= ferret99gt@1440: * ferret99gt@1440: * This program is free software; you can redistribute it and/or modify it under ferret99gt@1440: * the terms of the GNU General Public License, version 3.0, as published by the ferret99gt@1440: * Free Software Foundation. ferret99gt@1440: * ferret99gt@1440: * This program is distributed in the hope that it will be useful, but WITHOUT ferret99gt@1440: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ferret99gt@1440: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ferret99gt@1440: * details. ferret99gt@1440: * ferret99gt@1440: * You should have received a copy of the GNU General Public License along with ferret99gt@1440: * this program. If not, see . ferret99gt@1440: * ferret99gt@1440: * As a special exception, AlliedModders LLC gives you permission to link the ferret99gt@1440: * code of this program (as well as its derivative works) to "Half-Life 2," the ferret99gt@1440: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software ferret99gt@1440: * by the Valve Corporation. You must obey the GNU General Public License in ferret99gt@1440: * all respects for all other code used. Additionally, AlliedModders LLC grants ferret99gt@1440: * this exception to all derivative works. AlliedModders LLC defines further ferret99gt@1440: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), ferret99gt@1440: * or . ferret99gt@1440: * ferret99gt@1440: * Version: $Id$ ferret99gt@1440: */ pred@3440: pred@3440: //#define DEBUG pred@3440: pred@3440: #if defined DEBUG pred@3440: #define assert(%1) if (!(%1)) ThrowError("Debug Assertion Failed"); pred@3440: #define assert_msg(%1,%2) if (!(%1)) ThrowError(%2); pred@3440: #else pred@3440: #define assert(%1) pred@3440: #define assert_msg(%1,%2) pred@3440: #endif ferret99gt@1440: ferret99gt@1440: #pragma semicolon 1 ferret99gt@1440: #include pred@2133: #include pred@2133: #include ferret99gt@1440: ferret99gt@1479: public Plugin:myinfo = ferret99gt@1479: { ferret99gt@1479: name = "MapChooser", ferret99gt@1479: author = "AlliedModders LLC", ferret99gt@1479: description = "Automated Map Voting", ferret99gt@1479: version = SOURCEMOD_VERSION, ferret99gt@1479: url = "http://www.sourcemod.net/" ferret99gt@1479: }; ferret99gt@1440: pred@2133: /* Valve ConVars */ ferret99gt@1440: new Handle:g_Cvar_Winlimit = INVALID_HANDLE; ferret99gt@1440: new Handle:g_Cvar_Maxrounds = INVALID_HANDLE; ferret99gt@1479: new Handle:g_Cvar_Fraglimit = INVALID_HANDLE; pred@2133: new Handle:g_Cvar_Bonusroundtime = INVALID_HANDLE; ferret99gt@1440: pred@2133: /* Plugin ConVars */ ferret99gt@1440: new Handle:g_Cvar_StartTime = INVALID_HANDLE; ferret99gt@1479: new Handle:g_Cvar_StartRounds = INVALID_HANDLE; ferret99gt@1479: new Handle:g_Cvar_StartFrags = INVALID_HANDLE; ferret99gt@1440: new Handle:g_Cvar_ExtendTimeStep = INVALID_HANDLE; ferret99gt@1445: new Handle:g_Cvar_ExtendRoundStep = INVALID_HANDLE; ferret99gt@1479: new Handle:g_Cvar_ExtendFragStep = INVALID_HANDLE; ferret99gt@1440: new Handle:g_Cvar_ExcludeMaps = INVALID_HANDLE; ferret99gt@1479: new Handle:g_Cvar_IncludeMaps = INVALID_HANDLE; ferret99gt@1531: new Handle:g_Cvar_NoVoteMode = INVALID_HANDLE; ferret99gt@1531: new Handle:g_Cvar_Extend = INVALID_HANDLE; pred@2133: new Handle:g_Cvar_DontChange = INVALID_HANDLE; pred@2133: new Handle:g_Cvar_EndOfMapVote = INVALID_HANDLE; pred@2133: new Handle:g_Cvar_VoteDuration = INVALID_HANDLE; pred@3440: new Handle:g_Cvar_RunOff = INVALID_HANDLE; pred@3440: new Handle:g_Cvar_RunOffPercent = INVALID_HANDLE; ferret99gt@1440: ferret99gt@1440: new Handle:g_VoteTimer = INVALID_HANDLE; ferret99gt@1440: new Handle:g_RetryTimer = INVALID_HANDLE; ferret99gt@1440: pred@2133: /* Data Handles */ ferret99gt@1440: new Handle:g_MapList = INVALID_HANDLE; pred@2133: new Handle:g_NominateList = INVALID_HANDLE; pred@2133: new Handle:g_NominateOwners = INVALID_HANDLE; ferret99gt@1440: new Handle:g_OldMapList = INVALID_HANDLE; ferret99gt@1440: new Handle:g_NextMapList = INVALID_HANDLE; ferret99gt@1440: new Handle:g_VoteMenu = INVALID_HANDLE; ferret99gt@1440: ferret99gt@1861: new g_Extends; ferret99gt@1698: new g_TotalRounds; ferret99gt@1440: new bool:g_HasVoteStarted; pred@2133: new bool:g_WaitingForVote; pred@2133: new bool:g_MapVoteCompleted; pred@2133: new bool:g_ChangeMapAtRoundEnd; pred@2333: new bool:g_ChangeMapInProgress; dvander@1889: new g_mapFileSerial = -1; ferret99gt@1440: pred@2133: new MapChange:g_ChangeTime; pred@2133: pred@2133: new Handle:g_NominationsResetForward = INVALID_HANDLE; crimson@3150: new Handle:g_MapVoteStartedForward = INVALID_HANDLE; pred@2133: pred@2133: /* Upper bound of how many team there could be */ pred@2133: #define MAXTEAMS 10 pred@2133: new g_winCount[MAXTEAMS]; pred@2133: ferret99gt@1531: #define VOTE_EXTEND "##extend##" pred@2133: #define VOTE_DONTCHANGE "##dontchange##" ferret99gt@1531: ferret99gt@1440: public OnPluginStart() ferret99gt@1440: { ferret99gt@1440: LoadTranslations("mapchooser.phrases"); pred@2215: LoadTranslations("common.phrases"); ferret99gt@1440: januk@3826: new arraySize = ByteCountToCells(PLATFORM_MAX_PATH); ferret99gt@1664: g_MapList = CreateArray(arraySize); pred@2133: g_NominateList = CreateArray(arraySize); pred@2133: g_NominateOwners = CreateArray(1); ferret99gt@1664: g_OldMapList = CreateArray(arraySize); ferret99gt@1664: g_NextMapList = CreateArray(arraySize); pred@2133: pred@2133: g_Cvar_EndOfMapVote = CreateConVar("sm_mapvote_endvote", "1", "Specifies if MapChooser should run an end of map vote", _, true, 0.0, true, 1.0); ferret99gt@1440: ferret99gt@1479: g_Cvar_StartTime = CreateConVar("sm_mapvote_start", "3.0", "Specifies when to start the vote based on time remaining.", _, true, 1.0); pred@2133: g_Cvar_StartRounds = CreateConVar("sm_mapvote_startround", "2.0", "Specifies when to start the vote based on rounds remaining. Use 0 on TF2 to start vote during bonus round time", _, true, 0.0); ferret99gt@1479: g_Cvar_StartFrags = CreateConVar("sm_mapvote_startfrags", "5.0", "Specifies when to start the vote base on frags remaining.", _, true, 1.0); ferret99gt@1440: g_Cvar_ExtendTimeStep = CreateConVar("sm_extendmap_timestep", "15", "Specifies how much many more minutes each extension makes", _, true, 5.0); pred@2133: g_Cvar_ExtendRoundStep = CreateConVar("sm_extendmap_roundstep", "5", "Specifies how many more rounds each extension makes", _, true, 1.0); ferret99gt@1479: g_Cvar_ExtendFragStep = CreateConVar("sm_extendmap_fragstep", "10", "Specifies how many more frags are allowed when map is extended.", _, true, 5.0); ferret99gt@1440: g_Cvar_ExcludeMaps = CreateConVar("sm_mapvote_exclude", "5", "Specifies how many past maps to exclude from the vote.", _, true, 0.0); ferret99gt@1479: g_Cvar_IncludeMaps = CreateConVar("sm_mapvote_include", "5", "Specifies how many maps to include in the vote.", _, true, 2.0, true, 6.0); ferret99gt@1531: g_Cvar_NoVoteMode = CreateConVar("sm_mapvote_novote", "1", "Specifies whether or not MapChooser should pick a map if no votes are received.", _, true, 0.0, true, 1.0); ferret99gt@1861: g_Cvar_Extend = CreateConVar("sm_mapvote_extend", "0", "Number of extensions allowed each map.", _, true, 0.0); pred@2133: g_Cvar_DontChange = CreateConVar("sm_mapvote_dontchange", "1", "Specifies if a 'Don't Change' option should be added to early votes", _, true, 0.0); pred@2241: g_Cvar_VoteDuration = CreateConVar("sm_mapvote_voteduration", "20", "Specifies how long the mapvote should be available for.", _, true, 5.0); pred@3440: g_Cvar_RunOff = CreateConVar("sm_mapvote_runoff", "0", "Hold run of votes if winning choice is less than a certain margin", _, true, 0.0, true, 1.0); pred@3440: g_Cvar_RunOffPercent = CreateConVar("sm_mapvote_runoffpercent", "50", "If winning choice has less than this percent of votes, hold a runoff", _, true, 0.0, true, 100.0); pred@2215: ferret99gt@1479: RegAdminCmd("sm_mapvote", Command_Mapvote, ADMFLAG_CHANGEMAP, "sm_mapvote - Forces MapChooser to attempt to run a map vote now."); pred@2215: RegAdminCmd("sm_setnextmap", Command_SetNextmap, ADMFLAG_CHANGEMAP, "sm_setnextmap "); ferret99gt@1440: ferret99gt@1452: g_Cvar_Winlimit = FindConVar("mp_winlimit"); ferret99gt@1452: g_Cvar_Maxrounds = FindConVar("mp_maxrounds"); ferret99gt@1479: g_Cvar_Fraglimit = FindConVar("mp_fraglimit"); pred@2133: g_Cvar_Bonusroundtime = FindConVar("mp_bonusroundtime"); ferret99gt@1452: ferret99gt@1452: if (g_Cvar_Winlimit != INVALID_HANDLE || g_Cvar_Maxrounds != INVALID_HANDLE) ferret99gt@1440: { skamonkey@3399: decl String:folder[64]; skamonkey@3399: GetGameFolderName(folder, sizeof(folder)); skamonkey@3399: skamonkey@3399: if (strcmp(folder, "tf") == 0) skamonkey@3399: { skamonkey@3399: HookEvent("teamplay_win_panel", Event_TeamPlayWinPanel); skamonkey@3399: HookEvent("teamplay_restart_round", Event_TFRestartRound); skamonkey@3399: HookEvent("arena_win_panel", Event_TeamPlayWinPanel); skamonkey@3399: } skamonkey@3399: else if (strcmp(folder, "nucleardawn") == 0) skamonkey@3399: { skamonkey@3399: HookEvent("round_win", Event_RoundEnd); skamonkey@3399: } skamonkey@3399: else skamonkey@3399: { skamonkey@3399: HookEvent("round_end", Event_RoundEnd); skamonkey@3399: } ferret99gt@1440: } ferret99gt@1467: ferret99gt@1479: if (g_Cvar_Fraglimit != INVALID_HANDLE) ferret99gt@1479: { ferret99gt@1479: HookEvent("player_death", Event_PlayerDeath); ferret99gt@1479: } ferret99gt@1479: ferret99gt@1467: AutoExecConfig(true, "mapchooser"); pred@2133: pred@2133: //Change the mp_bonusroundtime max so that we have time to display the vote pred@2133: //If you display a vote during bonus time good defaults are 17 vote duration and 19 mp_bonustime pred@2133: if (g_Cvar_Bonusroundtime != INVALID_HANDLE) pred@2133: { pred@2133: SetConVarBounds(g_Cvar_Bonusroundtime, ConVarBound_Upper, true, 30.0); pred@2133: } pred@2133: pred@2133: g_NominationsResetForward = CreateGlobalForward("OnNominationRemoved", ET_Ignore, Param_String, Param_Cell); crimson@3150: g_MapVoteStartedForward = CreateGlobalForward("OnMapVoteStarted", ET_Ignore); pred@2133: } pred@2133: fyrenmoo@2676: public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max) pred@2133: { pred@2165: RegPluginLibrary("mapchooser"); pred@2165: pred@2133: CreateNative("NominateMap", Native_NominateMap); crimson@3150: CreateNative("RemoveNominationByMap", Native_RemoveNominationByMap); crimson@3150: CreateNative("RemoveNominationByOwner", Native_RemoveNominationByOwner); pred@2133: CreateNative("InitiateMapChooserVote", Native_InitiateVote); pred@2133: CreateNative("CanMapChooserStartVote", Native_CanVoteStart); pred@2133: CreateNative("HasEndOfMapVoteFinished", Native_CheckVoteDone); pred@2133: CreateNative("GetExcludeMapList", Native_GetExcludeMapList); crimson@3150: CreateNative("GetNominatedMapList", Native_GetNominatedMapList); pred@2223: CreateNative("EndOfMapVoteEnabled", Native_EndOfMapVoteEnabled); pred@2133: fyrenmoo@2676: return APLRes_Success; ferret99gt@1440: } ferret99gt@1440: ferret99gt@1606: public OnConfigsExecuted() ferret99gt@1440: { dvander@1889: if (ReadMapList(g_MapList, dvander@1889: g_mapFileSerial, dvander@1889: "mapchooser", dvander@1889: MAPLIST_FLAG_CLEARARRAY|MAPLIST_FLAG_MAPSFOLDER) dvander@1889: != INVALID_HANDLE) dvander@1889: ferret99gt@1440: { dvander@1889: if (g_mapFileSerial == -1) dvander@1889: { dvander@1889: LogError("Unable to create a valid map list."); dvander@1889: } ferret99gt@1440: } ferret99gt@1698: dvander@1889: CreateNextVote(); dvander@1889: SetupTimeleftTimer(); dvander@1889: ferret99gt@1698: g_TotalRounds = 0; ferret99gt@1861: ferret99gt@1861: g_Extends = 0; pred@2133: pred@2133: g_MapVoteCompleted = false; pred@2133: pred@2133: ClearArray(g_NominateList); pred@2133: ClearArray(g_NominateOwners); pred@2133: pred@2133: for (new i=0; i GetConVarInt(g_Cvar_ExcludeMaps)) ferret99gt@1606: { pred@2133: RemoveFromArray(g_OldMapList, 0); pred@2133: } pred@2133: } pred@2133: pred@2133: public OnClientDisconnect(client) pred@2133: { pred@2133: new index = FindValueInArray(g_NominateOwners, client); pred@2133: pred@2133: if (index == -1) pred@2133: { pred@2133: return; ferret99gt@1606: } ferret99gt@1606: januk@3826: new String:oldmap[PLATFORM_MAX_PATH]; pred@2133: GetArrayString(g_NominateList, index, oldmap, sizeof(oldmap)); pred@2133: Call_StartForward(g_NominationsResetForward); pred@2133: Call_PushString(oldmap); pred@2133: Call_PushCell(GetArrayCell(g_NominateOwners, index)); pred@2133: Call_Finish(); pred@2133: pred@2133: RemoveFromArray(g_NominateOwners, index); pred@2133: RemoveFromArray(g_NominateList, index); pred@2133: } pred@2133: pred@2215: public Action:Command_SetNextmap(client, args) pred@2133: { pred@2215: if (args < 1) ferret99gt@1606: { pred@2215: ReplyToCommand(client, "[SM] Usage: sm_setnextmap "); pred@2215: return Plugin_Handled; ferret99gt@1606: } pred@2215: januk@3826: decl String:map[PLATFORM_MAX_PATH]; pred@2215: GetCmdArg(1, map, sizeof(map)); pred@2215: pred@2215: if (!IsMapValid(map)) pred@2133: { pred@2215: ReplyToCommand(client, "[SM] %t", "Map was not found", map); pred@2215: return Plugin_Handled; pred@2133: } pred@2215: pred@2215: ShowActivity(client, "%t", "Changed Next Map", map); skamonkey@3217: LogAction(client, -1, "\"%L\" changed nextmap to \"%s\"", client, map); pred@2215: pred@2215: SetNextMap(map); pred@2215: g_MapVoteCompleted = true; pred@2215: pred@2215: return Plugin_Handled; ferret99gt@1440: } ferret99gt@1440: ferret99gt@1440: public OnMapTimeLeftChanged() ferret99gt@1440: { ferret99gt@1467: if (GetArraySize(g_MapList)) ferret99gt@1467: { ferret99gt@1467: SetupTimeleftTimer(); ferret99gt@1467: } ferret99gt@1440: } ferret99gt@1440: ferret99gt@1440: SetupTimeleftTimer() ferret99gt@1440: { ferret99gt@1440: new time; ferret99gt@1440: if (GetMapTimeLeft(time) && time > 0) ferret99gt@1440: { ferret99gt@1506: new startTime = GetConVarInt(g_Cvar_StartTime) * 60; pred@2133: if (time - startTime < 0 && GetConVarBool(g_Cvar_EndOfMapVote) && !g_MapVoteCompleted && !g_HasVoteStarted) ferret99gt@1440: { pred@2133: InitiateVote(MapChange_MapEnd, INVALID_HANDLE); ferret99gt@1440: } ferret99gt@1440: else ferret99gt@1440: { ferret99gt@1440: if (g_VoteTimer != INVALID_HANDLE) ferret99gt@1440: { ferret99gt@1440: KillTimer(g_VoteTimer); ferret99gt@1440: g_VoteTimer = INVALID_HANDLE; ferret99gt@1452: } ferret99gt@1440: pred@2333: //g_VoteTimer = CreateTimer(float(time - startTime), Timer_StartMapVote, _, TIMER_FLAG_NO_MAPCHANGE); pred@2333: new Handle:data; pred@2333: g_VoteTimer = CreateDataTimer(float(time - startTime), Timer_StartMapVote, data, TIMER_FLAG_NO_MAPCHANGE); pred@2333: WritePackCell(data, _:MapChange_MapEnd); pred@2333: WritePackCell(data, _:INVALID_HANDLE); pred@2333: ResetPack(data); ferret99gt@1440: } ferret99gt@1440: } ferret99gt@1440: } ferret99gt@1440: pred@2333: public Action:Timer_StartMapVote(Handle:timer, Handle:data) ferret99gt@1440: { ferret99gt@1440: if (timer == g_RetryTimer) ferret99gt@1440: { pred@2239: g_WaitingForVote = false; ferret99gt@1440: g_RetryTimer = INVALID_HANDLE; ferret99gt@1440: } ferret99gt@1440: else ferret99gt@1440: { ferret99gt@1440: g_VoteTimer = INVALID_HANDLE; ferret99gt@1440: } pred@2133: pred@2223: if (!GetArraySize(g_MapList) || !GetConVarBool(g_Cvar_EndOfMapVote) || g_MapVoteCompleted || g_HasVoteStarted) pred@2223: { pred@2223: return Plugin_Stop; pred@2333: } dvander@2336: dvander@2336: new MapChange:mapChange = MapChange:ReadPackCell(data); dvander@2336: new Handle:hndl = Handle:ReadPackCell(data); ferret99gt@1440: dvander@2336: InitiateVote(mapChange, hndl); ferret99gt@1440: ferret99gt@1440: return Plugin_Stop; ferret99gt@1440: } ferret99gt@1440: pred@2133: public Event_TFRestartRound(Handle:event, const String:name[], bool:dontBroadcast) pred@2133: { pred@2133: /* Game got restarted - reset our round count tracking */ pred@2133: g_TotalRounds = 0; pred@2133: } pred@2133: pred@2133: public Event_TeamPlayWinPanel(Handle:event, const String:name[], bool:dontBroadcast) pred@2032: { pred@2133: if (g_ChangeMapAtRoundEnd) pred@2133: { pred@2133: g_ChangeMapAtRoundEnd = false; pred@2179: CreateTimer(2.0, Timer_ChangeMap, INVALID_HANDLE, TIMER_FLAG_NO_MAPCHANGE); pred@2333: g_ChangeMapInProgress = true; pred@2133: } pred@2133: pred@2133: new bluescore = GetEventInt(event, "blue_score"); pred@2133: new redscore = GetEventInt(event, "red_score"); pred@2240: pred@2239: if(GetEventInt(event, "round_complete") == 1 || StrEqual(name, "arena_win_panel")) pred@2239: { pred@2239: g_TotalRounds++; pred@2239: pred@2239: if (!GetArraySize(g_MapList) || g_HasVoteStarted || g_MapVoteCompleted || !GetConVarBool(g_Cvar_EndOfMapVote)) pred@2239: { pred@2239: return; pred@2239: } pred@2239: pred@2241: CheckMaxRounds(g_TotalRounds); pred@2241: pred@2133: switch(GetEventInt(event, "winning_team")) pred@2133: { pred@2215: case 3: pred@2133: { pred@2133: CheckWinLimit(bluescore); pred@2133: } pred@2215: case 2: pred@2133: { pred@2133: CheckWinLimit(redscore); pred@2133: } pred@2133: //We need to do nothing on winning_team == 0 this indicates stalemate. pred@2133: default: pred@2133: { pred@2133: return; pred@2133: } pred@2133: } pred@2032: } pred@2032: } ferret99gt@1479: /* You ask, why don't you just use team_score event? And I answer... Because CSS doesn't. */ ferret99gt@1452: public Event_RoundEnd(Handle:event, const String:name[], bool:dontBroadcast) ferret99gt@1440: { pred@2133: if (g_ChangeMapAtRoundEnd) pred@2133: { pred@2133: g_ChangeMapAtRoundEnd = false; pred@2179: CreateTimer(2.0, Timer_ChangeMap, INVALID_HANDLE, TIMER_FLAG_NO_MAPCHANGE); pred@2333: g_ChangeMapInProgress = true; pred@2133: } pred@2133: skamonkey@3399: new winner; skamonkey@3399: if (strcmp(name, "round_win") == 0) skamonkey@3399: { skamonkey@3399: // Nuclear Dawn skamonkey@3399: winner = GetEventInt(event, "team"); skamonkey@3399: } skamonkey@3399: else skamonkey@3399: { skamonkey@3399: winner = GetEventInt(event, "winner"); skamonkey@3399: } ds@1952: pred@2133: if (winner == 0 || winner == 1 || !GetConVarBool(g_Cvar_EndOfMapVote)) ferret99gt@1440: { ferret99gt@1440: return; ferret99gt@1440: } ferret99gt@1479: pred@2133: if (winner >= MAXTEAMS) ferret99gt@1452: { pred@2133: SetFailState("Mod exceed maximum team count - Please file a bug report."); ferret99gt@1452: } ferret99gt@1479: ferret99gt@1698: g_TotalRounds++; ferret99gt@1479: pred@2133: g_winCount[winner]++; ds@1952: pred@2239: if (!GetArraySize(g_MapList) || g_HasVoteStarted || g_MapVoteCompleted) ferret99gt@1479: { pred@2239: return; ferret99gt@1479: } ferret99gt@1479: pred@2133: CheckWinLimit(g_winCount[winner]); pred@2133: CheckMaxRounds(g_TotalRounds); pred@2133: } pred@2133: pred@2133: public CheckWinLimit(winner_score) pred@2133: { ferret99gt@1452: if (g_Cvar_Winlimit != INVALID_HANDLE) ferret99gt@1440: { ferret99gt@1452: new winlimit = GetConVarInt(g_Cvar_Winlimit); ferret99gt@1452: if (winlimit) pred@2133: { pred@2133: if (winner_score >= (winlimit - GetConVarInt(g_Cvar_StartRounds))) ferret99gt@1452: { pred@2133: InitiateVote(MapChange_MapEnd, INVALID_HANDLE); ferret99gt@1452: } ferret99gt@1440: } ferret99gt@1440: } pred@2133: } pred@2133: pred@2133: public CheckMaxRounds(roundcount) pred@2133: { ferret99gt@1452: if (g_Cvar_Maxrounds != INVALID_HANDLE) ferret99gt@1440: { ferret99gt@1440: new maxrounds = GetConVarInt(g_Cvar_Maxrounds); ferret99gt@1440: if (maxrounds) ferret99gt@1440: { pred@2133: if (roundcount >= (maxrounds - GetConVarInt(g_Cvar_StartRounds))) ferret99gt@1440: { pred@2133: InitiateVote(MapChange_MapEnd, INVALID_HANDLE); ferret99gt@1440: } ferret99gt@1440: } ferret99gt@1440: } ferret99gt@1440: } ferret99gt@1440: ferret99gt@1479: public Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast) ferret99gt@1479: { ferret99gt@1528: if (!GetArraySize(g_MapList) || g_Cvar_Fraglimit == INVALID_HANDLE || g_HasVoteStarted) ferret99gt@1483: { ferret99gt@1483: return; ferret99gt@1483: } ferret99gt@1483: pred@2133: if (!GetConVarInt(g_Cvar_Fraglimit) || !GetConVarBool(g_Cvar_EndOfMapVote)) ferret99gt@1479: { ferret99gt@1479: return; ferret99gt@1479: } ferret99gt@1479: pred@2594: if (g_MapVoteCompleted) pred@2594: { pred@2594: return; pred@2594: } pred@2594: ferret99gt@1479: new fragger = GetClientOfUserId(GetEventInt(event, "attacker")); pred@2594: pred@2594: if (!fragger) pred@2594: { pred@2594: return; pred@2594: } pred@2594: pred@2594: if (GetClientFrags(fragger) >= (GetConVarInt(g_Cvar_Fraglimit) - GetConVarInt(g_Cvar_StartFrags))) ferret99gt@1479: { pred@2133: InitiateVote(MapChange_MapEnd, INVALID_HANDLE); ferret99gt@1479: } ferret99gt@1479: } ferret99gt@1479: ferret99gt@1479: public Action:Command_Mapvote(client, args) ferret99gt@1517: { pred@2133: InitiateVote(MapChange_MapEnd, INVALID_HANDLE); ferret99gt@1479: ferret99gt@1479: return Plugin_Handled; ferret99gt@1479: } ferret99gt@1479: pred@2333: /** pred@2333: * Starts a new map vote pred@2333: * pred@2333: * @param when When the resulting map change should occur. pred@2333: * @param inputlist Optional list of maps to use for the vote, otherwise an internal list of nominations + random maps will be used. pred@3440: * @param noSpecials Block special vote options like extend/nochange (upgrade this to bitflags instead?) pred@2333: */ pred@2333: InitiateVote(MapChange:when, Handle:inputlist=INVALID_HANDLE) ferret99gt@1440: { pred@2133: g_WaitingForVote = true; pred@2133: ferret99gt@1440: if (IsVoteInProgress()) ferret99gt@1440: { ferret99gt@1440: // Can't start a vote, try again in 5 seconds. pred@2333: //g_RetryTimer = CreateTimer(5.0, Timer_StartMapVote, _, TIMER_FLAG_NO_MAPCHANGE); pred@2333: pred@2333: new Handle:data; pred@2333: g_RetryTimer = CreateDataTimer(5.0, Timer_StartMapVote, data, TIMER_FLAG_NO_MAPCHANGE); pred@2333: WritePackCell(data, _:when); pred@2333: WritePackCell(data, _:inputlist); pred@2333: ResetPack(data); pred@2333: return; pred@2333: } pred@2333: pred@2333: /* If the main map vote has completed (and chosen result) and its currently changing (not a delayed change) we block further attempts */ pred@2333: if (g_MapVoteCompleted && g_ChangeMapInProgress) pred@2333: { ferret99gt@1440: return; pred@2133: } ferret99gt@1440: pred@2133: g_ChangeTime = when; pred@2133: pred@2133: g_WaitingForVote = false; pred@2133: ferret99gt@1440: g_HasVoteStarted = true; ferret99gt@1440: g_VoteMenu = CreateMenu(Handler_MapVoteMenu, MenuAction:MENU_ACTIONS_ALL); ferret99gt@1440: SetMenuTitle(g_VoteMenu, "Vote Nextmap"); pred@2133: SetVoteResultCallback(g_VoteMenu, Handler_MapVoteFinished); crimson@3150: crimson@3150: /* Call OnMapVoteStarted() Forward */ crimson@3150: Call_StartForward(g_MapVoteStartedForward); crimson@3150: Call_Finish(); pred@2133: pred@2133: /** pred@2133: * TODO: Make a proper decision on when to clear the nominations list. pred@2133: * Currently it clears when used, and stays if an external list is provided. pred@2133: * Is this the right thing to do? External lists will probably come from places pred@2133: * like sm_mapvote from the adminmenu in the future. pred@2133: */ pred@2133: januk@3826: decl String:map[PLATFORM_MAX_PATH]; pred@2133: pred@2133: /* No input given - User our internal nominations and maplist */ pred@2133: if (inputlist == INVALID_HANDLE) ferret99gt@1440: { pred@2133: new nominateCount = GetArraySize(g_NominateList); pred@2133: new voteSize = GetConVarInt(g_Cvar_IncludeMaps); pred@2133: pred@2133: /* Smaller of the two - It should be impossible for nominations to exceed the size though (cvar changed mid-map?) */ pred@2133: new nominationsToAdd = nominateCount >= voteSize ? voteSize : nominateCount; pred@2133: pred@2133: pred@2133: for (new i=0; i= availableMaps) januk@4359: { januk@4359: //Run out of maps, this will have to do. januk@4359: break; januk@4359: } januk@4359: pred@2133: GetArrayString(g_NextMapList, count, map, sizeof(map)); pred@2133: count++; pred@2133: pred@3440: /* Insert the map and increment our count */ pred@3440: AddMenuItem(g_VoteMenu, map, map); pred@3440: i++; pred@2133: } pred@2133: pred@2133: /* Wipe out our nominations list - Nominations have already been informed of this */ pred@2133: ClearArray(g_NominateOwners); pred@2133: ClearArray(g_NominateList); ferret99gt@1440: } pred@2133: else //We were given a list of maps to start the vote with pred@2133: { pred@2133: new size = GetArraySize(inputlist); pred@2133: pred@2133: for (new i=0; i 0) pred@2133: { pred@2133: ExtendMapTimeLimit(GetConVarInt(g_Cvar_ExtendTimeStep)*60); pred@2133: } pred@2133: } pred@2133: pred@2133: if (g_Cvar_Winlimit != INVALID_HANDLE) pred@2133: { pred@2133: new winlimit = GetConVarInt(g_Cvar_Winlimit); pred@2133: if (winlimit) pred@2133: { pred@2133: SetConVarInt(g_Cvar_Winlimit, winlimit + GetConVarInt(g_Cvar_ExtendRoundStep)); pred@2133: } pred@2133: } pred@2133: pred@2133: if (g_Cvar_Maxrounds != INVALID_HANDLE) pred@2133: { pred@2133: new maxrounds = GetConVarInt(g_Cvar_Maxrounds); pred@2133: if (maxrounds) pred@2133: { pred@2133: SetConVarInt(g_Cvar_Maxrounds, maxrounds + GetConVarInt(g_Cvar_ExtendRoundStep)); pred@2133: } pred@2133: } pred@2133: pred@2133: if (g_Cvar_Fraglimit != INVALID_HANDLE) pred@2133: { pred@2133: new fraglimit = GetConVarInt(g_Cvar_Fraglimit); pred@2133: if (fraglimit) pred@2133: { pred@2133: SetConVarInt(g_Cvar_Fraglimit, fraglimit + GetConVarInt(g_Cvar_ExtendFragStep)); pred@2133: } pred@2133: } pred@2133: pred@2133: PrintToChatAll("[SM] %t", "Current Map Extended", RoundToFloor(float(item_info[0][VOTEINFO_ITEM_VOTES])/float(num_votes)*100), num_votes); skamonkey@3217: LogAction(-1, -1, "Voting for next map has finished. The current map has been extended."); pred@2133: pred@2133: // We extended, so we'll have to vote again. pred@2133: g_HasVoteStarted = false; pred@2133: CreateNextVote(); pred@2133: SetupTimeleftTimer(); pred@2133: pred@2133: } pred@2133: else if (strcmp(map, VOTE_DONTCHANGE, false) == 0) pred@2133: { pred@2133: PrintToChatAll("[SM] %t", "Current Map Stays", RoundToFloor(float(item_info[0][VOTEINFO_ITEM_VOTES])/float(num_votes)*100), num_votes); skamonkey@3217: LogAction(-1, -1, "Voting for next map has finished. 'No Change' was the winner"); pred@2133: pred@2133: g_HasVoteStarted = false; pred@2133: CreateNextVote(); pred@2133: SetupTimeleftTimer(); pred@2133: } pred@2133: else pred@2133: { pred@2133: if (g_ChangeTime == MapChange_MapEnd) pred@2133: { pred@2133: SetNextMap(map); pred@2133: } pred@2133: else if (g_ChangeTime == MapChange_Instant) pred@2133: { pred@2133: new Handle:data; pred@2133: CreateDataTimer(2.0, Timer_ChangeMap, data); pred@2133: WritePackString(data, map); pred@2333: g_ChangeMapInProgress = false; pred@2133: } pred@2133: else // MapChange_RoundEnd pred@2133: { pred@2133: SetNextMap(map); pred@2133: g_ChangeMapAtRoundEnd = true; pred@2133: } pred@2133: pred@2133: g_HasVoteStarted = false; pred@2133: g_MapVoteCompleted = true; pred@2133: pred@2133: PrintToChatAll("[SM] %t", "Nextmap Voting Finished", map, RoundToFloor(float(item_info[0][VOTEINFO_ITEM_VOTES])/float(num_votes)*100), num_votes); skamonkey@3217: LogAction(-1, -1, "Voting for next map has finished. Nextmap: %s.", map); pred@2133: } pred@2133: } pred@2133: pred@3440: public Handler_MapVoteFinished(Handle:menu, pred@3440: num_votes, pred@3440: num_clients, pred@3440: const client_info[][2], pred@3440: num_items, pred@3440: const item_info[][2]) pred@3440: { pred@3440: if (GetConVarBool(g_Cvar_RunOff) && num_items > 1) pred@3440: { pred@3440: new Float:winningvotes = float(item_info[0][VOTEINFO_ITEM_VOTES]); pred@3440: new Float:required = num_votes * (GetConVarFloat(g_Cvar_RunOffPercent) / 100.0); pred@3440: skamonkey@4101: if (winningvotes < required) pred@3440: { pred@3440: /* Insufficient Winning margin - Lets do a runoff */ pred@3440: g_VoteMenu = CreateMenu(Handler_MapVoteMenu, MenuAction:MENU_ACTIONS_ALL); pred@3440: SetMenuTitle(g_VoteMenu, "Runoff Vote Nextmap"); pred@3440: SetVoteResultCallback(g_VoteMenu, Handler_VoteFinishedGeneric); pred@3440: januk@3826: decl String:map[PLATFORM_MAX_PATH]; januk@3826: decl String:info1[PLATFORM_MAX_PATH]; januk@3826: decl String:info2[PLATFORM_MAX_PATH]; pred@3440: pred@3440: GetMenuItem(menu, item_info[0][VOTEINFO_ITEM_INDEX], map, sizeof(map), _, info1, sizeof(info1)); pred@3440: AddMenuItem(g_VoteMenu, map, info1); pred@3440: GetMenuItem(menu, item_info[1][VOTEINFO_ITEM_INDEX], map, sizeof(map), _, info2, sizeof(info2)); pred@3440: AddMenuItem(g_VoteMenu, map, info2); pred@3440: pred@3440: new voteDuration = GetConVarInt(g_Cvar_VoteDuration); pred@3440: SetMenuExitButton(g_VoteMenu, false); pred@3440: VoteMenuToAll(g_VoteMenu, voteDuration); pred@3440: pred@3440: /* Notify */ pred@3440: new Float:map1percent = float(item_info[0][VOTEINFO_ITEM_VOTES])/ float(num_votes) * 100; pred@3440: new Float:map2percent = float(item_info[1][VOTEINFO_ITEM_VOTES])/ float(num_votes) * 100; pred@3440: pred@3440: pred@3440: PrintToChatAll("[SM] %t", "Starting Runoff", GetConVarFloat(g_Cvar_RunOffPercent), info1, map1percent, info2, map2percent); pred@3440: LogMessage("Voting for next map was indecisive, beginning runoff vote"); pred@3440: pred@3440: return; pred@3440: } pred@3440: } pred@3440: pred@3440: Handler_VoteFinishedGeneric(menu, num_votes, num_clients, client_info, num_items, item_info); pred@3440: } pred@3440: ferret99gt@1440: public Handler_MapVoteMenu(Handle:menu, MenuAction:action, param1, param2) ferret99gt@1440: { ferret99gt@1440: switch (action) ferret99gt@1440: { ferret99gt@1440: case MenuAction_End: ferret99gt@1440: { ferret99gt@1440: g_VoteMenu = INVALID_HANDLE; ferret99gt@1440: CloseHandle(menu); ferret99gt@1440: } ferret99gt@1440: ferret99gt@1440: case MenuAction_Display: ferret99gt@1440: { ferret99gt@1440: decl String:buffer[255]; ferret99gt@1440: Format(buffer, sizeof(buffer), "%T", "Vote Nextmap", param1); ferret99gt@1440: ferret99gt@1440: new Handle:panel = Handle:param2; ferret99gt@1440: SetPanelTitle(panel, buffer); ferret99gt@1479: } ferret99gt@1479: ferret99gt@1479: case MenuAction_DisplayItem: ferret99gt@1479: { ferret99gt@1479: if (GetMenuItemCount(menu) - 1 == param2) ferret99gt@1479: { januk@3826: decl String:map[PLATFORM_MAX_PATH], String:buffer[255]; ferret99gt@1479: GetMenuItem(menu, param2, map, sizeof(map)); ferret99gt@1531: if (strcmp(map, VOTE_EXTEND, false) == 0) ferret99gt@1479: { ferret99gt@1479: Format(buffer, sizeof(buffer), "%T", "Extend Map", param1); ferret99gt@1479: return RedrawMenuItem(buffer); ferret99gt@1479: } pred@2133: else if (strcmp(map, VOTE_DONTCHANGE, false) == 0) pred@2133: { pred@2133: Format(buffer, sizeof(buffer), "%T", "Dont Change", param1); pred@2133: return RedrawMenuItem(buffer); pred@2133: } ferret99gt@1479: } ferret99gt@1479: } pred@2133: ferret99gt@1440: case MenuAction_VoteCancel: ferret99gt@1440: { ferret99gt@1440: // If we receive 0 votes, pick at random. ferret99gt@1531: if (param1 == VoteCancel_NoVotes && GetConVarBool(g_Cvar_NoVoteMode)) ferret99gt@1440: { ferret99gt@1440: new count = GetMenuItemCount(menu); januk@3826: decl String:map[PLATFORM_MAX_PATH]; januk@4359: GetMenuItem(menu, 0, map, sizeof(map)); ferret99gt@1440: januk@4359: // Make sure the first map in the menu isn't one of the special items. januk@4359: // This would mean there are no real maps in the menu, because the special items are added after all maps. Don't do anything if that's the case. januk@4359: if (strcmp(map, VOTE_EXTEND, false) != 0 && strcmp(map, VOTE_DONTCHANGE, false) != 0) ferret99gt@1440: { januk@4359: // Get a random map from the list. januk@4359: new item = GetRandomInt(0, count - 1); ferret99gt@1440: GetMenuItem(menu, item, map, sizeof(map)); januk@4359: januk@4359: // Make sure it's not one of the special items. januk@4359: while (strcmp(map, VOTE_EXTEND, false) == 0 || strcmp(map, VOTE_DONTCHANGE, false) == 0) januk@4359: { januk@4359: item = GetRandomInt(0, count - 1); januk@4359: GetMenuItem(menu, item, map, sizeof(map)); januk@4359: } januk@4359: januk@4359: SetNextMap(map); januk@4359: g_MapVoteCompleted = true; ferret99gt@1440: } ferret99gt@1440: } ferret99gt@1440: else ferret99gt@1440: { pred@2185: // We were actually cancelled. I guess we do nothing. ferret99gt@1440: } pred@2239: pred@2239: g_HasVoteStarted = false; ferret99gt@1440: } ferret99gt@1440: } ferret99gt@1479: ferret99gt@1479: return 0; ferret99gt@1440: } ferret99gt@1440: pred@2133: public Action:Timer_ChangeMap(Handle:hTimer, Handle:dp) ferret99gt@1440: { pred@2333: g_ChangeMapInProgress = false; pred@2333: januk@3826: new String:map[PLATFORM_MAX_PATH]; pred@2133: pred@2133: if (dp == INVALID_HANDLE) ferret99gt@1440: { pred@2133: if (!GetNextMap(map, sizeof(map))) pred@2133: { pred@2133: //No passed map and no set nextmap. fail! pred@2133: return Plugin_Stop; pred@2133: } ferret99gt@1440: } pred@2133: else pred@2133: { pred@2133: ResetPack(dp); pred@2133: ReadPackString(dp, map, sizeof(map)); pred@2133: } pred@2133: pred@2203: ForceChangeLevel(map, "Map Vote"); pred@2133: pred@2133: return Plugin_Stop; ferret99gt@1440: } ferret99gt@1440: pred@3440: bool:RemoveStringFromArray(Handle:array, String:str[]) pred@3440: { pred@3440: new index = FindStringInArray(array, str); pred@3440: if (index != -1) pred@3440: { pred@3440: RemoveFromArray(array, index); pred@3440: return true; pred@3440: } pred@3440: pred@3440: return false; pred@3440: } pred@3440: ferret99gt@1440: CreateNextVote() ferret99gt@1440: { pred@3440: assert(g_NextMapList) pred@3440: ClearArray(g_NextMapList); ferret99gt@1440: januk@3826: decl String:map[PLATFORM_MAX_PATH]; pred@3440: new Handle:tempMaps = CloneArray(g_MapList); ferret99gt@1719: ferret99gt@1719: GetCurrentMap(map, sizeof(map)); pred@3440: RemoveStringFromArray(tempMaps, map); ferret99gt@1440: ferret99gt@1664: if (GetConVarInt(g_Cvar_ExcludeMaps) && GetArraySize(tempMaps) > GetConVarInt(g_Cvar_ExcludeMaps)) ferret99gt@1533: { ferret99gt@1533: for (new i = 0; i < GetArraySize(g_OldMapList); i++) ferret99gt@1533: { ferret99gt@1533: GetArrayString(g_OldMapList, i, map, sizeof(map)); pred@3440: RemoveStringFromArray(tempMaps, map); ferret99gt@1533: } ferret99gt@1533: } ferret99gt@1533: ferret99gt@1533: new limit = (GetConVarInt(g_Cvar_IncludeMaps) < GetArraySize(tempMaps) ? GetConVarInt(g_Cvar_IncludeMaps) : GetArraySize(tempMaps)); ferret99gt@1452: for (new i = 0; i < limit; i++) ferret99gt@1440: { ferret99gt@1533: new b = GetRandomInt(0, GetArraySize(tempMaps) - 1); ferret99gt@1533: GetArrayString(tempMaps, b, map, sizeof(map)); ferret99gt@1533: PushArrayString(g_NextMapList, map); ferret99gt@1533: RemoveFromArray(tempMaps, b); ferret99gt@1440: } ferret99gt@1642: ferret99gt@1642: CloseHandle(tempMaps); pred@2133: } pred@2133: pred@2133: bool:CanVoteStart() pred@2133: { pred@2133: if (g_WaitingForVote || g_HasVoteStarted) pred@2133: { pred@2133: return false; pred@2133: } pred@2133: pred@2133: return true; pred@2133: } pred@2133: pred@2133: NominateResult:InternalNominateMap(String:map[], bool:force, owner) pred@2133: { pred@2133: if (!IsMapValid(map)) pred@2133: { pred@2133: return Nominate_InvalidMap; pred@2133: } pred@2133: kyle@4208: /* Map already in the vote */ kyle@4208: if (FindStringInArray(g_NominateList, map) != -1) kyle@4208: { kyle@4208: return Nominate_AlreadyInVote; kyle@4208: } kyle@4208: pred@2133: new index; pred@2133: pred@2345: /* Look to replace an existing nomination by this client - Nominations made with owner = 0 aren't replaced */ pred@2345: if (owner && ((index = FindValueInArray(g_NominateOwners, owner)) != -1)) pred@2133: { januk@3826: new String:oldmap[PLATFORM_MAX_PATH]; pred@2133: GetArrayString(g_NominateList, index, oldmap, sizeof(oldmap)); pred@2133: Call_StartForward(g_NominationsResetForward); pred@2133: Call_PushString(oldmap); pred@2133: Call_PushCell(owner); pred@2133: Call_Finish(); pred@2133: pred@2133: SetArrayString(g_NominateList, index, map); pred@2133: return Nominate_Replaced; pred@2133: } pred@2133: pred@2133: /* Too many nominated maps. */ ferret99gt@4218: if (GetArraySize(g_NominateList) >= GetConVarInt(g_Cvar_IncludeMaps) && !force) pred@2133: { pred@2133: return Nominate_VoteFull; pred@2133: } pred@2133: pred@2133: PushArrayString(g_NominateList, map); pred@2133: PushArrayCell(g_NominateOwners, owner); pred@2133: pred@2133: while (GetArraySize(g_NominateList) > GetConVarInt(g_Cvar_IncludeMaps)) pred@2133: { januk@3826: new String:oldmap[PLATFORM_MAX_PATH]; pred@2133: GetArrayString(g_NominateList, 0, oldmap, sizeof(oldmap)); pred@2133: Call_StartForward(g_NominationsResetForward); pred@2133: Call_PushString(oldmap); pred@2133: Call_PushCell(GetArrayCell(g_NominateOwners, 0)); pred@2133: Call_Finish(); pred@2133: pred@2133: RemoveFromArray(g_NominateList, 0); pred@2133: RemoveFromArray(g_NominateOwners, 0); pred@2133: } pred@2133: pred@2133: return Nominate_Added; pred@2133: } pred@2133: pred@2133: /* Add natives to allow nominate and initiate vote to be call */ pred@2133: pred@2133: /* native bool:NominateMap(const String:map[], bool:force, &NominateError:error); */ pred@2133: public Native_NominateMap(Handle:plugin, numParams) pred@2133: { pred@2133: new len; pred@2133: GetNativeStringLength(1, len); pred@2133: pred@2133: if (len <= 0) pred@2133: { pred@2133: return false; pred@2133: } pred@2133: pred@2133: new String:map[len+1]; pred@2133: GetNativeString(1, map, len+1); pred@2133: pred@2133: return _:InternalNominateMap(map, GetNativeCell(2), GetNativeCell(3)); pred@2133: } pred@2133: crimson@3150: bool:InternalRemoveNominationByMap(String:map[]) crimson@3150: { crimson@3150: for (new i = 0; i < GetArraySize(g_NominateList); i++) crimson@3150: { januk@3826: new String:oldmap[PLATFORM_MAX_PATH]; crimson@3150: GetArrayString(g_NominateList, i, oldmap, sizeof(oldmap)); crimson@3150: crimson@3150: if(strcmp(map, oldmap, false) == 0) crimson@3150: { crimson@3150: Call_StartForward(g_NominationsResetForward); crimson@3150: Call_PushString(oldmap); crimson@3150: Call_PushCell(GetArrayCell(g_NominateOwners, i)); crimson@3150: Call_Finish(); crimson@3150: crimson@3150: RemoveFromArray(g_NominateList, i); crimson@3150: RemoveFromArray(g_NominateOwners, i); crimson@3150: crimson@3150: return true; crimson@3150: } crimson@3150: } crimson@3150: crimson@3150: return false; crimson@3150: } crimson@3150: crimson@3150: /* native bool:RemoveNominationByMap(const String:map[]); */ crimson@3150: public Native_RemoveNominationByMap(Handle:plugin, numParams) crimson@3150: { crimson@3150: new len; crimson@3150: GetNativeStringLength(1, len); crimson@3150: crimson@3150: if (len <= 0) crimson@3150: { crimson@3150: return false; crimson@3150: } crimson@3150: crimson@3150: new String:map[len+1]; crimson@3150: GetNativeString(1, map, len+1); crimson@3150: crimson@3150: return _:InternalRemoveNominationByMap(map); crimson@3150: } crimson@3150: crimson@3150: bool:InternalRemoveNominationByOwner(owner) crimson@3150: { crimson@3150: new index; crimson@3150: crimson@3150: if (owner && ((index = FindValueInArray(g_NominateOwners, owner)) != -1)) crimson@3150: { januk@3826: new String:oldmap[PLATFORM_MAX_PATH]; crimson@3150: GetArrayString(g_NominateList, index, oldmap, sizeof(oldmap)); crimson@3150: crimson@3150: Call_StartForward(g_NominationsResetForward); crimson@3150: Call_PushString(oldmap); crimson@3150: Call_PushCell(owner); crimson@3150: Call_Finish(); crimson@3150: crimson@3150: RemoveFromArray(g_NominateList, index); crimson@3150: RemoveFromArray(g_NominateOwners, index); crimson@3150: crimson@3150: return true; crimson@3150: } crimson@3150: crimson@3150: return false; crimson@3150: } crimson@3150: crimson@3150: /* native bool:RemoveNominationByOwner(owner); */ crimson@3150: public Native_RemoveNominationByOwner(Handle:plugin, numParams) crimson@3150: { crimson@3150: return _:InternalRemoveNominationByOwner(GetNativeCell(1)); crimson@3150: } crimson@3150: pred@2133: /* native InitiateMapChooserVote(); */ pred@2133: public Native_InitiateVote(Handle:plugin, numParams) pred@2133: { pred@2133: new MapChange:when = MapChange:GetNativeCell(1); pred@2133: new Handle:inputarray = Handle:GetNativeCell(2); pred@2133: skamonkey@3217: LogAction(-1, -1, "Starting map vote because outside request"); pred@2133: InitiateVote(when, inputarray); pred@2133: } pred@2133: pred@2133: public Native_CanVoteStart(Handle:plugin, numParams) pred@2133: { pred@2133: return CanVoteStart(); pred@2133: } pred@2133: pred@2133: public Native_CheckVoteDone(Handle:plugin, numParams) pred@2133: { pred@2133: return g_MapVoteCompleted; pred@2133: } pred@2133: pred@2223: public Native_EndOfMapVoteEnabled(Handle:plugin, numParams) pred@2223: { pred@2223: return GetConVarBool(g_Cvar_EndOfMapVote); pred@2223: } pred@2223: pred@2133: public Native_GetExcludeMapList(Handle:plugin, numParams) pred@2133: { pred@2133: new Handle:array = Handle:GetNativeCell(1); pred@2133: pred@2133: if (array == INVALID_HANDLE) pred@2133: { pred@2133: return; pred@2133: } pred@2133: new size = GetArraySize(g_OldMapList); januk@3826: decl String:map[PLATFORM_MAX_PATH]; pred@2133: pred@2133: for (new i=0; i