From 7ef2a1b3cd059bd4c80572e9f7ccda0686118450 Mon Sep 17 00:00:00 2001 From: Jackz Date: Thu, 11 Jun 2020 15:40:18 -0500 Subject: [PATCH] Added L4D2Tools and 200IQBots_FlyYouFools --- 200IQBots_FlyYouFools.smx | Bin 0 -> 6659 bytes 200IQBots_FlyYouFools.sp | 172 ++++++++++++++++++++++++++++++++++++++ L4D2Tools.smx | Bin 0 -> 6850 bytes L4D2Tools.sp | 142 +++++++++++++++++++++++++++++++ README.md | 26 ++++-- 5 files changed, 331 insertions(+), 9 deletions(-) create mode 100644 200IQBots_FlyYouFools.smx create mode 100644 200IQBots_FlyYouFools.sp create mode 100644 L4D2Tools.smx create mode 100644 L4D2Tools.sp diff --git a/200IQBots_FlyYouFools.smx b/200IQBots_FlyYouFools.smx new file mode 100644 index 0000000000000000000000000000000000000000..5dd0f7c0f9ce7b677bf026f127400b83cff03d9d GIT binary patch literal 6659 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 p+9m$x!P~3^?JyxZr&Wg50p* +#include +#define PLUGIN_VERSION "1.4" + +static bool bEscapeReady = false; +static int TankClient; +//static ConVar hTankDangerDistance; + +public Plugin myinfo = +{ + name = "Fly You Fools", + author = "ConnerRia & Jackzmc", + description = "Survivor bots will retreat from tank. ", + version = PLUGIN_VERSION, + url = "N/A" +} + +public OnPluginStart() +{ + EngineVersion g_Game = GetEngineVersion(); + if(g_Game != Engine_Left4Dead && g_Game != Engine_Left4Dead2) + { + SetFailState("Plugin supports Left 4 Dead series only."); + } + + CreateConVar("FlyYouFools_Version", PLUGIN_VERSION, "FlyYouFools Version", FCVAR_NOTIFY|FCVAR_REPLICATED|FCVAR_DONTRECORD); + //hTankDangerDistance = CreateConVar("200IQBots_TankDangerRange", "800.0", "The range by which survivors bots will detect the presence of tank and retreat. ", FCVAR_NOTIFY|FCVAR_REPLICATED); + + HookEvent("map_transition", Event_RoundStart, EventHookMode_Pre); + HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy); + HookEvent("tank_spawn", Event_TankSpawn); + HookEvent("tank_killed", Event_RoundStart); + HookEvent("finale_vehicle_incoming", Event_FinaleArriving); + + AutoExecConfig(true, "200IQBots_FlyYouFools"); + + FindExistingTank(); +} + +public OnMapStart() { + TankClient = -1; + bEscapeReady = false; +} + +public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) { + TankClient = -1; + bEscapeReady = false; +} + +public void Event_TankSpawn(Event event, const char[] name, bool dontBroadcast) { + TankClient = GetClientOfUserId(GetEventInt(event, "userid")); + CreateTimer(0.1, BotControlTimer, _, TIMER_REPEAT); +} +public void Event_FinaleArriving(Event event, const char[] name, bool dontBroadcast) { + bEscapeReady = true; +} +public Action BotControlTimer(Handle timer) +{ + //remove timer once tank no longer exists, is dead, or finale escape vehicle arrived + if(bEscapeReady || TankClient == -1 || !IsClientInGame(TankClient) || !IsPlayerAlive(TankClient)) { + return Plugin_Stop; + } + //Once an AI tank is awakened, m_lookatPlayer is set to a player ID + //Possible props: m_lookatPlayer, m_zombieState, m_hasVisibleThreats + int tank_target = GetEntPropEnt(TankClient, Prop_Send, "m_lookatPlayer", 0); + //bool hasVisibleThreats = GetEntProp(TankClient, Prop_Send, "m_hasVisibleThreats", 1) == 1; + //char targetted_name[64]; + if(tank_target > -1) { + //debug shit: + //GetClientName(tank_target, targetted_name, sizeof(targetted_name)); + //ShowHintToAll("tank_target: %d (%s) | visible threats: %b", tank_target, targetted_name, hasVisibleThreats); + for (new i = 1; i <= MaxClients; i++) + { + if (IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2 && IsFakeClient(i)) + { + //If distance between bot and tank is less than 200IQBots_TankDangerRange's float value + //if not tank target, and tank != visible threats, then attack + if(tank_target == i) { + L4D2_RunScript("CommandABot({cmd=2,bot=GetPlayerFromUserID(%i),target=GetPlayerFromUserID(%i)})", GetClientUserId(i), GetClientUserId(TankClient)); + }else { + float TankPosition[3]; + float BotPosition[3]; + + GetClientAbsOrigin(TankClient, TankPosition); + GetClientAbsOrigin(i, BotPosition); + + float distance = GetVectorDistance(BotPosition, TankPosition); + if(distance < 200) { + L4D2_RunScript("CommandABot({cmd=2,bot=GetPlayerFromUserID(%i),target=GetPlayerFromUserID(%i)})", GetClientUserId(i), GetClientUserId(TankClient)); + //do not attack if super close. + } else { + L4D2_RunScript("CommandABot({cmd=0,bot=GetPlayerFromUserID(%i),target=GetPlayerFromUserID(%i)})", GetClientUserId(i), GetClientUserId(TankClient)); + } + } + + } + } + } + return Plugin_Continue; +} + + + +public void FindExistingTank() { + for (int i = 1; i < MaxClients+1 ;i++) { + if (!IsClientInGame(i)) continue; + if (!IsFakeClient(i)) continue; + char name[16]; + GetClientName(i, name, sizeof(name)); + + if(StrContains(name,"Tank",true) > -1) { + PrintToServer("Found existing tank with id %d", i); + TankClient = i; + CreateTimer(0.1, BotControlTimer, _, TIMER_REPEAT); + break; + } + } +} + +//Credits to Timocop for the stock :D +/** +* Runs a single line of vscript code. +* NOTE: Dont use the "script" console command, it starts a new instance and leaks memory. Use this instead! +* +* @param sCode The code to run. +* @noreturn +*/ +stock void L4D2_RunScript(const char[] sCode, any ...) { + static iScriptLogic = INVALID_ENT_REFERENCE; + if(iScriptLogic == INVALID_ENT_REFERENCE || !IsValidEntity(iScriptLogic)) { + iScriptLogic = EntIndexToEntRef(CreateEntityByName("logic_script")); + if(iScriptLogic == INVALID_ENT_REFERENCE || !IsValidEntity(iScriptLogic)) + SetFailState("Could not create 'logic_script'"); + + DispatchSpawn(iScriptLogic); + } + + static char sBuffer[512]; + VFormat(sBuffer, sizeof(sBuffer), sCode, 2); + + SetVariantString(sBuffer); + AcceptEntityInput(iScriptLogic, "RunScriptCode"); +} +stock void ShowHintToAll(const char[] format, any ...) { + char buffer[254]; + VFormat(buffer, sizeof(buffer), format, 2); + static int hintInt = 0; + if(hintInt >= 9) { + PrintHintTextToAll("%s",buffer); + hintInt = 0; + } + hintInt++; +} +/** +* Get the classname of an item in a slot +* +* @param client The client to check inventory from +* @param slot The item slot index +* @param buffer The char[] buffer to set text to +* @param bufferSize The size of the buffer +* @return True if item, false if no item +*/ +stock bool GetItemClassSlot(int client, int slot, char[] buffer, int bufferSize) { + int item = GetPlayerWeaponSlot(client, slot); + if(item > -1) { + GetEdictClassname(item, buffer, bufferSize); + return true; + }else{ + return false; + } +} \ No newline at end of file diff --git a/L4D2Tools.smx b/L4D2Tools.smx new file mode 100644 index 0000000000000000000000000000000000000000..2032d7d2ca25cb6fdce33c2974416ceadd65fb6b GIT binary patch literal 6850 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 +#include +//#include + +#pragma newdecls required + +bool bLasersUsed[2048]; +ConVar hLaserNotice, hFinaleTimer; +int iFinaleStartTime; + +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."); + } + hLaserNotice = CreateConVar("sm_laser_use_notice", "1.0", "Enable notification of a laser box being used", FCVAR_NONE, true, 0.0, true, 1.0); + hFinaleTimer = CreateConVar("sm_time_finale", "2.0", "Record the time it takes to complete finale. 0 -> OFF, 1 -> Gauntlets Only, 2 -> All finales", FCVAR_NONE, true, 0.0, true, 2.0); + + HookEvent("player_use", Event_PlayerUse); + HookEvent("round_end", Event_RoundEnd); + HookEvent("gauntlet_finale_start", Event_GauntletStart); + HookEvent("finale_start", Event_FinaleStart); + HookEvent("finale_vehicle_leaving", Event_FinaleEnd); +} + +#if 1 +//laserNotice +public void Event_PlayerUse(Event event, const char[] name, bool dontBroadcast) { + if(hLaserNotice.BoolValue) { + char player_name[32]; + char entity_name[64]; + int player_id = GetClientOfUserId(event.GetInt("userid")); + int target_id = event.GetInt("targetid"); + + GetClientName(player_id, player_name, sizeof(player_name)); + GetEntityClassname(target_id, entity_name, sizeof(entity_name)); + + if(StrEqual(entity_name,"upgrade_laser_sight")) { + if(!bLasersUsed[target_id]) { + bLasersUsed[target_id] = true; + PrintToChatAll("%s picked up laser sights",player_name); + } + } + } +} +public void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast) { + for (int i = 1; i < sizeof(bLasersUsed) ;i++) { + bLasersUsed[i] = false; + } +} +#endif + + +#if 1 +//finaletimer +public void Event_GauntletStart(Event event, const char[] name, bool dontBroadcast) { + if(hFinaleTimer.IntValue > 0) { + iFinaleStartTime = GetTime(); + PrintToChatAll("The finale timer has been started"); + } +} +public void Event_FinaleStart(Event event, const char[] name, bool dontBroadcast) { + if(hFinaleTimer.IntValue == 2) { + iFinaleStartTime = GetTime(); + PrintToChatAll("The finale timer has been started"); + } +} +public void Event_FinaleEnd(Event event, const char[] name, bool dontBroadcast) { + if(hFinaleTimer.IntValue != 0) { + int difference = GetTime() - iFinaleStartTime; + iFinaleStartTime = 0; + + char time[32]; + FormatMs(difference, time, sizeof(time)); + PrintToChatAll("Finale took %s to complete", time); + } +} +#endif +/** + * Prints human readable duration from milliseconds + * + * @param ms The duration in milliseconds + * @param str The char array to use for text + * @param strSize The size of the string + */ +stock void FormatMs(int ms, char[] str, int strSize) { + int sec = ms / 1000; + int h = sec / 3600; + int m = (sec -(3600*h))/60; + int s = (sec -(3600*h)-(m*60)); + if(h >= 1) { + Format(str, strSize, "%d hour, %d.%d minutes", h, m, s); + }else if(m >= 1) { + Format(str, strSize, "%d minutes and %d seconds", m, s); + }else { + float raw_seconds = float(ms) / 1000; + Format(str, strSize, "%0.1f seconds", raw_seconds); + } + +} +stock void ShowHintToAll(const char[] format, any ...) { + char buffer[254]; + VFormat(buffer, sizeof(buffer), format, 2); + static int hintInt = 0; + if(hintInt >= 10) { + PrintHintTextToAll("%s",buffer); + hintInt = 0; + } + hintInt++; +} +stock void ShowHint(int client, const char[] format, any ...) { + char buffer[254]; + VFormat(buffer, sizeof(buffer), format, 2); + static int hintInt = 0; + if(hintInt >= 10) { + PrintHintText(client, "%s",buffer); + hintInt = 0; + } + hintInt++; +} \ No newline at end of file diff --git a/README.md b/README.md index 7224da9..750f88a 100644 --- a/README.md +++ b/README.md @@ -5,17 +5,17 @@ All my sourcemod plugins... shitty probably ## Descriptions * `csgo-knifehp` - On knife kill, gives the player 100 HP (configurable) * **Convars:** - * `knifehp_enable` - Enable regaining health on knife kill - * `knifehp_max_health` - Maximum health to set an attacker to - * `knifehp_amount` - Amount of health to give attacker + * `knifehp_enable <0/1>` - Enable regaining health on knife kill + * `knifehp_max_health <#>` - Maximum health to set an attacker to + * `knifehp_amount <#>` - Amount of health to give attacker * `l4d2-manual-director` - Probably going to be posted publicly sometime. allows you to spawn specials on cursor, or via director, forcefully, bypassing limits * **Convars:** * `manual_director_version|mandirector_version` - ... gets version - * `mandirector_notify_spawn` - Should spawning specials notify on use? - * `mandirector_announce_level` - Announcement types. 0 - None, 1 - Only bosses, 2 - Only specials+, 3 - Everything - * `mandirector_enable_tank` - Should tanks be allowed to be spawned? - * `mandirector_enable_witch` - Should witches be allowed to be spawned? - * `mandirector_enable_mob` - Should mobs be allowed to be spawned + * `mandirector_notify_spawn <1/0>` - Should spawning specials notify on use? + * `mandirector_announce_level <0/1/2/3>` - Announcement types. 0 - None, 1 - Only bosses, 2 - Only specials+, 3 - Everything + * `mandirector_enable_tank <0/1>` - Should tanks be allowed to be spawned? + * `mandirector_enable_witch <0/1>` - Should witches be allowed to be spawned? + * `mandirector_enable_mob <0/1>` - Should mobs be allowed to be spawned * **Commands:** * `sm_spawnspecial` - Spawn a special via director * `sm_forcespecial` - Force spawn a special via director, bypassing spawn limits @@ -36,4 +36,12 @@ All my sourcemod plugins... shitty probably 4,Francis,1,76,alive,0,,,,Francis 5,Louis,1,90,alive,0,,first_aid_kit,,Louis ``` -* `AutoWarpBot` - simple l4d2 plugin that will auto teleport everyone to checkpoint once all real players have reached the saferoom \ No newline at end of file +* `AutoWarpBot` - simple l4d2 plugin that will auto teleport everyone to checkpoint once all real players have reached the saferoom +* `L4D2Tools` - A group of misc tools for l4d2. Including: Notify on lasers use, and a finale timer (gauntlets or all finales) + * **Convars:** + * `sm_laser_use_notice <1/0>` - Enable notification of a laser box being used + * `sm_time_finale <0/1/2>` - Record the time it takes to complete finale. 0 -> OFF, 1 -> Gauntlets Only, 2 -> All finales +* `200IQBots_FlyYouFools` - Updated version of ConnerRia's plugin. Improves bots avoidance of tanks. + * Change from original is updated source syntax, some optimizations/cleanup, and fixes such as bots avoiding tank that has not been activated, or not escaping in vehicle due to presence of tank + * **Convars:** + * `FlyYouFools_Version` - Prints the version of plugin \ No newline at end of file