diff --git a/plugins/l4d2_feedthetrolls.smx b/plugins/l4d2_feedthetrolls.smx index 597380c..1003165 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 d444ff4..cc3a067 100644 --- a/scripting/include/feedthetrolls/base.inc +++ b/scripting/include/feedthetrolls/base.inc @@ -4,7 +4,7 @@ //Allow MAX_TROLLS to be defined elsewhere #if defined MAX_TROLLS #else - #define MAX_TROLLS 56 + #define MAX_TROLLS 55 #endif enum trollModifier { @@ -14,6 +14,12 @@ enum trollModifier { TrollMod_PlayerOnly = 1 << 2, // Does the troll only work on players, not bots? If set, troll only applied on real user. If not, troll applied to both bot and idler } +enum TrollEffectResponse { + TE_Success, // Success, continue menu + TE_Error, // Error, continue menu (retry) + TE_Menu // Switching menus / etc, don't continue menu +} + StringMap trollKV; char trollIds[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH]; char DEFAULT_FLAG_PROMPT_MULTIPLE[] = "Enable options (Multiple)"; @@ -102,11 +108,25 @@ enum struct Troll { /////// FLAGS bool GetFlagName(int index, char[] buffer, int maxlength) { - if(this.flagNames == null) return false; + if(this.flagNames == null || index >= this.flagNames.Length) return false; this.flagNames.GetString(index, buffer, maxlength); return true; } + bool GetFlagNames(int client, char[] output, int maxlength) { + if(this.flagNames == null) return false; + char buffer[16]; + for(int i = 0; i < this.flagNames.Length; i++) { + int value = 1 << i; + // If client has this flag: + if(this.activeFlagClients[client] & value) { + this.flagNames.GetString(i, buffer, sizeof(buffer)); + Format(output, maxlength, "%s%s,", output, buffer); + } + } + return true; + } + int AddCustomFlagPrompt(const char[] promptText, bool multiselect = false, int requireFlags = 0) { TrollFlagPrompt prompt; prompt.multiselect = multiselect; @@ -191,10 +211,10 @@ enum struct Troll { /////// TROLL ACTIVATION - void Activate(int client, int activator, trollModifier modifier = TrollMod_Invalid, int flags = 0, bool silent = false) { + TrollEffectResponse Activate(int client, int activator, trollModifier modifier = TrollMod_Invalid, int flags = 0, bool silent = false) { if(modifier == TrollMod_Invalid) modifier = this.GetDefaultMod(); // Sadly, unable to pass in to ApplyTroll, so it has to do unnecessary lookup via string - ApplyTroll(client, this.name, activator, modifier, flags, silent); + return ApplyTroll(client, this.name, activator, modifier, flags, silent); } @@ -328,13 +348,14 @@ void SetTrollFlags(int client, const char[] name, int flags = -1) { Trolls[index].Enable(client, flags); } -void ApplyTroll(int victim, const char[] name, int activator, trollModifier modifier, int flags = 0, bool silent = false) { + +TrollEffectResponse ApplyTroll(int victim, const char[] name, int activator, trollModifier modifier, int flags = 0, bool silent = false) { static Troll troll; int trollIndex = GetTroll(name, troll); if(trollIndex == -1) { ReplyToCommand(activator, "Unknown troll \"%s\"", name); PrintToServer("[FTT] %N attempted to apply unknown troll: %s", activator, name); - return; + return TE_Error; } bool isActive = Trolls[trollIndex].activeFlagClients[victim] > -1; @@ -372,7 +393,7 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi // If there is an idle player, apply troll to them ApplyTroll(player, name, activator, modifier, flags, silent); // And continue IF there is TrollMod_PlayerOnly mod - if(troll.mods & view_as(TrollMod_PlayerOnly)) return; + if(troll.mods & view_as(TrollMod_PlayerOnly)) return TE_Success; // Don't want to show two logs, so just ignore the bot silent = true; } @@ -385,9 +406,8 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi } // Applies any custom logic needed for a troll, mostly only used for TrollMod_Instant - if(!ApplyAffect(victim, troll, activator, modifier, flags)) { - return; - } + TrollEffectResponse response = ApplyAffect(victim, troll, activator, modifier, flags); + if(response != TE_Success) return response; // Let the menu handler deal with checking // Log all actions, indicating if constant or single-fire, and if any flags if(!silent) { @@ -403,42 +423,30 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi // Call_PushCell(flags); // Call_PushCell(activator); // Call_Finish(); - for(int i = 0; i < 32; i++) { - if(flags & (1 << i)) { - // If at least one flag already, reset to none: - if(flagName[0] != '\0') { - flagName[0] = '\0'; - break; - } - troll.GetFlagName(i, flagName, sizeof(flagName)); - } - } - if(flags > 0) { + troll.GetFlagNames(victim, flagName, sizeof(flagName)); // Checks if there is not more than one flag set on the bitfield - if(flags & flags - 1 == 0 && flags & flags + 1 == 0) { - // Get the flag name if there is only one flag set - troll.GetFlagName(GetIndexFromPower(flags), flagName, sizeof(flagName)); - } else { - Format(flagName, sizeof(flagName), "%d", flags); - } + // if(flags & flags - 1 == 0 && flags & flags + 1 == 0) { + // // Get the flag name if there is only one flag set + // troll.GetFlagName(GetIndexFromPower(flags), flagName, sizeof(flagName)); + // } else { + // Format(flagName, sizeof(flagName), "%d", flags); + // } + Format(flagName, sizeof(flagName), " (\x04%s|%d\x01)", flagName, flags); + // CFormatColor(flagName, sizeof(flagName)); } if(modifier & TrollMod_Constant) { - if(flags > 0) { - CShowActivityEx(activator, "[FTT] ", "activated constant {yellow}%s{default} ({yellow}%s{default}) for %N. ", troll.name, flagName, victim); - } else - CShowActivityEx(activator, "[FTT] ", "activated constant {yellow}%s{default} for %N. ", troll.name, victim); - } else if(flags > 0) { - CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} ({yellow}%s{default}) for %N. ", troll.name, flagName, victim); + CShowActivityEx(activator, "[FTT] ", "activated constant {yellow}%s{default}%s for %N. ", troll.name, flagName, victim); } else { - CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} for %N. ", troll.name, victim); + CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default}%s for %N. ", troll.name, flagName, victim); } LogAction(activator, victim, "\"%L\" activated \"%s\" (%d) for \"%L\"", activator, troll.name, flags, victim); } } else { CReplyToCommand(activator, "[FTT] Applied silently {yellow}\"%s\"{default} on %N with flags=%d", troll.name, victim, flags); } + return TE_Success; } bool IsTrollActive(int client, const char[] troll) { diff --git a/scripting/include/feedthetrolls/events.inc b/scripting/include/feedthetrolls/events.inc index 7ac9983..fb85a37 100644 --- a/scripting/include/feedthetrolls/events.inc +++ b/scripting/include/feedthetrolls/events.inc @@ -783,7 +783,7 @@ Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage if(pdata[attacker].pendingTrollBan > 0 && isSameTeam) { return Plugin_Stop; } - if(Trolls[t_slotRouletteIndex].IsActive(victim)) { + if(Trolls[t_slotRouletteIndex].IsActive(victim) && GetURandomFloat() < 0.10) { SetSlot(victim, -1); } if(victim != attacker) { @@ -861,7 +861,7 @@ public Action OnVocalizeCommand(int client, const char[] vocalize, int initiator SetEntPropFloat(client, Prop_Send, "m_flLaggedMovementValue", noRushingUsSpeed[client]); PrintToConsoleAdmins("[FTT] NoRushingUs: Dropping speed for %N (now %.1f%)", client, noRushingUsSpeed[client] * 100.0); } - if(Trolls[t_slotRouletteIndex].IsActive(client)) { + if(Trolls[t_slotRouletteIndex].IsActive(client) && GetURandomFloat() < 0.10) { SetSlot(client, -1); } if(Trolls[vocalGagID].IsActive(client)) { @@ -1093,7 +1093,7 @@ void Event_HealSuccess(Event event, const char[] name, bool dontBroadcast) { } public void L4D_OnVomitedUpon_Post(int victim, int attacker, bool boomerExplosion) { - if(Trolls[t_slotRouletteIndex].IsActive(victim)) { + if(Trolls[t_slotRouletteIndex].IsActive(victim) && GetURandomFloat() < 0.10) { SetSlot(victim, -1); } } diff --git a/scripting/include/feedthetrolls/menus.inc b/scripting/include/feedthetrolls/menus.inc index d5f87f8..5c62874 100644 --- a/scripting/include/feedthetrolls/menus.inc +++ b/scripting/include/feedthetrolls/menus.inc @@ -16,15 +16,15 @@ public int Insta_PlayerHandler(Menu menu, MenuAction action, int client, int par } void ShowInstaSpecialChooser(int activator, int userid, int instaMode) { - Menu spMenu = new Menu(Insta_SpecialHandler); - spMenu.SetTitle("Choose a Insta-Specialâ„¢"); - static char data[16]; + Menu menu = new Menu(Insta_SpecialHandler); + menu.SetTitle("Choose a Insta-Specialâ„¢"); + char data[16]; for(int i = 1; i <= 8; i++) { Format(data, sizeof(data), "%d|%d|%d", userid, instaMode, i); - spMenu.AddItem(data, SPECIAL_NAMES[i-1]); + menu.AddItem(data, SPECIAL_NAMES[i-1]); } - spMenu.ExitButton = true; - spMenu.Display(activator, 0); + menu.ExitButton = true; + menu.Display(activator, 0); } public int Insta_SpecialHandler(Menu menu, MenuAction action, int client, int param2) { @@ -212,8 +212,10 @@ public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int p } else if(!troll.IsActive(client) && troll.HasFlags()) { ShowSelectFlagMenu(param1, userid, -1, troll); } else { - troll.Activate(client, param1); - ShowTrollsForCategory(param1, userid, troll.categoryID); + TrollEffectResponse response = troll.Activate(client, param1); + // Only show menu if success or error, not TE_Menu + if(response != TE_Menu) + ShowTrollsForCategory(param1, userid, troll.categoryID); } } else if (action == MenuAction_End) @@ -277,11 +279,13 @@ public int ChooseTrollModiferHandler(Menu menu, MenuAction action, int param1, i // Show flag selection if troll is not enabled already ShowSelectFlagMenu(param1, userid, modifiers, troll); } else { + TrollEffectResponse response; if(modifiers == 1 || modifiers == 3) - troll.Activate(client, param1, TrollMod_Instant); + response = troll.Activate(client, param1, TrollMod_Instant); if(modifiers == 2 || modifiers == 3) - troll.Activate(client, param1, TrollMod_Constant); - ShowTrollsForCategory(param1, userid, troll.categoryID); + response = troll.Activate(client, param1, TrollMod_Constant); + if(response != TE_Menu) + ShowTrollsForCategory(param1, userid, troll.categoryID); } } else if (action == MenuAction_End) @@ -327,17 +331,19 @@ public int ChooseTrollFlagHandler(Menu menu, MenuAction action, int param1, int return 0; } + TrollEffectResponse response; // Done with prompts, apply flags & modifiers if(modifiers > 0) { if(modifiers & view_as(TrollMod_Instant)) - troll.Activate(client, param1, TrollMod_Instant, flags); + response = troll.Activate(client, param1, TrollMod_Instant, flags); if(modifiers & view_as(TrollMod_Constant)) - troll.Activate(client, param1, TrollMod_Constant, flags); + response = troll.Activate(client, param1, TrollMod_Constant, flags); } else { - troll.Activate(client, param1, TrollMod_Invalid, flags); + response = troll.Activate(client, param1, TrollMod_Invalid, flags); } // Jump back to selection screen - ShowTrollsForCategory(param1, userid, troll.categoryID); + if(response != TE_Menu) + ShowTrollsForCategory(param1, userid, troll.categoryID); } else if (action == MenuAction_End) delete menu; return 0; diff --git a/scripting/include/feedthetrolls/timers.inc b/scripting/include/feedthetrolls/timers.inc index c38f008..cb0712e 100644 --- a/scripting/include/feedthetrolls/timers.inc +++ b/scripting/include/feedthetrolls/timers.inc @@ -142,11 +142,11 @@ Action Timer_Main(Handle timer) { if(Trolls[t_slotRouletteIndex].IsActive(i) && Trolls[t_slotRouletteIndex].activeFlagClients[i] & 8) { float chance = 1.0; if(Trolls[t_slotRouletteIndex].activeFlagClients[i] & 16) { - chance = 0.2; + chance = 0.05; } else if(Trolls[t_slotRouletteIndex].activeFlagClients[i] & 32) { - chance = 0.4; + chance = 0.2; } else if(Trolls[t_slotRouletteIndex].activeFlagClients[i] & 64) { - chance = 0.6; + chance = 0.4; } if(GetURandomFloat() < chance) { @@ -481,20 +481,4 @@ Action Timer_RestoreHud(Handle h, int userid) { SetEntProp(client, Prop_Send, "m_iHideHUD", 0); } return Plugin_Handled; -} - -Action Timer_TurnCamera(Handle h, int client) { - if(!IsClientInGame(client)) { - Trolls[t_cameraTurnIndex].timerHandles[client] = null; - return Plugin_Stop; - } - static float ang[3]; - GetClientEyeAngles(client, ang); - if(Trolls[t_cameraTurnIndex].activeFlagClients[client] & 1) { - ang[1] += 2.0; - } else { - ang[0] += 2.0; - } - SetAbsAngles(client, ang); - return Plugin_Continue; } \ No newline at end of file diff --git a/scripting/include/feedthetrolls/trolls.inc b/scripting/include/feedthetrolls/trolls.inc index 82885bd..feca0cb 100644 --- a/scripting/include/feedthetrolls/trolls.inc +++ b/scripting/include/feedthetrolls/trolls.inc @@ -12,7 +12,6 @@ int t_damageBoostIndex; int t_reverseFFIndex; int t_throwItAllIndex; int t_hideHUDIndex; -int t_cameraTurnIndex; void SetupTrolls() { trollKV = new StringMap(); @@ -41,8 +40,10 @@ void SetupTrolls() { SetCategory("Infected"); SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", TrollMod_Instant | TrollMod_Constant); t_vomitPlayerIndex = SetupTroll("Vomit Player", "Shortcut to sm_vomitplayer. vomits the player.", TrollMod_Instant | TrollMod_Constant); - SetupTroll("Inface Special", "Shortcut to sm_inface", TrollMod_Instant); - SetupTroll("Insta Special", "Shortcut to sm_insta", TrollMod_Instant); + index = SetupTroll("Insta Special", "Shortcut to sm_insta", TrollMod_Instant); + Trolls[index].AddFlagPrompt(false); + Trolls[index].AddFlag("Around them (Director)", true); + Trolls[index].AddFlag("On top / in-face", false); SetupTroll("Goo", "Spawns a spitter puddle underneath them", TrollMod_Instant); index = SetupTroll("Sticky Goo", "Slows player down in goo", TrollMod_Constant); Trolls[index].AddFlagPrompt(false); @@ -130,7 +131,7 @@ void SetupTrolls() { Trolls[index].AddFlag("Confusing", false); // 32 Trolls[index].AddFlag("Annoying", false); // 64 Trolls[index].AddFlag("Unusable", false); // 128 - Trolls[index].SetTimer(0.3, Timer_SlotRoulette, 8); + Trolls[index].SetTimer(0.2, Timer_SlotRoulette, 8); t_slotRouletteIndex = index; @@ -236,13 +237,6 @@ void SetupTrolls() { Trolls[index].AddFlag("Severe Earthquake", false); //8 Trolls[index].AddFlag("Bouncy Castle", false); //16 t_randomizeVelocityIndex = index; - index = SetupTroll("Camera Turn", "Constantly turn their camera", TrollMod_Constant); - Trolls[index].SetTimer(0.1, Timer_TurnCamera); - Trolls[index].AddCustomFlagPrompt("Direction:", false); - Trolls[index].AddFlag("Left/Right", true); //1 - Trolls[index].AddFlag("Up/Down", false); //2 - t_cameraTurnIndex = index; - /// CATEGORY: MISC SetCategory("Misc"); @@ -300,7 +294,7 @@ void AddMagnetFlags(int index) { Trolls[index].AddFlag("Rare (10%)", false); } -bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier modifier, int flags) { +TrollEffectResponse ApplyAffect(int victim, const Troll troll, int activator, trollModifier modifier, int flags) { bool toActive = IsTrollActiveByRawID(victim, troll.id); if(StrEqual(troll.name, "Reset User")) { LogAction(activator, victim, "\"%L\" reset all effects for \"%L\"", activator, victim); @@ -311,7 +305,7 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod // SetEntityGravity(victim, 1.0); // SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0); ResetClient(victim, true); - return false; + return TE_Error; // Not an error, but don't want to show activation } else if(StrEqual(troll.name, "Slow Speed")) { if(toActive) { float movement = 0.0; @@ -346,10 +340,10 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod pdata[victim].flags |= view_as(Flag_PendingItemGive); }else{ ReplyToCommand(activator, "User does not have pills or adrenaline"); - return false; + return TE_Error; } //TODO: Implement TrollMod_Constant - return false; + return TE_Error; } else if(StrEqual(troll.name, "Throw It All")) { if(modifier & TrollMod_Instant) { if(flags & 1) { // Hacky, just throw their kit @@ -366,16 +360,15 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod SDKHook(wpn, SDKHook_Reload, Event_WeaponReload); else { ReplyToCommand(activator, "Victim does not have a primary weapon."); - return false; + return TE_Error; } } else if(StrEqual(troll.name, "Vomit Player")) L4D_CTerrorPlayer_OnVomitedUpon(victim, victim); - else if(StrEqual(troll.name, "Inface Special")) { - ShowInstaSpecialChooser(activator, GetClientUserId(victim), 1); - return false; - } else if(StrEqual(troll.name, "Insta Special")) { - ShowInstaSpecialChooser(activator, GetClientUserId(victim), 0); - return false; + else if(StrEqual(troll.name, "Insta Special")) { + int mode = 0; + if(flags & 2) mode = 1; + ShowInstaSpecialChooser(activator, GetClientUserId(victim), mode); + return TE_Menu; } else if(StrEqual(troll.name, "Goo")) { static float pos[3], ang[3]; GetClientAbsOrigin(victim, pos); @@ -391,17 +384,17 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod if(flags & 1) { if(!SpawnCarOnPlayer(victim)) { ReplyToCommand(activator, "Could not find a suitable area to spawn a car. Requires vertical space above victim."); - return false; + return TE_Error; } } else if(flags & 2) { if(!SpawnCarToPlayer(victim, 450.0)) { ReplyToCommand(activator, "Could not find a suitable area to spawn a car. Requires space ahead of victim"); - return false; + return TE_Error; } } else if(flags & 4) { if(!SpawnCarToPlayer(victim, -450.0)) { ReplyToCommand(activator, "Could not find a suitable area to spawn a car. Requires space behind victim"); - return false; + return TE_Error; } } } else if(StrEqual(troll.name, "Instant Commons")) { @@ -430,7 +423,7 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod TR_TraceRayFilter(pos, dropPos, MASK_SOLID, RayType_EndPoint, Filter_IgnorePlayer, victim); if(TR_DidHit()) { ReplyToCommand(activator, "Could not find a suitable area. Requires vertical space."); - return false; + return TE_Error; } float ang[3]; ang[0] = 90.0; @@ -445,11 +438,11 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod TR_TraceRayFilter(pos, dropPos, MASK_SOLID, RayType_EndPoint, Filter_IgnorePlayer, victim); if(TR_DidHit()) { ReplyToCommand(activator, "Could not find a suitable area. Requires vertical space."); - return false; + return TE_Error; } if(IsAnySurvivorInRange(pos, 55.0, victim)) { ReplyToCommand(activator, "Victim is too close to other players."); - return false; + return TE_Error; } float vel[3]; vel[2] = -90.0; @@ -459,12 +452,12 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod } else if(StrEqual(troll.name, "Dep Bots")) { if(!toActive) { StopHealingBots(); - return true; + return TE_Success; } else if(healTargetPlayer != 0) { if(stopHealingTimer != null) { TriggerTimer(stopHealingTimer); } - return true; + return TE_Success; } bool spawnExtra = flags & 2 > 0; @@ -523,7 +516,7 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod } else if(StrEqual(troll.name, "Smart Charge")) { if(pdata[victim].smartChargeActivator > 0) { ReplyToCommand(activator, "Target already has smart charge enabled"); - return false; + return TE_Error; } int timeout = 15; if(flags & 2) timeout = 30; @@ -563,5 +556,5 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod ReplyToCommand(activator, "[FTT/Debug] If nothing occurs, this troll possibly was not implemented correctly. "); #endif } - return true; + return TE_Success; } \ No newline at end of file