diff --git a/plugins/l4d2_feedthetrolls.smx b/plugins/l4d2_feedthetrolls.smx index a8574d7..bec7a80 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 c8afe85..d444ff4 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 54 + #define MAX_TROLLS 56 #endif enum trollModifier { @@ -14,18 +14,6 @@ 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 } -//up to 30 flags technically possiible -enum trollFlag { - Flag_1 = 1 << 0, - Flag_2 = 1 << 1, - Flag_3 = 1 << 2, - Flag_4 = 1 << 3, - Flag_5 = 1 << 4, - Flag_6 = 1 << 5, - Flag_7 = 1 << 6, - Flag_8 = 1 << 7, -} - StringMap trollKV; char trollIds[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH]; char DEFAULT_FLAG_PROMPT_MULTIPLE[] = "Enable options (Multiple)"; @@ -190,19 +178,6 @@ enum struct Troll { return this.flagNames != null && this.flagNames.Length > 0 && this.flagPrompts.Length > 0; } - bool IsFlagActive(int client, trollFlag flag) { - return this.activeFlagClients[client] & view_as(flag) != 0; - } - - bool IsFlagNameActive(int client, const char[] flagName) { - static char buffer[MAX_TROLL_FLAG_LENGTH]; - for(int i = 0; i < this.flagNames.Length; i++) { - this.flagNames.GetString(i, buffer, sizeof(buffer)); - if(StrEqual(buffer, flagName, false)) return this.IsFlagActive(client, view_as(i)); - } - return false; - } - int GetFlagCount() { return this.flagNames != null ? this.flagNames.Length : 0; } @@ -284,6 +259,7 @@ void ResetClient(int victim, bool wipe = true) { BaseComm_SetClientMute(victim, false); SetEntityGravity(victim, 1.0); SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0); + SetEntProp(victim, Prop_Send, "m_iHideHUD", 0) SDKUnhook(victim, SDKHook_WeaponCanUse, Event_ItemPickup); int wpn = GetClientWeaponEntIndex(victim, 0); if(wpn > -1) @@ -366,7 +342,7 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi // Clear troll specific timer: if(Trolls[trollIndex].timerInterval > 0.0) { if(!isActive) { - if(Trolls[trollIndex].timerRequiredFlags == 0 || Trolls[trollIndex].timerRequiredFlags & flags) { + if(modifier & TrollMod_Constant && (Trolls[trollIndex].timerRequiredFlags == 0 || Trolls[trollIndex].timerRequiredFlags & flags)) { Trolls[trollIndex].timerHandles[victim] = CreateTimer(Trolls[trollIndex].timerInterval, Trolls[trollIndex].timerFunction, victim, TIMER_REPEAT); } } else if(Trolls[trollIndex].timerHandles[victim] != null) { @@ -384,7 +360,7 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi float max = 1.0; if(Trolls[MetaInverseTrollID].activeFlagClients[activator] & 2) max = 0.5; else if(Trolls[MetaInverseTrollID].activeFlagClients[activator] & 4) max = 0.1; - if(GetRandomFloat() <= max) { + if(GetURandomFloat() <= max) { victim = activator; } } @@ -419,7 +395,7 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi CShowActivityEx(activator, "[FTT] ", "deactivated {yellow}%s{default} on %N. ", troll.name, victim); LogAction(activator, victim, "\"%L\" deactivated \"%s\" on \"%L\"", activator, troll.name, victim); } else { - static char flagName[MAX_TROLL_FLAG_LENGTH]; + char flagName[MAX_TROLL_FLAG_LENGTH]; // strcopy(flagName, sizeof(flagName), troll.name) // Call_StartForward(g_TrollAppliedForward); // Call_PushCell(victim); @@ -427,7 +403,6 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi // Call_PushCell(flags); // Call_PushCell(activator); // Call_Finish(); - flagName[0] = '\0'; for(int i = 0; i < 32; i++) { if(flags & (1 << i)) { // If at least one flag already, reset to none: @@ -438,32 +413,31 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi troll.GetFlagName(i, flagName, sizeof(flagName)); } } - if(flags > 0 && 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)); + + if(flags > 0) { + // 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(modifier & TrollMod_Constant) { if(flags > 0) { - if(flagName[0] != '\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} ({yellow}%d{default}) for %N. ", troll.name, flags, victim); - } + 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) { - if(flagName[0] != '\0') { - CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} ({yellow}%s{default}) for %N. ", troll.name, flagName, victim); - } else { - CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} ({yellow}%d{default}) for %N. ", troll.name, flags, victim); - } - } else + CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} ({yellow}%s{default}) for %N. ", troll.name, flagName, victim); + } else { CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} for %N. ", troll.name, victim); - + } LogAction(activator, victim, "\"%L\" activated \"%s\" (%d) for \"%L\"", activator, troll.name, flags, victim); } } else { - CReplyToCommand(activator, "ftt: Applied {yellow}\"%s\"{default} on %N with flags=%d", troll.name, victim, flags); + CReplyToCommand(activator, "[FTT] Applied silently {yellow}\"%s\"{default} on %N with flags=%d", troll.name, victim, flags); } } diff --git a/scripting/include/feedthetrolls/combos.inc b/scripting/include/feedthetrolls/combos.inc index 2f89c15..acb9e90 100644 --- a/scripting/include/feedthetrolls/combos.inc +++ b/scripting/include/feedthetrolls/combos.inc @@ -65,8 +65,8 @@ void SetupsTrollCombos() { SetupCombo(combo, "Nuclear"); combo.AddTroll("Slow Speed"); - combo.AddTroll("Special Magnet"); - combo.AddTroll("Tank Magnet"); + combo.AddTroll("Special Magnet", .flags=1); + combo.AddTroll("Tank Magnet", .flags=1); #if defined _behavior_included combo.AddTroll("Witch Magnet"); #endif diff --git a/scripting/include/feedthetrolls/commands.inc b/scripting/include/feedthetrolls/commands.inc index 785260c..6d844f2 100644 --- a/scripting/include/feedthetrolls/commands.inc +++ b/scripting/include/feedthetrolls/commands.inc @@ -732,6 +732,7 @@ Action Command_SetReverseFF(int client, int args) { ApplyTroll(target, "Reverse FF", client, TrollMod_Constant, flag); return Plugin_Handled; } + Action Command_SetMagnetShortcut(int client, int args) { if(args < 1) { ReplyToCommand(client, "Usage: sm_magnet "); @@ -745,4 +746,42 @@ Action Command_SetMagnetShortcut(int client, int args) { } ShowTrollsForCategory(client, GetClientUserId(target), 0); return Plugin_Handled; +} +Action Command_CarSplat(int client, int args) { + if(args < 1) { + ReplyToCommand(client, "Usage: sm_magnet [top/front/back]"); + return Plugin_Handled; + } + char arg[32]; + GetCmdArg(1, arg, sizeof(arg)); + int target = GetSinglePlayer(client, arg, COMMAND_FILTER_ALIVE); + if(target <= 0) { + return Plugin_Handled; + } + if(args == 2) { + GetCmdArg(2, arg, sizeof(arg)); + float speed = 450.0; + if(args == 3) { + GetCmdArg(3, arg, sizeof(arg)); + speed = StringToFloat(arg); + if(speed <= 0.0) speed = 450.0; + } + if(StrEqual(arg, "top")) { + SpawnCarOnPlayer(target); + } else if(StrEqual(arg, "front")) { + SpawnCarToPlayer(target, speed); + } else if(StrEqual(arg, "back")) { + SpawnCarToPlayer(target, -speed); + } else { + ReplyToCommand(client, "Invalid direction: top/front/back or blank for menu"); + return Plugin_Handled; + } + LogAction(client, target, "spawned car on/in %s of \"%L\"", arg, target); + ShowActivity(client, "spawned car (%s) of %N", arg, target); + } else { + Troll troll; + GetTroll("Car Splat", troll); + ShowSelectFlagMenu(client, GetClientUserId(target), view_as(TrollMod_Instant), troll); + } + return Plugin_Handled; } \ No newline at end of file diff --git a/scripting/include/feedthetrolls/events.inc b/scripting/include/feedthetrolls/events.inc index 32cd05a..f38a048 100644 --- a/scripting/include/feedthetrolls/events.inc +++ b/scripting/include/feedthetrolls/events.inc @@ -75,21 +75,21 @@ void EntityCreateCallback(int entity) { if(Trolls[badThrowID].IsActive(entOwner)) { static float pos[3]; GetClientEyePosition(entOwner, pos); - if(Trolls[badThrowID].IsFlagActive(entOwner, Flag_1) && StrEqual(class, "vomitjar_projectile", true)) { - AcceptEntityInput(entity, "Kill"); + if(Trolls[badThrowID].activeFlagClients[entOwner] & 1 && StrEqual(class, "vomitjar_projectile", true)) { + RemoveEntity(entity); 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(Trolls[badThrowID].IsFlagActive(entOwner, Flag_2) && StrEqual(class, "molotov_projectile", true)) { + } else if(Trolls[badThrowID].activeFlagClients[entOwner] & 2 && StrEqual(class, "molotov_projectile", true)) { // Burn them if no one near :) if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() <= hBadThrowHitSelf.FloatValue) { GetClientAbsOrigin(entOwner, pos); // Kill molotov if too close to a player, else teleport to feet if(IsAnyPlayerNear(entOwner, 500.0)) { - AcceptEntityInput(entity, "Kill"); + RemoveEntity(entity); EmitSoundToAll("weapons/molotov/molotov_detonate_1.wav", entOwner); } else { float vel[3]; @@ -101,7 +101,7 @@ void EntityCreateCallback(int entity) { SpawnItem("molotov", pos); AcceptEntityInput(entity, "Kill"); } - } else if(Trolls[badThrowID].IsFlagActive(entOwner, Flag_3) && StrEqual(class, "pipe_bomb_projectile", true)) { + } else if(Trolls[badThrowID].activeFlagClients[entOwner] & 3 && StrEqual(class, "pipe_bomb_projectile", true)) { if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() <= hBadThrowHitSelf.FloatValue) { TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR); ExplodeProjectile(entity); @@ -386,7 +386,9 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) { } bool WillMagnetRun(const Troll troll, int i) { - if(troll.activeFlagClients[i] == 0) return false; + // In the case none of the flags are set, return true (100% chance) + // Some systems may give magnet w/ no flags + if(troll.activeFlagClients[i] == 0) return true; float cChance = 1.0; //Skip first bit as it is ('Always') @@ -424,11 +426,13 @@ public Action OnClientSayCommand(int client, const char[] command, const char[] // Honk Processing static char strings[32][8]; int words = ExplodeString(sArgs, " ", strings, sizeof(strings), 5); + for(int i = 0; i < words; i++) { + // Strings should be padded by 7 characters (+ null term) to fill up 8 bytes if(GetRandomFloat() <= 0.8) strings[i] = "honk "; - else strings[i] = "squeak"; + else strings[i] = "squeak "; } - int length = 7 * words; + int length = 8 * words; char[] message = new char[length]; ImplodeStrings(strings, 32, " ", message, length); if(Trolls[honkID].activeFlagClients[client] & 1) @@ -761,71 +765,85 @@ public Action NerfGun_OnTakeDamage(int victim, int& attacker, int& inflictor, fl return Plugin_Continue; } -public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) { - //Stop FF from marked: - static int reverseFF; - if(reverseFF == 0) reverseFF = GetTrollID("Reverse FF"); +// Only triggered for players, victim is 0 < victim <= MaxClients +Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) { + // Ignore passing bots from FF if(attacker > 0 && attacker <= MaxClients) { if(GetClientTeam(attacker) == 4 && IsFakeClient(attacker)) return Plugin_Continue; } - - if(attacker > 0 && victim <= MaxClients && attacker <= MaxClients && IsClientInGame(attacker) && IsPlayerAlive(attacker)) { + // Boost all damage no matter what + if(Trolls[t_damageBoostIndex].IsActive(victim)) { + damage * 2; + return Plugin_Changed; + } + // Only apply for when attackers are players + if(attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker) && IsPlayerAlive(attacker)) { if(pdata[attacker].shootAtTarget == victim) return Plugin_Continue; - if(pdata[attacker].pendingTrollBan > 0 && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) { + bool isSameTeam = GetClientTeam(attacker) == GetClientTeam(victim); + if(pdata[attacker].pendingTrollBan > 0 && isSameTeam) { return Plugin_Stop; } - - - - if(damage > 0.0 && victim != attacker && Trolls[slipperyShoesIndex].IsActive(victim) && Trolls[slipperyShoesIndex].activeFlagClients[victim] & 16) { - L4D_StaggerPlayer(victim, victim, NULL_VECTOR); - } if(Trolls[t_slotRouletteIndex].IsActive(victim)) { SetSlot(victim, -1); } - - if(IsTrollActive(victim, "Damage Boost")) { - damage * 2; - return Plugin_Changed; - } else if(Trolls[reverseFF].IsActive(attacker) && attacker != victim && GetClientTeam(attacker) == GetClientTeam(victim) - && (damagetype == DMG_BURN && Trolls[reverseFF].activeFlagClients[attacker] & 32) - && (damagetype == DMG_BLAST && Trolls[reverseFF].activeFlagClients[attacker] & 64) - ) { - float returnDmg = damage; //default is 1:1 - if(Trolls[reverseFF].activeFlagClients[attacker] & 2) { - returnDmg *= 2.0; - } else if(Trolls[reverseFF].activeFlagClients[attacker] & 4) { - returnDmg /= 2.0; - } else if(Trolls[reverseFF].activeFlagClients[attacker] & 8) { - returnDmg = 0.0; - } else if(Trolls[reverseFF].activeFlagClients[attacker] & 16) { - returnDmg *= 3.0; + if(victim != attacker) { + if(damage > 0.0 && Trolls[slipperyShoesIndex].IsActive(victim) && Trolls[slipperyShoesIndex].activeFlagClients[victim] & 16) { + L4D_StaggerPlayer(victim, victim, NULL_VECTOR); } - SDKHooks_TakeDamage(attacker, attacker, attacker, returnDmg, damagetype, -1); - damage = 0.0; - return Plugin_Changed; - } + if(isSameTeam && Trolls[t_reverseFFIndex].IsActive(attacker)) { + // Should this be applied? (as in no FF granted) + bool disableFF = false; + if(damagetype == DMG_BURN) { + disableFF = Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 32 != 0; + } else if(damagetype == DMG_BLAST) { + disableFF = Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 64 != 0; + } else { + // Does not run if DMG_BURN or DMG_BLAST + disableFF = true; + } + if(disableFF) { + float returnDmg = damage; //default is 1:1 + if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 2) { + returnDmg *= 2.0; + } else if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 4) { + returnDmg /= 2.0; + } else if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 8) { + returnDmg = 0.0; + } else if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 16) { + returnDmg *= 3.0; + } + SDKHooks_TakeDamage(attacker, attacker, attacker, returnDmg, damagetype, -1); + damage = 0.0; + return Plugin_Changed; + } + } + // Only retailate if 2 (anyone) or 1 and they aren't an admin. If we are also a bot. + if(IsFakeClient(victim) && (hBotReverseFFDefend.IntValue == 2 || GetUserAdmin(attacker) == INVALID_ADMIN_ID)) { + // If the attacker is not a bot and on our team, then retaliate + if(!IsFakeClient(attacker) && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) { + if(hBotDefendChance.IntValue >= GetURandomFloat()) { + if(pdata[victim].shootAtTarget == attacker) { + pdata[attacker].shootAtTargetHealth -= RoundToCeil(damage); + pdata[victim].shootAtLoops += 4; + return Plugin_Continue; + } else if(pdata[victim].shootAtTarget > 0) { + // Don't switch, wait for timer to stop + return Plugin_Continue; + } + SetBotTarget(attacker, victim, GetClientRealHealth(attacker) - RoundFloat(damage)); + } + } + } + } + // If FF is fire / blast, allow through unless its from a bot, then stop. + // Prevents players with no FF from lighting team on fire and disconnecting, making their new bot do the FF if(damagetype & DMG_BURN || damagetype & DMG_BLAST) { if(IsFakeClient(attacker)) return Plugin_Handled; else return Plugin_Continue; } + // Don't let bots do damage to the wrong targets if they are "defending" themselves if(hBotReverseFFDefend.IntValue > 0 && IsFakeClient(attacker) && pdata[attacker].shootAtTarget == 0 && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) return Plugin_Stop; - if(attacker != victim && hBotReverseFFDefend.IntValue > 0 && hBotReverseFFDefend.IntValue == 2 || GetUserAdmin(attacker) == INVALID_ADMIN_ID) { - if(IsFakeClient(victim) && !IsFakeClient(attacker) && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) { - if(hBotDefendChance.IntValue >= GetRandomFloat()) { - if(pdata[victim].shootAtTarget == attacker) { - pdata[attacker].shootAtTargetHealth -= RoundFloat(damage); - pdata[victim].shootAtLoops += 4; - return Plugin_Continue; - } else if(pdata[victim].shootAtTarget > 0) { - // Don't switch, wait for timer to stop - return Plugin_Continue; - } - SetBotTarget(attacker, victim, GetClientRealHealth(attacker) - RoundFloat(damage)); - } - } - } } return Plugin_Continue; } diff --git a/scripting/include/feedthetrolls/misc.inc b/scripting/include/feedthetrolls/misc.inc index 9a27b0b..d3336c3 100644 --- a/scripting/include/feedthetrolls/misc.inc +++ b/scripting/include/feedthetrolls/misc.inc @@ -348,22 +348,6 @@ stock void ExplodeProjectile(int entity, bool smoke = true) { SetEntProp(entity, Prop_Data, "m_nNextThinkTick", 1); //for smoke } -bool SpawnCarOnPlayer(int target) { - float min[3] = { -30.0, -30.0, -2.0}; - float max[3] = { 30.0, 30.0, 50.0 }; - float pos[3]; - float ang[3]; - GetClientEyePosition(target, pos); - GetClientEyeAngles(target, ang); - if(IsAreaClear(pos, ang, min, max)) { - pos[2] += 40.0; - int id = CreateProp("prop_physics", MODEL_CAR, pos, ang); - CreateTimer(4.0, Timer_Delete, id); - return true; - } - return false; -} - stock int CreateProp(const char[] entClass, const char[] model, const float pos[3], const float ang[3] = { 0.0, 0.0, 0.0 }, const float vel[3] = {0.0, 0.0, 0.0}) { int entity = CreateEntityByName(entClass); DispatchKeyValue(entity, "model", model); @@ -412,6 +396,22 @@ bool SpawnCarToPlayer(int target, float distance) { return true; } +bool SpawnCarOnPlayer(int target) { + float min[3] = { -30.0, -30.0, -2.0}; + float max[3] = { 30.0, 30.0, 50.0 }; + float pos[3]; + float ang[3]; + GetClientEyePosition(target, pos); + GetClientEyeAngles(target, ang); + if(IsAreaClear(pos, ang, min, max)) { + pos[2] += 40.0; + int id = CreateProp("prop_physics", MODEL_CAR, pos, ang); + CreateTimer(4.0, Timer_Delete, id); + return true; + } + return false; +} + bool g_iPendingSurvivorAdd; int isCustomSurvivor[MAXPLAYERS+1]; @@ -446,7 +446,7 @@ void ClearInventory(int client) { } } -void StopHealingBots(bool dontKill = false) { +void StopHealingBots() { healTargetPlayer = 0; for(int i = 1; i <= MaxClients; i++) { pdata[i].flags &= ~view_as(Flag_IsTargettingHealer); diff --git a/scripting/include/feedthetrolls/timers.inc b/scripting/include/feedthetrolls/timers.inc index 6507755..28c7e1c 100644 --- a/scripting/include/feedthetrolls/timers.inc +++ b/scripting/include/feedthetrolls/timers.inc @@ -1,18 +1,16 @@ -Action Timer_ThrowTimer(Handle timer) { - int count = 0; - for(int i = 1; i < MaxClients; i++) { - if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && IsTrollActive(i, "Throw It All")) { - ThrowAllItems(i); - count++; - } +Action Timer_ThrowTimer(Handle timer, int client) { + if(!IsClientInGame(client)) { + Trolls[t_throwItAllIndex].timerHandles[client] = null; + return Plugin_Stop; } - return count > 0 ? Plugin_Continue : Plugin_Stop; + ThrowAllItems(client); + return Plugin_Continue; } int instantCommonRef[MAXPLAYERS+1]; Action Timer_RandomVelocity(Handle h, int client) { - if(!IsClientConnected(client)) { + if(!IsClientInGame(client)) { Trolls[t_randomizeVelocityIndex].timerHandles[client] = null; return Plugin_Stop; } @@ -139,7 +137,7 @@ Action Timer_Main(Handle timer) { amplitude = 100.0; freq = 200.0; } - ShakePlayer(i, amplitude, freq, MAIN_TIMER_INTERVAL_S + 1.0); + ShakePlayer(i, amplitude, freq, MAIN_TIMER_INTERVAL_S + 2.0); } if(Trolls[t_slotRouletteIndex].IsActive(i) && Trolls[t_slotRouletteIndex].activeFlagClients[i] & 8) { float chance = 1.0; @@ -155,6 +153,9 @@ Action Timer_Main(Handle timer) { SetSlot(i, -1); } } + if(Trolls[t_hideHUDIndex].IsActive(i)) { + HideHUDRandom(i); + } } } if(++loopTick >= 60) { @@ -163,7 +164,7 @@ Action Timer_Main(Handle timer) { return Plugin_Continue; } Action Timer_SlotRoulette(Handle h, int client) { - if(!IsClientConnected(client)) { + if(!IsClientInGame(client)) { Trolls[t_slotRouletteIndex].timerHandles[client] = null; return Plugin_Stop; } @@ -411,8 +412,7 @@ Action Timer_StopHealBots(Handle h, DataPack pack) { if(victim) { DisableTroll(victim, "Dep Bots"); } - // TODO: stop right one - StopHealingBots(true); + StopHealingBots(); return Plugin_Stop; } @@ -474,4 +474,27 @@ Action Timer_ResetGravity(Handle h, int entref) { SetEntityGravity(entity, 800.0); // could pull from sv_gravity but no ones gonna notice } return Plugin_Handled; +} +Action Timer_RestoreHud(Handle h, int userid) { + int client = GetClientOfUserId(userid); + if(client > 0) { + 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 cd2987a..ebcd154 100644 --- a/scripting/include/feedthetrolls/trolls.inc +++ b/scripting/include/feedthetrolls/trolls.inc @@ -8,7 +8,11 @@ int t_randomizeVelocityIndex; int t_vomitPlayerIndex; int t_shakeyCameraIndex; int t_slotRouletteIndex; -// int fireSpitMagnetTrollIndex; +int t_damageBoostIndex; +int t_reverseFFIndex; +int t_throwItAllIndex; +int t_hideHUDIndex; +int t_cameraTurnIndex; void SetupTrolls() { trollKV = new StringMap(); @@ -87,7 +91,8 @@ void SetupTrolls() { // CATEGORY: Items SetCategory("Items"); - SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant); + index = SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant); + Trolls[index].SetTimer(THROWITALL_INTERVAL, Timer_ThrowTimer); index = SetupTroll("Spicy Gas", "Gascans player picks up just ignite. Magic.", TrollMod_Constant); Trolls[index].AddFlagPrompt(false); Trolls[index].AddFlag("Always (100%)", false); @@ -159,7 +164,7 @@ void SetupTrolls() { /// CATEGORY: Health SetCategory("Health"); - SetupTroll("Damage Boost", "Makes a player take more damage than normal", TrollMod_Constant); + t_damageBoostIndex = 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); @@ -173,6 +178,7 @@ void SetupTrolls() { Trolls[index].AddCustomFlagPrompt("Modes", true); Trolls[index].AddFlag("Reverse Fire Damage", false); //32 Trolls[index].AddFlag("Reverse Explosions", false); //64 + t_reverseFFIndex = index; index = SetupTroll("Dep Bots", "Makes bots heal a player. At any cost", TrollMod_Constant); @@ -230,6 +236,12 @@ 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 @@ -253,13 +265,20 @@ void SetupTrolls() { Trolls[index].AddFlag("Violent", false); Trolls[index].AddFlag("Violent XX", false); t_shakeyCameraIndex = index; + index = SetupTroll("Hide HUD", "Horrible", TrollMod_Constant); + Trolls[index].AddFlagPrompt(false); + Trolls[index].AddFlag("Rare & Short", false); + Trolls[index].AddFlag("Sometimes & Medium", false); + Trolls[index].AddFlag("Constantly", true); + t_hideHUDIndex = index; + index = SetupTroll("Meta: Random", "Picks a random troll", TrollMod_Instant); index = SetupTroll("Meta: Inverse", "Uhm you are not supposed to see this...", TrollMod_Instant); Trolls[index].hidden = true; Trolls[index].AddFlagPrompt(false); Trolls[index].AddFlag("100%", true); Trolls[index].AddFlag("50%", false); Trolls[index].AddFlag("10%", false); - index = SetupTroll("Meta: Random", "Picks a random troll", TrollMod_Instant); + @@ -337,9 +356,6 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod ThrowItemToPlayer(victim, activator, 3); } else ThrowAllItems(victim); } - if(hThrowTimer == INVALID_HANDLE && modifier & TrollMod_Constant) { - hThrowTimer = CreateTimer(hThrowItemInterval.FloatValue, Timer_ThrowTimer, _, TIMER_REPEAT); - } } else if(StrEqual(troll.name, "Swarm")) { if(modifier & TrollMod_Instant) { L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", victim, 15000); @@ -519,6 +535,11 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod CreateTimer(1.0, Timer_CheckForChargerOpportunity, GetClientUserId(victim), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); } else if(StrEqual(troll.name, "No Rushing Us")) { SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0); + } else if(StrEqual(troll.name, "Hide HUD")) { + if(toActive) + HideHUDRandom(victim); + else + SetEntProp(victim, Prop_Send, "m_iHideHUD", 0); } else if(StrEqual(troll.name, "Meta: Random")) { int rndTroll = GetRandomInt(0, MAX_TROLLS); int rndFlags = 0; @@ -531,11 +552,10 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod } trollModifier rndMod = Trolls[rndTroll].GetDefaultMod(); if(Trolls[rndTroll].HasMod(TrollMod_Constant) && GetURandomFloat() > 0.5) { + rndMod = TrollMod_Instant; + } else if(Trolls[rndTroll].HasMod(TrollMod_Instant) && GetURandomFloat() > 0.5) { rndMod = TrollMod_Constant; } - if(Trolls[rndTroll].HasMod(TrollMod_Instant) && GetURandomFloat() > 0.5) { - rndMod |= TrollMod_Instant; - } Trolls[rndTroll].Activate(victim, activator, rndMod, rndFlags); } else if(~modifier & TrollMod_Constant) { PrintToServer("[FTT] Warn: Possibly invalid troll, no apply action defined for \"%s\"", troll.name); diff --git a/scripting/include/ftt.inc b/scripting/include/ftt.inc index 3fdc8fb..7242a69 100644 --- a/scripting/include/ftt.inc +++ b/scripting/include/ftt.inc @@ -15,10 +15,8 @@ GlobalForward g_PlayerMarkedForward; GlobalForward g_TrollAppliedForward; Handle g_hWitchAttack; int g_iWitchAttackVictim; -Handle hThrowTimer; ConVar hAllowEnemyTeam; -ConVar hThrowItemInterval; ConVar hAutoPunish; ConVar hShoveFailChance; ConVar hAutoPunishExpire;