plugins/basevotes.sp
author Michael McKoy <ferret99gt@gmail.com>
Wed Aug 08 23:35:16 2007 +0000 (2007-08-08)
changeset 1281 ebca4b94e0f9
child 1284 ac293d8351a3
permissions -rw-r--r--
Base Votes import.
     1 /**
     2  * basevotes.sp
     3  * Implements basic vote commands.
     4  * This file is part of SourceMod, Copyright (C) 2004-2007 AlliedModders LLC
     5  *
     6  * This program is free software; you can redistribute it and/or
     7  * modify it under the terms of the GNU General Public License
     8  * as published by the Free Software Foundation; either version 2
     9  * of the License, or (at your option) any later version.
    10  *
    11  * This program is distributed in the hope that it will be useful,
    12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  * GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License
    17  * along with this program; if not, write to the Free Software
    18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    19  *
    20  * Version: $Id$
    21  */
    22 
    23 #include <sourcemod>
    24 
    25 #pragma semicolon 1
    26 
    27 public Plugin:myinfo =
    28 {
    29 	name = "Basic Votes",
    30 	author = "AlliedModders LLC",
    31 	description = "Basic Vote Commands",
    32 	version = SOURCEMOD_VERSION,
    33 	url = "http://www.sourcemod.net/"
    34 };
    35 
    36 new Handle:g_hVoteMenu = INVALID_HANDLE;
    37 
    38 new Handle:g_hBanForward = INVALID_HANDLE;
    39 
    40 new Handle:g_Cvar_VoteMap = INVALID_HANDLE;
    41 new Handle:g_Cvar_VoteKick = INVALID_HANDLE;
    42 new Handle:g_Cvar_VoteBan = INVALID_HANDLE;
    43 //new Handle:g_Cvar_VoteSay = INVALID_HANDLE;
    44 
    45 enum voteType
    46 {
    47 	question = 0,
    48 	map,
    49 	kick,
    50 	ban
    51 }
    52 
    53 new voteType:g_voteType = voteType:question;
    54 
    55 // Menu API does not provide us with a way to pass multiple peices of data with a single
    56 // choice, so some globals are used to hold stuff.
    57 //
    58 #define VOTE_CLIENTID	0
    59 #define VOTE_USERID	1
    60 new g_voteClient[2];		/* Holds the target's client id and user id */
    61 
    62 #define VOTE_NAME	0
    63 #define VOTE_AUTHID	1
    64 #define	VOTE_IP		2
    65 new String:g_voteInfo[3][65];	/* Holds the target's name, authid, and IP */
    66 
    67 new String:g_voteArg[256];	/* Used to hold ban/kick reasons or vote questions */
    68 
    69 
    70 public OnPluginStart()
    71 {
    72 	LoadTranslations("common.phrases");
    73 	LoadTranslations("plugin.basevotes");
    74 	
    75 	RegAdminCmd("sm_votemap", Command_Votemap, ADMFLAG_VOTE|ADMFLAG_CHANGEMAP, "sm_votemap <mapname> [mapname2] ... [mapname5] ");
    76 	RegAdminCmd("sm_votekick", Command_Votekick, ADMFLAG_VOTE|ADMFLAG_KICK, "sm_votekick <player> [reason]");
    77 	RegAdminCmd("sm_voteban", Command_Voteban, ADMFLAG_VOTE|ADMFLAG_BAN, "sm_voteban <player> [reason]");
    78 	RegAdminCmd("sm_vote", Command_Vote, ADMFLAG_VOTE, "sm_vote <question> [Answer1] [Answer2] ... [Answer5]");
    79 
    80 	//g_Cvar_VoteShow = CreateConVar("sm_vote_show", "1", "Show player's votes? Default on.", 0, true, 0.0, true, 1.0);	
    81 
    82 	g_Cvar_VoteMap = CreateConVar("sm_vote_map", "0.60", "percent required for successful map vote.", 0, true, 0.05, true, 1.0);
    83 	g_Cvar_VoteKick = CreateConVar("sm_vote_kick", "0.60", "percent required for successful kick vote.", 0, true, 0.05, true, 1.0);	
    84 	g_Cvar_VoteBan = CreateConVar("sm_vote_ban", "0.60", "percent required for successful ban vote.", 0, true, 0.05, true, 1.0);	
    85 	
    86 	g_hBanForward = CreateGlobalForward("OnClientBanned", ET_Ignore, Param_Cell, Param_Cell, Param_Cell, Param_String);
    87 }
    88 
    89 public Action:Command_Votemap(client, args)
    90 {
    91 	if (args < 1)
    92 	{
    93 		ReplyToCommand(client, "[SM] Usage: sm_votemap <mapname> [mapname2] ... [mapname5]");
    94 		return Plugin_Handled;	
    95 	}
    96 	
    97 	if (IsVoteInProgress())
    98 	{
    99 		ReplyToCommand(client, "[SM] %t", "Vote in Progress");
   100 		return Plugin_Handled;
   101 	}
   102 	
   103 	decl String:text[256];
   104 	GetCmdArgString(text, sizeof(text));
   105 
   106 	decl String:maps[5][64];
   107 	new mapCount;	
   108 	new len, pos;
   109 	
   110 	while (pos != -1 && mapCount < 5)
   111 	{	
   112 		pos = BreakString(text[len], maps[mapCount], sizeof(maps[]));
   113 		
   114 		if (!IsMapValid(maps[mapCount]))
   115 		{
   116 			ReplyToCommand(client, "[SM] %t", "Map was not found", maps[mapCount]);
   117 			return Plugin_Handled;
   118 		}		
   119 
   120 		mapCount++;
   121 		
   122 		if (pos != -1)
   123 		{
   124 			len += pos;
   125 		}	
   126 	}
   127 
   128 	ShowActivity(client, "%t", "Initiated Vote Map");
   129 	
   130 	g_voteType = voteType:map;
   131 	
   132 	g_hVoteMenu = CreateMenu(Handler_VoteCallback);
   133 	
   134 	if (mapCount == 1)
   135 	{
   136 		strcopy(g_voteInfo[VOTE_NAME], sizeof(g_voteInfo[]), maps[0]);
   137 		SetMenuTitle(g_hVoteMenu, "Change Map To");
   138 		AddMenuItem(g_hVoteMenu, maps[0], "Yes");
   139 		AddMenuItem(g_hVoteMenu, "no", "No");
   140 	}
   141 	else
   142 	{
   143 		SetMenuTitle(g_hVoteMenu, "Map Vote");
   144 		for (new i = 0; i < mapCount; i++)
   145 		{
   146 			AddMenuItem(g_hVoteMenu, maps[i], maps[i]);
   147 		}	
   148 	}
   149 	
   150 	SetMenuExitButton(g_hVoteMenu, false);
   151 	VoteMenuToAll(g_hVoteMenu, 20);		
   152 	
   153 	return Plugin_Handled;	
   154 }
   155 
   156 public Action:Command_Vote(client, args)
   157 {
   158 	if (args < 1)
   159 	{
   160 		ReplyToCommand(client, "[SM] Usage: sm_vote <question> [Answer1] [Answer2] ... [Answer5]");
   161 		return Plugin_Handled;	
   162 	}
   163 	
   164 	if (IsVoteInProgress())
   165 	{
   166 		ReplyToCommand(client, "[SM] %t", "Vote in Progress");
   167 		return Plugin_Handled;
   168 	}
   169 	
   170 	decl String:text[256];
   171 	GetCmdArgString(text, sizeof(text));
   172 
   173 	decl String:answers[5][64];
   174 	new answerCount;	
   175 	new len = BreakString(text, g_voteArg, sizeof(g_voteArg));
   176 	new pos = len;
   177 	
   178 	while (pos != -1 && answerCount < 5)
   179 	{	
   180 		pos = BreakString(text[len], answers[answerCount], sizeof(answers[]));
   181 		answerCount++;
   182 		
   183 		if (pos != -1)
   184 		{
   185 			len += pos;
   186 		}	
   187 	}
   188 
   189 	ShowActivity(client, "%t", "Initiate Vote", g_voteArg);
   190 	
   191 	g_voteType = voteType:question;
   192 	
   193 	g_hVoteMenu = CreateMenu(Handler_VoteCallback);
   194 	SetMenuTitle(g_hVoteMenu, "%s?", g_voteArg);
   195 	
   196 	if (answerCount == 1)
   197 	{
   198 		AddMenuItem(g_hVoteMenu, "Yes", "Yes");
   199 		AddMenuItem(g_hVoteMenu, "No", "No");
   200 	}
   201 	else
   202 	{
   203 		for (new i = 0; i < answerCount; i++)
   204 		{
   205 			AddMenuItem(g_hVoteMenu, answers[i], answers[i]);
   206 		}	
   207 	}
   208 	
   209 	SetMenuExitButton(g_hVoteMenu, false);
   210 	VoteMenuToAll(g_hVoteMenu, 20);		
   211 	
   212 	return Plugin_Handled;	
   213 }
   214 
   215 public Action:Command_Votekick(client, args)
   216 {
   217 	if (args < 1)
   218 	{
   219 		ReplyToCommand(client, "[SM] Usage: sm_votekick <player> [reason]");
   220 		return Plugin_Handled;	
   221 	}
   222 	
   223 	if (IsVoteInProgress())
   224 	{
   225 		ReplyToCommand(client, "[SM] %t", "Vote in Progress");
   226 		return Plugin_Handled;
   227 	}	
   228 
   229 	decl String:text[256], String:arg[64];
   230 	GetCmdArgString(text, sizeof(text));
   231 	
   232 	new len = BreakString(text, arg, sizeof(arg));
   233 	
   234 	new target = FindTarget(client, arg);
   235 	if (target == -1)
   236 	{
   237 		return Plugin_Handled;
   238 	}
   239 	
   240 	if (len != -1)
   241 	{
   242 		strcopy(g_voteArg, sizeof(g_voteArg), text[len]);
   243 	}
   244 	else
   245 	{
   246 		g_voteArg[0] = '\0';
   247 	}
   248 	
   249 	g_voteClient[VOTE_CLIENTID] = target;
   250 	g_voteClient[VOTE_USERID] = GetClientUserId(target);
   251 
   252 	GetClientName(target, g_voteInfo[VOTE_NAME], sizeof(g_voteInfo[]));
   253 
   254 	ShowActivity(client, "%t", "Initiated Vote Kick", g_voteInfo[VOTE_NAME]);
   255 	
   256 	g_voteType = voteType:kick;
   257 	
   258 	g_hVoteMenu = CreateMenu(Handler_VoteCallback);
   259 	SetMenuTitle(g_hVoteMenu, "Votekick Player");
   260 	AddMenuItem(g_hVoteMenu, "No", "Yes");
   261 	AddMenuItem(g_hVoteMenu, "No", "No");
   262 	SetMenuExitButton(g_hVoteMenu, false);
   263 	VoteMenuToAll(g_hVoteMenu, 20);
   264 	
   265 	return Plugin_Handled;
   266 }
   267 
   268 public Action:Command_Voteban(client, args)
   269 {
   270 	if (args < 1)
   271 	{
   272 		ReplyToCommand(client, "[SM] Usage: sm_voteban <player> [reason]");
   273 		return Plugin_Handled;	
   274 	}
   275 	
   276 	if (IsVoteInProgress())
   277 	{
   278 		ReplyToCommand(client, "[SM] %t", "Vote in Progress");
   279 		return Plugin_Handled;
   280 	}	
   281 
   282 	decl String:text[256], String:arg[64];
   283 	GetCmdArgString(text, sizeof(text));
   284 	
   285 	new len = BreakString(text, arg, sizeof(arg));
   286 	
   287 	new target = FindTarget(client, arg);
   288 	if (target == -1)
   289 	{
   290 		return Plugin_Handled;
   291 	}
   292 	
   293 	if (len != -1)
   294 	{
   295 		strcopy(g_voteArg, sizeof(g_voteArg), text[len]);
   296 	}
   297 	else
   298 	{
   299 		g_voteArg[0] = '\0';
   300 	}
   301 	
   302 	g_voteClient[VOTE_CLIENTID] = target;
   303 	g_voteClient[VOTE_USERID] = GetClientUserId(target);
   304 
   305 	GetClientName(target, g_voteInfo[VOTE_NAME], sizeof(g_voteInfo[]));
   306 	GetClientAuthString(target, g_voteInfo[VOTE_AUTHID], sizeof(g_voteInfo[]));
   307 	GetClientIP(target, g_voteInfo[VOTE_IP], sizeof(g_voteInfo[]));
   308 
   309 	ShowActivity(client, "%t", "Initiated Vote Ban", g_voteInfo[VOTE_NAME]);
   310 
   311 	g_voteType = voteType:ban;
   312 	
   313 	g_hVoteMenu = CreateMenu(Handler_VoteCallback);
   314 	SetMenuTitle(g_hVoteMenu, "Voteban Player");
   315 	AddMenuItem(g_hVoteMenu, "No", "Yes");
   316 	AddMenuItem(g_hVoteMenu, "No", "No");
   317 	SetMenuExitButton(g_hVoteMenu, false);
   318 	VoteMenuToAll(g_hVoteMenu, 20);
   319 	
   320 	return Plugin_Handled;
   321 }
   322 
   323 public Handler_VoteCallback(Handle:menu, MenuAction:action, param1, param2)
   324 {
   325 	if (action == MenuAction_End)
   326 	{
   327 		VoteMenuClose();
   328 	}
   329 	else if (action == MenuAction_Display)
   330 	{
   331 	}
   332 	else if (action == MenuAction_DisplayItem)
   333 	{
   334 		decl String:display[64];
   335 		GetMenuItem(menu, param2, "", 0, _, display, sizeof(display));
   336 	 
   337 	 	if(strcmp(display, "No") == 0 || strcmp(display, "Yes") == 0)
   338 	 	{
   339 			decl String:buffer[255];
   340 			Format(buffer, sizeof(buffer), "%T", display, param1);
   341 
   342 			return RedrawMenuItem(buffer);
   343 		}
   344 	}
   345 	/* else if (action == MenuAction_Select)
   346 	{
   347 		VoteSelect(menu, param1, param2);
   348 	}*/
   349 	else if (action == MenuAction_VoteEnd)
   350 	{
   351 		decl String:item[64], String:display[64];
   352 		new Float:percent, Float:limit, votes, totalVotes;
   353 		GetMenuVoteInfo(param2, votes, totalVotes);
   354 		
   355 		if (totalVotes < 1)
   356 		{
   357 			PrintToChatAll("[SM] %t", "No Votes Cast");
   358 			return;
   359 		}
   360 		
   361 		GetMenuItem(menu, param1, item, sizeof(item), _, display, sizeof(display));
   362 		
   363 		if (strcmp(display,"No") == 0 && param1 == 1)
   364 		{
   365 			votes = totalVotes - votes; // Reverse the votes to be in relation to the Yes option.
   366 		}
   367 		
   368 		percent = GetVotePercent(votes, totalVotes);
   369 		
   370 		switch(g_voteType)
   371 		{
   372 			case (voteType:map):
   373 				limit = GetConVarFloat(g_Cvar_VoteMap);
   374 				
   375 			case (voteType:kick):
   376 				limit = GetConVarFloat(g_Cvar_VoteKick);
   377 				
   378 			case (voteType:ban):
   379 				limit = GetConVarFloat(g_Cvar_VoteBan);
   380 		}
   381 
   382 		// A multi-argument vote is "always successful", but have to check if its a Yes/No vote.
   383 		if ((strcmp(display,"Yes") == 0 && FloatCompare(percent,limit) < 0 && param1 == 0) || (strcmp(display,"No") == 0 && param1 == 1))
   384 		{
   385 			LogMessage("Vote failed.");
   386 			PrintToChatAll("[SM] %t", "Vote Failed", RoundToNearest(100.0*limit), RoundToNearest(100.0*percent), totalVotes);
   387 		}
   388 		else
   389 		{
   390 			PrintToChatAll("[SM] %t", "Vote Successful", RoundToNearest(100.0*percent), totalVotes);
   391 			
   392 			switch(g_voteType)
   393 			{
   394 				case (voteType:question):
   395 				{
   396 					PrintToChatAll("[SM] %t", "Vote End", g_voteArg, item, RoundToNearest(100.0*percent), totalVotes);
   397 				}
   398 				
   399 				case (voteType:map):
   400 				{
   401 					LogMessage("Changing map to %s due to vote.", item);
   402 					PrintToChatAll("[SM] %t", "Changing map", item);
   403 					new Handle:dp;
   404 					CreateDataTimer(5.0, Timer_ChangeMap, dp);
   405 					WritePackString(dp, item);		
   406 				}
   407 					
   408 				case (voteType:kick):
   409 				{
   410 					if (g_voteArg[0] == '\0')
   411 					{
   412 						strcopy(g_voteArg, sizeof(g_voteArg), "Votekicked");
   413 					}
   414 					
   415 					PrintToChatAll("[SM] %t", "Kicked player", g_voteInfo[VOTE_NAME]);					
   416 					LogMessage("Vote kick successful, kicked \"%L\" (reason \"%s\")", g_voteClient[VOTE_USERID], g_voteArg);
   417 					
   418 					ServerCommand("kickid %d \"%s\"", g_voteClient[VOTE_USERID], g_voteArg);					
   419 				}
   420 					
   421 				case (voteType:ban):
   422 				{
   423 					/* Fire the ban forward */
   424 					Call_StartForward(g_hBanForward);
   425 					Call_PushCell(0);
   426 					Call_PushCell(g_voteClient[VOTE_USERID]);
   427 					Call_PushCell(30);
   428 					Call_PushString(g_voteArg);
   429 					Call_Finish();
   430 				
   431 					if (g_voteArg[0] == '\0')
   432 					{
   433 						strcopy(g_voteArg, sizeof(g_voteArg), "Votebanned");
   434 					}
   435 					
   436 					PrintToChatAll("[SM] %t", "Banned player", g_voteInfo[VOTE_NAME], 30);
   437 					LogMessage("Vote ban successful, banned \"%L\" (minutes \"30\") (reason \"%s\")", g_voteClient[VOTE_USERID], g_voteArg);
   438 					
   439 					ServerCommand("banid %d %s", 30, g_voteClient[VOTE_AUTHID]);
   440 					ServerCommand("kickid %d \"%s\"", g_voteClient[VOTE_USERID], g_voteArg);				
   441 				}
   442 			}
   443 		}
   444 	}
   445 }
   446 
   447 /*
   448 VoteSelect(Handle:menu, param1, param2 = 0)
   449 {
   450 	if (GetConVarInt(g_Cvar_VoteShow) == 1)
   451 	{
   452 		decl String:voter[64], String:junk[64], String:choice[64];
   453 		GetClientName(param1, voter, sizeof(voter));
   454 		GetMenuItem(menu, param2, junk, sizeof(junk), _, choice, sizeof(choice));
   455 		PrintToChatAll("[SM] %T", "Vote Select", LANG_SERVER, voter, choice);
   456 	}
   457 }
   458 */
   459 
   460 VoteMenuClose()
   461 {
   462 	CloseHandle(g_hVoteMenu);
   463 	g_hVoteMenu = INVALID_HANDLE;
   464 }
   465 
   466 Float:GetVotePercent(votes, totalVotes)
   467 {
   468 	return FloatDiv(float(votes),float(totalVotes));
   469 }
   470 
   471 public Action:Timer_ChangeMap(Handle:timer, Handle:dp)
   472 {
   473 	decl String:mapname[65];
   474 	
   475 	ResetPack(dp);
   476 	ReadPackString(dp, mapname, sizeof(mapname));
   477 	
   478 	ServerCommand("changelevel \"%s\"", mapname);
   479 	
   480 	return Plugin_Stop;
   481 }