diff --git a/plugins/l4d2_feedthetrolls.smx b/plugins/l4d2_feedthetrolls.smx index 255bd73..eb5ba6e 100644 Binary files a/plugins/l4d2_feedthetrolls.smx and b/plugins/l4d2_feedthetrolls.smx differ diff --git a/scripting/include/feedthetrolls/base.inc b/scripting/include/feedthetrolls/base.inc index bf5de3c..6aa8277 100644 --- a/scripting/include/feedthetrolls/base.inc +++ b/scripting/include/feedthetrolls/base.inc @@ -1,6 +1,6 @@ #define MAX_TROLL_NAME_LENGTH 32 -#define MAX_TROLLS 25 +#define MAX_TROLLS 28 //#define DEBUG 1 enum trollModifier { @@ -11,14 +11,17 @@ enum trollModifier { enum struct Troll { - char name[32]; + char name[MAX_TROLL_NAME_LENGTH]; char description[128]; bool runsOnce; int flags; + int categoryID; - void GetID(char[] name, int length) { - strcopy(name, length, this.name); + char _id[MAX_TROLL_NAME_LENGTH]; + + void GetID(char[] name) { + strcopy(name, MAX_TROLL_NAME_LENGTH, this.name); ReplaceString(name, MAX_TROLL_NAME_LENGTH, " ", "", false); } @@ -33,6 +36,10 @@ enum struct Troll { else if(this.flags == view_as(TrollMod_Constant)) return TrollMod_Constant; else return TrollMod_Invalid; } + + void Activate(int victim, int activator, trollModifier modifier, bool silent = false) { + ApplyTroll(victim, this._id, activator, modifier, silent); + } } Troll Trolls[MAX_TROLLS+1]; @@ -50,7 +57,8 @@ void ResetClient(int victim, bool wipe = true) { if(wpn > -1) SDKUnhook(wpn, SDKHook_Reload, Event_WeaponReload); } - +ArrayList categories; +static int categoryID = 0; int SetupTroll(const char[] name, const char description[128], int flags) { if(flags == 0) { ThrowError("Troll \"%s\" has no flags defined.", name); @@ -59,11 +67,13 @@ 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].categoryID = categoryID; 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); strcopy(trollIds[i], MAX_TROLL_NAME_LENGTH, key); + strcopy(Trolls[i]._id, MAX_TROLL_NAME_LENGTH, key); trollKV.SetValue(key, i); return i++; } @@ -110,7 +120,9 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi victim = FindIdlePlayerBot(victim); } - ApplyAffect(victim, name, activator, modifier); + if(!ApplyAffect(victim, name, activator, modifier)) { + return; + } if(!silent) { if(IsTrollActive(victim, name)) { @@ -127,11 +139,11 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi } } -void ApplyAffect(int victim, const char[] name, int activator, trollModifier modifier) { +bool ApplyAffect(int victim, const char[] name, int activator, trollModifier modifier) { if(StrEqual(name, "ResetTroll")) { ShowActivity(activator, "reset troll effects for %N. ", victim); ActiveTrolls[victim] = 0; - return; + return false; } else if(StrEqual(name, "SlowSpeed")) SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 0.8); else if(StrEqual(name, "HigherGravity")) @@ -151,26 +163,6 @@ void ApplyAffect(int victim, const char[] name, int activator, trollModifier mod DisableTroll(victim, "UziRules"); DisableTroll(victim, "PrimaryDisable"); SDKHook(victim, SDKHook_WeaponCanUse, Event_ItemPickup); - } else if(StrEqual(name, "Clumsy")) { - int wpn = GetClientSecondaryWeapon(victim); - bool hasMelee = DoesClientHaveMelee(victim); - if(hasMelee) { - float pos[3]; - int clients[4]; - GetClientAbsOrigin(victim, pos); - int clientCount = GetClientsInRange(pos, RangeType_Visibility, clients, sizeof(clients)); - for(int i = 0; i < clientCount; i++) { - if(clients[i] != victim) { - float targPos[3]; - GetClientAbsOrigin(clients[i], targPos); - SDKHooks_DropWeapon(victim, wpn, targPos); - // g_iTrollUsers[victim] = mode; - CreateTimer(0.2, Timer_GivePistol); - return; - } - } - SDKHooks_DropWeapon(victim, wpn); - } } else if(StrEqual(name, "CameTooEarly")) { ReplyToCommand(activator, "This troll mode is not implemented."); } else if(StrEqual(name, "KillMeSoftly")) { @@ -181,10 +173,10 @@ void ApplyAffect(int victim, const char[] name, int activator, trollModifier mod g_bPendingItemGive[victim] = true; }else{ ReplyToCommand(activator, "User does not have pills or adrenaline"); - return; + return false; } //TODO: Implement TrollMod_Constant - return; + return false; } else if(StrEqual(name, "ThrowItAll")) { if(modifier == TrollMod_Instant) ThrowAllItems(victim); @@ -198,7 +190,7 @@ void ApplyAffect(int victim, const char[] name, int activator, trollModifier mod }else{ ReplyToCommand(activator, "Invalid modifier for mode."); - return; + return false; } } else if(StrEqual(name, "GunJam")) { int wpn = GetClientWeaponEntIndex(victim, 0); @@ -208,12 +200,19 @@ void ApplyAffect(int victim, const char[] name, int activator, trollModifier mod ReplyToCommand(activator, "Victim does not have a primary weapon."); } else if(StrEqual(name, "VomitPlayer")) L4D_CTerrorPlayer_OnVomitedUpon(victim, victim); - else { + else if(StrEqual(name, "InfaceSpecial")) { + FakeClientCommand(victim, "sm_inface"); + return false; + } else if(StrEqual(name, "InstaSpecial")) { + FakeClientCommand(victim, "sm_insta"); + return false; + } else { #if defined DEBUG PrintToServer("[FTT] Possibly invalid troll, no action: %s", name); ReplyToCommand(activator, "[FTT/Debug] If nothing occurs, this troll possibly was not implemented correctly. "); #endif } + return true; } bool IsTrollActive(int client, const char[] troll) { @@ -238,34 +237,53 @@ void DisableTroll(int client, const char[] troll) { } } +void SetCategory(const char[] newCat) { + categoryID = categories.PushString(newCat); +} +void GetCategory(int category, char[] buffer, int size) { + categories.GetString(category, buffer, size); +} void SetupTrolls() { trollKV = new StringMap(); + categories = new ArrayList(ByteCountToCells(16)); SetupTroll("Reset Troll", "Resets the user, removes all troll effects", TrollMod_Instant); + + SetCategory("Magnet / Horde"); 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("Swarm", "Swarms a player with zombies. Requires swarm plugin", TrollMod_Instant | TrollMod_Constant); SetupTroll("Vomit Player", "Shortcut to sm_vomitplayer. vomits the player.", TrollMod_Instant); - SetupTroll("Throw It All", "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("Primary Disable", "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("Gun Jam", "On reload, small chance their gun gets jammed - Can't reload.", TrollMod_Constant); + SetupTroll("Inface Special", "Shortcut to sm_inface", TrollMod_Instant); + SetupTroll("Insta Special", "Shortcut to sm_insta", TrollMod_Instant); + + SetCategory("Items"); + SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant); + SetupTroll("Bad Throw", "Player drops throwables on throw, and biles/molotovs themselves", TrollMod_Constant); SetupTroll("No Pickup", "Prevents a player from picking up ANY (new) item. Use ThrowItAll to make them drop", TrollMod_Constant); + SetupTroll("UziRules", "Picking up a weapon gives them a UZI instead", TrollMod_Constant); + SetupTroll("Primary Disable", "Player cannot pickup any weapons, only melee/pistols", TrollMod_Constant); + SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", TrollMod_Instant); + + SetCategory("Chat"); + SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", TrollMod_Instant); + SetupTroll("No Profanity", "Replaces some words with random phrases", TrollMod_Constant); + SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant); SetupTroll("Honk", "Honk", TrollMod_Constant); - SetupTroll("No Shove", "Prevents a player from shoving", TrollMod_Constant); + SetupTroll("Meow", "Makes the player meow", TrollMod_Constant); + + SetCategory("Health"); 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("KillMeSoftly", "Make player eat or waste pills whenever possible", TrollMod_Instant | TrollMod_Constant); + + SetCategory("Misc"); + SetupTroll("Gun Jam", "On reload, small chance their gun gets jammed - Can't reload.", 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("No Shove", "Prevents a player from shoving", TrollMod_Constant); SetupTroll("CameTooEarly", "When they shoot, random chance they empty whole clip", TrollMod_Constant); - SetupTroll("Meow", "Makes the player meow", TrollMod_Constant); //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 index 1255342..2b050b7 100644 --- a/scripting/include/feedthetrolls/commands.inc +++ b/scripting/include/feedthetrolls/commands.inc @@ -1,7 +1,7 @@ public Action Command_InstaSpecial(int client, int args) { if(args < 1) { Menu menu = new Menu(Insta_PlayerHandler); - menu.SetTitle("Choose a player"); + menu.SetTitle("InstaSpecial: 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]; @@ -59,7 +59,7 @@ public Action Command_InstaSpecial(int client, int args) { public Action Command_InstaSpecialFace(int client, int args) { if(args < 1) { Menu menu = new Menu(Insta_PlayerHandler); - menu.SetTitle("Choose a player"); + menu.SetTitle("Inface: 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]; @@ -201,7 +201,7 @@ public Action Command_ResetUser(int client, int args) { public Action Command_ApplyUser(int client, int args) { if(args < 2) { Menu menu = new Menu(ChoosePlayerHandler); - menu.SetTitle("Choose a player"); + menu.SetTitle("Choose a player to troll"); for(int i = 1; i < MaxClients; i++) { if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { static char userid[8], display[16]; diff --git a/scripting/include/feedthetrolls/events.inc b/scripting/include/feedthetrolls/events.inc index 51417eb..f5bf90a 100644 --- a/scripting/include/feedthetrolls/events.inc +++ b/scripting/include/feedthetrolls/events.inc @@ -12,6 +12,8 @@ public void OnMapStart() { 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"); + PrecacheSound("weapons/ceda_jar/ceda_jar_explode.wav"); + PrecacheSound("weapons/molotov/molotov_detonate_1.wav"); //CreateTimer(30.0, Timer_AutoPunishCheck, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); } public void OnClientPutInServer(int client) { @@ -219,7 +221,8 @@ public Action OnClientSayCommand(int client, const char[] command, const char[] int words = ExplodeString(sArgs, " ", strings, 32, MAX_PHRASE_LENGTH); for(int i = 0; i < words; i++) { //TODO: Check for valid working - if((phrases = GetPhrasesArray(strings[i])) && phrases.Length > 0) { + phrases = GetPhrasesArray(strings[i]); + if(phrases != null && 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); @@ -368,4 +371,48 @@ public Action Event_WitchVictimSet(Event event, const char[] name, bool dontBroa pack.WriteCell(GetClientUserId(closestClient)); pack.WriteCell(witch); } +} + +public void OnEntityCreated(int entity, const char[] classname) { + if(IsValidEntity(entity) && StrContains(classname, "_projectile", true) > -1 ) { + RequestFrame(EntityCreateCallback, entity); + } +} +void EntityCreateCallback(int entity) { + if(!HasEntProp(entity, Prop_Send, "m_hOwnerEntity") || !IsValidEntity(entity)) return; + static char class[16]; + + GetEntityClassname(entity, class, sizeof(class)); + int entOwner = GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity"); + if(entOwner > 0 && entOwner <= MaxClients && IsTrollActive(entOwner, "BadThrow")) { + static float pos[3]; + GetClientEyePosition(entOwner, pos); + if(StrContains(class, "vomitjar", true) > -1) { + AcceptEntityInput(entity, "Kill"); + if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() > hBadThrowHitSelf.FloatValue) { + L4D_CTerrorPlayer_OnVomitedUpon(entOwner, entOwner); + EmitSoundToAll("weapons/ceda_jar/ceda_jar_explode.wav", entOwner); + FindClosestClient(entOwner, false, pos); + } + SpawnItem("vomitjar", pos); + } else if(StrContains(class, "molotov", true) > -1) { + // Burn them if no one near :) + if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() > hBadThrowHitSelf.FloatValue) { + GetClientAbsOrigin(entOwner, pos); + if(IsAnyPlayerNear(entOwner, 500.0)) { + AcceptEntityInput(entity, "Kill"); + EmitSoundToAll("weapons/molotov/molotov_detonate_1.wav", entOwner); + } else { // or delete if there is + TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR); + } + } else { + SpawnItem("molotov", pos); + AcceptEntityInput(entity, "Kill"); + } + } else if(StrContains(class, "pipe_bomb", true) > -1) { + if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() > hBadThrowHitSelf.FloatValue) + TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR); + SpawnItem("pipe_bomb", pos); + } + } } \ No newline at end of file diff --git a/scripting/include/feedthetrolls/menus.inc b/scripting/include/feedthetrolls/menus.inc index d5b8726..63a2e6d 100644 --- a/scripting/include/feedthetrolls/menus.inc +++ b/scripting/include/feedthetrolls/menus.inc @@ -13,9 +13,8 @@ public int Insta_PlayerHandler(Menu menu, MenuAction action, int client, int par 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]); + Format(info, sizeof(info), "%d|%d|%d", userid, instaMode, i); + spMenu.AddItem(info, SPECIAL_NAMES[i-1]); } spMenu.ExitButton = true; spMenu.Display(client, 0); @@ -58,21 +57,42 @@ public int ChooseMarkedTroll(Menu menu, MenuAction action, int activator, int pa 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]; + static char info[8]; menu.GetItem(param2, info, sizeof(info)); int userid = StringToInt(info); + SetupCategoryMenu(param1, userid); + } else if (action == MenuAction_End) + delete menu; +} + +public int ChooseCategoryHandler(Menu menu, MenuAction action, int param1, int param2) { + if (action == MenuAction_Select) { + static char info[32]; + menu.GetItem(param2, info, sizeof(info)); + static char str[2][8]; + ExplodeString(info, "|", str, 2, 8, false); + int userid = StringToInt(str[0]); + int category = StringToInt(str[1]); + Menu trollMenu = new Menu(ChooseModeMenuHandler); - trollMenu.SetTitle("Choose a troll mode"); + GetCategory(category, info, sizeof(info)); + Format(info, sizeof(info), "Category: %s", info); + trollMenu.SetTitle(info); //TODO: Update - static char id[8]; static Troll troll; - for(int i = 0; i <= MAX_TROLLS; i++) { + + // add 'return' btn + Format(info, sizeof(info), "%d|-1", userid); + trollMenu.AddItem(info, "<= Go Back"); + + // Add all menus that have same category + for(int i = 0; i < trollKV.Size; i++) { GetTrollByKeyIndex(i, troll); - // int trollIndex = GetTrollByKeyIndex(i, troll); - // Pass key index - Format(id, sizeof(id), "%d|%d", userid, i); - trollMenu.AddItem(id, troll.name); + if(troll.categoryID == category) { + Format(info, sizeof(info), "%d|%d", userid, i); + trollMenu.AddItem(info, troll.name); + } } trollMenu.ExitButton = true; trollMenu.Display(param1, 0); @@ -81,7 +101,6 @@ public int ChoosePlayerHandler(Menu menu, MenuAction action, int param1, int par } 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)); @@ -90,21 +109,44 @@ public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int p int userid = StringToInt(str[0]); int client = GetClientOfUserId(userid); int keyIndex = StringToInt(str[1]); + if(keyIndex == -1) { + SetupCategoryMenu(param1, userid); + return; + } static Troll troll; static char trollID[MAX_TROLL_NAME_LENGTH]; GetTrollByKeyIndex(keyIndex, troll); - troll.GetID(trollID, MAX_TROLL_NAME_LENGTH); + troll.GetID(trollID); //If troll has multiple flags, prompt: - if(troll.HasMod(TrollMod_Instant) && troll.HasMod(TrollMod_Constant)) { + if(StrEqual(trollID, "ThrowItAll")) { + // Setup menu to call itself, but with an extra data point + Menu itmMenu = new Menu(ChooseClumsySlotHandler); + itmMenu.SetTitle("Choose Item To Throw"); + + static char itmName[32]; + Format(info, sizeof(info), "%d|-1", userid); + itmMenu.AddItem(info, "All Items"); + for(int slot = 0; slot <= 4; slot++) { + int item = GetPlayerWeaponSlot(client, slot); + if(item > -1) { + GetEdictClassname(item, itmName, sizeof(itmName)); + Format(info, sizeof(info), "%d|%d", userid, slot); + itmMenu.AddItem(info, itmName[7]); + } + } + itmMenu.ExitButton = true; + itmMenu.Display(param1, 0); + } else if(troll.HasMod(TrollMod_Instant) && troll.HasMod(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"); + + Format(info, sizeof(info), "%d|%d|1", userid, keyIndex); + modiferMenu.AddItem(info, "Activate once"); + Format(info, sizeof(info), "%d|%d|2", userid, keyIndex); + modiferMenu.AddItem(info, "Activate Periodically"); + Format(info, sizeof(info), "%d|%d|3", userid, keyIndex); + modiferMenu.AddItem(info, "Activate Periodically & Instantly"); + modiferMenu.ExitButton = true; modiferMenu.Display(param1, 0); } else { @@ -114,6 +156,27 @@ public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int p delete menu; } +public int ChooseClumsySlotHandler(Menu menu, MenuAction action, int param1, int param2) { + if (action == MenuAction_Select) { + static char info[8]; + menu.GetItem(param2, info, sizeof(info)); + static char str[2][8]; + ExplodeString(info, "|", str, 2, 8, false); + int client = GetClientOfUserId(StringToInt(str[0])); + int slot = StringToInt(str[1]); + PrintToChatAll("%d", slot); + if(slot == -1) { + for(int i = 0; i <= 4; i++) { + ThrowItemToClosestPlayer(client, i); + } + } else { + ThrowItemToClosestPlayer(client, slot); + } + ShowActivity(param1, "activated troll \"Throw It All\" for %N. ", client); + } 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]; @@ -122,19 +185,34 @@ public int ChooseTrollModiferHandler(Menu menu, MenuAction action, int param1, i 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 flags = StringToInt(str[2]); + + static Troll troll; + GetTrollByKeyIndex(keyIndex, troll); + if(flags == 1 || flags == 3) - ApplyTroll(client, trollID, param1, TrollMod_Instant); + troll.Activate(client, param1, TrollMod_Instant); + // ApplyTroll(client, trollID, param1, TrollMod_Instant); if(flags == 2 || flags == 3) - ApplyTroll(client, trollID, param1, TrollMod_Constant); + troll.Activate(client, param1, TrollMod_Constant); + // ApplyTroll(client, trollID, param1, TrollMod_Constant); } else if (action == MenuAction_End) delete menu; } public void StopItemGive(int client) { g_bPendingItemGive[client] = false; +} + +void SetupCategoryMenu(int client, int victimUserID) { + Menu categoryMenu = new Menu(ChooseCategoryHandler); + categoryMenu.SetTitle("Choose a troll category"); + static char category[16], id[8]; + for(int i = 0; i < categories.Length; i++) { + categories.GetString(i, category, sizeof(category)); + Format(id, sizeof(id), "%d|%d", victimUserID, i); + categoryMenu.AddItem(id, category); + } + categoryMenu.ExitButton = true; + categoryMenu.Display(client, 0); } \ No newline at end of file diff --git a/scripting/include/feedthetrolls/misc.inc b/scripting/include/feedthetrolls/misc.inc index 8abd2e7..aee892c 100644 --- a/scripting/include/feedthetrolls/misc.inc +++ b/scripting/include/feedthetrolls/misc.inc @@ -116,6 +116,116 @@ ArrayList GetPhrasesArray(const char[] key) { keyLower[i] = CharToLower(key[i]); } ArrayList phrases; - REPLACEMENT_PHRASES.GetValue(keyLower, phrases); - return phrases; -} \ No newline at end of file + if(REPLACEMENT_PHRASES.GetValue(keyLower, phrases)) { + return phrases; + } else { + return null; + } +} + + +int FindClosestClientAdminPriority(int source, bool ignoreBots, float pos[3]) { + int c = FindClosestAdmin(source, ignoreBots, pos); + if(c == -1) return FindClosestClient(source, ignoreBots, pos); + else return c; +} + +int FindClosestClient(int source, bool ignoreBots, float pos[3]) { + int closest = -1; + float minDist = -1.0; + static float pos1[3]; + static float pos2[3]; + GetClientAbsOrigin(source, pos1); + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i) && (!ignoreBots || !IsFakeClient(i)) && i != source) { + GetClientAbsOrigin(i, pos2); + float dist = GetVectorDistance(pos1, pos2); + if(minDist == -1.0 || dist <= minDist) { + closest = i; + minDist = dist; + } + } + } + GetClientEyePosition(closest, pos); + return closest; +} + +int FindClosestAdmin(int source, bool ignoreBots, float pos[3]) { + int closest = -1; + float minDist = -1.0; + static float pos1[3]; + static float pos2[3]; + GetClientAbsOrigin(source, pos); + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i) && (|ignoreBots || !IsFakeClient(i)) && GetUserAdmin(i) != INVALID_ADMIN_ID && i != source) { + GetClientAbsOrigin(i, pos2); + float dist = GetVectorDistance(pos1, pos2); + if(minDist == -1.0 || dist <= minDist) { + closest = i; + minDist = dist; + } + } + } + GetClientEyePosition(closest, pos); + return closest; +} + +int SpawnItem(const char[] entityName, float pos[3], float ang[3] = NULL_VECTOR) { + static char classname[32]; + Format(classname, sizeof(classname), "weapon_%s", entityName); + int spawner = CreateEntityByName(classname); + if(spawner == -1) return -1; + DispatchKeyValue(spawner, "solid", "6"); + // DispatchKeyValue(entity_weapon, "model", g_bLeft4Dead2 ? g_sWeaponModels2[model] : g_sWeaponModels[model]); + DispatchKeyValue(spawner, "rendermode", "3"); + DispatchKeyValue(spawner, "disableshadows", "1"); + TeleportEntity(spawner, pos, ang, NULL_VECTOR); + DispatchSpawn(spawner); + TeleportEntity(spawner, pos, ang, NULL_VECTOR); + return spawner; +} + +bool IsAnyPlayerNear(int source, float range) { + static float pos1[3]; + static float pos2[3]; + GetClientAbsOrigin(source, pos1); + for(int i = 1; i <= MaxClients; i++) { + if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i) && i != source) { + GetClientAbsOrigin(i, pos2); + float dist = GetVectorDistance(pos1, pos2); + PrintToChatAll("%f <= %f: %b", dist, range, (dist <= range)); + if(dist <= range) return true; + } + } + return false; +} + +void ThrowItemToClosestPlayer(int victim, int slot) { + int wpn = GetPlayerWeaponSlot(victim, slot); + if(slot != 1 || DoesClientHaveMelee(victim)) { + static float pos[3]; + int clients[4]; + GetClientAbsOrigin(victim, pos); + int clientCount = GetClientsInRange(pos, RangeType_Visibility, clients, sizeof(clients)); + for(int i = 0; i < clientCount; i++) { + if(clients[i] != victim) { + static float targPos[3]; + GetClientAbsOrigin(clients[i], targPos); + SDKHooks_DropWeapon(victim, wpn, targPos); + if(slot == 1) + CreateTimer(0.2, Timer_GivePistol, GetClientUserId(victim)); + return; + } + } + // No client found, drop on ground: + SDKHooks_DropWeapon(victim, wpn, NULL_VECTOR); + } +} + +void DropItem(int victim, int slot) { + int wpn = GetPlayerWeaponSlot(victim, slot); + if(slot != 1 || DoesClientHaveMelee(victim)) { + SDKHooks_DropWeapon(victim, wpn, NULL_VECTOR); + } +} + diff --git a/scripting/include/feedthetrolls/specials.inc b/scripting/include/feedthetrolls/specials.inc index e346f01..6af943a 100644 --- a/scripting/include/feedthetrolls/specials.inc +++ b/scripting/include/feedthetrolls/specials.inc @@ -72,7 +72,7 @@ bool SpawnSpecialNear(int target, int specialType) { if(specialType >= sizeof(SPECIAL_NAMES)) return false; 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); + int special = (specialType == 7) ? L4D2_SpawnWitch(pos, NULL_VECTOR) : L4D2_SpawnSpecial(specialType, pos, NULL_VECTOR); if(special == -1) return false; if(specialType == 7) SetWitchTarget(special, target); diff --git a/scripting/include/feedthetrolls/timers.inc b/scripting/include/feedthetrolls/timers.inc index 42f69d7..4bc0932 100644 --- a/scripting/include/feedthetrolls/timers.inc +++ b/scripting/include/feedthetrolls/timers.inc @@ -42,11 +42,14 @@ public Action Timer_Main(Handle timer) { 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_GivePistol(Handle timer, int user) { + int client = GetClientOfUserId(user); + if(client > 0) { + int flags = GetCommandFlags("give"); + SetCommandFlags("give", flags & ~FCVAR_CHEAT); + FakeClientCommand(client, "give pistol"); + SetCommandFlags("give", flags); + } } public Action Timer_ThrowWeapon(Handle timer, Handle pack) { @@ -67,7 +70,7 @@ public Action Timer_ThrowWeapon(Handle timer, Handle pack) { GetEdictClassname(wpn, name, sizeof(name)); if(!StrEqual(name, "weapon_pistol", false)) { SDKHooks_DropWeapon(victim, wpn, dest); - CreateTimer(0.2, Timer_GivePistol, victim); + CreateTimer(0.2, Timer_GivePistol, GetClientUserId(victim)); } }else SDKHooks_DropWeapon(victim, wpn, dest); diff --git a/scripting/include/ftt.inc b/scripting/include/ftt.inc index 0686720..eebd39b 100644 --- a/scripting/include/ftt.inc +++ b/scripting/include/ftt.inc @@ -21,6 +21,7 @@ Handle g_hWitchAttack; Handle hThrowTimer; //CONVARS ConVar hVictimsList, hThrowItemInterval, hAutoPunish, hMagnetChance, hShoveFailChance, hAutoPunishExpire, hMagnetTargetMode, hWitchTargetIncapp; +ConVar hBadThrowHitSelf; //BOOLS bool lateLoaded; //Is plugin late loaded bool bChooseVictimAvailable = false; //For charge player feature, is it available? @@ -28,7 +29,7 @@ bool bChooseVictimAvailable = false; //For charge player feature, is it availabl int g_iAmmoTable; //Loads the ammo table to get ammo amounts int gChargerVictim = -1; //For charge player feature -float ZERO_VECTOR[3] = {0.0, 0.0, 0.0}; + #include #include diff --git a/scripting/l4d2_feedthetrolls.sp b/scripting/l4d2_feedthetrolls.sp index 189f840..8950dc4 100644 --- a/scripting/l4d2_feedthetrolls.sp +++ b/scripting/l4d2_feedthetrolls.sp @@ -67,6 +67,7 @@ public void OnPluginStart() { hMagnetTargetMode = CreateConVar("sm_ftt_magnet_targetting", "1", "How does the specials target players. Add bits together\n0= Target until Dead, 1=Specials ignore incapped, 2=Tank ignores incapped"); hShoveFailChance = CreateConVar("sm_ftt_shove_fail_chance", "0.5", "The % chance that a shove fails", FCVAR_NONE, true, 0.0, true, 1.0); hWitchTargetIncapp = CreateConVar("sm_ftt_witch_target_incapped", "1", "Should the witch target witch magnet victims who are incapped?\n 0 = No, 1 = Yes", FCVAR_NONE, true, 0.0, true, 1.0); + hBadThrowHitSelf = CreateConVar("sm_ftt_badthrow_fail_chance", "1", "The % chance that on a throw, they will instead hit themselves. 0 to disable", FCVAR_NONE, true, 0.0, true, 1.0); RegAdminCmd("sm_ftl", Command_ListTheTrolls, ADMFLAG_KICK, "Lists all the trolls currently ingame."); RegAdminCmd("sm_ftm", Command_ListModes, ADMFLAG_KICK, "Lists all the troll modes and their description"); @@ -94,7 +95,6 @@ public void OnPluginStart() { HookEntityOutput("func_button", "OnPressed", Event_ButtonPress); } } - /////////////////////////////////////////////////////////////////////////////// // CVAR CHANGES /////////////////////////////////////////////////////////////////////////////// @@ -201,7 +201,7 @@ stock bool SetPrimaryReserveAmmo(int client, int amount) { } stock void SendChatToAll(int client, const char[] message) { - char nameBuf[MAX_NAME_LENGTH]; + static char nameBuf[MAX_NAME_LENGTH]; for (int i = 1; i <= MaxClients; i++) { if (IsClientInGame(i) && IsFakeClient(i)) { @@ -213,7 +213,7 @@ stock void SendChatToAll(int client, const char[] message) { stock float GetTempHealth(int client) { //First filter -> Must be a valid client, successfully in-game and not an spectator (The dont have health). - if(!client || !IsValidEntity(client) || !IsClientInGame(client)|| !IsPlayerAlive(client) || IsClientObserver(client)) { + if(client <= 0 || !IsValidEntity(client) || !IsClientInGame(client)|| !IsPlayerAlive(client) || IsClientObserver(client)) { return -1.0; } diff --git a/scripting/l4d2_forceset.sp b/scripting/l4d2_forceset.sp new file mode 100644 index 0000000..6c4fc28 --- /dev/null +++ b/scripting/l4d2_forceset.sp @@ -0,0 +1,48 @@ +#include +#include +#include + +#pragma semicolon 1 +#pragma newdecls required + +ConVar g_cvSurvivorSet; + +public Plugin myinfo = +{ + name = "[L4D2] Survivor Set Enforcer", + author = "DeathChaos, modified by Psyk0tik (Crasher_3637)", + description = "Forces L4D2 survivor set.", + version = "1.0", + url = "" +}; + +public void OnPluginStart() +{ + g_cvSurvivorSet = CreateConVar("l4d_force_survivorset", "0", "Forces specified survivor set (0 - no change, 1 - force L4D1, 2 - Force L4D2)", _, true, 0.0, true, 2.0); +} + +public Action L4D_OnGetSurvivorSet(int &retVal) +{ + int iSet = g_cvSurvivorSet.IntValue; + if (iSet > 0) + { + retVal = iSet; + + return Plugin_Handled; + } + + return Plugin_Continue; +} + +public Action L4D_OnFastGetSurvivorSet(int &retVal) +{ + int iSet = g_cvSurvivorSet.IntValue; + if (iSet > 0) + { + retVal = iSet; + + return Plugin_Handled; + } + + return Plugin_Continue; +} \ No newline at end of file