1.1 --- a/plugins/mapchooser.sp Fri Nov 04 10:02:32 2011 -0400
1.2 +++ b/plugins/mapchooser.sp Sat Nov 05 20:36:20 2011 -0400
1.3 @@ -31,6 +31,16 @@
1.4 *
1.5 * Version: $Id$
1.6 */
1.7 +
1.8 +//#define DEBUG
1.9 +
1.10 +#if defined DEBUG
1.11 + #define assert(%1) if (!(%1)) ThrowError("Debug Assertion Failed");
1.12 + #define assert_msg(%1,%2) if (!(%1)) ThrowError(%2);
1.13 +#else
1.14 + #define assert(%1)
1.15 + #define assert_msg(%1,%2)
1.16 +#endif
1.17
1.18 #pragma semicolon 1
1.19 #include <sourcemod>
1.20 @@ -66,6 +76,8 @@
1.21 new Handle:g_Cvar_DontChange = INVALID_HANDLE;
1.22 new Handle:g_Cvar_EndOfMapVote = INVALID_HANDLE;
1.23 new Handle:g_Cvar_VoteDuration = INVALID_HANDLE;
1.24 +new Handle:g_Cvar_RunOff = INVALID_HANDLE;
1.25 +new Handle:g_Cvar_RunOffPercent = INVALID_HANDLE;
1.26
1.27 new Handle:g_VoteTimer = INVALID_HANDLE;
1.28 new Handle:g_RetryTimer = INVALID_HANDLE;
1.29 @@ -126,6 +138,8 @@
1.30 g_Cvar_Extend = CreateConVar("sm_mapvote_extend", "0", "Number of extensions allowed each map.", _, true, 0.0);
1.31 g_Cvar_DontChange = CreateConVar("sm_mapvote_dontchange", "1", "Specifies if a 'Don't Change' option should be added to early votes", _, true, 0.0);
1.32 g_Cvar_VoteDuration = CreateConVar("sm_mapvote_voteduration", "20", "Specifies how long the mapvote should be available for.", _, true, 5.0);
1.33 + 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);
1.34 + 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);
1.35
1.36 RegAdminCmd("sm_mapvote", Command_Mapvote, ADMFLAG_CHANGEMAP, "sm_mapvote - Forces MapChooser to attempt to run a map vote now.");
1.37 RegAdminCmd("sm_setnextmap", Command_SetNextmap, ADMFLAG_CHANGEMAP, "sm_setnextmap <map>");
1.38 @@ -526,6 +540,7 @@
1.39 *
1.40 * @param when When the resulting map change should occur.
1.41 * @param inputlist Optional list of maps to use for the vote, otherwise an internal list of nominations + random maps will be used.
1.42 + * @param noSpecials Block special vote options like extend/nochange (upgrade this to bitflags instead?)
1.43 */
1.44 InitiateVote(MapChange:when, Handle:inputlist=INVALID_HANDLE)
1.45 {
1.46 @@ -586,6 +601,7 @@
1.47 {
1.48 GetArrayString(g_NominateList, i, map, sizeof(map));
1.49 AddMenuItem(g_VoteMenu, map, map);
1.50 + RemoveStringFromArray(g_NextMapList, map);
1.51
1.52 /* Notify Nominations that this map is now free */
1.53 Call_StartForward(g_NominationsResetForward);
1.54 @@ -598,6 +614,7 @@
1.55 for (new i=nominationsToAdd; i<nominateCount; i++)
1.56 {
1.57 GetArrayString(g_NominateList, i, map, sizeof(map));
1.58 + /* These maps shouldn't be excluded from the vote as they weren't really nominated at all */
1.59
1.60 /* Notify Nominations that this map is now free */
1.61 Call_StartForward(g_NominationsResetForward);
1.62 @@ -617,13 +634,9 @@
1.63 GetArrayString(g_NextMapList, count, map, sizeof(map));
1.64 count++;
1.65
1.66 - //Check if this map is in the nominate list (and thus already in the vote) */
1.67 - if (FindStringInArray(g_NominateList, map) == -1)
1.68 - {
1.69 - /* Insert the map and increment our count */
1.70 - AddMenuItem(g_VoteMenu, map, map);
1.71 - i++;
1.72 - }
1.73 + /* Insert the map and increment our count */
1.74 + AddMenuItem(g_VoteMenu, map, map);
1.75 + i++;
1.76
1.77 if (count >= availableMaps)
1.78 {
1.79 @@ -670,19 +683,13 @@
1.80 PrintToChatAll("[SM] %t", "Nextmap Voting Started");
1.81 }
1.82
1.83 -public Handler_MapVoteFinished(Handle:menu,
1.84 +public Handler_VoteFinishedGeneric(Handle:menu,
1.85 num_votes,
1.86 num_clients,
1.87 const client_info[][2],
1.88 num_items,
1.89 const item_info[][2])
1.90 {
1.91 - if (num_votes == 0)
1.92 - {
1.93 - LogError("No Votes recorded yet Advanced callback fired - Tell pRED* to fix this");
1.94 - return;
1.95 - }
1.96 -
1.97 decl String:map[32];
1.98 GetMenuItem(menu, item_info[0][VOTEINFO_ITEM_INDEX], map, sizeof(map));
1.99
1.100 @@ -771,6 +778,53 @@
1.101 }
1.102 }
1.103
1.104 +public Handler_MapVoteFinished(Handle:menu,
1.105 + num_votes,
1.106 + num_clients,
1.107 + const client_info[][2],
1.108 + num_items,
1.109 + const item_info[][2])
1.110 +{
1.111 + if (GetConVarBool(g_Cvar_RunOff) && num_items > 1)
1.112 + {
1.113 + new Float:winningvotes = float(item_info[0][VOTEINFO_ITEM_VOTES]);
1.114 + new Float:required = num_votes * (GetConVarFloat(g_Cvar_RunOffPercent) / 100.0);
1.115 +
1.116 + if (winningvotes <= required)
1.117 + {
1.118 + /* Insufficient Winning margin - Lets do a runoff */
1.119 + g_VoteMenu = CreateMenu(Handler_MapVoteMenu, MenuAction:MENU_ACTIONS_ALL);
1.120 + SetMenuTitle(g_VoteMenu, "Runoff Vote Nextmap");
1.121 + SetVoteResultCallback(g_VoteMenu, Handler_VoteFinishedGeneric);
1.122 +
1.123 + decl String:map[32];
1.124 + decl String:info1[32];
1.125 + decl String:info2[32];
1.126 +
1.127 + GetMenuItem(menu, item_info[0][VOTEINFO_ITEM_INDEX], map, sizeof(map), _, info1, sizeof(info1));
1.128 + AddMenuItem(g_VoteMenu, map, info1);
1.129 + GetMenuItem(menu, item_info[1][VOTEINFO_ITEM_INDEX], map, sizeof(map), _, info2, sizeof(info2));
1.130 + AddMenuItem(g_VoteMenu, map, info2);
1.131 +
1.132 + new voteDuration = GetConVarInt(g_Cvar_VoteDuration);
1.133 + SetMenuExitButton(g_VoteMenu, false);
1.134 + VoteMenuToAll(g_VoteMenu, voteDuration);
1.135 +
1.136 + /* Notify */
1.137 + new Float:map1percent = float(item_info[0][VOTEINFO_ITEM_VOTES])/ float(num_votes) * 100;
1.138 + new Float:map2percent = float(item_info[1][VOTEINFO_ITEM_VOTES])/ float(num_votes) * 100;
1.139 +
1.140 +
1.141 + PrintToChatAll("[SM] %t", "Starting Runoff", GetConVarFloat(g_Cvar_RunOffPercent), info1, map1percent, info2, map2percent);
1.142 + LogMessage("Voting for next map was indecisive, beginning runoff vote");
1.143 +
1.144 + return;
1.145 + }
1.146 + }
1.147 +
1.148 + Handler_VoteFinishedGeneric(menu, num_votes, num_clients, client_info, num_items, item_info);
1.149 +}
1.150 +
1.151 public Handler_MapVoteMenu(Handle:menu, MenuAction:action, param1, param2)
1.152 {
1.153 switch (action)
1.154 @@ -865,33 +919,35 @@
1.155 return Plugin_Stop;
1.156 }
1.157
1.158 +bool:RemoveStringFromArray(Handle:array, String:str[])
1.159 +{
1.160 + new index = FindStringInArray(array, str);
1.161 + if (index != -1)
1.162 + {
1.163 + RemoveFromArray(array, index);
1.164 + return true;
1.165 + }
1.166 +
1.167 + return false;
1.168 +}
1.169 +
1.170 CreateNextVote()
1.171 {
1.172 - if(g_NextMapList != INVALID_HANDLE)
1.173 - {
1.174 - ClearArray(g_NextMapList);
1.175 - }
1.176 + assert(g_NextMapList)
1.177 + ClearArray(g_NextMapList);
1.178
1.179 decl String:map[32];
1.180 - new index, Handle:tempMaps = CloneArray(g_MapList);
1.181 + new Handle:tempMaps = CloneArray(g_MapList);
1.182
1.183 GetCurrentMap(map, sizeof(map));
1.184 - index = FindStringInArray(tempMaps, map);
1.185 - if (index != -1)
1.186 - {
1.187 - RemoveFromArray(tempMaps, index);
1.188 - }
1.189 + RemoveStringFromArray(tempMaps, map);
1.190
1.191 if (GetConVarInt(g_Cvar_ExcludeMaps) && GetArraySize(tempMaps) > GetConVarInt(g_Cvar_ExcludeMaps))
1.192 {
1.193 for (new i = 0; i < GetArraySize(g_OldMapList); i++)
1.194 {
1.195 GetArrayString(g_OldMapList, i, map, sizeof(map));
1.196 - index = FindStringInArray(tempMaps, map);
1.197 - if (index != -1)
1.198 - {
1.199 - RemoveFromArray(tempMaps, index);
1.200 - }
1.201 + RemoveStringFromArray(tempMaps, map);
1.202 }
1.203 }
1.204