From b1782c1c281524cb45295d5183086b49614a705c Mon Sep 17 00:00:00 2001 From: Jackz Date: Fri, 18 Dec 2020 22:33:59 -0600 Subject: [PATCH] Add l4d2_swarm plugin --- README.md | 18 +++ plugins/l4d2_swarm.smx | Bin 0 -> 8601 bytes scripting/l4d2_swarm.sp | 251 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 269 insertions(+) create mode 100644 plugins/l4d2_swarm.smx create mode 100644 scripting/l4d2_swarm.sp diff --git a/README.md b/README.md index 53e723e..27f485d 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ All my sourcemod plugins... shitty probably * [l4d2_avoid_minigun](#l4d2_avoid_minigun) * [l4d2_ai_minigun](#l4d2_ai_minigun) * [L4D2Tools](#L4D2Tools) +* [l4d2_swarm](#l4d2_swarm) ## Descriptions ### csgo-knifehp @@ -119,3 +120,20 @@ A collection of small tools: Notification of when someone picks up laser sights * **Convars:** * `sm_laser_use_notice <0/1>` - Enable notification of when a laser box was used first * `sm_time_finale <0/1/2>` - Record the time it takes to complete finale. 0 -> OFF, 1 -> Gauntlets Only, 2 -> All finales + +### l4d2_swarm +This plugin is used to counter trolls and otherwise bad players. It simply uses the new script function RushVictim() to make all zombies in X radius attack Y target. It's that simple. + +This really only affects wandering zombies, mobs and panic events, but it may work slightly when bile or pipes are thrown. It does not and can't change the targets of zombies. + +* **Convars:** + * `sm_swarm_default_range <20-Infinity>` - The default range for commands & menus. Defaults to 7,500 +* **Commands:** + * `sm_swarm [player] [range]` - Swarm a player, or random if none." + * Aliases: `sm_rush` + * `sm_rushmenu` - Opens a menu to quickly rush any player. Can be bound to a key to quickly rush as well + * Aliases: `sm_rmenu` + * `sm_swarmtoggle [range]` - Will continuously run the swarm method on the player at the range. Use the command again or type "disable" for player to disable. Switching players will not disable, just switches target. + * Aliases: `sm_rushtoggle`, `sm_rt` + * `sm_rushtogglemenu` - Will open a menu to quickly select a player to continuously rush. + * Aliases: `sm_rtmenu` \ No newline at end of file diff --git a/plugins/l4d2_swarm.smx b/plugins/l4d2_swarm.smx new file mode 100644 index 0000000000000000000000000000000000000000..71d3c1937007e78a4b49427e87bcecfcfc77e7f1 GIT binary patch literal 8601 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 +#include +#include "jutils.inc" + +ConVar hSwarmDefaultRange; +//Swarm target is a userid +int SwarmTarget, SwarmRadius; + +Handle timer = INVALID_HANDLE; + +public Plugin myinfo = +{ + name = PLUGIN_NAME, + author = PLUGIN_AUTHOR, + description = PLUGIN_DESCRIPTION, + version = PLUGIN_VERSION, + url = PLUGIN_URL +}; + +public void OnPluginStart() +{ + EngineVersion g_Game = GetEngineVersion(); + if(g_Game != Engine_Left4Dead && g_Game != Engine_Left4Dead2) + { + SetFailState("This plugin is for L4D/L4D2 only."); + } + + hSwarmDefaultRange = CreateConVar("sm_swarm_default_range", "7500", "The default range swarms will affect (As a default argument or in use in menus)", FCVAR_NONE, true, 20.0); + SwarmRadius = hSwarmDefaultRange.IntValue; + + LoadTranslations("common.phrases"); + RegAdminCmd("sm_swarm", Cmd_Swarm, ADMFLAG_ROOT, "sm_swarm [player] [range] - Zombies swarm player (or random if not set)"); + RegAdminCmd("sm_rush", Cmd_Swarm, ADMFLAG_ROOT, "sm_swarm [player] [range] - Zombies swarm player (or random if not set)"); + RegAdminCmd("sm_rushmenu", Cmd_SwarmMenu, ADMFLAG_ROOT, "sm_swarmmenu - Open swarm menu"); + RegAdminCmd("sm_rmenu", Cmd_SwarmMenu, ADMFLAG_ROOT, "sm_swarmmenu - Open swarm menu"); + + RegAdminCmd("sm_swarmtoggle", Cmd_SwarmToggle, ADMFLAG_ROOT, "sm_swarmtoggle [range]"); + RegAdminCmd("sm_rushtoggle", Cmd_SwarmToggle, ADMFLAG_ROOT, "sm_swarmtoggle [range]"); + RegAdminCmd("sm_rt", Cmd_SwarmToggle, ADMFLAG_ROOT, "sm_swarmtoggle [range]"); + RegAdminCmd("sm_rushtogglemenu", Cmd_SwarmToggleMenu, ADMFLAG_ROOT, "sm_swarmtogglemenu - Open swarm toggle menu"); + RegAdminCmd("sm_rtmenu", Cmd_SwarmToggleMenu, ADMFLAG_ROOT, "sm_swarmtogglemenu - Open swarm toggle menu"); +} + + +public Action Cmd_SwarmToggle(int client, int args) { + //SwarmTarget, SwarmRadius + if(args == 0) { + ReplyToCommand(client, "Usage: sm_rushtoggle [radius]"); + }else{ + char arg1[32], arg2[32]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + + if(StrEqual(arg1, "disable", true)) { + SwarmTarget = -1; + SwarmRadius = hSwarmDefaultRange.IntValue; + ReplyToCommand(client, "Deactivated swarm toggle."); + CloseHandle(timer); + } + + int range = StringToInt(arg2); + if(range <= 0) range = hSwarmDefaultRange.IntValue; + SwarmRadius = range; + + char target_name[MAX_TARGET_LENGTH]; + int target_list[1], target_count; + bool tn_is_ml; + + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + 1, + COMMAND_FILTER_ALIVE, /* Only allow alive players */ + target_name, + sizeof(target_name), + tn_is_ml)) <= 0) + { + /* This function replies to the admin with a failure message */ + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + if(target_list[0] == SwarmTarget) { + SwarmTarget = -1; + SwarmRadius = hSwarmDefaultRange.IntValue; + ReplyToCommand(client, "Deactivated swarm toggle."); + CloseHandle(timer); + timer = INVALID_HANDLE; + }else{ + SwarmTarget = target_list[0]; + SwarmUser(GetClientUserId(target_list[0]), range); + ReplyToCommand(client, "Now continously swarming victim %N. Radius: %d", target_list[0], range); + if(timer == INVALID_HANDLE) + timer = CreateTimer(1.0, Timer_Swarm, _, TIMER_REPEAT); + } + } + return Plugin_Handled; +} + +public Action Cmd_Swarm(int client, int args) { + if(args == 0) { + SwarmUser(-1, hSwarmDefaultRange.IntValue); + ReplyToCommand(client, "Swarming random player at %d radius.", hSwarmDefaultRange.IntValue); + }else{ + char arg1[32], arg2[32]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + + int range = StringToInt(arg2); + if(range <= 0) range = hSwarmDefaultRange.IntValue; + + char target_name[MAX_TARGET_LENGTH]; + int target_list[1], target_count; + bool tn_is_ml; + + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + 1, + COMMAND_FILTER_ALIVE, /* Only allow alive players */ + target_name, + sizeof(target_name), + tn_is_ml)) <= 0) + { + /* This function replies to the admin with a failure message */ + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + /*int entity = -1; + do { + entity = FindEntityByClassname(entity, "zombie"); + } while(entity != -1) + + for (int target = 1; target <= MaxClients; target++) + { + if (IsClientInGame(target) && IsPlayerAlive(target) && GetClientTeam(ta)) + { + if (IsPlayerAlive(target) && GetClientTeam(target) == 3) + { + new Float:targetVector[3]; + GetClientAbsimpact(target, targetVector); + + new Float:distance = GetVectorDistance(targetVector, impact); + if (distance < DISTANCESETTING) + { + //ACTIONS ON AFFECTED TARGET + } + } + } + } */ + SwarmUser(GetClientUserId(target_list[0]), range); + ReplyToCommand(client, "Swarming victim %N. Radius: %d", target_list[0], range); + } + return Plugin_Handled; +} +public Action Cmd_SwarmMenu(int client, int args) { + Menu menu = new Menu(Handle_SwarmMenu); + menu.SetTitle("Swarm a Player"); + char name[32], idStr[4]; + for(int id = 1; id < MaxClients; id++) { + if(IsClientConnected(id) && IsClientInGame(id) && IsPlayerAlive(id)) { + GetClientName(id, name, sizeof(name)); + Format(idStr, sizeof(idStr), "%d", GetClientUserId(id)); + menu.AddItem(idStr, name); + } + } + menu.ExitButton = true; + menu.Display(client, 0); +} +public Action Cmd_SwarmToggleMenu(int client, int args) { + Menu menu = new Menu(Handle_SwarmMenuToggle); + menu.SetTitle("Toggle Swarm On Player"); + menu.AddItem("disable", "Disable"); + char name[32], idStr[3]; + for(int id = 1; id < MaxClients; id++) { + if(IsClientConnected(id) && IsClientInGame(id) && IsPlayerAlive(id)) { + GetClientName(id, name, sizeof(name)); + Format(idStr, sizeof(idStr), "%d", GetClientUserId(id)); + menu.AddItem(idStr, name); + } + } + menu.ExitButton = true; + menu.Display(client, 0); +} + +public int Handle_SwarmMenu(Menu menu, MenuAction action, int client, int index) +{ + /* If an option was selected, tell the client about the item. */ + if (action == MenuAction_Select) + { + char info[4]; + menu.GetItem(index, info, sizeof(info)); + int userid = StringToInt(info); + SwarmUser(userid, hSwarmDefaultRange.IntValue); + PrintToChat(client, "Swarming player %N with radius %d", userid, hSwarmDefaultRange.IntValue); + Cmd_SwarmMenu(client, 0); + } else if (action == MenuAction_End) { + delete menu; + } +} + +public int Handle_SwarmMenuToggle(Menu menu, MenuAction action, int client, int index) +{ + /* If an option was selected, tell the client about the item. */ + if (action == MenuAction_Select) + { + char info[4]; + menu.GetItem(index, info, sizeof(info)); + if(StrEqual(info, "disable", true)) { + SwarmTarget = -1; + SwarmRadius = hSwarmDefaultRange.IntValue; + PrintToChat(client, "Disabled swarm toggle.", SwarmTarget, SwarmRadius); + CloseHandle(timer); + timer = INVALID_HANDLE; + }else{ + SwarmTarget = StringToInt(info); + int clientID = GetClientOfUserId(SwarmTarget); + PrintToChat(client, "Toggled swarm on for %N. Radius: %d", clientID, SwarmRadius); + if(timer == INVALID_HANDLE) + timer = CreateTimer(1.0, Timer_Swarm, _, TIMER_REPEAT); + } + } else if (action == MenuAction_End) { + delete menu; + } +} + +public Action Timer_Swarm(Handle timerH, any data) { + if(SwarmTarget >= 0 && IsClientConnected(SwarmTarget) && IsPlayerAlive(SwarmTarget)) { + SwarmUser(SwarmTarget, SwarmRadius); + return Plugin_Continue; + }else { + return Plugin_Stop; + } +} + + +void SwarmUser(int clientUserId, int range) { + L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", clientUserId, range); +} \ No newline at end of file