diff --git a/scripting/include/events.inc b/scripting/include/events.inc new file mode 100644 index 0000000..9e53585 --- /dev/null +++ b/scripting/include/events.inc @@ -0,0 +1,372 @@ +public void OnPluginEnd() { + UnhookEntityOutput("func_button", "OnPressed", Event_ButtonPress); +} +public void OnMapEnd() { + UnhookEntityOutput("func_button", "OnPressed", Event_ButtonPress); +} +public void OnMapStart() { + AddFileToDownloadsTable("sound/custom/meow1.mp3"); + PrecacheSound("custom/meow1.mp3"); + + lastButtonUser = -1; + HookEntityOutput("func_button", "OnPressed", Event_ButtonPress); + CreateTimer(MAIN_TIMER_INTERVAL_S, Timer_Main, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); + PrecacheSound("player/footsteps/clown/concrete1.wav"); + //CreateTimer(30.0, Timer_AutoPunishCheck, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); +} +public void OnClientPutInServer(int client) { + g_PendingBanTroll[client] = false; + SDKHook(client, SDKHook_OnTakeDamage, Event_TakeDamage); +} +public void OnClientAuthorized(int client, const char[] auth) { + if(!IsFakeClient(client)) { + strcopy(steamids[client], 64, auth); + } +} +public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) { + int client = GetClientOfUserId(event.GetInt("userid")); + if(g_PendingBanTroll[client]) { + g_PendingBanTroll[client] = false; + if(!IsFakeClient(client) && GetUserAdmin(client) == INVALID_ADMIN_ID) { + BanIdentity(steamids[client], 0, BANFLAG_AUTHID, "TrollMarked", "ftt", 0); + } + } + steamids[client][0] = '\0'; + ActiveTrolls[client] = 0; + g_iAttackerTarget[client] = 0; +} +public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) { + int client = GetClientOfUserId(event.GetInt("userid")); + g_iAttackerTarget[client] = 0; +} +public Action Event_WeaponReload(int weapon) { + int client = GetEntPropEnt(weapon, Prop_Send, "m_hOwner"); + if(IsTrollActive(client, "GunJam")) { + float dec = GetRandomFloat(0.0, 1.0); + if(FloatCompare(dec, 0.50) == -1) { //10% chance gun jams + return Plugin_Stop; + } + } + return Plugin_Continue; +} +public Action Event_ButtonPress(const char[] output, int entity, int client, float delay) { + if(client > 0 && client <= MaxClients) { + lastButtonUser = client; + } + return Plugin_Continue; +} + +public void Event_PanicEventCreate(Event event, const char[] name, bool dontBroadcast) { + int client = GetClientOfUserId(event.GetInt("userid")); + if(client) { + lastButtonUser = client; + } +} +public void Event_CarAlarm(Event event, const char[] name, bool dontBroadcast) { + int user = event.GetInt("userid"); + int client = GetClientOfUserId(user); + if(client) { + PrintToChatAll("%N has alerted the horde!", client); + L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", user, 15000); + } + //Ignore car alarms for autopunish + lastButtonUser = -1; +} +public Action L4D2_OnChooseVictim(int attacker, int &curTarget) { + // ========================= + // OVERRIDE VICTIM + // ========================= + if(hMagnetChance.FloatValue < GetRandomFloat()) return Plugin_Continue; + L4D2Infected class = view_as(GetEntProp(attacker, Prop_Send, "m_zombieClass")); + int existingTarget = GetClientOfUserId(g_iAttackerTarget[attacker]); + if(existingTarget > 0 && IsPlayerAlive(existingTarget) && (hMagnetTargetMode.IntValue & 1 != 1 || !IsPlayerIncapped(existingTarget))) { + if(class == L4D2Infected_Tank && (hMagnetTargetMode.IntValue % 2 != 2 || !IsPlayerIncapped(existingTarget))) { + curTarget = existingTarget; + return Plugin_Changed; + }else if(hMagnetTargetMode.IntValue & 1 != 1 || !IsPlayerIncapped(existingTarget)) { + curTarget = existingTarget; + return Plugin_Changed; + } + } + + float closestDistance, survPos[3], spPos[3]; + GetClientAbsOrigin(attacker, spPos); + int closestClient = -1; + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { + //Ignore incapped players if turned on: + if(IsPlayerIncapped(i)) { + if((class == L4D2Infected_Tank && hMagnetTargetMode.IntValue & 2 == 2) || hMagnetTargetMode.IntValue & 1 == 1 ) continue; + } + + if(class == L4D2Infected_Tank && IsTrollActive(i, "TankMagnet") || (class != L4D2Infected_Tank && IsTrollActive(i, "SpecialMagnet"))) { + GetClientAbsOrigin(i, survPos); + float dist = GetVectorDistance(survPos, spPos, true); + if(closestClient == -1 || dist < closestDistance) { + closestDistance = dist; + closestClient = i; + } + } + } + } + + if(closestClient > 0) { + g_iAttackerTarget[attacker] = GetClientUserId(closestClient); + curTarget = closestClient; + return Plugin_Changed; + } + return Plugin_Continue; +} +public Action L4D2_OnEntityShoved(int client, int entity, int weapon, float vecDir[3], bool bIsHighPounce) { + if(client > 0 && client <= MaxClients && IsTrollActive(client, "NoShove") && hShoveFailChance.FloatValue > GetRandomFloat()) { + return Plugin_Handled; + } + return Plugin_Continue; +} +public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) { + if(sArgs[0] == '@') return Plugin_Continue; + if(IsTrollActive(client, "Honk")) { + static char strings[32][7]; + int words = ExplodeString(sArgs, " ", strings, sizeof(strings), 5); + for(int i = 0; i < words; i++) { + if(GetRandomFloat() <= 0.8) strings[i] = "honk"; + else strings[i] = "squeak"; + } + int length = 7 * words; + char[] message = new char[length]; + ImplodeStrings(strings, 32, " ", message, length); + CPrintToChatAll("{blue}%N {default}: %s", client, message); + PrintToServer("%N: %s", client, sArgs); + return Plugin_Handled; + }else if(IsTrollActive(client, "iCantSpellNoMore")) { + int type = GetRandomInt(1, trollKV.Size + 8); + char letterSrc, replaceChar; + switch(type) { + case 1: { + letterSrc = 'e'; + replaceChar = 'b'; + } + case 2: { + letterSrc = 't'; + replaceChar = 'e'; + } + case 3: { + letterSrc = 'i'; + replaceChar = 'e'; + } + case 4: { + letterSrc = 'a'; + replaceChar = 's'; + } + case 5: { + letterSrc = 'u'; + replaceChar = 'i'; + } + case 6: { + letterSrc = '.'; + replaceChar = '/'; + } + case 7: { + letterSrc = 'm'; + replaceChar = 'n'; + } + case 8: { + letterSrc = 'n'; + replaceChar = 'm'; + } + case 9: { + letterSrc = 'l'; + replaceChar = 'b'; + } + case 10: { + letterSrc = 'l'; + replaceChar = 'b'; + } + case 11: { + letterSrc = 'h'; + replaceChar = 'j'; + } + case 12: { + letterSrc = 'o'; + replaceChar = 'i'; + } + case 13: { + letterSrc = 'e'; + replaceChar = 'r'; + } + + default: + return Plugin_Continue; + } + int strLength = strlen(sArgs); + char[] newMessage = new char[strLength + 20]; + int n = 0; + while (sArgs[n] != '\0') { + if(sArgs[n] == letterSrc) { + newMessage[n] = replaceChar; + }else{ + newMessage[n] = sArgs[n]; + } + n++; + } + PrintToServer("%N: %s", client, sArgs); + CPrintToChatAll("{blue}%N {default}: %s", client, newMessage); + return Plugin_Handled; + }else if(IsTrollActive(client, "NoProfanity")) { + //TODO: Check all replacement words, if none were replaced then do full word + //TODO: Lowercase .getstring + static char strings[32][MAX_PHRASE_LENGTH]; + ArrayList phrases; + bool foundWord = false; + int words = ExplodeString(sArgs, " ", strings, 32, MAX_PHRASE_LENGTH); + for(int i = 0; i < words; i++) { + if(REPLACEMENT_PHRASES.GetValue(strings[i], phrases) && phrases.Length > 0) { + foundWord = true; + int c = phrases.GetString(GetRandomInt(0, phrases.Length - 1), strings[i], MAX_PHRASE_LENGTH); + PrintToServer("replacement: %s (%d)", strings[i], c); + } + } + int length = MAX_PHRASE_LENGTH * words; + char[] message = new char[length]; + if(foundWord) { + ImplodeStrings(strings, 32, " ", message, length); + } else { + REPLACEMENT_PHRASES.GetValue("_Full Message Phrases", phrases); + phrases.GetString(GetRandomInt(0, phrases.Length - 1), message, MAX_PHRASE_LENGTH); + } + CPrintToChatAll("{blue}%N {default}: %s", client, message); + PrintToServer("%N: %s", client, sArgs); + return Plugin_Handled; + } + return Plugin_Continue; +} + +public Action Event_ItemPickup(int client, int weapon) { + if(IsTrollActive(client, "NoPickup")) { + return Plugin_Stop; + }else{ + static char wpnName[64]; + GetEdictClassname(weapon, wpnName, sizeof(wpnName)); + if(StrContains(wpnName, "rifle") > -1 + || StrContains(wpnName, "smg") > -1 + || StrContains(wpnName, "weapon_grenade_launcher") > -1 + || StrContains(wpnName, "sniper") > -1 + || StrContains(wpnName, "shotgun") > -1 + ) { + //If 4: Only UZI, if 5: Can't switch. + if(IsTrollActive(client, "UziRules")) { + static char currentWpn[32]; + GetClientWeaponName(client, 0, currentWpn, sizeof(currentWpn)); + if(StrEqual(wpnName, "weapon_smg", true)) { + return Plugin_Continue; + } else if(StrEqual(currentWpn, "weapon_smg", true)) { + return Plugin_Stop; + }else{ + int flags = GetCommandFlags("give"); + SetCommandFlags("give", flags & ~FCVAR_CHEAT); + FakeClientCommand(client, "give smg"); + SetCommandFlags("give", flags); + return Plugin_Stop; + } + }else if(IsTrollActive(client, "PrimaryDisable")) { + return Plugin_Stop; + } + return Plugin_Continue; + }else{ + return Plugin_Continue; + } + } +} + +public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2]) { + if(g_bPendingItemGive[client] && !(buttons & IN_ATTACK2)) { + int target = GetClientAimTarget(client, true); + if(target > -1) { + buttons |= IN_ATTACK2; + RequestFrame(StopItemGive, client); + return Plugin_Changed; + } + return Plugin_Continue; + } + return Plugin_Continue; +} + +public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) { + //Stop FF from marked: + if(attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker) && IsPlayerAlive(attacker)) { + if(g_PendingBanTroll[attacker] && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) { + + return Plugin_Stop; + } + if(IsTrollActive(attacker, "DamageBoost")) { + damage * 2; + return Plugin_Changed; + } + } + return Plugin_Continue; +} + +public Action SoundHook(int[] clients, int& numClients, char sample[PLATFORM_MAX_PATH], int& entity, int& channel, float& volume, int& level, int& pitch, int& flags, char[] soundEntry, int& seed) { + if(lastButtonUser > -1 && StrEqual(sample, "npc/mega_mob/mega_mob_incoming.wav")) { + PrintToConsoleAll("CRESCENDO STARTED BY %N", lastButtonUser); + #if defined DEBUG + PrintToChatAll("CRESCENDO STARTED BY %N", lastButtonUser); + #endif + + lastCrescendoUser = lastButtonUser; + if(IsPlayerFarDistance(lastButtonUser, AUTOPUNISH_FLOW_MIN_DISTANCE)) { + NotifyAllAdmins("Autopunishing player %N for activation of event far from team", lastButtonUser); + ShowActivity(0, "activated autopunish for crescendo activator %N (auto)", lastButtonUser); + ActivateAutoPunish(lastButtonUser); + } + lastButtonUser = -1; + }else if(numClients > 0 && entity > 0 && entity <= MaxClients) { + if(StrContains(sample, "survivor\\voice") > -1) { + if(IsTrollActive(entity, "Honk")) { + strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav"); + return Plugin_Changed; + } else if(IsTrollActive(entity, "VocalizeGag")) { + return Plugin_Handled; + } else if(IsTrollActive(entity, "Meow")) { + strcopy(sample, sizeof(sample), "custom/meow1.mp3"); + return Plugin_Changed; + } + } + + } + return Plugin_Continue; +} + +public Action Event_WitchVictimSet(Event event, const char[] name, bool dontBroadcast) { + int witch = event.GetInt("witchid"); + float closestDistance, survPos[3], witchPos[3]; + GetEntPropVector(witch, Prop_Send, "m_vecOrigin", witchPos); + int closestClient = -1; + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { + //Ignore incapped players if hWitchIgnoreIncapp turned on: + if(IsPlayerIncapped(i) && !hWitchTargetIncapp.BoolValue) { + continue; + } + + if(IsTrollActive(i, "WitchMagnet")) { + GetClientAbsOrigin(i, survPos); + float dist = GetVectorDistance(survPos, witchPos, true); + if(closestClient == -1 || dist < closestDistance) { + closestDistance = dist; + closestClient = i; + } + } + } + } + + if(closestClient > 0) { + DataPack pack; + CreateDataTimer(0.1, Timer_NextWitchSet, pack); + pack.WriteCell(GetClientUserId(closestClient)); + pack.WriteCell(witch); + CreateDataTimer(0.2, Timer_NextWitchSet, pack); + pack.WriteCell(GetClientUserId(closestClient)); + pack.WriteCell(witch); + } +} \ No newline at end of file diff --git a/scripting/include/feedthetrolls/base.inc b/scripting/include/feedthetrolls/base.inc index ecd9846..4101e58 100644 --- a/scripting/include/feedthetrolls/base.inc +++ b/scripting/include/feedthetrolls/base.inc @@ -4,21 +4,34 @@ //#define DEBUG 1 enum TrollModifier { - TrollMod_None = 0, - TrollMod_InstantFire = 1, - TrollMod_Repeat = 2 + TrollMod_Instant = 1, + TrollMod_Constant = 2 } + enum struct Troll { char name[32]; char description[128]; bool runsOnce; + int flags; void GetID(char[] name, int length) { strcopy(name, length, this.name); ReplaceString(name, MAX_TROLL_NAME_LENGTH, " ", "", false); } + + bool HasMod(TrollMod mod) { + return ((this.flags >> view_as(mod)) & 1) == view_as(mod); + } + + // Gets the default modifier to use + TrollModifier GetDefaultMod() { + // If the flags is equal to the 2^n flag, then it must be the only flag: + if(this.flags == TrollMod_Instant) return TrollMod_Instant; + else if(this.flags == TrollMod_Constant) return TrollMod_Constant; + else return -1; + } } Troll Trolls[MAX_TROLLS+1]; @@ -27,11 +40,21 @@ int ActiveTrolls[MAXPLAYERS+1]; StringMap trollKV; char trollIds[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH]; -int SetupTroll(const char[] name, const char description[128], bool hasMods) { +void ResetClient(int victim, bool wipe = true) { + if(wipe) ActiveTrolls[victim] = 0; + SetEntityGravity(victim, 1.0); + SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0); + SDKUnhook(victim, SDKHook_WeaponCanUse, Event_ItemPickup); + int wpn = GetClientWeaponEntIndex(victim, 0); + if(wpn > -1) + SDKUnhook(wpn, SDKHook_Reload, Event_WeaponReload); +} + +int SetupTroll(const char[] name, const char description[128], int flags) { static int i = 0; strcopy(Trolls[i].name, MAX_TROLL_NAME_LENGTH, name); strcopy(Trolls[i].description, 128, description); - Trolls[i].runsOnce = !hasMods; + Trolls[i].flags = flags; static char key[MAX_TROLL_NAME_LENGTH]; strcopy(key, MAX_TROLL_NAME_LENGTH, name); ReplaceString(key, MAX_TROLL_NAME_LENGTH, " ", "", false); @@ -207,31 +230,31 @@ void DisableTroll(int client, const char[] troll) { void SetupTrolls() { trollKV = new StringMap(); - SetupTroll("Reset Troll", "Resets the user, removes all troll effects", false); - SetupTroll("Special Magnet", "Attracts ALL specials to any alive target with this troll enabled", false); - SetupTroll("Tank Magnet", "Attracts ALL tanks to any alive target with this troll enabled", false); - SetupTroll("Witch Magnet", "All witches when startled will target any player with this troll", false); - SetupTroll("Vomit Player", "Shortcut to sm_vomitplayer. vomits the player.", false); - SetupTroll("ThrowItAll", "Player throws all their items at nearby player, periodically", true); - SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", false); - SetupTroll("No Profanity", "Replaces some words with random phrases", false); - SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", false); - SetupTroll("UziRules", "Picking up a weapon gives them a UZI instead", false); - SetupTroll("Slow Speed", "Sets player speed to 0.8x of normal speed", false); - SetupTroll("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", false); - SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", false); - SetupTroll("PrimaryDisable", "Player cannot pickup any weapons, only melee/pistols", true); - SetupTroll("Clusmy", "Player drops axe periodically or on demand", true); - SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", false); - SetupTroll("KillMeSoftly", "Make player eat or waste pills whenever possible", false); - SetupTroll("GunJam", "On reload, small chance their gun gets jammed - Can't reload.", false); - SetupTroll("NoPickup", "Prevents a player from picking up ANY (new) item. Use ThrowItAll to make them drop", true); - SetupTroll("Honk", "Honk", false); - SetupTroll("No Shove", "Prevents a player from shoving", false); - SetupTroll("Damage Boost", "Makes a player take more damage than normal", false); - SetupTroll("Temp Health Quick Drain", "Makes a player's temporarily health drain very quickly", false); - SetupTroll("Slow Drain", "Will make the player slowly lose health over time", false); - SetupTroll("CameTooEarly", "When they shoot, random chance they empty whole clip", true); + SetupTroll("Reset Troll", "Resets the user, removes all troll effects", TrollMod_Instant); + SetupTroll("Special Magnet", "Attracts ALL specials to any alive target with this troll enabled", TrollMod_Constant); + SetupTroll("Tank Magnet", "Attracts ALL tanks to any alive target with this troll enabled", TrollMod_Constant); + SetupTroll("Witch Magnet", "All witches when startled will target any player with this troll", TrollMod_Constant); + SetupTroll("Vomit Player", "Shortcut to sm_vomitplayer. vomits the player.", TrollMod_Instant); + SetupTroll("ThrowItAll", "Player throws all their items at nearby player, periodically", TrollMod_Instant | TrollMod_Constant); + SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant); + SetupTroll("No Profanity", "Replaces some words with random phrases", TrollMod_Constant); + SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", TrollMod_Instant); + SetupTroll("UziRules", "Picking up a weapon gives them a UZI instead", TrollMod_Constant); + SetupTroll("Slow Speed", "Sets player speed to 0.8x of normal speed", TrollMod_Constant); + SetupTroll("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", TrollMod_Constant); + SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", TrollMod_Instant); + SetupTroll("PrimaryDisable", "Player cannot pickup any weapons, only melee/pistols", TrollMod_Constant); + SetupTroll("Clusmy", "Player drops axe periodically or on demand", TrollMod_Instant | TrollMod_Constant); + SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", TrollMod_Instant); + SetupTroll("KillMeSoftly", "Make player eat or waste pills whenever possible", TrollMod_Instant | TrollMod_Constant); + SetupTroll("GunJam", "On reload, small chance their gun gets jammed - Can't reload.", TrollMod_Constant); + SetupTroll("NoPickup", "Prevents a player from picking up ANY (new) item. Use ThrowItAll to make them drop", TrollMod_Constant); + SetupTroll("Honk", "Honk", TrollMod_Constant); + SetupTroll("No Shove", "Prevents a player from shoving", TrollMod_Constant); + SetupTroll("Damage Boost", "Makes a player take more damage than normal", TrollMod_Constant); + SetupTroll("Temp Health Quick Drain", "Makes a player's temporarily health drain very quickly", TrollMod_Constant); + SetupTroll("Slow Drain", "Will make the player slowly lose health over time", TrollMod_Constant); + SetupTroll("CameTooEarly", "When they shoot, random chance they empty whole clip", TrollMod_Constant); SetupTroll("Meow", "Makes the player meow", false); //INFO: UP MAX_TROLLS when adding new trolls! } \ No newline at end of file diff --git a/scripting/include/feedthetrolls/commands.inc b/scripting/include/feedthetrolls/commands.inc new file mode 100644 index 0000000..abb2ec0 --- /dev/null +++ b/scripting/include/feedthetrolls/commands.inc @@ -0,0 +1,348 @@ +public Action Command_InstaSpecial(int client, int args) { + if(args < 1) { + Menu menu = new Menu(Insta_PlayerHandler); + menu.SetTitle("Choose a player"); + for(int i = 1; i < MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { + static char userid[8], display[16]; + Format(userid, sizeof(userid), "%d|0", GetClientUserId(i)); + GetClientName(i, display, sizeof(display)); + menu.AddItem(userid, display); + } + } + menu.ExitButton = true; + menu.Display(client, 0); + } else { + char arg1[32], arg2[32] = "jockey"; + GetCmdArg(1, arg1, sizeof(arg1)); + if(args >= 2) { + GetCmdArg(2, arg2, sizeof(arg2)); + } + char target_name[MAX_TARGET_LENGTH]; + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + MaxClients, + COMMAND_FILTER_ALIVE, + 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 specialType = GetSpecialType(arg2); + static float pos[3]; + if(specialType == -1) { + ReplyToCommand(client, "Unknown special \"%s\"", arg2); + return Plugin_Handled; + } + for (int i = 0; i < target_count; i++) { + int target = target_list[i]; + if(GetClientTeam(target) == 2) { + SpawnSpecialNear(target, specialType); + }else{ + ReplyToTargetError(client, target_count); + } + } + ShowActivity(client, "spawned Insta-%s™ near %s", arg2, target_name); + } + + + return Plugin_Handled; +} + +public Action Command_InstaSpecialFace(int client, int args) { + if(args < 1) { + Menu menu = new Menu(Insta_PlayerHandler); + menu.SetTitle("Choose a player"); + for(int i = 1; i < MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { + static char userid[8], display[16]; + Format(userid, sizeof(userid), "%d|1", GetClientUserId(i)); + GetClientName(i, display, sizeof(display)); + menu.AddItem(userid, display); + } + } + menu.ExitButton = true; + menu.Display(client, 0); + } else { + char arg1[32], arg2[32] = "jockey"; + GetCmdArg(1, arg1, sizeof(arg1)); + if(args >= 2) { + GetCmdArg(2, arg2, sizeof(arg2)); + } + char target_name[MAX_TARGET_LENGTH]; + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + MaxClients, + COMMAND_FILTER_ALIVE, + 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 specialType = GetSpecialType(arg2); + static float pos[3]; + if(specialType == -1) { + ReplyToCommand(client, "Unknown special \"%s\"", arg2); + return Plugin_Handled; + } + for (int i = 0; i < target_count; i++) { + int target = target_list[i]; + if(GetClientTeam(target) == 2) { + SpawnSpecialInFace(target, specialType); + }else{ + ReplyToTargetError(client, target_count); + } + } + ShowActivity(client, "spawned Insta-%s™ on %s", arg2, target_name); + } + return Plugin_Handled; +} + + +public Action Command_WitchAttack(int client, int args) { + if(args < 1) { + ReplyToCommand(client, "Usage: sm_witch_attack "); + } else { + char arg1[32]; + GetCmdArg(1, arg1, sizeof(arg1)); + char target_name[MAX_TARGET_LENGTH]; + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + 1, + COMMAND_FILTER_ALIVE | COMMAND_FILTER_NO_MULTI, /* 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 target = target_list[0]; + if(GetClientTeam(target) == 2) { + int witch = INVALID_ENT_REFERENCE; + while ((witch = FindEntityByClassname(witch, "witch")) != INVALID_ENT_REFERENCE) { + SetWitchTarget(witch, target); + + ShowActivity(client, "all witches target %s", target_name); + } + }else{ + ReplyToTargetError(client, target_count); + } + } + + return Plugin_Handled; +} + +public Action Command_FeedTheCrescendoTroll(int client, int args) { + if(lastCrescendoUser > -1) { + ActivateAutoPunish(lastCrescendoUser); + ReplyToCommand(client, "Activated auto punish on %N", lastCrescendoUser); + ShowActivity(client, "activated autopunish for crescendo activator %N",lastCrescendoUser); + }else{ + ReplyToCommand(client, "No player could be found to autopunish."); + } + return Plugin_Handled; +} + +public Action Command_ResetUser(int client, int args) { + if(args < 1) { + ReplyToCommand(client, "Usage: sm_ftr "); + }else{ + char arg1[32]; + GetCmdArg(1, arg1, sizeof(arg1)); + char target_name[MAX_TARGET_LENGTH]; + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + MAXPLAYERS, + COMMAND_FILTER_CONNECTED, /* 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; + } + + for (int i = 0; i < target_count; i++) { + if(ActiveTrolls[target_list[i]] > 0) { + ResetClient(target_list[i], true); + ShowActivity(client, "reset troll effects on \"%N\". ", target_list[i]); + } + } + } + return Plugin_Handled; +} + +public Action Command_ApplyUser(int client, int args) { + if(args < 2) { + Menu menu = new Menu(ChoosePlayerHandler); + menu.SetTitle("Choose a player"); + for(int i = 1; i < MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { + static char userid[8], display[16]; + Format(userid, sizeof(userid), "%d", GetClientUserId(i)); + GetClientName(i, display, sizeof(display)); + menu.AddItem(userid, display); + } + } + menu.ExitButton = true; + menu.Display(client, 0); + }else{ + char arg1[32], arg2[32], arg3[8]; + GetCmdArg(1, arg1, sizeof(arg1)); + GetCmdArg(2, arg2, sizeof(arg2)); + GetCmdArg(3, arg3, sizeof(arg3)); + + bool silent = StrEqual(arg3, "silent") || StrEqual(arg3, "quiet") || StrEqual(arg3, "mute"); + static char name[MAX_TROLL_NAME_LENGTH]; + if(!GetTrollID(StringToInt(arg2), name)) { + ReplyToCommand(client, "Not a valid mode. Must be greater than 0. Usage: sm_fta [player] [mode]. Use sm_ftr to reset."); + }else{ + char target_name[MAX_TARGET_LENGTH]; + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + MAXPLAYERS, + 0, + 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; + } + for (int i = 0; i < target_count; i++) { + if(IsClientInGame(target_list[i]) && GetClientTeam(target_list[i]) == 2) + ApplyTroll(target_list[i], name, client, TrollMod_Instant, silent); + } + } + } + return Plugin_Handled; +} + +public Action Command_ListModes(int client, int args) { + static char name[MAX_TROLL_NAME_LENGTH]; + static Troll troll; + for(int i = 0; i <= MAX_TROLLS; i++) { + GetTrollByKeyIndex(i, troll); + ReplyToCommand(client, "%d. %s - %s", i, troll.name, troll.description); + } + return Plugin_Handled; +} + +public Action Command_ListTheTrolls(int client, int args) { + int count = 0; + //TODO: Update + char[][] modeListArr = new char[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH]; + static char modeList[255]; + for(int i = 1; i < MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && ActiveTrolls[i] > 0) { + int modeCount = 0; + static char name[MAX_TROLL_NAME_LENGTH]; + for(int j = 1; j <= MAX_TROLLS; j++) { + GetTrollID(j, name); + if(IsTrollActive(i, name)) { + strcopy(modeListArr[modeCount], MAX_TROLL_NAME_LENGTH, name); + modeCount++; + } + } + + ImplodeStrings(modeListArr, modeCount, ", ", modeList, sizeof(modeList)); + ReplyToCommand(client, "%N | %s", i, modeList); + count++; + } + } + if(count == 0) { + ReplyToCommand(client, "No clients have a mode applied."); + } + return Plugin_Handled; +} + +public Action Command_MarkPendingTroll(int client, int args) { + if(args == 0) { + Menu menu = new Menu(ChooseMarkedTroll); + menu.SetTitle("Choose a troll to mark"); + static char userid[8], display[16]; + for(int i = 1; i < MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { + AdminId admin = GetUserAdmin(i); + if(admin == INVALID_ADMIN_ID) { + Format(userid, sizeof(userid), "%d", GetClientUserId(i)); + GetClientName(i, display, sizeof(display)); + menu.AddItem(userid, display); + }else{ + ReplyToCommand(client, "%N is an admin cannot be marked.", i); + } + } + } + menu.ExitButton = true; + menu.Display(client, 0); + } else { + char arg1[32]; + GetCmdArg(1, arg1, sizeof(arg1)); + char target_name[MAX_TARGET_LENGTH]; + int target_list[MAXPLAYERS], target_count; + bool tn_is_ml; + if ((target_count = ProcessTargetString( + arg1, + client, + target_list, + 1, + COMMAND_FILTER_NO_MULTI , /* 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 target = target_list[0]; + if(GetClientTeam(target) == 2) { + ToggleMarkPlayer(client, target); + }else{ + ReplyToCommand(client, "Player does not exist or is not a survivor."); + } + } + return Plugin_Handled; +} + +public Action Command_FeedTheTrollMenu(int client, int args) { + ReplyToCommand(client, "sm_ftl - Lists all the active trolls on players"); + ReplyToCommand(client, "sm_ftm - Lists all available troll modes & descriptions"); + ReplyToCommand(client, "sm_ftr - Resets target users' of their trolls"); + ReplyToCommand(client, "sm_fta - Applies a troll mode on targets"); + ReplyToCommand(client, "sm_ftt - Opens this menu"); + ReplyToCommand(client, "sm_ftc - Will apply a punishment to last crescendo activator"); + ReplyToCommand(client, "sm_mark - Marks the user to be banned on disconnect, prevents their FF."); + return Plugin_Handled; +} \ No newline at end of file diff --git a/scripting/include/feedthetrolls/menus.inc b/scripting/include/feedthetrolls/menus.inc new file mode 100644 index 0000000..db19ba1 --- /dev/null +++ b/scripting/include/feedthetrolls/menus.inc @@ -0,0 +1,141 @@ +public int Insta_PlayerHandler(Menu menu, MenuAction action, int client, int param2) { + /* If an option was selected, tell the client about the item. */ + if (action == MenuAction_Select) { + static char info[16]; + menu.GetItem(param2, info, sizeof(info)); + + static char str[2][8]; + ExplodeString(info, "|", str, 2, 8, false); + + int userid = StringToInt(str[0]); + int instaMode = StringToInt(str[1]); + + Menu spMenu = new Menu(Insta_SpecialHandler); + spMenu.SetTitle("Choose a Insta-Special™"); + for(int i = 1; i <= 6; i++) { + static char id[8]; + Format(id, sizeof(id), "%d|%d|%d", userid, instaMode, i); + spMenu.AddItem(id, SPECIAL_NAMES[i-1]); + } + spMenu.ExitButton = true; + spMenu.Display(client, 0); + } else if (action == MenuAction_End) + delete menu; +} + +public int Insta_SpecialHandler(Menu menu, MenuAction action, int client, int param2) { + /* If an option was selected, tell the client about the item. */ + if (action == MenuAction_Select) { + static char info[16]; + menu.GetItem(param2, info, sizeof(info)); + static char str[3][8]; + ExplodeString(info, "|", str, 3, 8, false); + int target = GetClientOfUserId(StringToInt(str[0])); + bool inFace = StrEqual(str[1], "1"); + int special = StringToInt(str[2]); + if(inFace) { + SpawnSpecialInFace(target, special); + ShowActivity(client, "spawned Insta-%s™ near %N", SPECIAL_NAMES[special-1], target); + } else { + SpawnSpecialNear(target, special); + ShowActivity(client, "spawned Insta-%s™ near %N", SPECIAL_NAMES[special-1], target); + } + } else if (action == MenuAction_End) + delete menu; +} + + +public int ChooseMarkedTroll(Menu menu, MenuAction action, int activator, int param2) { + if (action == MenuAction_Select) { + static char info[16]; + menu.GetItem(param2, info, sizeof(info)); + int target = GetClientOfUserId(StringToInt(info)); + ToggleMarkPlayer(activator, target); + } else if (action == MenuAction_End) + delete menu; +} + +public int ChoosePlayerHandler(Menu menu, MenuAction action, int param1, int param2) { + /* If an option was selected, tell the client about the item. */ + if (action == MenuAction_Select) { + static char info[16]; + menu.GetItem(param2, info, sizeof(info)); + int userid = StringToInt(info); + + Menu trollMenu = new Menu(ChooseModeMenuHandler); + trollMenu.SetTitle("Choose a troll mode"); + //TODO: Update + static char id[8]; + static char name[MAX_TROLL_NAME_LENGTH]; + for(int i = 0; i <= MAX_TROLLS; i++) { + GetTrollID(i, name); + // int trollIndex = GetTrollByKeyIndex(i, troll); + // Pass key index + Format(id, sizeof(id), "%d|%d", userid, i); + trollMenu.AddItem(id, name); + } + trollMenu.ExitButton = true; + trollMenu.Display(param1, 0); + } else if (action == MenuAction_End) + delete menu; +} + +public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int param2) { + /* If an option was selected, tell the client about the item. */ + if (action == MenuAction_Select) { + static char info[16]; + menu.GetItem(param2, info, sizeof(info)); + static char str[2][8]; + ExplodeString(info, "|", str, 2, 8, false); + int userid = StringToInt(str[0]); + int client = GetClientOfUserId(userid); + int keyIndex = StringToInt(str[1]); + static Troll troll; + static char trollID[MAX_TROLL_NAME_LENGTH]; + GetTrollByKeyIndex(keyIndex, troll); + troll.GetID(trollID, MAX_TROLL_NAME_LENGTH); + //If troll has multiple flags, prompt: + if(troll.HasMode(TrollMod_Instant) && troll.HasMode + (TrollMod_Constant)) { + Menu modiferMenu = new Menu(ChooseTrollModiferHandler); + modiferMenu.SetTitle("Choose Troll Modifer Option"); + static char singleUse[16], multiUse[16], bothUse[16]; + Format(singleUse, sizeof(singleUse), "%d|%d|1", userid, keyIndex); + Format(multiUse, sizeof(multiUse), "%d|%d|2", userid, keyIndex); + Format(bothUse, sizeof(bothUse), "%d|%d|3", userid, keyIndex); + modiferMenu.AddItem(singleUse, "Activate once"); + modiferMenu.AddItem(multiUse, "Activate Periodically"); + modiferMenu.AddItem(bothUse, "Activate Periodically & Instantly"); + modiferMenu.ExitButton = true; + modiferMenu.Display(param1, 0); + } else { + ApplyTroll(client, trollID, param1, troll.GetDefaultMod()); + } + } else if (action == MenuAction_End) + delete menu; +} + +public int ChooseTrollModiferHandler(Menu menu, MenuAction action, int param1, int param2) { + if (action == MenuAction_Select) { + static char info[16]; + menu.GetItem(param2, info, sizeof(info)); + static char str[3][8]; + ExplodeString(info, "|", str, 3, 8, false); + int client = GetClientOfUserId(StringToInt(str[0])); + int keyIndex = StringToInt(str[1]); + static Troll troll; + static char trollID[MAX_TROLL_NAME_LENGTH]; + GetTrollByKeyIndex(keyIndex, troll); + troll.GetID(trollID, MAX_TROLL_NAME_LENGTH); + int modifier = StringToInt(str[2]); + if(modifier == 2 || modifier == 3) + ApplyTroll(client, trollID, param1, TrollMod_Repeat); + else + ApplyTroll(client, trollID, param1, TrollMod_InstantFire); + } else if (action == MenuAction_End) + delete menu; +} + +public void StopItemGive(int client) { + g_bPendingItemGive[client] = false; +} \ No newline at end of file diff --git a/scripting/include/feedthetrolls/misc.inc b/scripting/include/feedthetrolls/misc.inc new file mode 100644 index 0000000..a390be0 --- /dev/null +++ b/scripting/include/feedthetrolls/misc.inc @@ -0,0 +1,109 @@ +#define AUTOPUNISH_FLOW_MIN_DISTANCE 5000.0 +#define AUTOPUNISH_MODE_COUNT 3 + +void ActivateAutoPunish(int client) { + if(hAutoPunish.IntValue & 2 == 2) + ApplyTroll(lastButtonUser, "SpecialMagnet", 0, TrollMod_Constant); + if(hAutoPunish.IntValue & 1 == 1) + ApplyTroll(lastButtonUser, "TankMagnet", 0, TrollMod_Constant); + if(hAutoPunish.IntValue & 8 == 8) + ApplyTroll(lastButtonUser, "VomitPlayer", 0, TrollMod_Instant); + else if(hAutoPunish.IntValue & 4 == 4) + ApplyTroll(lastButtonUser, "Swarm", 0, TrollMod_Instant); + if(hAutoPunishExpire.IntValue > 0) { + CreateTimer(60.0 * hAutoPunishExpire.FloatValue, Timer_ResetAutoPunish, GetClientOfUserId(lastButtonUser)); + } +} + +void SetWitchTarget(int witch, int target) { + Behavior behavior = Behavior(witch, WITCH_QUERY); + BehaviorAction action = behavior.CurrentAction.Last; + + BehaviorAction newaction = view_as(AllocateMemory(18556)); + SDKCall(g_hWitchAttack, newaction, target); + + IActionResult result; result.Init(CHANGE_TO, newaction); + result.ToAction(action); +} + +bool ToggleMarkPlayer(int client, int target) { + if(g_PendingBanTroll[target]) { + g_PendingBanTroll[target] = false; + ShowActivity(client, "unmarked %N as troll", target); + return true; + }else{ + AdminId admin_client = GetUserAdmin(client); + AdminId admin_target = GetUserAdmin(target); + if(admin_client != INVALID_ADMIN_ID && admin_target == INVALID_ADMIN_ID ) { + Call_StartForward(g_PlayerMarkedForward); + Call_PushCell(client); + Call_PushCell(target); + Call_Finish(); + g_PendingBanTroll[target] = true; + ShowActivity(client, "marked %N as troll", target); + return true; + }else{ + ReplyToCommand(client, "cannot mark %N as troll as they are an admin.", target); + return false; + } + } +} + +stock int FindIdlePlayerBot(int client) { + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsFakeClient(i)) { + int user = GetEntProp(i, Prop_Send, "m_humanSpectatorUserID"); + int bot = GetClientOfUserId(user); + return bot > 0 ? bot : client; + } + } + return client; +} +stock bool IsPlayerIncapped(int client) { + return GetEntProp(client, Prop_Send, "m_isIncapacitated") == 1; +} + + +#define MAX_PHRASES_PER_WORD 8 +#define MAX_PHRASE_LENGTH 191 +StringMap REPLACEMENT_PHRASES; +//TODO: Load from cfg +/* Example: +exWord +{ + "1" "phrase1" + "2" "phrase2" +} +*/ +void LoadPhrases() { + KeyValues kv = new KeyValues("Phrases"); + ArrayList phrases = new ArrayList(ByteCountToCells(MAX_PHRASE_LENGTH)); + + char sPath[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, sPath, sizeof(sPath), "data/ftt_phrases.cfg"); + + if(!FileExists(sPath) || !kv.ImportFromFile(sPath)) { + delete kv; + PrintToServer("[FTT] Could not load phrase list from data/ftt_phrases.cfg"); + return; + } + static char word[32]; + char phrase[MAX_PHRASE_LENGTH]; + // Go through all the words: + kv.GotoFirstSubKey(); + int i = 0; + static char buffer[4]; + do { + kv.GetSectionName(word, sizeof(word)); + phrases.Clear(); + for(;;) { + IntToString(++i, buffer, sizeof(buffer)); + kv.GetString(buffer, phrase, MAX_PHRASE_LENGTH, "_null"); + if(strcmp(phrase, "_null") == 0) break; + phrases.PushString(phrase); + } + i = 0; + REPLACEMENT_PHRASES.SetValue(word, phrases.Clone(), true); + } while (kv.GotoNextKey(false)); + delete kv; +} diff --git a/scripting/include/feedthetrolls/specials.inc b/scripting/include/feedthetrolls/specials.inc new file mode 100644 index 0000000..0e70aa7 --- /dev/null +++ b/scripting/include/feedthetrolls/specials.inc @@ -0,0 +1,82 @@ +char SPECIAL_NAMES[][] = { + "Smoker", "Boomer", "Hunter", "Spitter", "Jockey", "Charger", "Witch" +}; + +stock int GetSpecialType(const char[] input) { + for(int i = 0; i < sizeof(SPECIAL_NAMES); i++) { + if(strcmp(SPECIAL_NAMES[i], input, false) == 0) return i + 1; + } + return -1; +} + +stock bool FindSuitablePosition(int target, const float pos[3], float outputPos[3], float minDistance = 19000.0, int tries = 100) { + outputPos = pos; + for(int i = tries; i > 0; i--) { + // int nav = L4D_GetNearestNavArea(pos); + // L4D_FindRandomSpot(nav, testPos); + // float dist = GetVectorDistance(testPos, pos, true); + outputPos[0] += GetRandomFloat(-30.0, 30.0); + outputPos[1] += GetRandomFloat(-30.0, 30.0); + float dist = GetVectorDistance(outputPos, pos, true); + if(dist >= minDistance && L4D2Direct_GetTerrorNavArea(outputPos) != Address_Null) { //5m^2 + return true; + } + } + return false; +} + +float GetIdealMinDistance(int specialType) { + switch(specialType) { + // /*Boomer*/ case 2: return 1200.0; + /*Charger*/ case 6: return 19000.0; + /*Smoker*/ case 1: return 20000.0; + + default: + return 12000.0; + } +} + +bool SpawnSpecialInFace(int target, int specialType) { + static float pos[3], ang[3]; + static float testPos[3]; + testPos = pos; + GetClientAbsOrigin(target, pos); + GetClientEyeAngles(target, ang); + if(specialType != 5 && specialType != 2) { //If charger/hunter, find a suitable area that is at least 5 m away + float minDistance = GetIdealMinDistance(specialType); + GetHorizontalPositionFromOrigin(pos, ang, minDistance, testPos); + FindSuitablePosition(target, pos, testPos, minDistance, 100); + pos = testPos; + } else { // Else spawn a little bit off, and above (above for jockeys) + pos[2] += 10.0; + pos[0] += 5.0; + } + pos[2] += 1.0; + NegateVector(ang); + int special = (specialType == 7) ? L4D2_SpawnWitch(pos, ang) : L4D2_SpawnSpecial(specialType, pos, ang); + if(special == -1) return false; + + if(specialType == 7) + SetWitchTarget(special, target); + else + g_iAttackerTarget[special] = GetClientUserId(target); + + if(specialType == 2) { //Kill boomer + ForcePlayerSuicide(special); + } + return true; +} + +bool SpawnSpecialNear(int target, int specialType) { + static float pos[3]; + if(L4D_GetRandomPZSpawnPosition(target, specialType, 10, pos)) { + int special = (specialType == 7) ? L4D2_SpawnWitch(pos, ZERO_VECTOR) : L4D2_SpawnSpecial(specialType, pos, ZERO_VECTOR); + if(special == -1) return false; + if(specialType == 7) + SetWitchTarget(special, target); + else + g_iAttackerTarget[special] = GetClientUserId(target); + return true; + } + return false; +} \ No newline at end of file diff --git a/scripting/include/feedthetrolls/timers.inc b/scripting/include/feedthetrolls/timers.inc new file mode 100644 index 0000000..42f69d7 --- /dev/null +++ b/scripting/include/feedthetrolls/timers.inc @@ -0,0 +1,93 @@ +public Action Timer_ThrowTimer(Handle timer) { + int count = 0; + for(int i = 1; i < MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && IsTrollActive(i, "ThrowItAll")) { + ThrowAllItems(i); + count++; + } + } + return count > 0 ? Plugin_Continue : Plugin_Stop; +} + +public Action Timer_Main(Handle timer) { + static int loop; + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i)) { + if(IsTrollActive(i, "SlowDrain")) { + if(loop % 4 == 0) { + int hp = GetClientHealth(i); + if(hp > 50) { + SetEntProp(i, Prop_Send, "m_iHealth", hp - 1); + } + } + }else if(IsTrollActive(i, "TempHealthQuickDrain")) { + if(loop % 2 == 0) { + float bufferTime = GetEntPropFloat(i, Prop_Send, "m_healthBufferTime"); + float buffer = GetEntPropFloat(i, Prop_Send, "m_healthBuffer"); + float tempHealth = GetTempHealth(i); + if(tempHealth > 0.0) { + PrintToConsole(i, "%f | %f %f", tempHealth, buffer, bufferTime); + //SetEntPropFloat(i, Prop_Send, "m_healthBuffer", buffer - 10.0); + SetEntPropFloat(i, Prop_Send, "m_healthBufferTime", bufferTime - 7.0); + } + } + }else if(IsTrollActive(i, "Swarm")) { + L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", GetClientUserId(i), 15000); + } + } + } + if(++loop >= 60) { + loop = 0; + } + return Plugin_Continue; +} + +public Action Timer_GivePistol(Handle timer, int client) { + int flags = GetCommandFlags("give"); + SetCommandFlags("give", flags & ~FCVAR_CHEAT); + FakeClientCommand(client, "give pistol"); + SetCommandFlags("give", flags|FCVAR_CHEAT); +} + +public Action Timer_ThrowWeapon(Handle timer, Handle pack) { + ResetPack(pack); + float dest[3]; + dest[0] = ReadPackFloat(pack); + dest[1] = ReadPackFloat(pack); + dest[2] = ReadPackFloat(pack); + int slot = ReadPackCell(pack); + int victim = ReadPackCell(pack); + + int wpnRef = GetPlayerWeaponSlot(victim, slot); + if(wpnRef != -1) { + int wpn = EntRefToEntIndex(wpnRef); + if(wpn != INVALID_ENT_REFERENCE) { + if(slot == 1) { + static char name[16]; + GetEdictClassname(wpn, name, sizeof(name)); + if(!StrEqual(name, "weapon_pistol", false)) { + SDKHooks_DropWeapon(victim, wpn, dest); + CreateTimer(0.2, Timer_GivePistol, victim); + } + }else + SDKHooks_DropWeapon(victim, wpn, dest); + } + } +} + +public Action Timer_ResetAutoPunish(Handle timer, int user) { + int client = GetClientOfUserId(user); + if(client) { + if(hAutoPunish.IntValue & 2 == 2) + DisableTroll(client, "SpecialMagnet"); + if(hAutoPunish.IntValue & 1 == 1) + DisableTroll(client, "TankMagnet"); + } +} + +public Action Timer_NextWitchSet(Handle timer, DataPack pack) { + pack.Reset(); + int client = GetClientOfUserId(pack.ReadCell()); + int witch = pack.ReadCell(); + SetWitchTarget(witch, client); +} \ No newline at end of file diff --git a/scripting/include/ftt.inc b/scripting/include/ftt.inc index ef0b223..96a24cc 100644 --- a/scripting/include/ftt.inc +++ b/scripting/include/ftt.inc @@ -1,9 +1,3 @@ -#define AUTOPUNISH_FLOW_MIN_DISTANCE 5000.0 -#define AUTOPUNISH_MODE_COUNT 3 -// #define TROLL_MODE_COUNT 26 -// - - enum L4D2Infected { L4D2Infected_None = 0, @@ -37,204 +31,5 @@ int gChargerVictim = -1; //For charge player feature float ZERO_VECTOR[3] = {0.0, 0.0, 0.0}; #include - -void ResetClient(int victim, bool wipe = true) { - if(wipe) ActiveTrolls[victim] = 0; - SetEntityGravity(victim, 1.0); - SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0); - SDKUnhook(victim, SDKHook_WeaponCanUse, Event_ItemPickup); - int wpn = GetClientWeaponEntIndex(victim, 0); - if(wpn > -1) - SDKUnhook(wpn, SDKHook_Reload, Event_WeaponReload); -} - -void ActivateAutoPunish(int client) { - if(hAutoPunish.IntValue & 2 == 2) - ApplyTroll(lastButtonUser, "SpecialMagnet", 0, TrollMod_None); - if(hAutoPunish.IntValue & 1 == 1) - ApplyTroll(lastButtonUser, "TankMagnet", 0, TrollMod_None); - if(hAutoPunish.IntValue & 8 == 8) - ApplyTroll(lastButtonUser, "VomitPlayer", 0, TrollMod_None); - else if(hAutoPunish.IntValue & 4 == 4) - ApplyTroll(lastButtonUser, "Swarm", 0, TrollMod_None); - if(hAutoPunishExpire.IntValue > 0) { - CreateTimer(60.0 * hAutoPunishExpire.FloatValue, Timer_ResetAutoPunish, GetClientOfUserId(lastButtonUser)); - } -} - -void SetWitchTarget(int witch, int target) { - Behavior behavior = Behavior(witch, WITCH_QUERY); - BehaviorAction action = behavior.CurrentAction.Last; - - BehaviorAction newaction = view_as(AllocateMemory(18556)); - SDKCall(g_hWitchAttack, newaction, target); - - IActionResult result; result.Init(CHANGE_TO, newaction); - result.ToAction(action); -} - -bool ToggleMarkPlayer(int client, int target) { - if(g_PendingBanTroll[target]) { - g_PendingBanTroll[target] = false; - ShowActivity(client, "unmarked %N as troll", target); - return true; - }else{ - AdminId admin_client = GetUserAdmin(client); - AdminId admin_target = GetUserAdmin(target); - if(admin_client != INVALID_ADMIN_ID && admin_target == INVALID_ADMIN_ID ) { - Call_StartForward(g_PlayerMarkedForward); - Call_PushCell(client); - Call_PushCell(target); - Call_Finish(); - g_PendingBanTroll[target] = true; - ShowActivity(client, "marked %N as troll", target); - return true; - }else{ - ReplyToCommand(client, "cannot mark %N as troll as they are an admin.", target); - return false; - } - } -} - -stock int FindIdlePlayerBot(int client) { - for(int i = 1; i <= MaxClients; i++) { - if(IsClientConnected(i) && IsFakeClient(i)) { - int user = GetEntProp(i, Prop_Send, "m_humanSpectatorUserID"); - int bot = GetClientOfUserId(user); - return bot > 0 ? bot : client; - } - } - return client; -} -stock bool IsPlayerIncapped(int client) { - return GetEntProp(client, Prop_Send, "m_isIncapacitated") == 1; -} -char SPECIAL_NAMES[][] = { - "Smoker", "Boomer", "Hunter", "Spitter", "Jockey", "Charger", "Witch" -}; -stock int GetSpecialType(const char[] input) { - for(int i = 0; i < sizeof(SPECIAL_NAMES); i++) { - if(strcmp(SPECIAL_NAMES[i], input, false) == 0) return i + 1; - } - return -1; -} - -stock bool FindSuitablePosition(int target, const float pos[3], float outputPos[3], float minDistance = 19000.0, int tries = 100) { - outputPos = pos; - for(int i = tries; i > 0; i--) { - // int nav = L4D_GetNearestNavArea(pos); - // L4D_FindRandomSpot(nav, testPos); - // float dist = GetVectorDistance(testPos, pos, true); - outputPos[0] += GetRandomFloat(-30.0, 30.0); - outputPos[1] += GetRandomFloat(-30.0, 30.0); - float dist = GetVectorDistance(outputPos, pos, true); - if(dist >= minDistance && L4D2Direct_GetTerrorNavArea(outputPos) != Address_Null) { //5m^2 - return true; - } - } - return false; -} - -#define MAX_PHRASES_PER_WORD 8 -#define MAX_PHRASE_LENGTH 191 -StringMap REPLACEMENT_PHRASES; -//TODO: Load from cfg -/* Example: -exWord -{ - "1" "phrase1" - "2" "phrase2" -} -*/ -void LoadPhrases() { - KeyValues kv = new KeyValues("Phrases"); - ArrayList phrases = new ArrayList(ByteCountToCells(MAX_PHRASE_LENGTH)); - - char sPath[PLATFORM_MAX_PATH]; - BuildPath(Path_SM, sPath, sizeof(sPath), "data/ftt_phrases.cfg"); - - if(!FileExists(sPath) || !kv.ImportFromFile(sPath)) { - delete kv; - PrintToServer("[FTT] Could not load phrase list from data/ftt_phrases.cfg"); - return; - } - static char word[32]; - char phrase[MAX_PHRASE_LENGTH]; - // Go through all the words: - kv.GotoFirstSubKey(); - int i = 0; - static char buffer[4]; - do { - kv.GetSectionName(word, sizeof(word)); - phrases.Clear(); - for(;;) { - IntToString(++i, buffer, sizeof(buffer)); - kv.GetString(buffer, phrase, MAX_PHRASE_LENGTH, "_null"); - if(strcmp(phrase, "_null") == 0) break; - phrases.PushString(phrase); - } - i = 0; - REPLACEMENT_PHRASES.SetValue(word, phrases.Clone(), true); - } while (kv.GotoNextKey(false)); - delete kv; -} - -float GetIdealMinDistance(int specialType) { - switch(specialType) { - // /*Boomer*/ case 2: return 1200.0; - /*Charger*/ case 6: return 19000.0; - /*Smoker*/ case 1: return 20000.0; - - default: - return 12000.0; - } -} - -public Action Timer_Kill(Handle h, int client) { - AcceptEntityInput(client, "Kill"); -} -//TODO: Add Insta-Witch -bool SpawnSpecialInFace(int target, int specialType) { - static float pos[3], ang[3]; - static float testPos[3]; - testPos = pos; - GetClientAbsOrigin(target, pos); - GetClientEyeAngles(target, ang); - if(specialType != 5 && specialType != 2) { //If charger/hunter, find a suitable area that is at least 5 m away - float minDistance = GetIdealMinDistance(specialType); - GetHorizontalPositionFromOrigin(pos, ang, minDistance, testPos); - FindSuitablePosition(target, pos, testPos, minDistance, 100); - pos = testPos; - } else { // Else spawn a little bit off, and above (above for jockeys) - pos[2] += 10.0; - pos[0] += 5.0; - } - pos[2] += 1.0; - NegateVector(ang); - int special = (specialType == 7) ? L4D2_SpawnWitch(pos, ang) : L4D2_SpawnSpecial(specialType, pos, ang); - if(special == -1) return false; - - if(specialType == 7) - SetWitchTarget(special, target); - else - g_iAttackerTarget[special] = GetClientUserId(target); - - if(specialType == 2) { //Kill boomer - ForcePlayerSuicide(special); - } - return true; -} - -bool SpawnSpecialNear(int target, int specialType) { - static float pos[3]; - if(L4D_GetRandomPZSpawnPosition(target, specialType, 10, pos)) { - int special = (specialType == 7) ? L4D2_SpawnWitch(pos, ZERO_VECTOR) : L4D2_SpawnSpecial(specialType, pos, ZERO_VECTOR); - if(special == -1) return false; - if(specialType == 7) - SetWitchTarget(special, target); - else - g_iAttackerTarget[special] = GetClientUserId(target); - return true; - } - return false; -} \ No newline at end of file +#include +#include \ No newline at end of file diff --git a/scripting/l4d2_feedthetrolls.sp b/scripting/l4d2_feedthetrolls.sp index 8e3311a..e74e532 100644 --- a/scripting/l4d2_feedthetrolls.sp +++ b/scripting/l4d2_feedthetrolls.sp @@ -102,385 +102,6 @@ public void OnPluginStart() { // EVENTS /////////////////////////////////////////////////////////////////////////////// -public void OnPluginEnd() { - UnhookEntityOutput("func_button", "OnPressed", Event_ButtonPress); -} -public void OnMapEnd() { - UnhookEntityOutput("func_button", "OnPressed", Event_ButtonPress); -} -public void OnMapStart() { - AddFileToDownloadsTable("sound/custom/meow1.mp3"); - PrecacheSound("custom/meow1.mp3"); - - lastButtonUser = -1; - HookEntityOutput("func_button", "OnPressed", Event_ButtonPress); - CreateTimer(MAIN_TIMER_INTERVAL_S, Timer_Main, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); - PrecacheSound("player/footsteps/clown/concrete1.wav"); - //CreateTimer(30.0, Timer_AutoPunishCheck, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); -} -public void OnClientPutInServer(int client) { - g_PendingBanTroll[client] = false; - SDKHook(client, SDKHook_OnTakeDamage, Event_TakeDamage); -} -public void OnClientAuthorized(int client, const char[] auth) { - if(!IsFakeClient(client)) { - strcopy(steamids[client], 64, auth); - } -} -public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) { - int client = GetClientOfUserId(event.GetInt("userid")); - if(g_PendingBanTroll[client]) { - g_PendingBanTroll[client] = false; - if(!IsFakeClient(client) && GetUserAdmin(client) == INVALID_ADMIN_ID) { - BanIdentity(steamids[client], 0, BANFLAG_AUTHID, "TrollMarked", "ftt", 0); - } - } - steamids[client][0] = '\0'; - ActiveTrolls[client] = 0; - g_iAttackerTarget[client] = 0; -} -public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) { - int client = GetClientOfUserId(event.GetInt("userid")); - g_iAttackerTarget[client] = 0; -} -public Action Event_WeaponReload(int weapon) { - int client = GetEntPropEnt(weapon, Prop_Send, "m_hOwner"); - if(IsTrollActive(client, "GunJam")) { - float dec = GetRandomFloat(0.0, 1.0); - if(FloatCompare(dec, 0.50) == -1) { //10% chance gun jams - return Plugin_Stop; - } - } - return Plugin_Continue; -} -public Action Event_ButtonPress(const char[] output, int entity, int client, float delay) { - if(client > 0 && client <= MaxClients) { - lastButtonUser = client; - } - return Plugin_Continue; -} - -public void Event_PanicEventCreate(Event event, const char[] name, bool dontBroadcast) { - int client = GetClientOfUserId(event.GetInt("userid")); - if(client) { - lastButtonUser = client; - } -} -public void Event_CarAlarm(Event event, const char[] name, bool dontBroadcast) { - int user = event.GetInt("userid"); - int client = GetClientOfUserId(user); - if(client) { - PrintToChatAll("%N has alerted the horde!", client); - L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", user, 15000); - } - //Ignore car alarms for autopunish - lastButtonUser = -1; -} -public Action L4D2_OnChooseVictim(int attacker, int &curTarget) { - // ========================= - // OVERRIDE VICTIM - // ========================= - if(hMagnetChance.FloatValue < GetRandomFloat()) return Plugin_Continue; - L4D2Infected class = view_as(GetEntProp(attacker, Prop_Send, "m_zombieClass")); - int existingTarget = GetClientOfUserId(g_iAttackerTarget[attacker]); - if(existingTarget > 0 && IsPlayerAlive(existingTarget) && (hMagnetTargetMode.IntValue & 1 != 1 || !IsPlayerIncapped(existingTarget))) { - if(class == L4D2Infected_Tank && (hMagnetTargetMode.IntValue % 2 != 2 || !IsPlayerIncapped(existingTarget))) { - curTarget = existingTarget; - return Plugin_Changed; - }else if(hMagnetTargetMode.IntValue & 1 != 1 || !IsPlayerIncapped(existingTarget)) { - curTarget = existingTarget; - return Plugin_Changed; - } - } - - float closestDistance, survPos[3], spPos[3]; - GetClientAbsOrigin(attacker, spPos); - int closestClient = -1; - for(int i = 1; i <= MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { - //Ignore incapped players if turned on: - if(IsPlayerIncapped(i)) { - if((class == L4D2Infected_Tank && hMagnetTargetMode.IntValue & 2 == 2) || hMagnetTargetMode.IntValue & 1 == 1 ) continue; - } - - if(class == L4D2Infected_Tank && IsTrollActive(i, "TankMagnet") || (class != L4D2Infected_Tank && IsTrollActive(i, "SpecialMagnet"))) { - GetClientAbsOrigin(i, survPos); - float dist = GetVectorDistance(survPos, spPos, true); - if(closestClient == -1 || dist < closestDistance) { - closestDistance = dist; - closestClient = i; - } - } - } - } - - if(closestClient > 0) { - g_iAttackerTarget[attacker] = GetClientUserId(closestClient); - curTarget = closestClient; - return Plugin_Changed; - } - return Plugin_Continue; -} -public Action L4D2_OnEntityShoved(int client, int entity, int weapon, float vecDir[3], bool bIsHighPounce) { - if(client > 0 && client <= MaxClients && IsTrollActive(client, "NoShove") && hShoveFailChance.FloatValue > GetRandomFloat()) { - return Plugin_Handled; - } - return Plugin_Continue; -} -public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) { - if(sArgs[0] == '@') return Plugin_Continue; - if(IsTrollActive(client, "Honk")) { - static char strings[32][7]; - int words = ExplodeString(sArgs, " ", strings, sizeof(strings), 5); - for(int i = 0; i < words; i++) { - if(GetRandomFloat() <= 0.8) strings[i] = "honk"; - else strings[i] = "squeak"; - } - int length = 7 * words; - char[] message = new char[length]; - ImplodeStrings(strings, 32, " ", message, length); - CPrintToChatAll("{blue}%N {default}: %s", client, message); - PrintToServer("%N: %s", client, sArgs); - return Plugin_Handled; - }else if(IsTrollActive(client, "iCantSpellNoMore")) { - int type = GetRandomInt(1, trollKV.Size + 8); - char letterSrc, replaceChar; - switch(type) { - case 1: { - letterSrc = 'e'; - replaceChar = 'b'; - } - case 2: { - letterSrc = 't'; - replaceChar = 'e'; - } - case 3: { - letterSrc = 'i'; - replaceChar = 'e'; - } - case 4: { - letterSrc = 'a'; - replaceChar = 's'; - } - case 5: { - letterSrc = 'u'; - replaceChar = 'i'; - } - case 6: { - letterSrc = '.'; - replaceChar = '/'; - } - case 7: { - letterSrc = 'm'; - replaceChar = 'n'; - } - case 8: { - letterSrc = 'n'; - replaceChar = 'm'; - } - case 9: { - letterSrc = 'l'; - replaceChar = 'b'; - } - case 10: { - letterSrc = 'l'; - replaceChar = 'b'; - } - case 11: { - letterSrc = 'h'; - replaceChar = 'j'; - } - case 12: { - letterSrc = 'o'; - replaceChar = 'i'; - } - case 13: { - letterSrc = 'e'; - replaceChar = 'r'; - } - - default: - return Plugin_Continue; - } - int strLength = strlen(sArgs); - char[] newMessage = new char[strLength + 20]; - int n = 0; - while (sArgs[n] != '\0') { - if(sArgs[n] == letterSrc) { - newMessage[n] = replaceChar; - }else{ - newMessage[n] = sArgs[n]; - } - n++; - } - PrintToServer("%N: %s", client, sArgs); - CPrintToChatAll("{blue}%N {default}: %s", client, newMessage); - return Plugin_Handled; - }else if(IsTrollActive(client, "NoProfanity")) { - //TODO: Check all replacement words, if none were replaced then do full word - //TODO: Lowercase .getstring - static char strings[32][MAX_PHRASE_LENGTH]; - ArrayList phrases; - bool foundWord = false; - int words = ExplodeString(sArgs, " ", strings, 32, MAX_PHRASE_LENGTH); - for(int i = 0; i < words; i++) { - if(REPLACEMENT_PHRASES.GetValue(strings[i], phrases) && phrases.Length > 0) { - foundWord = true; - int c = phrases.GetString(GetRandomInt(0, phrases.Length - 1), strings[i], MAX_PHRASE_LENGTH); - PrintToServer("replacement: %s (%d)", strings[i], c); - } - } - int length = MAX_PHRASE_LENGTH * words; - char[] message = new char[length]; - if(foundWord) { - ImplodeStrings(strings, 32, " ", message, length); - } else { - REPLACEMENT_PHRASES.GetValue("_Full Message Phrases", phrases); - phrases.GetString(GetRandomInt(0, phrases.Length - 1), message, MAX_PHRASE_LENGTH); - } - CPrintToChatAll("{blue}%N {default}: %s", client, message); - PrintToServer("%N: %s", client, sArgs); - return Plugin_Handled; - } - return Plugin_Continue; -} - -public Action Event_ItemPickup(int client, int weapon) { - if(IsTrollActive(client, "NoPickup")) { - return Plugin_Stop; - }else{ - static char wpnName[64]; - GetEdictClassname(weapon, wpnName, sizeof(wpnName)); - if(StrContains(wpnName, "rifle") > -1 - || StrContains(wpnName, "smg") > -1 - || StrContains(wpnName, "weapon_grenade_launcher") > -1 - || StrContains(wpnName, "sniper") > -1 - || StrContains(wpnName, "shotgun") > -1 - ) { - //If 4: Only UZI, if 5: Can't switch. - if(IsTrollActive(client, "UziRules")) { - static char currentWpn[32]; - GetClientWeaponName(client, 0, currentWpn, sizeof(currentWpn)); - if(StrEqual(wpnName, "weapon_smg", true)) { - return Plugin_Continue; - } else if(StrEqual(currentWpn, "weapon_smg", true)) { - return Plugin_Stop; - }else{ - int flags = GetCommandFlags("give"); - SetCommandFlags("give", flags & ~FCVAR_CHEAT); - FakeClientCommand(client, "give smg"); - SetCommandFlags("give", flags); - return Plugin_Stop; - } - }else if(IsTrollActive(client, "PrimaryDisable")) { - return Plugin_Stop; - } - return Plugin_Continue; - }else{ - return Plugin_Continue; - } - } -} - -public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2]) { - if(g_bPendingItemGive[client] && !(buttons & IN_ATTACK2)) { - int target = GetClientAimTarget(client, true); - if(target > -1) { - buttons |= IN_ATTACK2; - RequestFrame(StopItemGive, client); - return Plugin_Changed; - } - return Plugin_Continue; - } - return Plugin_Continue; -} - -public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) { - //Stop FF from marked: - if(attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker) && IsPlayerAlive(attacker)) { - if(g_PendingBanTroll[attacker] && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) { - - return Plugin_Stop; - } - if(IsTrollActive(attacker, "DamageBoost")) { - damage * 2; - return Plugin_Changed; - } - } - return Plugin_Continue; -} - -public Action SoundHook(int[] clients, int& numClients, char sample[PLATFORM_MAX_PATH], int& entity, int& channel, float& volume, int& level, int& pitch, int& flags, char[] soundEntry, int& seed) { - if(lastButtonUser > -1 && StrEqual(sample, "npc/mega_mob/mega_mob_incoming.wav")) { - PrintToConsoleAll("CRESCENDO STARTED BY %N", lastButtonUser); - #if defined DEBUG - PrintToChatAll("CRESCENDO STARTED BY %N", lastButtonUser); - #endif - - lastCrescendoUser = lastButtonUser; - if(IsPlayerFarDistance(lastButtonUser, AUTOPUNISH_FLOW_MIN_DISTANCE)) { - NotifyAllAdmins("Autopunishing player %N for activation of event far from team", lastButtonUser); - ShowActivity(0, "activated autopunish for crescendo activator %N (auto)", lastButtonUser); - ActivateAutoPunish(lastButtonUser); - } - lastButtonUser = -1; - }else if(numClients > 0 && entity > 0 && entity <= MaxClients) { - if(StrContains(sample, "survivor\\voice") > -1) { - if(IsTrollActive(entity, "Honk")) { - strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav"); - return Plugin_Changed; - } else if(IsTrollActive(entity, "VocalizeGag")) { - return Plugin_Handled; - } else if(IsTrollActive(entity, "Meow")) { - strcopy(sample, sizeof(sample), "custom/meow1.mp3"); - return Plugin_Changed; - } - } - - } - return Plugin_Continue; -} - -public Action Event_WitchVictimSet(Event event, const char[] name, bool dontBroadcast) { - int witch = event.GetInt("witchid"); - float closestDistance, survPos[3], witchPos[3]; - GetEntPropVector(witch, Prop_Send, "m_vecOrigin", witchPos); - int closestClient = -1; - for(int i = 1; i <= MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { - //Ignore incapped players if hWitchIgnoreIncapp turned on: - if(IsPlayerIncapped(i) && !hWitchTargetIncapp.BoolValue) { - continue; - } - - if(IsTrollActive(i, "WitchMagnet")) { - GetClientAbsOrigin(i, survPos); - float dist = GetVectorDistance(survPos, witchPos, true); - if(closestClient == -1 || dist < closestDistance) { - closestDistance = dist; - closestClient = i; - } - } - } - } - - if(closestClient > 0) { - DataPack pack; - CreateDataTimer(0.1, Timer_NextWitchSet, pack); - pack.WriteCell(GetClientUserId(closestClient)); - pack.WriteCell(witch); - CreateDataTimer(0.2, Timer_NextWitchSet, pack); - pack.WriteCell(GetClientUserId(closestClient)); - pack.WriteCell(witch); - } -} - -public Action Timer_NextWitchSet(Handle timer, DataPack pack) { - pack.Reset(); - int client = GetClientOfUserId(pack.ReadCell()); - int witch = pack.ReadCell(); - SetWitchTarget(witch, client); -} /////////////////////////////////////////////////////////////////////////////// // CVAR CHANGES @@ -499,591 +120,16 @@ public void Change_ThrowInterval(ConVar convar, const char[] oldValue, const cha // COMMANDS /////////////////////////////////////////////////////////////////////////////// -public Action Command_InstaSpecial(int client, int args) { - if(args < 1) { - Menu menu = new Menu(Insta_PlayerHandler); - menu.SetTitle("Choose a player"); - for(int i = 1; i < MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { - static char userid[8], display[16]; - Format(userid, sizeof(userid), "%d|0", GetClientUserId(i)); - GetClientName(i, display, sizeof(display)); - menu.AddItem(userid, display); - } - } - menu.ExitButton = true; - menu.Display(client, 0); - } else { - char arg1[32], arg2[32] = "jockey"; - GetCmdArg(1, arg1, sizeof(arg1)); - if(args >= 2) { - GetCmdArg(2, arg2, sizeof(arg2)); - } - char target_name[MAX_TARGET_LENGTH]; - int target_list[MAXPLAYERS], target_count; - bool tn_is_ml; - if ((target_count = ProcessTargetString( - arg1, - client, - target_list, - MaxClients, - COMMAND_FILTER_ALIVE, - 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 specialType = GetSpecialType(arg2); - static float pos[3]; - if(specialType == -1) { - ReplyToCommand(client, "Unknown special \"%s\"", arg2); - return Plugin_Handled; - } - for (int i = 0; i < target_count; i++) { - int target = target_list[i]; - if(GetClientTeam(target) == 2) { - SpawnSpecialNear(target, specialType); - }else{ - ReplyToTargetError(client, target_count); - } - } - ShowActivity(client, "spawned Insta-%s™ near %s", arg2, target_name); - } - - - return Plugin_Handled; -} - -public Action Command_InstaSpecialFace(int client, int args) { - if(args < 1) { - Menu menu = new Menu(Insta_PlayerHandler); - menu.SetTitle("Choose a player"); - for(int i = 1; i < MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { - static char userid[8], display[16]; - Format(userid, sizeof(userid), "%d|1", GetClientUserId(i)); - GetClientName(i, display, sizeof(display)); - menu.AddItem(userid, display); - } - } - menu.ExitButton = true; - menu.Display(client, 0); - } else { - char arg1[32], arg2[32] = "jockey"; - GetCmdArg(1, arg1, sizeof(arg1)); - if(args >= 2) { - GetCmdArg(2, arg2, sizeof(arg2)); - } - char target_name[MAX_TARGET_LENGTH]; - int target_list[MAXPLAYERS], target_count; - bool tn_is_ml; - if ((target_count = ProcessTargetString( - arg1, - client, - target_list, - MaxClients, - COMMAND_FILTER_ALIVE, - 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 specialType = GetSpecialType(arg2); - static float pos[3]; - if(specialType == -1) { - ReplyToCommand(client, "Unknown special \"%s\"", arg2); - return Plugin_Handled; - } - for (int i = 0; i < target_count; i++) { - int target = target_list[i]; - if(GetClientTeam(target) == 2) { - SpawnSpecialInFace(target, specialType); - }else{ - ReplyToTargetError(client, target_count); - } - } - ShowActivity(client, "spawned Insta-%s™ on %s", arg2, target_name); - } - return Plugin_Handled; -} - - -public Action Command_WitchAttack(int client, int args) { - if(args < 1) { - ReplyToCommand(client, "Usage: sm_witch_attack "); - } else { - char arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - char target_name[MAX_TARGET_LENGTH]; - int target_list[MAXPLAYERS], target_count; - bool tn_is_ml; - if ((target_count = ProcessTargetString( - arg1, - client, - target_list, - 1, - COMMAND_FILTER_ALIVE | COMMAND_FILTER_NO_MULTI, /* 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 target = target_list[0]; - if(GetClientTeam(target) == 2) { - int witch = INVALID_ENT_REFERENCE; - while ((witch = FindEntityByClassname(witch, "witch")) != INVALID_ENT_REFERENCE) { - SetWitchTarget(witch, target); - - ShowActivity(client, "all witches target %s", target_name); - } - }else{ - ReplyToTargetError(client, target_count); - } - } - - return Plugin_Handled; -} - -public Action Command_FeedTheCrescendoTroll(int client, int args) { - if(lastCrescendoUser > -1) { - ActivateAutoPunish(lastCrescendoUser); - ReplyToCommand(client, "Activated auto punish on %N", lastCrescendoUser); - ShowActivity(client, "activated autopunish for crescendo activator %N",lastCrescendoUser); - }else{ - ReplyToCommand(client, "No player could be found to autopunish."); - } - return Plugin_Handled; -} - -public Action Command_ResetUser(int client, int args) { - if(args < 1) { - ReplyToCommand(client, "Usage: sm_ftr "); - }else{ - char arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - char target_name[MAX_TARGET_LENGTH]; - int target_list[MAXPLAYERS], target_count; - bool tn_is_ml; - if ((target_count = ProcessTargetString( - arg1, - client, - target_list, - MAXPLAYERS, - COMMAND_FILTER_CONNECTED, /* 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; - } - - for (int i = 0; i < target_count; i++) { - if(ActiveTrolls[target_list[i]] > 0) { - ResetClient(target_list[i], true); - ShowActivity(client, "reset troll effects on \"%N\". ", target_list[i]); - } - } - } - return Plugin_Handled; -} - -public Action Command_ApplyUser(int client, int args) { - if(args < 2) { - Menu menu = new Menu(ChoosePlayerHandler); - menu.SetTitle("Choose a player"); - for(int i = 1; i < MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { - static char userid[8], display[16]; - Format(userid, sizeof(userid), "%d", GetClientUserId(i)); - GetClientName(i, display, sizeof(display)); - menu.AddItem(userid, display); - } - } - menu.ExitButton = true; - menu.Display(client, 0); - }else{ - char arg1[32], arg2[32], arg3[8]; - GetCmdArg(1, arg1, sizeof(arg1)); - GetCmdArg(2, arg2, sizeof(arg2)); - GetCmdArg(3, arg3, sizeof(arg3)); - - bool silent = StrEqual(arg3, "silent") || StrEqual(arg3, "quiet") || StrEqual(arg3, "mute"); - static char name[MAX_TROLL_NAME_LENGTH]; - if(!GetTrollID(StringToInt(arg2), name)) { - ReplyToCommand(client, "Not a valid mode. Must be greater than 0. Usage: sm_fta [player] [mode]. Use sm_ftr to reset."); - }else{ - char target_name[MAX_TARGET_LENGTH]; - int target_list[MAXPLAYERS], target_count; - bool tn_is_ml; - if ((target_count = ProcessTargetString( - arg1, - client, - target_list, - MAXPLAYERS, - 0, - 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; - } - - for (int i = 0; i < target_count; i++) { - if(IsClientInGame(target_list[i]) && GetClientTeam(target_list[i]) == 2) - ApplyTroll(target_list[i], name, client,TrollMod_None, silent); - } - } - } - return Plugin_Handled; -} - -public Action Command_ListModes(int client, int args) { - static char name[MAX_TROLL_NAME_LENGTH]; - static Troll troll; - for(int i = 0; i <= MAX_TROLLS; i++) { - GetTrollByKeyIndex(i, troll); - ReplyToCommand(client, "%d. %s - %s", i, troll.name, troll.description); - } - return Plugin_Handled; -} - -public Action Command_ListTheTrolls(int client, int args) { - int count = 0; - //TODO: Update - char[][] modeListArr = new char[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH]; - static char modeList[255]; - for(int i = 1; i < MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && ActiveTrolls[i] > 0) { - int modeCount = 0; - static char name[MAX_TROLL_NAME_LENGTH]; - for(int j = 1; j <= MAX_TROLLS; j++) { - GetTrollID(j, name); - if(IsTrollActive(i, name)) { - strcopy(modeListArr[modeCount], MAX_TROLL_NAME_LENGTH, name); - modeCount++; - } - } - - ImplodeStrings(modeListArr, modeCount, ", ", modeList, sizeof(modeList)); - ReplyToCommand(client, "%N | %s", i, modeList); - count++; - } - } - if(count == 0) { - ReplyToCommand(client, "No clients have a mode applied."); - } - return Plugin_Handled; -} - -public Action Command_MarkPendingTroll(int client, int args) { - if(args == 0) { - Menu menu = new Menu(ChooseMarkedTroll); - menu.SetTitle("Choose a troll to mark"); - static char userid[8], display[16]; - for(int i = 1; i < MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { - AdminId admin = GetUserAdmin(i); - if(admin == INVALID_ADMIN_ID) { - Format(userid, sizeof(userid), "%d", GetClientUserId(i)); - GetClientName(i, display, sizeof(display)); - menu.AddItem(userid, display); - }else{ - ReplyToCommand(client, "%N is an admin cannot be marked.", i); - } - } - } - menu.ExitButton = true; - menu.Display(client, 0); - } else { - char arg1[32]; - GetCmdArg(1, arg1, sizeof(arg1)); - char target_name[MAX_TARGET_LENGTH]; - int target_list[MAXPLAYERS], target_count; - bool tn_is_ml; - if ((target_count = ProcessTargetString( - arg1, - client, - target_list, - 1, - COMMAND_FILTER_NO_MULTI , /* 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 target = target_list[0]; - if(GetClientTeam(target) == 2) { - ToggleMarkPlayer(client, target); - }else{ - ReplyToCommand(client, "Player does not exist or is not a survivor."); - } - } - return Plugin_Handled; -} - -public Action Command_FeedTheTrollMenu(int client, int args) { - ReplyToCommand(client, "sm_ftl - Lists all the active trolls on players"); - ReplyToCommand(client, "sm_ftm - Lists all available troll modes & descriptions"); - ReplyToCommand(client, "sm_ftr - Resets target users' of their trolls"); - ReplyToCommand(client, "sm_fta - Applies a troll mode on targets"); - ReplyToCommand(client, "sm_ftt - Opens this menu"); - ReplyToCommand(client, "sm_ftc - Will apply a punishment to last crescendo activator"); - ReplyToCommand(client, "sm_mark - Marks the user to be banned on disconnect, prevents their FF."); - return Plugin_Handled; -} /////////////////////////////////////////////////////////////////////////////// // MENU HANDLER /////////////////////////////////////////////////////////////////////////////// -public int Insta_PlayerHandler(Menu menu, MenuAction action, int client, int param2) { - /* If an option was selected, tell the client about the item. */ - if (action == MenuAction_Select) { - static char info[16]; - menu.GetItem(param2, info, sizeof(info)); - - static char str[2][8]; - ExplodeString(info, "|", str, 2, 8, false); - - int userid = StringToInt(str[0]); - int instaMode = StringToInt(str[1]); - - Menu spMenu = new Menu(Insta_SpecialHandler); - spMenu.SetTitle("Choose a Insta-Special™"); - for(int i = 1; i <= 6; i++) { - static char id[8]; - Format(id, sizeof(id), "%d|%d|%d", userid, instaMode, i); - spMenu.AddItem(id, SPECIAL_NAMES[i-1]); - } - spMenu.ExitButton = true; - spMenu.Display(client, 0); - } else if (action == MenuAction_End) - delete menu; -} - -public int Insta_SpecialHandler(Menu menu, MenuAction action, int client, int param2) { - /* If an option was selected, tell the client about the item. */ - if (action == MenuAction_Select) { - static char info[16]; - menu.GetItem(param2, info, sizeof(info)); - static char str[3][8]; - ExplodeString(info, "|", str, 3, 8, false); - int target = GetClientOfUserId(StringToInt(str[0])); - bool inFace = StrEqual(str[1], "1"); - int special = StringToInt(str[2]); - if(inFace) { - SpawnSpecialInFace(target, special); - ShowActivity(client, "spawned Insta-%s™ near %N", SPECIAL_NAMES[special-1], target); - } else { - SpawnSpecialNear(target, special); - ShowActivity(client, "spawned Insta-%s™ near %N", SPECIAL_NAMES[special-1], target); - } - } else if (action == MenuAction_End) - delete menu; -} - - -public int ChooseMarkedTroll(Menu menu, MenuAction action, int activator, int param2) { - if (action == MenuAction_Select) { - static char info[16]; - menu.GetItem(param2, info, sizeof(info)); - int target = GetClientOfUserId(StringToInt(info)); - ToggleMarkPlayer(activator, target); - } else if (action == MenuAction_End) - delete menu; -} - -public int ChoosePlayerHandler(Menu menu, MenuAction action, int param1, int param2) { - /* If an option was selected, tell the client about the item. */ - if (action == MenuAction_Select) { - static char info[16]; - menu.GetItem(param2, info, sizeof(info)); - int userid = StringToInt(info); - - Menu trollMenu = new Menu(ChooseModeMenuHandler); - trollMenu.SetTitle("Choose a troll mode"); - //TODO: Update - static char id[8]; - static char name[MAX_TROLL_NAME_LENGTH]; - for(int i = 0; i <= MAX_TROLLS; i++) { - GetTrollID(i, name); - // int trollIndex = GetTrollByKeyIndex(i, troll); - // Pass key index - Format(id, sizeof(id), "%d|%d", userid, i); - trollMenu.AddItem(id, name); - } - trollMenu.ExitButton = true; - trollMenu.Display(param1, 0); - } else if (action == MenuAction_End) - delete menu; -} - -public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int param2) { - /* If an option was selected, tell the client about the item. */ - if (action == MenuAction_Select) { - static char info[16]; - menu.GetItem(param2, info, sizeof(info)); - static char str[2][8]; - ExplodeString(info, "|", str, 2, 8, false); - int userid = StringToInt(str[0]); - int client = GetClientOfUserId(userid); - int keyIndex = StringToInt(str[1]); - static Troll troll; - static char trollID[MAX_TROLL_NAME_LENGTH]; - GetTrollByKeyIndex(keyIndex, troll); - troll.GetID(trollID, MAX_TROLL_NAME_LENGTH); - //If mode has an option to be single-time fired/continous/both, prompt: - if(!troll.runsOnce) { - Menu modiferMenu = new Menu(ChooseTrollModiferHandler); - modiferMenu.SetTitle("Choose Troll Modifer Option"); - static char singleUse[16], multiUse[16], bothUse[16]; - Format(singleUse, sizeof(singleUse), "%d|%d|1", userid, keyIndex); - Format(multiUse, sizeof(multiUse), "%d|%d|2", userid, keyIndex); - Format(bothUse, sizeof(bothUse), "%d|%d|3", userid, keyIndex); - modiferMenu.AddItem(singleUse, "Activate once"); - modiferMenu.AddItem(multiUse, "Activate Periodically"); - modiferMenu.AddItem(bothUse, "Activate Periodically & Instantly"); - modiferMenu.ExitButton = true; - modiferMenu.Display(param1, 0); - } else { - ApplyTroll(client, trollID, param1, TrollMod_None); - } - } else if (action == MenuAction_End) - delete menu; -} - -public int ChooseTrollModiferHandler(Menu menu, MenuAction action, int param1, int param2) { - if (action == MenuAction_Select) { - static char info[16]; - menu.GetItem(param2, info, sizeof(info)); - static char str[3][8]; - ExplodeString(info, "|", str, 3, 8, false); - int client = GetClientOfUserId(StringToInt(str[0])); - int keyIndex = StringToInt(str[1]); - static Troll troll; - static char trollID[MAX_TROLL_NAME_LENGTH]; - GetTrollByKeyIndex(keyIndex, troll); - troll.GetID(trollID, MAX_TROLL_NAME_LENGTH); - int modifier = StringToInt(str[2]); - if(modifier == 2 || modifier == 3) - ApplyTroll(client, trollID, param1, TrollMod_Repeat); - else - ApplyTroll(client, trollID, param1, TrollMod_InstantFire); - } else if (action == MenuAction_End) - delete menu; -} - -public void StopItemGive(int client) { - g_bPendingItemGive[client] = false; -} /////////////////////////////////////////////////////////////////////////////// // TIMERS /////////////////////////////////////////////////////////////////////////////// -public Action Timer_ThrowTimer(Handle timer) { - int count = 0; - for(int i = 1; i < MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && IsTrollActive(i, "ThrowItAll")) { - ThrowAllItems(i); - count++; - } - } - return count > 0 ? Plugin_Continue : Plugin_Stop; -} - -public Action Timer_Main(Handle timer) { - static int loop; - for(int i = 1; i <= MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i)) { - if(IsTrollActive(i, "SlowDrain")) { - if(loop % 4 == 0) { - int hp = GetClientHealth(i); - if(hp > 50) { - SetEntProp(i, Prop_Send, "m_iHealth", hp - 1); - } - } - }else if(IsTrollActive(i, "TempHealthQuickDrain")) { - if(loop % 2 == 0) { - float bufferTime = GetEntPropFloat(i, Prop_Send, "m_healthBufferTime"); - float buffer = GetEntPropFloat(i, Prop_Send, "m_healthBuffer"); - float tempHealth = GetTempHealth(i); - if(tempHealth > 0.0) { - PrintToConsole(i, "%f | %f %f", tempHealth, buffer, bufferTime); - //SetEntPropFloat(i, Prop_Send, "m_healthBuffer", buffer - 10.0); - SetEntPropFloat(i, Prop_Send, "m_healthBufferTime", bufferTime - 7.0); - } - } - }else if(IsTrollActive(i, "Swarm")) { - L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", GetClientUserId(i), 15000); - } - } - } - if(++loop >= 60) { - loop = 0; - } - return Plugin_Continue; -} - -public Action Timer_GivePistol(Handle timer, int client) { - int flags = GetCommandFlags("give"); - SetCommandFlags("give", flags & ~FCVAR_CHEAT); - FakeClientCommand(client, "give pistol"); - SetCommandFlags("give", flags|FCVAR_CHEAT); -} - -public Action Timer_ThrowWeapon(Handle timer, Handle pack) { - ResetPack(pack); - float dest[3]; - dest[0] = ReadPackFloat(pack); - dest[1] = ReadPackFloat(pack); - dest[2] = ReadPackFloat(pack); - int slot = ReadPackCell(pack); - int victim = ReadPackCell(pack); - - int wpnRef = GetPlayerWeaponSlot(victim, slot); - if(wpnRef != -1) { - int wpn = EntRefToEntIndex(wpnRef); - if(wpn != INVALID_ENT_REFERENCE) { - if(slot == 1) { - static char name[16]; - GetEdictClassname(wpn, name, sizeof(name)); - if(!StrEqual(name, "weapon_pistol", false)) { - SDKHooks_DropWeapon(victim, wpn, dest); - CreateTimer(0.2, Timer_GivePistol, victim); - } - }else - SDKHooks_DropWeapon(victim, wpn, dest); - } - } -} - -public Action Timer_ResetAutoPunish(Handle timer, int user) { - int client = GetClientOfUserId(user); - if(client) { - if(hAutoPunish.IntValue & 2 == 2) - DisableTroll(client, "SpecialMagnet"); - if(hAutoPunish.IntValue & 1 == 1) - DisableTroll(client, "TankMagnet"); - } -} // ///////////////////////////////////////////////////////////////////////////// // NATIVES & FORWARDS