plugins/basecommands.sp
author David Anderson <dvander@alliedmods.net>
Sun Aug 26 19:51:24 2007 +0000 (2007-08-26)
changeset 1375 b7acfca8070d
parent 1374 76f2c00429b1
child 1376 1d799689de9a
permissions -rw-r--r--
fixed amb830 - basefunvotes.sp was named wrong
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Basic Commands Plugin
     5  * Implements basic admin commands.
     6  *
     7  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     8  * =============================================================================
     9  *
    10  * This program is free software; you can redistribute it and/or modify it under
    11  * the terms of the GNU General Public License, version 3.0, as published by the
    12  * Free Software Foundation.
    13  * 
    14  * This program is distributed in the hope that it will be useful, but WITHOUT
    15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    16  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    17  * details.
    18  *
    19  * You should have received a copy of the GNU General Public License along with
    20  * this program.  If not, see <http://www.gnu.org/licenses/>.
    21  *
    22  * As a special exception, AlliedModders LLC gives you permission to link the
    23  * code of this program (as well as its derivative works) to "Half-Life 2," the
    24  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    25  * by the Valve Corporation.  You must obey the GNU General Public License in
    26  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    27  * this exception to all derivative works.  AlliedModders LLC defines further
    28  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    29  * or <http://www.sourcemod.net/license.php>.
    30  *
    31  * Version: $Id$
    32  */
    33 
    34 #pragma semicolon 1
    35 
    36 #include <sourcemod>
    37 
    38 public Plugin:myinfo =
    39 {
    40 	name = "Basic Commands",
    41 	author = "AlliedModders LLC",
    42 	description = "Basic Admin Commands",
    43 	version = SOURCEMOD_VERSION,
    44 	url = "http://www.sourcemod.net/"
    45 };
    46 
    47 new Handle:hBanForward = INVALID_HANDLE;
    48 new Handle:hAddBanForward = INVALID_HANDLE;
    49 new Handle:hBanRemoved = INVALID_HANDLE;
    50 
    51 public OnPluginStart()
    52 {
    53 	LoadTranslations("common.phrases");
    54 
    55 	RegAdminCmd("sm_kick", Command_Kick, ADMFLAG_KICK, "sm_kick <#userid|name> [reason]");
    56 	RegAdminCmd("sm_map", Command_Map, ADMFLAG_CHANGEMAP, "sm_map <map>");
    57 	RegAdminCmd("sm_rcon", Command_Rcon, ADMFLAG_RCON, "sm_rcon <args>");
    58 	RegAdminCmd("sm_cvar", Command_Cvar, ADMFLAG_CONVARS, "sm_cvar <cvar> [value]");
    59 	RegAdminCmd("sm_execcfg", Command_ExecCfg, ADMFLAG_CONFIG, "sm_execcfg <filename>");
    60 	RegAdminCmd("sm_who", Command_Who, ADMFLAG_GENERIC, "sm_who [#userid|name]");
    61 	RegAdminCmd("sm_ban", Command_Ban, ADMFLAG_BAN, "sm_ban <#userid|name> <minutes|0> [reason]");
    62 	RegAdminCmd("sm_unban", Command_Unban, ADMFLAG_UNBAN, "sm_unban <steamid>");
    63 	RegAdminCmd("sm_addban", Command_AddBan, ADMFLAG_RCON, "sm_addban <time> <steamid> [reason]");
    64 	RegAdminCmd("sm_banip", Command_BanIp, ADMFLAG_BAN, "sm_banip <time> <ip|#userid|name> [reason]");
    65 	RegAdminCmd("sm_reloadadmins", Command_ReloadAdmins, ADMFLAG_BAN, "sm_reloadadmins");
    66 	RegAdminCmd("sm_cancelvote", Command_CancelVote, ADMFLAG_VOTE, "sm_cancelvote");
    67 	
    68 	hBanForward = CreateGlobalForward("OnClientBanned", ET_Hook, Param_Cell, Param_Cell, Param_Cell, Param_String);
    69 	hAddBanForward = CreateGlobalForward("OnBanAdded", ET_Hook, Param_Cell, Param_String, Param_Cell, Param_String);
    70 	hBanRemoved = CreateGlobalForward("OnBanRemoved", ET_Hook, Param_Cell, Param_String);
    71 }
    72 
    73 public Action:Command_ReloadAdmins(client, args)
    74 {
    75 	/* Dump it all! */
    76 	DumpAdminCache(AdminCache_Groups, true);
    77 	DumpAdminCache(AdminCache_Overrides, true);
    78 
    79 	LogMessage("\"%L\" refreshed the admin cache.", client);
    80 	ReplyToCommand(client, "[SM] %t", "Admin cache refreshed");
    81 
    82 	return Plugin_Handled;
    83 }
    84 
    85 public Action:Command_BanIp(client, args)
    86 {
    87 	if (args < 2)
    88 	{
    89 		ReplyToCommand(client, "[SM] Usage: sm_banip <time> <ip|#userid|name> [reason]");
    90 		return Plugin_Handled;
    91 	}
    92 
    93 	decl String:arg[50], String:time[20];
    94 	GetCmdArg(1, time, sizeof(time));
    95 	GetCmdArg(2, arg, sizeof(arg));
    96 	
    97 	if (StrEqual(arg, "0"))
    98 	{
    99 		ReplyToCommand(client, "[SM] %t", "Cannot ban that IP");
   100 		return Plugin_Handled;
   101 	}
   102 	
   103 	new clients[1];
   104 	new numClients = SearchForClients(arg, clients, 1);
   105 
   106 	new bool:has_rcon;
   107 	
   108 	if (client == 0 || (client == 1 && !IsDedicatedServer()))
   109 	{
   110 		has_rcon = true;
   111 	} else {
   112 		new AdminId:id = GetUserAdmin(client);
   113 		has_rcon = (id == INVALID_ADMIN_ID) ? false : GetAdminFlag(id, Admin_RCON);
   114 	}
   115 	
   116 	new bool:hit_client = false;
   117 	if (numClients == 1 
   118 		&& !IsFakeClient(clients[0])
   119 		&& (has_rcon || CanUserTarget(client, clients[0])))
   120 	{
   121 		GetClientIP(clients[0], arg, sizeof(arg));
   122 		hit_client = true;
   123 	}
   124 	
   125 	if (!hit_client && !has_rcon)
   126 	{
   127 		ReplyToCommand(client, "[SM] %t", "No Access");
   128 		return Plugin_Handled;
   129 	}
   130 
   131 	new minutes = StringToInt(time);
   132 
   133 	decl String:reason[128];
   134 	if (args >= 3)
   135 	{
   136 		GetCmdArg(3, reason, sizeof(reason));
   137 	}
   138 
   139 	new Action:act = Plugin_Continue;
   140 	Call_StartForward(hAddBanForward);
   141 	Call_PushCell(client);
   142 	Call_PushString(arg);
   143 	Call_PushCell(minutes);
   144 	Call_PushString(reason);
   145 	Call_Finish(act);
   146 
   147 	if (act < Plugin_Handled)
   148 	{
   149 		LogMessage("\"%L\" added ban (minutes \"%d\") (ip \"%s\") (reason \"%s\")", client, minutes, arg, reason);
   150 		ReplyToCommand(client, "[SM] %t", "Ban added");
   151 	}
   152 
   153 	if (act < Plugin_Stop)
   154 	{
   155 		ServerCommand("addip %d %s", minutes, arg);
   156 		ServerCommand("writeip");
   157 	}
   158 
   159 	return Plugin_Handled;
   160 }
   161 
   162 public Action:Command_AddBan(client, args)
   163 {
   164 	if (args < 2)
   165 	{
   166 		ReplyToCommand(client, "[SM] Usage: sm_addban <time> <steamid> [reason]");
   167 		return Plugin_Handled;
   168 	}
   169 
   170 	decl String:arg[50], String:time[20];
   171 	GetCmdArg(1, time, sizeof(time));
   172 	GetCmdArg(2, arg, sizeof(arg));
   173 
   174 	new minutes = StringToInt(time);
   175 
   176 	new String:reason[128];
   177 	if (args >= 3)
   178 	{
   179 		GetCmdArg(3, reason, sizeof(reason));
   180 	}
   181 
   182 	new Action:act = Plugin_Continue;
   183 	Call_StartForward(hAddBanForward);
   184 	Call_PushCell(client);
   185 	Call_PushString(arg);
   186 	Call_PushCell(minutes);
   187 	Call_PushString(reason);
   188 	Call_Finish(act);
   189 
   190 	if (act < Plugin_Handled)
   191 	{
   192 		LogMessage("\"%L\" added ban (minutes \"%d\") (id \"%s\") (reason \"%s\")", client, minutes, arg, reason);
   193 		ReplyToCommand(client, "[SM] %t", "Ban added");
   194 	}
   195 
   196 	if (act < Plugin_Stop)
   197 	{
   198 		ServerCommand("banid %d %s", minutes, arg);
   199 		ServerCommand("writeid");
   200 	}
   201 
   202 	return Plugin_Handled;
   203 }
   204 
   205 public Action:Command_Unban(client, args)
   206 {
   207 	if (args < 1)
   208 	{
   209 		ReplyToCommand(client, "[SM] Usage: sm_unban <steamid>");
   210 		return Plugin_Handled;
   211 	}
   212 
   213 	decl String:arg[50], String:new_arg[50];
   214 	new start=0;
   215 	GetCmdArgString(arg, sizeof(arg));
   216 
   217 	if(arg[start] == '"')
   218 	{
   219 		start++;
   220 	}
   221 
   222 	if (strncmp(arg[start], "STEAM_0:", 8, false) == 0)
   223 	{
   224 		start += 8;
   225 	} else if (strncmp(arg[start], "0:1:", 4) == 0 || strncmp(arg[start], "0:0:", 4) == 0) {
   226 		start += 2;
   227 	}
   228 
   229 	Format(new_arg, sizeof(new_arg), "STEAM_0:%s", arg[start]);
   230 
   231 	/* Remove white spaces */
   232 	new len = TrimString(new_arg);
   233 	if(new_arg[len - 1] == '"')
   234 	{
   235 		new_arg[len - 1] = '\0';
   236 	}
   237 
   238 	new Action:act = Plugin_Continue;
   239 	Call_StartForward(hBanRemoved);
   240 	Call_PushCell(client);
   241 	Call_PushString(new_arg);
   242 	Call_Finish(act);
   243 
   244 	if (act < Plugin_Handled)
   245 	{
   246 		LogMessage("\"%L\" removed ban (filter \"%s\")", client, new_arg);
   247 		ReplyToCommand(client, "[SM] %t", "Removed bans matching", new_arg);
   248 	}
   249 
   250 	if (act < Plugin_Stop)
   251 	{
   252 		ServerCommand("removeid %s", new_arg);
   253 		ServerCommand("writeid");
   254 	}
   255 
   256 	return Plugin_Handled;
   257 }
   258 
   259 public Action:Command_Ban(client, args)
   260 {
   261 	if (args < 2)
   262 	{
   263 		ReplyToCommand(client, "[SM] Usage: sm_ban <#userid|name> <minutes|0> [reason]");
   264 		return Plugin_Handled;
   265 	}
   266 
   267 	decl String:arg[65];
   268 	GetCmdArg(1, arg, sizeof(arg));
   269 
   270 	new target = FindTarget(client, arg, true);
   271 	if (target == -1)
   272 	{
   273 		return Plugin_Handled;
   274 	}
   275 
   276 	decl String:s_time[12];
   277 	GetCmdArg(2, s_time, sizeof(s_time));
   278 
   279 	new time = StringToInt(s_time);
   280 
   281 	decl String:reason[128];
   282 	if (args >= 3)
   283 	{
   284 		GetCmdArg(3, reason, sizeof(reason));
   285 	} else {
   286 		reason[0] = '\0';
   287 	}
   288 
   289 	decl String:authid[64];
   290 	GetClientAuthString(target, authid, sizeof(authid));
   291 	GetClientName(target, arg, sizeof(arg));
   292 
   293 	/* Fire the ban forward */
   294 	new Action:act = Plugin_Continue;
   295 	Call_StartForward(hBanForward);
   296 	Call_PushCell(client);
   297 	Call_PushCell(target);
   298 	Call_PushCell(time);
   299 	Call_PushString(reason);
   300 	Call_Finish(act);
   301 
   302 	if (act < Plugin_Handled)
   303 	{
   304 		if (!time)
   305 		{
   306 			if (reason[0] == '\0')
   307 			{
   308 				ShowActivity(client, "%t", "Permabanned player", arg);
   309 			} else {
   310 				ShowActivity(client, "%t", "Permabanned player reason", arg, reason);
   311 			}
   312 		} else {
   313 			if (reason[0] == '\0')
   314 			{
   315 				ShowActivity(client, "%t", "Banned player", arg, time);
   316 			} else {
   317 				ShowActivity(client, "%t", "Banned player reason", arg, time, reason);
   318 			}
   319 		}
   320 		LogMessage("\"%L\" banned \"%L\" (minutes \"%d\") (reason \"%s\")", client, target, time, reason);
   321 	}
   322 
   323 	if (act < Plugin_Stop)
   324 	{
   325 		if (reason[0] == '\0')
   326 		{
   327 			strcopy(reason, sizeof(reason), "Banned");
   328 		}
   329 
   330 		ServerCommand("banid %d %s", time, authid);
   331 		KickClient(target, "%s", reason);
   332 
   333 		if (time == 0)
   334 		{
   335 			ServerCommand("writeid");
   336 		}
   337 	}
   338 
   339 	return Plugin_Handled;
   340 }
   341 
   342 #define FLAG_STRINGS		14
   343 new String:g_FlagNames[FLAG_STRINGS][20] =
   344 {
   345 	"reservation",
   346 	"admin",
   347 	"kick",
   348 	"ban",
   349 	"unban",
   350 	"slay",
   351 	"map",
   352 	"cvars",
   353 	"cfg",
   354 	"chat",
   355 	"vote",
   356 	"pass",
   357 	"rcon",
   358 	"cheat"
   359 };
   360 
   361 FlagsToString(String:buffer[], maxlength, flags)
   362 {
   363 	decl String:joins[FLAG_STRINGS][20];
   364 	new total;
   365 
   366 	for (new i=0; i<FLAG_STRINGS; i++)
   367 	{
   368 		if (flags & (1<<i))
   369 		{
   370 			strcopy(joins[total++], 20, g_FlagNames[i]);
   371 		}
   372 	}
   373 
   374 	ImplodeStrings(joins, total, ", ", buffer, maxlength);
   375 }
   376 
   377 public Action:Command_Who(client, args)
   378 {
   379 	if (args < 1)
   380 	{
   381 		/* Display header */
   382 		decl String:t_access[16], String:t_name[16];
   383 		Format(t_access, sizeof(t_access), "%t", "Access", client);
   384 		Format(t_name, sizeof(t_name), "%t", "Name", client);
   385 
   386 		PrintToConsole(client, "%-24.23s %s", t_name, t_access);
   387 
   388 		/* List all players */
   389 		new maxClients = GetMaxClients();
   390 		decl String:flagstring[255];
   391 
   392 		for (new i=1; i<=maxClients; i++)
   393 		{
   394 			if (!IsClientInGame(i))
   395 			{
   396 				continue;
   397 			}
   398 			new flags = GetUserFlagBits(i);
   399 			if (flags == 0)
   400 			{
   401 				strcopy(flagstring, sizeof(flagstring), "none");
   402 			} else if (flags & ADMFLAG_ROOT) {
   403 				strcopy(flagstring, sizeof(flagstring), "root");
   404 			} else {
   405 				FlagsToString(flagstring, sizeof(flagstring), flags);
   406 			}
   407 			decl String:name[65];
   408 			GetClientName(i, name, sizeof(name));
   409 			PrintToConsole(client, "%d. %-24.23s %s", i, name, flagstring);
   410 		}
   411 
   412 		if (GetCmdReplySource() == SM_REPLY_TO_CHAT)
   413 		{
   414 			ReplyToCommand(client, "[SM] %t", "See console for output");
   415 		}
   416 
   417 		return Plugin_Handled;
   418 	}
   419 
   420 	decl String:arg[65];
   421 	GetCmdArg(1, arg, sizeof(arg));
   422 
   423 	new clients[2];
   424 	new numClients = SearchForClients(arg, clients, 2);
   425 
   426 	if (numClients == 0)
   427 	{
   428 		ReplyToCommand(client, "[SM] %t", "No matching client");
   429 		return Plugin_Handled;
   430 	} else if (numClients > 1) {
   431 		ReplyToCommand(client, "[SM] %t", "More than one client matches", arg);
   432 		return Plugin_Handled;
   433 	}
   434 
   435 	new flags = GetUserFlagBits(clients[0]);
   436 	decl String:flagstring[255];
   437 	if (flags == 0)
   438 	{
   439 		strcopy(flagstring, sizeof(flagstring), "none");
   440 	} else if (flags & ADMFLAG_ROOT) {
   441 		strcopy(flagstring, sizeof(flagstring), "root");
   442 	} else {
   443 		FlagsToString(flagstring, sizeof(flagstring), flags);
   444 	}
   445 
   446 	ReplyToCommand(client, "[SM] %t: %s", "Access", flagstring);
   447 
   448 	return Plugin_Handled;
   449 }
   450 
   451 public Action:Command_ExecCfg(client, args)
   452 {
   453 	if (args < 1)
   454 	{
   455 		ReplyToCommand(client, "[SM] Usage: sm_execcfg <filename>");
   456 		return Plugin_Handled;
   457 	}
   458 
   459 	new String:path[64] = "cfg/";
   460 	GetCmdArg(1, path[4], sizeof(path)-4);
   461 
   462 	if (!FileExists(path))
   463 	{
   464 		ReplyToCommand(client, "[SM] %t", "Config not found", path[4]);
   465 		return Plugin_Handled;
   466 	}
   467 
   468 	ShowActivity(client, "%t", "Executed config", path[4]);
   469 
   470 	LogMessage("\"%L\" executed config (file \"%s\")", client, path[4]);
   471 
   472 	ServerCommand("exec \"%s\"", path[4]);
   473 
   474 	return Plugin_Handled;
   475 }
   476 
   477 public Action:Command_Cvar(client, args)
   478 {
   479 	if (args < 1)
   480 	{
   481 		ReplyToCommand(client, "[SM] Usage: sm_cvar <cvar> [value]");
   482 		return Plugin_Handled;
   483 	}
   484 
   485 	decl String:cvarname[33];
   486 	GetCmdArg(1, cvarname, sizeof(cvarname));
   487 
   488 	new Handle:hndl = FindConVar(cvarname);
   489 	if (hndl == INVALID_HANDLE)
   490 	{
   491 		ReplyToCommand(client, "[SM] %t", "Unable to find cvar", cvarname);
   492 		return Plugin_Handled;
   493 	}
   494 
   495 	new bool:allowed = false;
   496 	if (GetConVarFlags(hndl) & FCVAR_PROTECTED)
   497 	{
   498 		/* If they're root, allow anything */
   499 		if ((GetUserFlagBits(client) & ADMFLAG_ROOT) == ADMFLAG_ROOT)
   500 		{
   501 			allowed = true;
   502 		}
   503 		/* If they're not root, and getting sv_password, see if they have ADMFLAG_PASSWORD */
   504 		else if (StrEqual(cvarname, "sv_password") && (GetUserFlagBits(client) & ADMFLAG_PASSWORD))
   505 		{
   506 			allowed = true;
   507 		}
   508 	}
   509 	/* Do a check for the cheat cvar */
   510 	else if (StrEqual(cvarname, "sv_cheats"))
   511 	{
   512 		if (GetUserFlagBits(client) & ADMFLAG_CHEATS
   513 			|| GetUserFlagBits(client) & ADMFLAG_ROOT)
   514 		{
   515 			allowed = true;
   516 		}
   517 	}
   518 	/* If we drop down to here, it was a normal cvar. */
   519 	else
   520 	{
   521 		allowed = true;
   522 	}
   523 
   524 	if (!allowed)
   525 	{
   526 		ReplyToCommand(client, "[SM] %t", "No access to cvar");
   527 		return Plugin_Handled;
   528 	}
   529 
   530 	decl String:value[255];
   531 	if (args < 2)
   532 	{
   533 		GetConVarString(hndl, value, sizeof(value));
   534 
   535 		ReplyToCommand(client, "[SM] %t", "Value of cvar", cvarname, value);
   536 		return Plugin_Handled;
   537 	}
   538 
   539 	GetCmdArg(2, value, sizeof(value));
   540 
   541 	if ((GetConVarFlags(hndl) & FCVAR_PROTECTED) != FCVAR_PROTECTED)
   542 	{
   543 		ShowActivity(client, "%t", "Cvar changed", cvarname, value);
   544 	} else {
   545 		ReplyToCommand(client, "[SM] %t", "Cvar changed", cvarname, value);
   546 	}
   547 
   548 	LogMessage("\"%L\" changed cvar (cvar \"%s\") (value \"%s\")", client, cvarname, value);
   549 
   550 	SetConVarString(hndl, value, true);
   551 
   552 	return Plugin_Handled;
   553 }
   554 
   555 public Action:Command_Rcon(client, args)
   556 {
   557 	if (args < 1)
   558 	{
   559 		ReplyToCommand(client, "[SM] Usage: sm_rcon <args>");
   560 		return Plugin_Handled;
   561 	}
   562 
   563 	decl String:argstring[255];
   564 	GetCmdArgString(argstring, sizeof(argstring));
   565 
   566 	LogMessage("\"%L\" console command (cmdline \"%s\")", client, argstring);
   567 
   568 	ServerCommand("%s", argstring);
   569 
   570 	return Plugin_Handled;
   571 }
   572 
   573 public Action:Command_Map(client, args)
   574 {
   575 	if (args < 1)
   576 	{
   577 		ReplyToCommand(client, "[SM] Usage: sm_map <map>");
   578 		return Plugin_Handled;
   579 	}
   580 
   581 	decl String:map[64];
   582 	GetCmdArg(1, map, sizeof(map));
   583 
   584 	if (!IsMapValid(map))
   585 	{
   586 		ReplyToCommand(client, "[SM] %t", "Map was not found", map);
   587 		return Plugin_Handled;
   588 	}
   589 
   590 	ShowActivity(client, "%t", "Changing map", map);
   591 
   592 	LogMessage("\"%L\" changed map to \"%s\"", client, map);
   593 
   594 	new Handle:dp;
   595 	CreateDataTimer(3.0, Timer_ChangeMap, dp);
   596 	WritePackString(dp, map);
   597 
   598 	return Plugin_Handled;
   599 }
   600 
   601 public Action:Timer_ChangeMap(Handle:timer, Handle:dp)
   602 {
   603 	decl String:map[65];
   604 
   605 	ResetPack(dp);
   606 	ReadPackString(dp, map, sizeof(map));
   607 
   608 	ServerCommand("changelevel \"%s\"", map);
   609 
   610 	return Plugin_Stop;
   611 }
   612 
   613 public Action:Command_Kick(client, args)
   614 {
   615 	if (args < 1)
   616 	{
   617 		ReplyToCommand(client, "[SM] Usage: sm_kick <#userid|name> [reason]");
   618 		return Plugin_Handled;
   619 	}
   620 
   621 
   622 	decl String:Arguments[256];
   623 	GetCmdArgString(Arguments, sizeof(Arguments));
   624 
   625 	decl String:arg[65];
   626 	new len = BreakString(Arguments, arg, sizeof(arg));
   627 
   628 	new target = FindTarget(client, arg);
   629 	if (target == -1)
   630 	{
   631 		return Plugin_Handled;
   632 	}
   633 
   634 	GetClientName(target, arg, sizeof(arg));
   635 
   636 	if (len == -1)
   637 	{
   638 		/* Safely null terminate */
   639 		len = 0;
   640 		Arguments[0] = '\0';
   641 	}
   642 
   643 	ShowActivity(client, "%t", "Kicked player", arg);
   644 	LogMessage("\"%L\" kicked \"%L\" (reason \"%s\")", client, target, Arguments[len]);
   645 
   646 	KickClient(target, "%s", Arguments[len]);
   647 
   648 	return Plugin_Handled;
   649 }
   650 
   651 public Action:Command_CancelVote(client, args)
   652 {
   653 	if (!IsVoteInProgress())
   654 	{
   655 		ReplyToCommand(client, "[SM] %t", "Vote Not In Progress");
   656 		return Plugin_Handled;
   657 	}
   658 
   659 	ShowActivity(client, "%t", "Cancelled Vote");
   660 	
   661 	CancelVote();
   662 	
   663 	return Plugin_Handled;
   664 }