plugins/funcommands/timebomb.sp
author Matt Woodrow <pred@alliedmods.net>
Mon Jul 28 07:47:28 2008 +0000 (2008-07-28)
changeset 2215 bcbfee080d08
parent 1952 b7aa2b626807
child 2289 44045ead61cd
permissions -rw-r--r--
Pending Map should no longer be shown when mapvotes are disabled.
Removed tf2 include from mapchooser.
Moved sm_setnextmap to mapchooser and made it block the end of map vote.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Basefuncommands Plugin
     5  * Provides TimeBomb functionality
     6  *
     7  * SourceMod (C)2004-2008 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 new Handle:g_TimeBombTimers[MAXPLAYERS+1];
    35 new g_TimeBombTracker[MAXPLAYERS+1];
    36 
    37 new Handle:g_TimeBombTicks = INVALID_HANDLE;
    38 new Handle:g_TimeBombRadius = INVALID_HANDLE;
    39 new Handle:g_TimeBombMode = INVALID_HANDLE;
    40 
    41 SetupTimeBomb()
    42 {
    43 	RegAdminCmd("sm_timebomb", Command_TimeBomb, ADMFLAG_SLAY, "sm_timebomb <#userid|name> [0/1]");	
    44 	
    45 	g_TimeBombTicks = CreateConVar("sm_timebomb_ticks", "10", "Sets how long the timebomb fuse is.", 0, true, 5.0, true, 120.0);
    46 	g_TimeBombRadius = CreateConVar("sm_timebomb_radius", "600", "Sets the bomb blast radius.", 0, true, 50.0, true, 3000.0);
    47 	g_TimeBombMode = CreateConVar("sm_timebomb_mode", "0", "Who is killed by the timebomb? 0 = Target only, 1 = Target's team, 2 = Everyone", 0, true, 0.0, true, 2.0);
    48 }
    49 
    50 CreateTimeBomb(client)
    51 {
    52 	g_TimeBombTimers[client] = CreateTimer(1.0, Timer_TimeBomb, client, TIMER_REPEAT);
    53 	g_TimeBombTracker[client] = GetConVarInt(g_TimeBombTicks);
    54 }
    55 
    56 KillTimeBomb(client)
    57 {
    58 	KillTimer(g_TimeBombTimers[client]);
    59 	g_TimeBombTimers[client] = INVALID_HANDLE;
    60 }
    61 
    62 KillAllTimeBombs()
    63 {
    64 	new maxclients = GetMaxClients();
    65 	for (new i = 1; i <= maxclients; i++)
    66 	{
    67 		if (g_TimeBombTimers[i] != INVALID_HANDLE)
    68 		{
    69 			KillTimeBomb(i);
    70 		}
    71 	}
    72 }
    73 
    74 PerformTimeBomb(client, target, toggle)
    75 {
    76 	switch (toggle)
    77 	{
    78 		case (2):
    79 		{
    80 			if (g_TimeBombTimers[target] == INVALID_HANDLE)
    81 			{
    82 				CreateTimeBomb(target);
    83 				LogAction(client, target, "\"%L\" set a TimeBomb on \"%L\"", client, target);
    84 			}
    85 			else
    86 			{
    87 				KillTimeBomb(target);
    88 				SetEntityRenderColor(client, 255, 255, 255, 255);
    89 				LogAction(client, target, "\"%L\" removed a TimeBomb on \"%L\"", client, target);
    90 			}			
    91 		}
    92 
    93 		case (1):
    94 		{
    95 			if (g_TimeBombTimers[target] == INVALID_HANDLE)
    96 			{
    97 				CreateTimeBomb(target);
    98 				LogAction(client, target, "\"%L\" set a TimeBomb on \"%L\"", client, target);
    99 			}			
   100 		}
   101 		
   102 		case (0):
   103 		{
   104 			if (g_TimeBombTimers[target] != INVALID_HANDLE)
   105 			{
   106 				KillTimeBomb(target);
   107 				SetEntityRenderColor(client, 255, 255, 255, 255);
   108 				LogAction(client, target, "\"%L\" removed a TimeBomb on \"%L\"", client, target);
   109 			}			
   110 		}
   111 	}
   112 }
   113 
   114 public Action:Timer_TimeBomb(Handle:timer, any:client)
   115 {
   116 	if (!IsClientInGame(client) || !IsPlayerAlive(client))
   117 	{
   118 		KillTimeBomb(client);		
   119 
   120 		return Plugin_Handled;
   121 	}
   122 	
   123 	g_TimeBombTracker[client]--;
   124 	
   125 	new Float:vec[3];
   126 	GetClientEyePosition(client, vec);
   127 	
   128 	if (g_TimeBombTracker[client] > 0)
   129 	{
   130 		new color;
   131 		
   132 		if (g_TimeBombTracker[client] > 1)
   133 		{
   134 			color = RoundToFloor(g_TimeBombTracker[client] * (128.0 / GetConVarFloat(g_TimeBombTicks)));
   135 			EmitAmbientSound(SOUND_BEEP, vec, client, SNDLEVEL_RAIDSIREN);	
   136 		}
   137 		else
   138 		{
   139 			color = 0;
   140 			EmitAmbientSound(SOUND_FINAL, vec, client, SNDLEVEL_RAIDSIREN);
   141 		}
   142 		
   143 		SetEntityRenderColor(client, 255, 128, color, 255);
   144 
   145 		decl String:name[64];
   146 		GetClientName(client, name, sizeof(name));
   147 		PrintCenterTextAll("%t", "Till Explodes", name, g_TimeBombTracker[client]);
   148 		
   149 		GetClientAbsOrigin(client, vec);
   150 		vec[2] += 10;
   151 
   152 		TE_SetupBeamRingPoint(vec, 10.0, GetConVarFloat(g_TimeBombRadius) / 3.0, g_BeamSprite, g_HaloSprite, 0, 15, 0.5, 5.0, 0.0, greyColor, 10, 0);
   153 		TE_SendToAll();
   154 		TE_SetupBeamRingPoint(vec, 10.0, GetConVarFloat(g_TimeBombRadius) / 3.0, g_BeamSprite, g_HaloSprite, 0, 10, 0.6, 10.0, 0.5, whiteColor, 10, 0);
   155 		TE_SendToAll();
   156 	}
   157 	else
   158 	{
   159 		TE_SetupExplosion(vec, g_ExplosionSprite, 5.0, 1, 0, GetConVarInt(g_TimeBombRadius), 5000);
   160 		TE_SendToAll();
   161 
   162 		EmitAmbientSound(SOUND_BOOM, vec, client, SNDLEVEL_RAIDSIREN);
   163 
   164 		ForcePlayerSuicide(client);
   165 		KillTimeBomb(client);
   166 		SetEntityRenderColor(client, 255, 255, 255, 255);
   167 		
   168 		if (GetConVarInt(g_TimeBombMode) > 0)
   169 		{
   170 			new teamOnly = ((GetConVarInt(g_TimeBombMode) == 1) ? true : false);
   171 			new maxClients = GetMaxClients();
   172 			
   173 			//g_FilteredEntity = client;
   174 			
   175 			for (new i = 1; i < maxClients; i++)
   176 			{
   177 				if (!IsClientInGame(i) || !IsPlayerAlive(i) || i == client)
   178 				{
   179 					continue;
   180 				}
   181 				
   182 				if (teamOnly && GetClientTeam(i) != GetClientTeam(client))
   183 				{
   184 					continue;
   185 				}
   186 				
   187 				new Float:pos[3];
   188 				GetClientEyePosition(i, pos);
   189 				
   190 				new Float:distance = GetVectorDistance(vec, pos);
   191 				
   192 				if (distance > GetConVarFloat(g_TimeBombRadius))
   193 				{
   194 					continue;
   195 				}
   196 				
   197 				new damage = 220;
   198 				damage = RoundToFloor(damage * ((GetConVarFloat(g_TimeBombRadius) - distance) / GetConVarFloat(g_TimeBombRadius)));
   199 					
   200 				SlapPlayer(i, damage, false);
   201 				TE_SetupExplosion(pos, g_ExplosionSprite, 0.05, 1, 0, 1, 1);
   202 				TE_SendToAll();				
   203 				
   204 				/*
   205 				new Float:dir[3];
   206 				SubtractVectors(vec, pos, dir);
   207 				TR_TraceRayFilter(vec, dir, MASK_SOLID, RayType_Infinite, TR_Filter_Client);
   208 
   209 				if (i == TR_GetEntityIndex())
   210 				{
   211 					new damage = 100;
   212 					new radius = GetConVarInt(g_TimeBombRadius) / 2;
   213 					
   214 					if (distance > radius)
   215 					{
   216 						distance -= radius;
   217 						damage = RoundToFloor(damage * ((radius - distance) / radius));
   218 					}
   219 					
   220 					SlapPlayer(i, damage, false);
   221 				}
   222 				*/
   223 			}		
   224 		}
   225 	}
   226 			
   227 	return Plugin_Handled;
   228 }
   229 
   230 public AdminMenu_TimeBomb(Handle:topmenu, 
   231 					  TopMenuAction:action,
   232 					  TopMenuObject:object_id,
   233 					  param,
   234 					  String:buffer[],
   235 					  maxlength)
   236 {
   237 	if (action == TopMenuAction_DisplayOption)
   238 	{
   239 		Format(buffer, maxlength, "%T", "TimeBomb player", param);
   240 	}
   241 	else if (action == TopMenuAction_SelectOption)
   242 	{
   243 		DisplayTimeBombMenu(param);
   244 	}
   245 }
   246 
   247 DisplayTimeBombMenu(client)
   248 {
   249 	new Handle:menu = CreateMenu(MenuHandler_TimeBomb);
   250 	
   251 	decl String:title[100];
   252 	Format(title, sizeof(title), "%T:", "TimeBomb player", client);
   253 	SetMenuTitle(menu, title);
   254 	SetMenuExitBackButton(menu, true);
   255 	
   256 	AddTargetsToMenu(menu, client, true, true);
   257 	
   258 	DisplayMenu(menu, client, MENU_TIME_FOREVER);
   259 }
   260 
   261 public MenuHandler_TimeBomb(Handle:menu, MenuAction:action, param1, param2)
   262 {
   263 	if (action == MenuAction_End)
   264 	{
   265 		CloseHandle(menu);
   266 	}
   267 	else if (action == MenuAction_Cancel)
   268 	{
   269 		if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
   270 		{
   271 			DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
   272 		}
   273 	}
   274 	else if (action == MenuAction_Select)
   275 	{
   276 		decl String:info[32];
   277 		new userid, target;
   278 		
   279 		GetMenuItem(menu, param2, info, sizeof(info));
   280 		userid = StringToInt(info);
   281 
   282 		if ((target = GetClientOfUserId(userid)) == 0)
   283 		{
   284 			PrintToChat(param1, "[SM] %t", "Player no longer available");
   285 		}
   286 		else if (!CanUserTarget(param1, target))
   287 		{
   288 			PrintToChat(param1, "[SM] %t", "Unable to target");
   289 		}
   290 		else
   291 		{
   292 			new String:name[32];
   293 			GetClientName(target, name, sizeof(name));
   294 			
   295 			PerformTimeBomb(param1, target, 2);
   296 			ShowActivity2(param1, "[SM] ", "%t", "Toggled TimeBomb on target", "_s", name);
   297 		}
   298 		
   299 		/* Re-draw the menu if they're still valid */
   300 		if (IsClientInGame(param1) && !IsClientInKickQueue(param1))
   301 		{
   302 			DisplayTimeBombMenu(param1);
   303 		}
   304 	}
   305 }
   306 
   307 public Action:Command_TimeBomb(client, args)
   308 {
   309 	if (args < 1)
   310 	{
   311 		ReplyToCommand(client, "[SM] Usage: sm_timebomb <#userid|name> [0/1]");
   312 		return Plugin_Handled;
   313 	}
   314 
   315 	decl String:arg[65];
   316 	GetCmdArg(1, arg, sizeof(arg));
   317 	
   318 	new toggle = 2;
   319 	if (args > 1)
   320 	{
   321 		decl String:arg2[2];
   322 		GetCmdArg(2, arg2, sizeof(arg2));
   323 		if (arg2[0])
   324 		{
   325 			toggle = 1;
   326 		}
   327 		else
   328 		{
   329 			toggle = 0;
   330 		}
   331 	}
   332 
   333 	decl String:target_name[MAX_TARGET_LENGTH];
   334 	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
   335 	
   336 	if ((target_count = ProcessTargetString(
   337 			arg,
   338 			client,
   339 			target_list,
   340 			MAXPLAYERS,
   341 			COMMAND_FILTER_ALIVE,
   342 			target_name,
   343 			sizeof(target_name),
   344 			tn_is_ml)) <= 0)
   345 	{
   346 		ReplyToTargetError(client, target_count);
   347 		return Plugin_Handled;
   348 	}
   349 	
   350 	for (new i = 0; i < target_count; i++)
   351 	{
   352 		PerformTimeBomb(client, target_list[i], toggle);
   353 	}
   354 	
   355 	if (tn_is_ml)
   356 	{
   357 		ShowActivity2(client, "[SM] ", "%t", "Toggled TimeBomb on target", target_name);
   358 	}
   359 	else
   360 	{
   361 		ShowActivity2(client, "[SM] ", "%t", "Toggled TimeBomb on target", "_s", target_name);
   362 	}
   363 	
   364 	return Plugin_Handled;
   365 }