plugins/funcommands/ice.sp
author Nicholas Hastings <skamonkey@gmail.com>
Sat Mar 16 13:50:36 2013 -0400 (2013-03-16)
changeset 3816 31650bb3c7e8
parent 3097 071e0b432500
child 3961 0dc477c29792
permissions -rw-r--r--
Add GetPlayerResourceEntity to SDKTools; deprecate old, broken TF2-specific impl (bug 5491, r=asherkin).
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Basefuncommands Plugin
     5  * Provides freeze and freezebomb 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 g_FreezeSerial[MAXPLAYERS+1] = { 0, ... };
    35 new g_FreezeBombSerial[MAXPLAYERS+1] = { 0, ... };
    36 new g_FreezeTime[MAXPLAYERS+1] = { 0, ... };
    37 new g_FreezeBombTime[MAXPLAYERS+1] = { 0, ... };
    38 
    39 new Handle:g_Cvar_FreezeDuration = INVALID_HANDLE;
    40 new Handle:g_Cvar_FreezeBombTicks = INVALID_HANDLE;
    41 new Handle:g_Cvar_FreezeBombRadius = INVALID_HANDLE;
    42 new Handle:g_Cvar_FreezeBombMode = INVALID_HANDLE;
    43 
    44 FreezeClient(client, time)
    45 {
    46 	if (g_FreezeSerial[client] != 0)
    47 	{
    48 		UnfreezeClient(client);
    49 		return;
    50 	}
    51 	SetEntityMoveType(client, MOVETYPE_NONE);
    52 	SetEntityRenderColor(client, 0, 128, 255, 192);
    53 
    54 	new Float:vec[3];
    55 	GetClientEyePosition(client, vec);
    56 	EmitAmbientSound(SOUND_FREEZE, vec, client, SNDLEVEL_RAIDSIREN);
    57 
    58 	g_FreezeTime[client] = time;
    59 	g_FreezeSerial[client] = ++ g_Serial_Gen;
    60 	CreateTimer(1.0, Timer_Freeze, client | (g_Serial_Gen << 7), DEFAULT_TIMER_FLAGS);
    61 }
    62 
    63 UnfreezeClient(client)
    64 {
    65 	g_FreezeSerial[client] = 0;
    66 	g_FreezeTime[client] = 0;
    67 
    68 	if (IsClientInGame(client))
    69 	{
    70 		new Float:vec[3];
    71 		GetClientAbsOrigin(client, vec);
    72 		vec[2] += 10;	
    73 		
    74 		GetClientEyePosition(client, vec);
    75 		EmitAmbientSound(SOUND_FREEZE, vec, client, SNDLEVEL_RAIDSIREN);
    76 
    77 		SetEntityMoveType(client, MOVETYPE_WALK);
    78 		
    79 		SetEntityRenderColor(client, 255, 255, 255, 255);
    80 	}
    81 }
    82 
    83 CreateFreezeBomb(client)
    84 {
    85 	if (g_FreezeBombSerial[client] != 0)
    86 	{
    87 		KillFreezeBomb(client);
    88 		return;
    89 	}
    90 	g_FreezeBombTime[client] = GetConVarInt(g_Cvar_FreezeBombTicks);
    91 	g_FreezeBombSerial[client] = ++g_Serial_Gen;
    92 	CreateTimer(1.0, Timer_FreezeBomb, client | (g_Serial_Gen << 7), DEFAULT_TIMER_FLAGS);
    93 }
    94 
    95 KillFreezeBomb(client)
    96 {
    97 	g_FreezeBombSerial[client] = 0;
    98 	g_FreezeBombTime[client] = 0;
    99 
   100 	if (IsClientInGame(client))
   101 	{
   102 		SetEntityRenderColor(client, 255, 255, 255, 255);
   103 	}
   104 }
   105 
   106 KillAllFreezes( )
   107 {
   108 	for(new i = 1; i <= MaxClients; i++)
   109 	{
   110 		if (g_FreezeSerial[i] != 0)
   111 		{
   112 			UnfreezeClient(i);
   113 		}
   114 
   115 		if (g_FreezeBombSerial[i] != 0)
   116 		{
   117 			KillFreezeBomb(i);
   118 		}
   119 	}
   120 }
   121 
   122 PerformFreeze(client, target, time)
   123 {
   124 	FreezeClient(target, time);
   125 	LogAction(client, target, "\"%L\" froze \"%L\"", client, target);
   126 }
   127 
   128 PerformFreezeBomb(client, target)
   129 {
   130 	if (g_FreezeBombSerial[target] != 0)
   131 	{
   132 		KillFreezeBomb(target);
   133 		LogAction(client, target, "\"%L\" removed a FreezeBomb on \"%L\"", client, target);
   134 	}
   135 	else
   136 	{
   137 		CreateFreezeBomb(target);
   138 		LogAction(client, target, "\"%L\" set a FreezeBomb on \"%L\"", client, target);
   139 	}
   140 }
   141 
   142 public Action:Timer_Freeze(Handle:timer, any:value)
   143 {
   144 	new client = value & 0x7f;
   145 	new serial = value >> 7;
   146 
   147 	if (!IsClientInGame(client)
   148 		|| !IsPlayerAlive(client)
   149 		|| g_FreezeSerial[client] != serial)
   150 	{
   151 		UnfreezeClient(client);
   152 		return Plugin_Stop;
   153 	}
   154 
   155 	if (g_FreezeTime[client] == 0)
   156 	{
   157 		UnfreezeClient(client);
   158 		
   159 		/* HintText doesn't work on Dark Messiah */
   160 		if (g_GameEngine != SOURCE_SDK_DARKMESSIAH)
   161 		{
   162 			PrintHintText(client, "%t", "Unfrozen");
   163 		}
   164 		else
   165 		{
   166 			PrintCenterText(client, "%t", "Unfrozen");
   167 		}
   168 		
   169 		return Plugin_Stop;
   170 	}
   171 
   172 	if (g_GameEngine != SOURCE_SDK_DARKMESSIAH)
   173 	{
   174 		PrintHintText(client, "%t", "You will be unfrozen", g_FreezeTime[client]);
   175 	}
   176 	else
   177 	{
   178 		PrintCenterText(client, "%t", "You will be unfrozen", g_FreezeTime[client]);
   179 	}
   180 	
   181 	g_FreezeTime[client]--;
   182 	SetEntityMoveType(client, MOVETYPE_NONE);
   183 	SetEntityRenderColor(client, 0, 128, 255, 135);
   184 
   185 	new Float:vec[3];
   186 	GetClientAbsOrigin(client, vec);
   187 	vec[2] += 10;
   188 
   189 	if (g_GlowSprite > -1)
   190 	{
   191 		TE_SetupGlowSprite(vec, g_GlowSprite, 0.95, 1.5, 50);
   192 	}
   193 	else
   194 	{
   195 		TE_SetupGlowSprite(vec, g_HaloSprite, 0.95, 1.5, 50);
   196 	}
   197 	
   198 	TE_SendToAll();
   199 
   200 	return Plugin_Continue;
   201 }
   202 
   203 public Action:Timer_FreezeBomb(Handle:timer, any:value)
   204 {
   205 	new client = value & 0x7f;
   206 	new serial = value >> 7;
   207 
   208 	if (!IsClientInGame(client)
   209 		|| !IsPlayerAlive(client)
   210 		|| g_FreezeBombSerial[client] != serial)
   211 	{
   212 		KillFreezeBomb(client);
   213 		return Plugin_Stop;
   214 	}
   215 
   216 	new Float:vec[3];
   217 	GetClientEyePosition(client, vec);
   218 	g_FreezeBombTime[client]--;
   219 
   220 	if (g_FreezeBombTime[client] > 0)
   221 	{
   222 		new color;
   223 
   224 		if (g_FreezeBombTime[client] > 1)
   225 		{
   226 			color = RoundToFloor(g_FreezeBombTime[client] * (255.0 / GetConVarFloat(g_Cvar_FreezeBombTicks)));
   227 			EmitAmbientSound(SOUND_BEEP, vec, client, SNDLEVEL_RAIDSIREN);	
   228 		}
   229 		else
   230 		{
   231 			color = 0;
   232 			EmitAmbientSound(SOUND_FINAL, vec, client, SNDLEVEL_RAIDSIREN);
   233 		}
   234 		
   235 		SetEntityRenderColor(client, color, color, 255, 255);
   236 
   237 		decl String:name[64];
   238 		GetClientName(client, name, sizeof(name));
   239 		PrintCenterTextAll("%t", "Till Explodes", name, g_FreezeBombTime[client]);
   240 
   241 		GetClientAbsOrigin(client, vec);
   242 		vec[2] += 10;
   243 
   244 		TE_SetupBeamRingPoint(vec, 10.0, GetConVarFloat(g_Cvar_FreezeBombRadius) / 3.0, g_BeamSprite, g_HaloSprite, 0, 15, 0.5, 5.0, 0.0, greyColor, 10, 0);
   245 		TE_SendToAll();
   246 		TE_SetupBeamRingPoint(vec, 10.0, GetConVarFloat(g_Cvar_FreezeBombRadius) / 3.0, g_BeamSprite, g_HaloSprite, 0, 10, 0.6, 10.0, 0.5, whiteColor, 10, 0);
   247 		TE_SendToAll();
   248 		return Plugin_Continue;
   249 	}
   250 	else
   251 	{
   252 		if (g_ExplosionSprite > -1)
   253 		{
   254 			TE_SetupExplosion(vec, g_ExplosionSprite, 5.0, 1, 0, GetConVarInt(g_Cvar_FreezeBombRadius), 5000);
   255 			TE_SendToAll();
   256 		}
   257 
   258 		EmitAmbientSound(SOUND_BOOM, vec, client, SNDLEVEL_RAIDSIREN);
   259 
   260 		KillFreezeBomb(client);
   261 		FreezeClient(client, GetConVarInt(g_Cvar_FreezeDuration));
   262 		
   263 		if (GetConVarInt(g_Cvar_FreezeBombMode) > 0)
   264 		{
   265 			new bool:teamOnly = ((GetConVarInt(g_Cvar_FreezeBombMode) == 1) ? true : false);
   266 			
   267 			for (new i = 1; i <= MaxClients; i++)
   268 			{
   269 				if (!IsClientInGame(i) || !IsPlayerAlive(i) || i == client)
   270 				{
   271 					continue;
   272 				}
   273 				
   274 				if (teamOnly && GetClientTeam(i) != GetClientTeam(client))
   275 				{
   276 					continue;
   277 				}
   278 				
   279 				new Float:pos[3];
   280 				GetClientEyePosition(i, pos);
   281 				
   282 				new Float:distance = GetVectorDistance(vec, pos);
   283 				
   284 				if (distance > GetConVarFloat(g_Cvar_FreezeBombRadius))
   285 				{
   286 					continue;
   287 				}
   288 				
   289 				if (g_BeamSprite2 > -1)
   290 				{
   291 					TE_SetupBeamPoints(vec, pos, g_BeamSprite2, g_HaloSprite, 0, 1, 0.7, 20.0, 50.0, 1, 1.5, blueColor, 10);
   292 				}
   293 				else
   294 				{
   295 					TE_SetupBeamPoints(vec, pos, g_BeamSprite, g_HaloSprite, 0, 1, 0.7, 20.0, 50.0, 1, 1.5, blueColor, 10);
   296 				}
   297 				TE_SendToAll();
   298 				
   299 				FreezeClient(i, GetConVarInt(g_Cvar_FreezeDuration));
   300 			}		
   301 		}
   302 		return Plugin_Stop;
   303 	}
   304 }
   305 
   306 public AdminMenu_Freeze(Handle:topmenu, 
   307 					  TopMenuAction:action,
   308 					  TopMenuObject:object_id,
   309 					  param,
   310 					  String:buffer[],
   311 					  maxlength)
   312 {
   313 	if (action == TopMenuAction_DisplayOption)
   314 	{
   315 		Format(buffer, maxlength, "%T", "Freeze player", param);
   316 	}
   317 	else if (action == TopMenuAction_SelectOption)
   318 	{
   319 		DisplayFreezeMenu(param);
   320 	}
   321 }
   322 
   323 public AdminMenu_FreezeBomb(Handle:topmenu, 
   324 					  TopMenuAction:action,
   325 					  TopMenuObject:object_id,
   326 					  param,
   327 					  String:buffer[],
   328 					  maxlength)
   329 {
   330 	if (action == TopMenuAction_DisplayOption)
   331 	{
   332 		Format(buffer, maxlength, "%T", "FreezeBomb player", param);
   333 	}
   334 	else if (action == TopMenuAction_SelectOption)
   335 	{
   336 		DisplayFreezeBombMenu(param);
   337 	}
   338 }
   339 
   340 DisplayFreezeMenu(client)
   341 {
   342 	new Handle:menu = CreateMenu(MenuHandler_Freeze);
   343 	
   344 	decl String:title[100];
   345 	Format(title, sizeof(title), "%T:", "Freeze player", client);
   346 	SetMenuTitle(menu, title);
   347 	SetMenuExitBackButton(menu, true);
   348 	
   349 	AddTargetsToMenu(menu, client, true, true);
   350 	
   351 	DisplayMenu(menu, client, MENU_TIME_FOREVER);
   352 }
   353 
   354 DisplayFreezeBombMenu(client)
   355 {
   356 	new Handle:menu = CreateMenu(MenuHandler_FreezeBomb);
   357 	
   358 	decl String:title[100];
   359 	Format(title, sizeof(title), "%T:", "FreezeBomb player", client);
   360 	SetMenuTitle(menu, title);
   361 	SetMenuExitBackButton(menu, true);
   362 	
   363 	AddTargetsToMenu(menu, client, true, true);
   364 	
   365 	DisplayMenu(menu, client, MENU_TIME_FOREVER);
   366 }
   367 
   368 public MenuHandler_Freeze(Handle:menu, MenuAction:action, param1, param2)
   369 {
   370 	if (action == MenuAction_End)
   371 	{
   372 		CloseHandle(menu);
   373 	}
   374 	else if (action == MenuAction_Cancel)
   375 	{
   376 		if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
   377 		{
   378 			DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
   379 		}
   380 	}
   381 	else if (action == MenuAction_Select)
   382 	{
   383 		decl String:info[32];
   384 		new userid, target;
   385 		
   386 		GetMenuItem(menu, param2, info, sizeof(info));
   387 		userid = StringToInt(info);
   388 
   389 		if ((target = GetClientOfUserId(userid)) == 0)
   390 		{
   391 			PrintToChat(param1, "[SM] %t", "Player no longer available");
   392 		}
   393 		else if (!CanUserTarget(param1, target))
   394 		{
   395 			PrintToChat(param1, "[SM] %t", "Unable to target");
   396 		}
   397 		else
   398 		{
   399 			new String:name[32];
   400 			GetClientName(target, name, sizeof(name));
   401 			
   402 			PerformFreeze(param1, target, GetConVarInt(g_Cvar_FreezeDuration));
   403 			ShowActivity2(param1, "[SM] ", "%t", "Froze target", "_s", name);
   404 		}
   405 		
   406 		/* Re-draw the menu if they're still valid */
   407 		if (IsClientInGame(param1) && !IsClientInKickQueue(param1))
   408 		{
   409 			DisplayFreezeMenu(param1);
   410 		}
   411 	}
   412 }
   413 
   414 public MenuHandler_FreezeBomb(Handle:menu, MenuAction:action, param1, param2)
   415 {
   416 	if (action == MenuAction_End)
   417 	{
   418 		CloseHandle(menu);
   419 	}
   420 	else if (action == MenuAction_Cancel)
   421 	{
   422 		if (param2 == MenuCancel_ExitBack && hTopMenu != INVALID_HANDLE)
   423 		{
   424 			DisplayTopMenu(hTopMenu, param1, TopMenuPosition_LastCategory);
   425 		}
   426 	}
   427 	else if (action == MenuAction_Select)
   428 	{
   429 		decl String:info[32];
   430 		new userid, target;
   431 		
   432 		GetMenuItem(menu, param2, info, sizeof(info));
   433 		userid = StringToInt(info);
   434 
   435 		if ((target = GetClientOfUserId(userid)) == 0)
   436 		{
   437 			PrintToChat(param1, "[SM] %t", "Player no longer available");
   438 		}
   439 		else if (!CanUserTarget(param1, target))
   440 		{
   441 			PrintToChat(param1, "[SM] %t", "Unable to target");
   442 		}
   443 		else
   444 		{
   445 			new String:name[32];
   446 			GetClientName(target, name, sizeof(name));
   447 			
   448 			PerformFreezeBomb(param1, target);
   449 			ShowActivity2(param1, "[SM] ", "%t", "Toggled FreezeBomb on target", "_s", name);
   450 		}
   451 		
   452 		/* Re-draw the menu if they're still valid */
   453 		if (IsClientInGame(param1) && !IsClientInKickQueue(param1))
   454 		{
   455 			DisplayFreezeBombMenu(param1);
   456 		}
   457 	}
   458 }
   459 
   460 public Action:Command_Freeze(client, args)
   461 {
   462 	if (args < 1)
   463 	{
   464 		ReplyToCommand(client, "[SM] Usage: sm_freeze <#userid|name> [time]");
   465 		return Plugin_Handled;
   466 	}
   467 
   468 	decl String:arg[65];
   469 	GetCmdArg(1, arg, sizeof(arg));
   470 	
   471 	new seconds = GetConVarInt(g_Cvar_FreezeDuration);
   472 	
   473 	if (args > 1)
   474 	{
   475 		decl String:time[20];
   476 		GetCmdArg(2, time, sizeof(time));
   477 		if (StringToIntEx(time, seconds) == 0)
   478 		{
   479 			ReplyToCommand(client, "[SM] %t", "Invalid Amount");
   480 			return Plugin_Handled;
   481 		}
   482 	}	
   483 
   484 	decl String:target_name[MAX_TARGET_LENGTH];
   485 	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
   486 	
   487 	if ((target_count = ProcessTargetString(
   488 			arg,
   489 			client,
   490 			target_list,
   491 			MAXPLAYERS,
   492 			COMMAND_FILTER_ALIVE,
   493 			target_name,
   494 			sizeof(target_name),
   495 			tn_is_ml)) <= 0)
   496 	{
   497 		ReplyToTargetError(client, target_count);
   498 		return Plugin_Handled;
   499 	}
   500 	
   501 	for (new i = 0; i < target_count; i++)
   502 	{
   503 		PerformFreeze(client, target_list[i], seconds);
   504 	}
   505 	
   506 	if (tn_is_ml)
   507 	{
   508 		ShowActivity2(client, "[SM] ", "%t", "Froze target", target_name);
   509 	}
   510 	else
   511 	{
   512 		ShowActivity2(client, "[SM] ", "%t", "Froze target", "_s", target_name);
   513 	}
   514 	
   515 	return Plugin_Handled;
   516 }
   517 
   518 public Action:Command_FreezeBomb(client, args)
   519 {
   520 	if (args < 1)
   521 	{
   522 		ReplyToCommand(client, "[SM] Usage: sm_freezebomb <#userid|name>");
   523 		return Plugin_Handled;
   524 	}
   525 
   526 	decl String:arg[65];
   527 	GetCmdArg(1, arg, sizeof(arg));
   528 
   529 	decl String:target_name[MAX_TARGET_LENGTH];
   530 	decl target_list[MAXPLAYERS], target_count, bool:tn_is_ml;
   531 	
   532 	if ((target_count = ProcessTargetString(
   533 			arg,
   534 			client,
   535 			target_list,
   536 			MAXPLAYERS,
   537 			COMMAND_FILTER_ALIVE,
   538 			target_name,
   539 			sizeof(target_name),
   540 			tn_is_ml)) <= 0)
   541 	{
   542 		ReplyToTargetError(client, target_count);
   543 		return Plugin_Handled;
   544 	}
   545 	
   546 	for (new i = 0; i < target_count; i++)
   547 	{
   548 		PerformFreezeBomb(client, target_list[i]);
   549 	}
   550 	
   551 	if (tn_is_ml)
   552 	{
   553 		ShowActivity2(client, "[SM] ", "%t", "Toggled FreezeBomb on target", target_name);
   554 	}
   555 	else
   556 	{
   557 		ShowActivity2(client, "[SM] ", "%t", "Toggled FreezeBomb on target", "_s", target_name);
   558 	}
   559 	
   560 	return Plugin_Handled;
   561 }