Update FTT

This commit is contained in:
Jackzie 2021-11-09 10:25:34 -06:00
parent 956df81ba8
commit ca2831ec53
No known key found for this signature in database
GPG key ID: 1E834FE36520537A
10 changed files with 271 additions and 127 deletions

Binary file not shown.

View file

@ -4,13 +4,14 @@
//Allow MAX_TROLLS to be defined elsewhere //Allow MAX_TROLLS to be defined elsewhere
#if defined MAX_TROLLS #if defined MAX_TROLLS
#else #else
#define MAX_TROLLS 32 #define MAX_TROLLS 33
#endif #endif
enum trollModifier { enum trollModifier {
TrollMod_Invalid = 0, TrollMod_Invalid = 0,
TrollMod_Instant = 1, TrollMod_Instant = 1 << 0,
TrollMod_Constant = 2 TrollMod_Constant = 1 << 1,
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 //up to 30 flags technically possiible
@ -32,6 +33,7 @@ char DEFAULT_FLAG_PROMPT[] = "Choose flags";
bool SilentMenuSelected[MAXPLAYERS+1]; bool SilentMenuSelected[MAXPLAYERS+1];
static int g_trollAddPromptIndex; static int g_trollAddPromptIndex;
ArrayList gRandomClients;
enum struct TrollFlagPrompt { enum struct TrollFlagPrompt {
char promptText[MAX_TROLL_FLAG_LENGTH]; char promptText[MAX_TROLL_FLAG_LENGTH];
@ -57,13 +59,14 @@ enum struct Troll {
char name[MAX_TROLL_NAME_LENGTH]; char name[MAX_TROLL_NAME_LENGTH];
char description[128]; char description[128];
bool hidden;
int mods; int mods;
// Flags
int activeFlagClients[MAXPLAYERS+1]; int activeFlagClients[MAXPLAYERS+1];
ArrayList flagNames;
bool flagsMultiselectable;
char flagPrompt[MAX_TROLL_FLAG_LENGTH]; char flagPrompt[MAX_TROLL_FLAG_LENGTH];
ArrayList flagNames;
ArrayList flagPrompts; ArrayList flagPrompts;
bool HasMod(trollModifier mod) { bool HasMod(trollModifier mod) {
@ -177,6 +180,7 @@ enum struct Troll {
void Activate(int client, int activator, trollModifier modifier = TrollMod_Invalid, int flags = 0) { void Activate(int client, int activator, trollModifier modifier = TrollMod_Invalid, int flags = 0) {
if(modifier == TrollMod_Invalid) modifier = this.GetDefaultMod(); if(modifier == TrollMod_Invalid) modifier = this.GetDefaultMod();
// Sadly, unable to pass in <this> to ApplyTroll, so it has to do unnecessary lookup via string
ApplyTroll(client, this.name, activator, modifier, flags); ApplyTroll(client, this.name, activator, modifier, flags);
} }
@ -195,6 +199,17 @@ enum struct Troll {
bool IsActive(int client) { bool IsActive(int client) {
return this.activeFlagClients[client] != -1; return this.activeFlagClients[client] != -1;
} }
int GetRandomClient(int start = 0) {
gRandomClients.Clear();
for(int i = start + 1; i <= MaxClients; i++) {
if(this.activeFlagClients[i] != -1) {
gRandomClients.Push(i);
}
}
if(gRandomClients.Length == 0) return -1;
return GetRandomInt(0, gRandomClients.Length);
}
} }
Troll Trolls[MAX_TROLLS+1]; Troll Trolls[MAX_TROLLS+1];
@ -203,12 +218,13 @@ ArrayList categories;
static int categoryID = -1; static int categoryID = -1;
void ResetClient(int victim, bool wipe = true) { void ResetClient(int victim, bool wipe = true) {
if(victim == 0) return; if(victim == 0 || !IsClientConnected(victim)) return;
if(wipe) { if(wipe) {
for(int i = 0; i <= MAX_TROLLS; i++) { for(int i = 0; i <= MAX_TROLLS; i++) {
Trolls[i].activeFlagClients[victim] = -1; Trolls[i].activeFlagClients[victim] = -1;
} }
} }
SetEntityGravity(victim, 1.0); SetEntityGravity(victim, 1.0);
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0); SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
SDKUnhook(victim, SDKHook_WeaponCanUse, Event_ItemPickup); SDKUnhook(victim, SDKHook_WeaponCanUse, Event_ItemPickup);
@ -217,14 +233,14 @@ void ResetClient(int victim, bool wipe = true) {
SDKUnhook(wpn, SDKHook_Reload, Event_WeaponReload); SDKUnhook(wpn, SDKHook_Reload, Event_WeaponReload);
} }
int SetupTroll(const char[] name, const char description[128], int mods, bool flagsMultiselectable = false) { int SetupTroll(const char[] name, const char description[128], int mods) {
if(mods == 0) {
ThrowError("Troll \"%s\" has no flags defined.", name);
return -1;
}
static int i = 0; static int i = 0;
if(i == MAX_TROLLS + 1) { if(mods == 0) {
ThrowError("Troll \"%s\" has no modifiers defined.", name);
return -1;
} else if(i == MAX_TROLLS + 1) {
ThrowError("Maximum number of trolls (%d) reached. Up MAX_TROLLS value.", MAX_TROLLS); ThrowError("Maximum number of trolls (%d) reached. Up MAX_TROLLS value.", MAX_TROLLS);
return -1;
} }
g_trollAddPromptIndex = 0; g_trollAddPromptIndex = 0;
Trolls[i].id = i; Trolls[i].id = i;
@ -232,7 +248,6 @@ int SetupTroll(const char[] name, const char description[128], int mods, bool fl
strcopy(Trolls[i].description, 128, description); strcopy(Trolls[i].description, 128, description);
Trolls[i].categoryID = categoryID; Trolls[i].categoryID = categoryID;
Trolls[i].mods = mods; Trolls[i].mods = mods;
Trolls[i].flagsMultiselectable = flagsMultiselectable;
Trolls[i].flagPrompts = new ArrayList(sizeof(TrollFlagPrompt)); Trolls[i].flagPrompts = new ArrayList(sizeof(TrollFlagPrompt));
strcopy(trollIds[i], MAX_TROLL_NAME_LENGTH, name); strcopy(trollIds[i], MAX_TROLL_NAME_LENGTH, name);
@ -284,7 +299,7 @@ void ToggleTroll(int client, const char[] name, int flags = 0) {
troll.activeFlagClients[client] = flags; troll.activeFlagClients[client] = flags;
} }
void ApplyTroll(int victim, const char[] name, int activator, trollModifier modifier, int flags = 0) { void ApplyTroll(int victim, const char[] name, int activator, trollModifier modifier, int flags = 0, bool silent = false) {
static Troll troll; static Troll troll;
int trollIndex = GetTroll(name, troll); int trollIndex = GetTroll(name, troll);
if(trollIndex == -1) { if(trollIndex == -1) {
@ -292,21 +307,46 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi
return; return;
} }
if(GetClientTeam(victim) == 1) { if(!silent && SilentMenuSelected[activator]) silent = true;
//Victim is spectating, find its bot
victim = FindIdlePlayerBot(victim); static int MetaInverseTrollID;
if(!MetaInverseTrollID) MetaInverseTrollID = GetTrollID("Meta: Inverse");
if(activator > 0 && Trolls[MetaInverseTrollID].IsActive(activator)) {
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) {
victim = activator;
}
} }
// If victim is a survivor bot, check if has an idle player
if(IsFakeClient(victim) && GetClientTeam(victim) == 2) {
int player = GetSpectatorClient(victim);
if(player > 0) {
// 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<int>(TrollMod_PlayerOnly)) return;
// Don't want to show two logs, so just ignore the bot
silent = true;
}
}
// Applies any custom logic needed for a troll, mostly only used for TrollMod_Instant
if(!ApplyAffect(victim, troll, activator, modifier, flags)) { if(!ApplyAffect(victim, troll, activator, modifier, flags)) {
return; return;
} }
// Log all actions, indicating if constant or single-fire, and if any flags
bool isActive = IsTrollActive(victim, troll.name); bool isActive = IsTrollActive(victim, troll.name);
if(!SilentMenuSelected[activator]) { if(!silent) {
if(isActive) { if(isActive) {
ShowActivityEx(activator, "[FTT] ", "deactivated troll \"%s\" on %N. ", troll.name, victim); ShowActivityEx(activator, "[FTT] ", "deactivated troll \"%s\" on %N. ", troll.name, victim);
LogAction(activator, victim, "\"%L\" deactivated troll \"%s\" on \"%L\"", activator, troll.name, victim); LogAction(activator, victim, "\"%L\" deactivated troll \"%s\" on \"%L\"", activator, troll.name, victim);
} else { } else {
if(modifier == TrollMod_Constant) { if(modifier & TrollMod_Constant) {
if(flags > 0) { if(flags > 0) {
ShowActivityEx(activator, "[FTT] ", "activated constant troll \"%s\" (%d) for %N. ", troll.name, flags, victim); ShowActivityEx(activator, "[FTT] ", "activated constant troll \"%s\" (%d) for %N. ", troll.name, flags, victim);
} else } else
@ -318,8 +358,11 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi
LogAction(activator, victim, "\"%L\" activated troll \"%s\" (%d) for \"%L\"", activator, troll.name, flags, victim); LogAction(activator, victim, "\"%L\" activated troll \"%s\" (%d) for \"%L\"", activator, troll.name, flags, victim);
} }
} else SilentMenuSelected[activator] = false; } else {
if(modifier == TrollMod_Constant) { ReplyToCommand(activator, "apply troll \"%s\" flags=%d on %N", troll.name, flags, victim);
}
// Toggle on flags for client, if it's not a single run.
if(modifier & TrollMod_Constant) {
Trolls[troll.id].activeFlagClients[victim] = isActive ? -1 : flags; Trolls[troll.id].activeFlagClients[victim] = isActive ? -1 : flags;
} }
} }

View file

@ -13,6 +13,10 @@ public Action Command_InstaSpecial(int client, int args) {
menu.ExitButton = true; menu.ExitButton = true;
menu.Display(client, 0); menu.Display(client, 0);
} else { } else {
if(gInstaSpecialType > -1) {
ReplyToCommand(client, "Please wait for last Insta to spawn.");
return Plugin_Handled;
}
char arg1[32], arg2[32] = "jockey"; char arg1[32], arg2[32] = "jockey";
GetCmdArg(1, arg1, sizeof(arg1)); GetCmdArg(1, arg1, sizeof(arg1));
if(args >= 2) { if(args >= 2) {
@ -78,6 +82,10 @@ public Action Command_InstaSpecialFace(int client, int args) {
menu.ExitButton = true; menu.ExitButton = true;
menu.Display(client, 0); menu.Display(client, 0);
} else { } else {
if(gInstaSpecialType > -1) {
ReplyToCommand(client, "Please wait for last Insta to spawn.");
return Plugin_Handled;
}
char arg1[32], arg2[32] = "jockey"; char arg1[32], arg2[32] = "jockey";
GetCmdArg(1, arg1, sizeof(arg1)); GetCmdArg(1, arg1, sizeof(arg1));
if(args >= 2) { if(args >= 2) {
@ -215,6 +223,7 @@ public Action Command_ResetUser(int client, int args) {
public Action Command_ApplyUser(int client, int args) { public Action Command_ApplyUser(int client, int args) {
if(args < 1) { if(args < 1) {
SilentMenuSelected[client] = false;
ShowTrollMenu(client); ShowTrollMenu(client);
}else{ }else{
char arg1[32], arg2[16]; char arg1[32], arg2[16];
@ -244,12 +253,14 @@ public Action Command_ApplyUser(int client, int args) {
for(int i = 0; i < categories.Length; i++) { for(int i = 0; i < categories.Length; i++) {
categories.GetString(i, key, sizeof(key)); categories.GetString(i, key, sizeof(key));
if(StrEqual(key, arg2, false)) { if(StrEqual(key, arg2, false)) {
SilentMenuSelected[client] = false;
ShowTrollsForCategory(client, GetClientUserId(target_list[0]), i); ShowTrollsForCategory(client, GetClientUserId(target_list[0]), i);
return Plugin_Handled; return Plugin_Handled;
} }
} }
ReplyToCommand(client, "[FTT] Unknown category: '%s'", arg2); ReplyToCommand(client, "[FTT] Unknown category: '%s'", arg2);
} }
SilentMenuSelected[client] = false;
SetupCategoryMenu(client, target_list[0]); SetupCategoryMenu(client, target_list[0]);
} }
return Plugin_Handled; return Plugin_Handled;
@ -304,6 +315,7 @@ public Action Command_ListModes(int client, int args) {
static Troll troll; static Troll troll;
for(int i = 0; i <= MAX_TROLLS; i++) { for(int i = 0; i <= MAX_TROLLS; i++) {
GetTrollByKeyIndex(i, troll); GetTrollByKeyIndex(i, troll);
if(troll.hidden) continue;
ReplyToCommand(client, "%d. %s - %s", i, troll.name, troll.description); ReplyToCommand(client, "%d. %s - %s", i, troll.name, troll.description);
} }
return Plugin_Handled; return Plugin_Handled;
@ -346,6 +358,7 @@ public Action Command_ListTheTrolls(int client, int args) {
} }
for(int j = 1; j <= MAX_TROLLS; j++) { for(int j = 1; j <= MAX_TROLLS; j++) {
if(Trolls[j].hidden) continue;
if(trollIds[j][0] != '\0' && IsTrollActive(target, trollIds[j])) { if(trollIds[j][0] != '\0' && IsTrollActive(target, trollIds[j])) {
if(Trolls[j].activeFlagClients[target] > 0) { if(Trolls[j].activeFlagClients[target] > 0) {
static char list[MAX_TROLL_FLAG_LENGTH*8]; //May in future need to up magic number 8 (supports 8 active flags ) static char list[MAX_TROLL_FLAG_LENGTH*8]; //May in future need to up magic number 8 (supports 8 active flags )
@ -423,7 +436,7 @@ public Action Command_MarkPendingTroll(int client, int args) {
menu.ExitButton = true; menu.ExitButton = true;
menu.Display(client, 0); menu.Display(client, 0);
} else { } else {
char arg1[32]; static char arg1[32];
GetCmdArg(1, arg1, sizeof(arg1)); GetCmdArg(1, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH]; char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count; int target_list[MAXPLAYERS], target_count;
@ -452,13 +465,45 @@ public Action Command_MarkPendingTroll(int client, int args) {
return Plugin_Handled; return Plugin_Handled;
} }
public Action Command_MarkNoob(int client, int args) {
if(args == 0) {
ReplyToCommand(client, "sm_noob <player>");
return Plugin_Handled;
}
static char target_name[MAX_TARGET_LENGTH];
GetCmdArg(1, target_name, sizeof(target_name));
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
target_name,
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];
//Todo: Check if marked as noob or not, undo if so, add if not
ShowActivityEx(client, "[FTT] ", "marked %N as a noob", target_name);
LogAction(client, target, "\"%L\" marked \"%L\" as a noob", client, target);
return Plugin_Handled;
}
public Action Command_FeedTheTrollMenu(int client, int args) { public Action Command_FeedTheTrollMenu(int client, int args) {
ReplyToCommand(client, "sm_ftl - Lists all the active trolls on players"); ReplyToCommand(client, "sm_ftl [player(s)] - Lists all the active trolls on players. Will show flag names if a player is specified.");
ReplyToCommand(client, "sm_ftm - Lists all available troll modes & descriptions"); ReplyToCommand(client, "sm_ftm - Lists all available trolls & descriptions");
ReplyToCommand(client, "sm_ftr - Resets target users' of their trolls"); ReplyToCommand(client, "sm_ftr <player(s)> - Resets target users' of any active trolls");
ReplyToCommand(client, "sm_fta - Applies a troll mode on targets"); ReplyToCommand(client, "sm_fta [player] [category] - Apply a troll on a player, with optional shortcut to player and/or category");
ReplyToCommand(client, "sm_ftt - Opens this menu"); ReplyToCommand(client, "sm_ftt - Shows this text");
ReplyToCommand(client, "sm_ftc - Will apply a punishment to last crescendo activator"); ReplyToCommand(client, "sm_ftc - Will apply a punishment to the last crescendo/event activator");
ReplyToCommand(client, "sm_mark - Marks the user to be banned on disconnect, prevents their FF."); ReplyToCommand(client, "sm_mark - Marks the user to be banned on disconnect, prevents their FF.");
return Plugin_Handled; return Plugin_Handled;
} }

View file

@ -19,6 +19,29 @@ public void OnMapStart() {
public void OnClientPutInServer(int client) { public void OnClientPutInServer(int client) {
g_PendingBanTroll[client] = 0; g_PendingBanTroll[client] = 0;
SDKHook(client, SDKHook_OnTakeDamage, Event_TakeDamage); SDKHook(client, SDKHook_OnTakeDamage, Event_TakeDamage);
}
public void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) {
int userid = event.GetInt("userid");
CreateTimer(0.1, Timer_CheckSpecial, userid);
}
public Action Timer_CheckSpecial(Handle h, int specialID) {
int special = GetClientOfUserId(specialID);
if(special > 0 && gInstaSpecialType > -1 && IsFakeClient(special) && GetClientTeam(special) == 3) {
int type = GetEntProp(special, Prop_Send, "m_zombieClass");
if(type == gInstaSpecialType) {
gInstaSpecialType = -1;
g_iAttackerTarget[special] = gInstaSpecialTarget;
gInstaSpecialMagnet[GetClientOfUserId(gInstaSpecialTarget)]++;
TeleportEntity(special, gInstaSpecialSpawnPos, gInstaSpecialSpawnAng, NULL_VECTOR);
if(gInstaSpecialInstaKill) {
SDKHooks_TakeDamage(special, special, special, 1000.0);
}
}
}
}
public void Frame_InstaSpawned(int special) {
} }
public void OnClientAuthorized(int client, const char[] auth) { public void OnClientAuthorized(int client, const char[] auth) {
if(!IsFakeClient(client)) { if(!IsFakeClient(client)) {
@ -39,6 +62,14 @@ public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroa
} }
public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) { public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid")); int client = GetClientOfUserId(event.GetInt("userid"));
if(client > 0 && g_iAttackerTarget[client] > 0) {
int target = GetClientOfUserId(g_iAttackerTarget[client]);
gInstaSpecialMagnet[target]--;
if(gInstaSpecialMagnet[target] == 0) {
PrintToServer("[FTT] gInstaSpecialMagnet droped below 0");
gInstaSpecialMagnet[target] = 0;
}
}
g_iAttackerTarget[client] = 0; g_iAttackerTarget[client] = 0;
} }
public Action Event_WeaponReload(int weapon) { public Action Event_WeaponReload(int weapon) {
@ -85,11 +116,14 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
if(hMagnetChance.FloatValue < GetRandomFloat()) return Plugin_Continue; if(hMagnetChance.FloatValue < GetRandomFloat()) return Plugin_Continue;
L4D2Infected class = view_as<L4D2Infected>(GetEntProp(attacker, Prop_Send, "m_zombieClass")); L4D2Infected class = view_as<L4D2Infected>(GetEntProp(attacker, Prop_Send, "m_zombieClass"));
int existingTarget = GetClientOfUserId(g_iAttackerTarget[attacker]); int existingTarget = GetClientOfUserId(g_iAttackerTarget[attacker]);
if(existingTarget > 0 && IsPlayerAlive(existingTarget) && (hMagnetTargetMode.IntValue & 1 != 1 || !IsPlayerIncapped(existingTarget))) { if(existingTarget > 0 && IsPlayerAlive(existingTarget)) {
if(class == L4D2Infected_Tank && (hMagnetTargetMode.IntValue % 2 != 2 || !IsPlayerIncapped(existingTarget))) { if(gInstaSpecialMagnet[existingTarget] > 0) {
curTarget = existingTarget; curTarget = existingTarget;
return Plugin_Changed; return Plugin_Changed;
}else if(hMagnetTargetMode.IntValue & 1 != 1 || !IsPlayerIncapped(existingTarget)) { } else if(class == L4D2Infected_Tank && (!IsPlayerIncapped(existingTarget) || hMagnetTargetMode.IntValue & 2) && WillMagnetRun(Trolls[tankMagnetID], existingTarget)) {
curTarget = existingTarget;
return Plugin_Changed;
}else if((!IsPlayerIncapped(existingTarget) || hMagnetTargetMode.IntValue & 1) && WillMagnetRun(Trolls[spMagnetID], existingTarget)) {
curTarget = existingTarget; curTarget = existingTarget;
return Plugin_Changed; return Plugin_Changed;
} }
@ -102,7 +136,7 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
//Ignore incapped players if turned on: //Ignore incapped players if turned on:
if(IsPlayerIncapped(i)) { if(IsPlayerIncapped(i)) {
if((class == L4D2Infected_Tank && hMagnetTargetMode.IntValue & 2 == 2) || hMagnetTargetMode.IntValue & 1 == 1 ) continue; if((class == L4D2Infected_Tank && hMagnetTargetMode.IntValue & 2) || (class != L4D2Infected_Tank && hMagnetTargetMode.IntValue & 1)) continue;
} }
if(class == L4D2Infected_Tank && Trolls[tankMagnetID].IsActive(i) || (class != L4D2Infected_Tank && Trolls[spMagnetID].IsActive(i))) { if(class == L4D2Infected_Tank && Trolls[tankMagnetID].IsActive(i) || (class != L4D2Infected_Tank && Trolls[spMagnetID].IsActive(i))) {
@ -355,10 +389,10 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
return Plugin_Continue; return Plugin_Continue;
} }
static int invertedTrollIndex; static int invertedTrollIndex;
if(invertedTrollIndex <= 0) { if(invertedTrollIndex == 0) {
invertedTrollIndex = GetTrollID("Inverted Controls"); invertedTrollIndex = GetTrollID("Inverted Controls");
} }
if(IsTrollActiveByRawID(client, invertedTrollIndex)) { if(Trolls[invertedTrollIndex].IsActive(client)) {
if(buttons & IN_MOVELEFT || buttons & IN_MOVERIGHT) { if(buttons & IN_MOVELEFT || buttons & IN_MOVERIGHT) {
vel[1] = -vel[1]; vel[1] = -vel[1];
} }
@ -397,7 +431,7 @@ public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float&
if(IsTrollActive(victim, "Damage Boost")) { if(IsTrollActive(victim, "Damage Boost")) {
damage * 2; damage * 2;
return Plugin_Changed; return Plugin_Changed;
} else if(Trolls[reverseFF].IsActive(attacker) && attacker != victim && GetClientTeam(attacker) != GetClientTeam(victim)) { } else if(Trolls[reverseFF].IsActive(attacker) && attacker != victim && GetClientTeam(attacker) == GetClientTeam(victim)) {
float returnDmg = damage; //default is 1:1 float returnDmg = damage; //default is 1:1
if(Trolls[reverseFF].activeFlagClients[attacker] & 4) { if(Trolls[reverseFF].activeFlagClients[attacker] & 4) {
returnDmg /= 2.0; returnDmg /= 2.0;
@ -413,6 +447,8 @@ public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float&
} }
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) { 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) {
static int honkID;
if(honkID == 0) honkID = GetTrollID("Honk / Meow");
if(lastButtonUser > -1 && StrEqual(sample, "npc/mega_mob/mega_mob_incoming.wav")) { if(lastButtonUser > -1 && StrEqual(sample, "npc/mega_mob/mega_mob_incoming.wav")) {
PrintToConsoleAll("CRESCENDO STARTED BY %N", lastButtonUser); PrintToConsoleAll("CRESCENDO STARTED BY %N", lastButtonUser);
#if defined DEBUG #if defined DEBUG
@ -429,22 +465,16 @@ public Action SoundHook(int[] clients, int& numClients, char sample[PLATFORM_MAX
lastButtonUser = -1; lastButtonUser = -1;
}else if(numClients > 0 && entity > 0 && entity <= MaxClients) { }else if(numClients > 0 && entity > 0 && entity <= MaxClients) {
if(StrContains(sample, "survivor\\voice") > -1) { if(StrContains(sample, "survivor\\voice") > -1) {
static int honkID;
if(honkID == 0) {
honkID = GetTrollID("Honk / Meow");
}
if(Trolls[honkID].IsActive(entity)) { if(Trolls[honkID].IsActive(entity)) {
if(Trolls[honkID].activeFlagClients[entity] & 1) if(Trolls[honkID].activeFlagClients[entity] & 1)
strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav"); strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav");
else if(Trolls[honkID].activeFlagClients[entity] & 2) else if(Trolls[honkID].activeFlagClients[entity] & 2)
strcopy(sample, sizeof(sample), "custom/meow1.mp3"); strcopy(sample, sizeof(sample), "custom/meow1.mp3");
else return Plugin_Continue; else return Plugin_Continue;
return Plugin_Changed;
} else if(IsTrollActive(entity, "Vocalize Gag")) { } else if(IsTrollActive(entity, "Vocalize Gag")) {
return Plugin_Handled; return Plugin_Handled;
} }
} }
} }
return Plugin_Continue; return Plugin_Continue;
} }
@ -457,7 +487,7 @@ public Action Event_WitchVictimSet(Event event, const char[] name, bool dontBroa
for(int i = 1; i <= MaxClients; i++) { for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
//Ignore incapped players if hWitchIgnoreIncapp turned on: //Ignore incapped players if hWitchIgnoreIncapp turned on:
if(IsPlayerIncapped(i) && !hWitchTargetIncapp.BoolValue) { if(IsPlayerIncapped(i) && ~hMagnetTargetMode.IntValue & 4) {
continue; continue;
} }

View file

@ -227,14 +227,15 @@ public int ChooseTrollFlagHandler(Menu menu, MenuAction action, int param1, int
if (action == MenuAction_Select) { if (action == MenuAction_Select) {
static char info[32]; static char info[32];
menu.GetItem(param2, info, sizeof(info)); menu.GetItem(param2, info, sizeof(info));
static char str[5][8]; static char str[6][8];
ExplodeString(info, "|", str, 5, 8, false); ExplodeString(info, "|", str, 6, 8, false);
int userid = StringToInt(str[0]); int userid = StringToInt(str[0]);
int client = GetClientOfUserId(userid); int client = GetClientOfUserId(userid);
int keyIndex = StringToInt(str[1]); int keyIndex = StringToInt(str[1]);
int modifiers = StringToInt(str[2]); int modifiers = StringToInt(str[2]);
int flags = StringToInt(str[3]); int flags = StringToInt(str[3]);
int nextIndex = StringToInt(str[4]); int index = StringToInt(str[4]);
bool isDone = StringToInt(str[5]) == 1; // 0 = cont, 1 = done
if(client == 0) { if(client == 0) {
ReplyToCommand(param1, "FTT: Could not acquire player"); ReplyToCommand(param1, "FTT: Could not acquire player");
@ -247,13 +248,17 @@ public int ChooseTrollFlagHandler(Menu menu, MenuAction action, int param1, int
static TrollFlagPrompt prompt; static TrollFlagPrompt prompt;
// If told to go to next prompt, find the next VALID prompt // If told to go to next prompt, find the next VALID prompt
// Valid prompt is one where the required flags for it, are active // Valid prompt is one where the required flags for it, are active
if(nextIndex != -1) { if(isDone || index == -1) {
nextIndex = GetNextPrompt(troll, flags, nextIndex); int nextIndex = GetNextPrompt(troll, flags, index);
// If there is a prompt available, show it, else fall down // If there is a prompt available, show it, else fall down
if(nextIndex != -1) { if(nextIndex != -1) {
ShowSelectFlagMenu(param1, userid, modifiers, troll, flags, nextIndex); ShowSelectFlagMenu(param1, userid, modifiers, troll, flags, nextIndex);
return; return;
} }
// else fall through & apply
} else {
ShowSelectFlagMenu(param1, userid, modifiers, troll, flags, index);
return;
} }
// Done with prompts, apply flags & modifiers // Done with prompts, apply flags & modifiers
@ -302,6 +307,7 @@ void ShowTrollMenu(int client) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
IntToString(GetClientUserId(i), userid, sizeof(userid)); IntToString(GetClientUserId(i), userid, sizeof(userid));
int specClient = GetSpectatorClient(i); int specClient = GetSpectatorClient(i);
// Incase player is idle, grab their bot instead of them
if(specClient > 0) if(specClient > 0)
Format(display, sizeof(display), "%N (Idle)", specClient); Format(display, sizeof(display), "%N (Idle)", specClient);
else else
@ -328,6 +334,8 @@ void ShowTrollsForCategory(int client, int userid, int category) {
static char name[MAX_TROLL_NAME_LENGTH+8]; static char name[MAX_TROLL_NAME_LENGTH+8];
for(int i = 0; i < trollKV.Size; i++) { for(int i = 0; i < trollKV.Size; i++) {
GetTrollByKeyIndex(i, troll); GetTrollByKeyIndex(i, troll);
// If troll is hidden and using normal menu, do not show
if(troll.hidden && !SilentMenuSelected[client]) continue;
if(troll.categoryID == category) { if(troll.categoryID == category) {
Format(info, sizeof(info), "%d|%d", userid, i); Format(info, sizeof(info), "%d|%d", userid, i);
if(troll.IsActive(victim)) { if(troll.IsActive(victim)) {
@ -356,19 +364,11 @@ void ShowSelectFlagMenu(int activator, int victimUserID, int modifiers, Troll tr
Format(info, sizeof(info), "%s: %s", troll.name, info); Format(info, sizeof(info), "%s: %s", troll.name, info);
flagMenu.SetTitle(info); flagMenu.SetTitle(info);
// If there is another prompt, go to this index, or be done (-1)
int nextIndex = (promptIndex < troll.flagPrompts.Length - 1) ? promptIndex + 1 : -1;
if(prompt.multiselect) { if(prompt.multiselect) {
if(prevFlags == 0) prevFlags = prompt.defaults; if(prevFlags == 0) prevFlags = prompt.defaults;
// If there is a next prompt (even if may not be suitable), show a "next prompt" msg instead Format(info, sizeof(info), "%d|%d|%d|%d|%d|1", victimUserID, troll.id, modifiers, prevFlags, promptIndex);
Format(info, sizeof(info), "%d|%d|%d|%d|%d", victimUserID, troll.id, modifiers, prevFlags, nextIndex); flagMenu.AddItem(info, "Apply / Next Prompt");
if(nextIndex == -1)
flagMenu.AddItem(info, "Apply Troll / Finish");
else
flagMenu.AddItem(info, "Next Prompt");
for(int i = 0; i < troll.flagNames.Length; i++) { for(int i = 0; i < troll.flagNames.Length; i++) {
int a = 1 << i; int a = 1 << i;
@ -378,21 +378,22 @@ void ShowSelectFlagMenu(int activator, int victimUserID, int modifiers, Troll tr
if(prevFlags > 0 && prevFlags & a) if(prevFlags > 0 && prevFlags & a)
Format(name, sizeof(name), "%s (On)", name); Format(name, sizeof(name), "%s (On)", name);
int newFlags = prevFlags ^ a; //Toggle the flag instead of setting like below, as it's toggleable here int newFlags = prevFlags ^ a; //Toggle the flag instead of setting like below, as it's toggleable here
Format(info, sizeof(info), "%d|%d|%d|%d|%d", victimUserID, troll.id, modifiers, newFlags, promptIndex); Format(info, sizeof(info), "%d|%d|%d|%d|%d|0", victimUserID, troll.id, modifiers, newFlags, promptIndex);
flagMenu.AddItem(info, name); flagMenu.AddItem(info, name);
} }
} }
} else { } else {
// Single choice only // Single choice only
for(int i = 0; i < troll.flagNames.Length; i++) { for(int i = 0; i < troll.flagNames.Length; i++) {
if(prompt.flags & 1 << i) { int a = 1 << i;
if(prompt.flags & a) {
troll.flagNames.GetString(i, name, sizeof(name)); troll.flagNames.GetString(i, name, sizeof(name));
// Add (default) indicator // Add (default) indicator
if(prompt.defaults & 1 << i) if(prompt.defaults & a)
Format(name, sizeof(name), "%s (default)", name); Format(name, sizeof(name), "%s (default)", name);
int newFlags = prevFlags | 1 << i; //Set flag with any from previous prompts int newFlags = prevFlags | a; //Set flag with any from previous prompts
Format(info, sizeof(info), "%d|%d|%d|%d|%d", victimUserID, troll.id, modifiers, newFlags, nextIndex); Format(info, sizeof(info), "%d|%d|%d|%d|%d|1", victimUserID, troll.id, modifiers, newFlags, promptIndex);
flagMenu.AddItem(info, name); flagMenu.AddItem(info, name);
} }
} }
@ -433,7 +434,8 @@ void ShowThrowItAllMenu(int client, int userid) {
int GetNextPrompt(Troll troll, int flags, int currentPrompt = 0) { int GetNextPrompt(Troll troll, int flags, int currentPrompt = 0) {
static TrollFlagPrompt prompt; static TrollFlagPrompt prompt;
//If this prompt requires flags but they don't exist, skip to next that is valid or be done: //If this prompt requires flags but they don't exist, skip to next that is valid or be done:
for(int i = currentPrompt; i < troll.flagPrompts.Length; i++) { if(currentPrompt + 1 == troll.flagPrompts.Length) return -1;
for(int i = currentPrompt + 1; i < troll.flagPrompts.Length; i++) {
troll.GetFlagPrompt(i, prompt); troll.GetFlagPrompt(i, prompt);
if(prompt.requireFlags & flags) { if(prompt.requireFlags & flags) {
return i; return i;

View file

@ -53,16 +53,18 @@ bool ToggleMarkPlayer(int client, int target) {
} }
} }
stock int FindIdlePlayerBot(int client) { // Finds the survivor bot that took over an idle player
for(int i = 1; i <= MaxClients; i++) { int GetSpectatorClient(int bot) {
if(IsClientConnected(i) && IsFakeClient(i)) { if(!IsFakeClient(bot)) return -1;
int user = GetEntProp(i, Prop_Send, "m_humanSpectatorUserID"); static char netclass[16];
int bot = GetClientOfUserId(user); GetEntityNetClass(bot, netclass, sizeof(netclass));
return bot > 0 ? bot : client; if(strcmp(netclass, "SurvivorBot") == 0 ) {
int user = GetEntProp(bot, Prop_Send, "m_humanSpectatorUserID");
if(user > 0) return GetClientOfUserId(user);
} }
return -1;
} }
return client;
}
stock bool IsPlayerIncapped(int client) { stock bool IsPlayerIncapped(int client) {
return GetEntProp(client, Prop_Send, "m_isIncapacitated") == 1; return GetEntProp(client, Prop_Send, "m_isIncapacitated") == 1;
} }
@ -238,14 +240,3 @@ void DropItem(int victim, int slot) {
SDKHooks_DropWeapon(victim, wpn, NULL_VECTOR); SDKHooks_DropWeapon(victim, wpn, NULL_VECTOR);
} }
} }
int GetSpectatorClient(int bot) {
if(!IsFakeClient(bot)) return -1;
static char netclass[16];
GetEntityNetClass(bot, netclass, sizeof(netclass));
if(strcmp(netclass, "SurvivorBot") == 0 ) {
int user = GetEntProp(bot, Prop_Send, "m_humanSpectatorUserID");
if(user > 0) return GetClientOfUserId(user);
}
return -1;
}

View file

@ -43,6 +43,8 @@ bool SpawnSpecialInFace(int target, int specialType) {
testPos = pos; testPos = pos;
GetClientAbsOrigin(target, pos); GetClientAbsOrigin(target, pos);
GetClientEyeAngles(target, ang); GetClientEyeAngles(target, ang);
if(specialType == 2)
gInstaSpecialInstaKill = true;
if(specialType != 5 && specialType != 2) { //If not jockey/hunter find a suitable area that is at least 5 m away if(specialType != 5 && specialType != 2) { //If not jockey/hunter find a suitable area that is at least 5 m away
float minDistance = GetIdealMinDistance(specialType); float minDistance = GetIdealMinDistance(specialType);
GetHorizontalPositionFromOrigin(pos, ang, minDistance, testPos); GetHorizontalPositionFromOrigin(pos, ang, minDistance, testPos);
@ -57,14 +59,15 @@ bool SpawnSpecialInFace(int target, int specialType) {
pos[2] += 1.0; pos[2] += 1.0;
NegateVector(ang); NegateVector(ang);
return SpawnSpecialInternal(specialType, target, pos, NULL_VECTOR) > 0; return SpawnSpecialInternal(specialType, target, pos, NULL_VECTOR) != -1;
} }
bool SpawnSpecialNear(int target, int specialType) { bool SpawnSpecialNear(int target, int specialType) {
gInstaSpecialInstaKill = false;
if(specialType > 8) return false; if(specialType > 8) return false;
static float pos[3]; static float pos[3];
if(L4D_GetRandomPZSpawnPosition(target, specialType, 10, pos)) { if(L4D_GetRandomPZSpawnPosition(target, specialType, 10, pos)) {
return SpawnSpecialInternal(specialType, target, pos, NULL_VECTOR) > 0; return SpawnSpecialInternal(specialType, target, pos, NULL_VECTOR) != -1;
} }
return false; return false;
} }
@ -80,11 +83,19 @@ void BypassLimit() {
int SpawnSpecialInternal(int type, int target, float pos[3], float ang[3]) { int SpawnSpecialInternal(int type, int target, float pos[3], float ang[3]) {
if(type <= 6) { if(type <= 6) {
// BypassLimit(); // Bypass limit:
int special = L4D2_SpawnSpecial(type, pos, ang); gInstaSpecialType = type;
if(special != -1) gInstaSpecialTarget = GetClientUserId(target);
g_iAttackerTarget[special] = GetClientUserId(target); gInstaSpecialSpawnPos = pos;
return special; gInstaSpecialSpawnAng = pos;
CreateTimer(2.0, Timer_InstaFailed);
int bot = CreateFakeClient("ManualDirectorBot");
if (bot != 0) {
ChangeClientTeam(bot, 3);
CreateTimer(0.1, Timer_KickBot, bot);
}
CheatCommand(target, "z_spawn_old", SPECIAL_NAMES[type-1], "auto");
return 0;
} }
else if(type == 7) { else if(type == 7) {
int witch = L4D2_SpawnWitch(pos, ang); int witch = L4D2_SpawnWitch(pos, ang);
@ -102,3 +113,9 @@ int SpawnSpecialInternal(int type, int target, float pos[3], float ang[3]) {
} }
else return -1; else return -1;
} }
/* TODO: Bypass limit:
Spawn special auto, far away, mark with global vars:
1. special type (check)
2. its target
3. float[3] to TP it to

View file

@ -101,3 +101,10 @@ public Action Timer_KickBot(Handle timer, int client) {
if(IsFakeClient(client)) KickClient(client); if(IsFakeClient(client)) KickClient(client);
} }
} }
public Action Timer_InstaFailed(Handle h) {
if(gInstaSpecialType != -1) {
gInstaSpecialType = -1;
gInstaSpecialTarget = 0;
}
}

View file

@ -3,15 +3,16 @@
void SetupTrolls() { void SetupTrolls() {
trollKV = new StringMap(); trollKV = new StringMap();
categories = new ArrayList(ByteCountToCells(16)); categories = new ArrayList(ByteCountToCells(16));
gRandomClients = new ArrayList();
int index; int index;
SetupTroll("Reset User", "Resets the user, removes all troll effects", TrollMod_Instant); SetupTroll("Reset User", "Resets the user, removes all troll effects", TrollMod_Instant);
SetCategory("Magnets"); SetCategory("Magnets");
index = SetupTroll("Special Magnet", "Attracts ALL specials to any alive target with this troll enabled", TrollMod_Constant, false); index = SetupTroll("Special Magnet", "Attracts ALL specials to any alive target with this troll enabled", TrollMod_Constant);
AddMagnetFlags(index); AddMagnetFlags(index);
index = SetupTroll("Tank Magnet", "Attracts ALL tanks to any alive target with this troll enabled", TrollMod_Constant, false); index = SetupTroll("Tank Magnet", "Attracts ALL tanks to any alive target with this troll enabled", TrollMod_Constant);
AddMagnetFlags(index); AddMagnetFlags(index);
index = SetupTroll("Witch Magnet", "All witches when startled will target any player with this troll", TrollMod_Constant, false); index = SetupTroll("Witch Magnet", "All witches when startled will target any player with this troll", TrollMod_Constant);
SetCategory("Infected"); SetCategory("Infected");
SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", TrollMod_Instant | TrollMod_Constant); SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", TrollMod_Instant | TrollMod_Constant);
@ -21,12 +22,12 @@ void SetupTrolls() {
SetupTroll("Goo", "Spawns a spitter puddle underneath them", TrollMod_Instant); SetupTroll("Goo", "Spawns a spitter puddle underneath them", TrollMod_Instant);
SetCategory("Items"); SetCategory("Items");
index = SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant, false); index = SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant);
//Can't add directly, is custom troll: //Can't add directly, is custom troll:
// Trolls[index].AddFlag("Throw to Admin", true); // Trolls[index].AddFlag("Throw to Admin", true);
// Trolls[index].AddFlag("Drop At Feet", false); // Trolls[index].AddFlag("Drop At Feet", false);
// Trolls[index].AddFlag("Drop At Admin", false); // Trolls[index].AddFlag("Drop At Admin", false);
index = SetupTroll("Bad Throw", "Player drops throwables on throw, and biles/molotovs themselves", TrollMod_Constant, true); index = SetupTroll("Bad Throw", "Player drops throwables on throw, and biles/molotovs themselves", TrollMod_Constant | TrollMod_PlayerOnly);
Trolls[index].AddFlagPrompt(true); Trolls[index].AddFlagPrompt(true);
Trolls[index].AddFlag("Biles", true); Trolls[index].AddFlag("Biles", true);
Trolls[index].AddFlag("Molotovs", true); Trolls[index].AddFlag("Molotovs", true);
@ -42,8 +43,8 @@ void SetupTrolls() {
SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", TrollMod_Instant); SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", TrollMod_Instant);
SetCategory("Chat"); SetCategory("Chat");
SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", TrollMod_Constant); SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", TrollMod_Constant | TrollMod_PlayerOnly);
index = SetupTroll("No Profanity", "Replaces some words with random phrases", TrollMod_Constant); index = SetupTroll("No Profanity", "Replaces some words with random phrases", TrollMod_Constant | TrollMod_PlayerOnly);
Trolls[index].AddFlagPrompt(false); Trolls[index].AddFlagPrompt(false);
Trolls[index].AddFlag("Only Replace Swears", false); Trolls[index].AddFlag("Only Replace Swears", false);
Trolls[index].AddFlag("Replace Full Messages", true); Trolls[index].AddFlag("Replace Full Messages", true);
@ -51,21 +52,21 @@ void SetupTrolls() {
Trolls[index].AddFlag("Show Modified to Them", true); Trolls[index].AddFlag("Show Modified to Them", true);
Trolls[index].AddFlag("Show Original to Them", false); Trolls[index].AddFlag("Show Original to Them", false);
SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant); SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant);
index = SetupTroll("Honk / Meow", "Honk or Meow", TrollMod_Constant, false); index = SetupTroll("Honk / Meow", "Honk or Meow", TrollMod_Constant);
Trolls[index].AddCustomFlagPrompt("Choose Sound Type:"); Trolls[index].AddCustomFlagPrompt("Choose Sound Type:");
Trolls[index].AddFlag("Honk", true); Trolls[index].AddFlag("Honk", true);
Trolls[index].AddFlag("Meow", false); Trolls[index].AddFlag("Meow", false);
Trolls[index].AddCustomFlagPrompt("Choose Chat modifier:", false, 1); Trolls[index].AddCustomFlagPrompt("Choose Chat modifier:", false, 1);
Trolls[index].AddFlag("Show Modified to Them", true); Trolls[index].AddFlag("Show Modified to Them", true);
Trolls[index].AddFlag("Show Original to Them", false); Trolls[index].AddFlag("Show Original to Them", false);
SetupTroll("Reversed", "Reserves their message", TrollMod_Constant); SetupTroll("Reversed", "Reserves their message", TrollMod_Constant | TrollMod_PlayerOnly);
SetCategory("Health"); SetCategory("Health");
SetupTroll("Damage Boost", "Makes a player take more damage than normal", 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("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("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); SetupTroll("KillMeSoftly", "Make player eat or waste pills whenever possible", TrollMod_Instant | TrollMod_Constant);
index = SetupTroll("Reverse FF", "All damage dealt to a player is reversed", TrollMod_Constant, false); index = SetupTroll("Reverse FF", "All damage dealt to a player is reversed", TrollMod_Constant);
Trolls[index].AddCustomFlagPrompt("Choose Reverse FF", false); Trolls[index].AddCustomFlagPrompt("Choose Reverse FF", false);
Trolls[index].AddFlag("1:1 Ratio", true); Trolls[index].AddFlag("1:1 Ratio", true);
Trolls[index].AddFlag("2x Ratio", false); Trolls[index].AddFlag("2x Ratio", false);
@ -76,9 +77,15 @@ void SetupTrolls() {
SetupTroll("Slow Speed", "Sets player speed to 0.8x of normal speed", 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("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", TrollMod_Constant);
SetupTroll("No Shove", "Prevents a player from shoving", 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("CameTooEarly", "When they shoot, random chance they empty whole clip", TrollMod_Constant | TrollMod_PlayerOnly);
SetupTroll("Inverted Controls", "Well, aint it obvious", TrollMod_Constant); SetupTroll("Inverted Controls", "Well, aint it obvious", TrollMod_Constant | TrollMod_PlayerOnly);
SetupTroll("Stagger", "Like a slap, but different", TrollMod_Instant); SetupTroll("Stagger", "Like a slap, but different", TrollMod_Instant);
index = SetupTroll("Meta: Inverse", "Uhm you are not supposed to see this...", TrollMod_Instant | TrollMod_PlayerOnly);
Trolls[index].hidden = true;
Trolls[index].AddFlagPrompt(false);
Trolls[index].AddFlag("100%", true);
Trolls[index].AddFlag("50%", false);
Trolls[index].AddFlag("10%", false);
//INFO: UP MAX_TROLLS when adding new trolls! //INFO: UP MAX_TROLLS when adding new trolls!
@ -142,13 +149,13 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod
//TODO: Implement TrollMod_Constant //TODO: Implement TrollMod_Constant
return false; return false;
} else if(StrEqual(troll.name, "Throw It All")) { } else if(StrEqual(troll.name, "Throw It All")) {
if(modifier == TrollMod_Instant) if(modifier & TrollMod_Instant)
ThrowAllItems(victim); ThrowAllItems(victim);
if(hThrowTimer == INVALID_HANDLE && modifier == TrollMod_Constant) { if(hThrowTimer == INVALID_HANDLE && modifier & TrollMod_Constant) {
hThrowTimer = CreateTimer(hThrowItemInterval.FloatValue, Timer_ThrowTimer, _, TIMER_REPEAT); hThrowTimer = CreateTimer(hThrowItemInterval.FloatValue, Timer_ThrowTimer, _, TIMER_REPEAT);
} }
} else if(StrEqual(troll.name, "Swarm")) { } else if(StrEqual(troll.name, "Swarm")) {
if(modifier == TrollMod_Instant) { if(modifier & TrollMod_Instant) {
L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", victim, 15000); L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", victim, 15000);
} }
return true; return true;
@ -163,10 +170,10 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod
} else if(StrEqual(troll.name, "Vomit Player")) } else if(StrEqual(troll.name, "Vomit Player"))
L4D_CTerrorPlayer_OnVomitedUpon(victim, victim); L4D_CTerrorPlayer_OnVomitedUpon(victim, victim);
else if(StrEqual(troll.name, "Inface Special")) { else if(StrEqual(troll.name, "Inface Special")) {
FakeClientCommand(victim, "sm_inface"); FakeClientCommand(activator, "sm_inface");
return false; return false;
} else if(StrEqual(troll.name, "Insta Special")) { } else if(StrEqual(troll.name, "Insta Special")) {
FakeClientCommand(victim, "sm_insta"); FakeClientCommand(activator, "sm_insta");
return false; return false;
} else if(StrEqual(troll.name, "Goo")) { } else if(StrEqual(troll.name, "Goo")) {
static float pos[3], ang[3]; static float pos[3], ang[3];

View file

@ -38,14 +38,16 @@ public void OnPluginStart() {
SetFailState("This plugin is for L4D/L4D2 only."); SetFailState("This plugin is for L4D/L4D2 only.");
} }
LoadTranslations("common.phrases"); LoadTranslations("common.phrases");
g_iAmmoTable = FindSendPropInfo("CTerrorPlayer", "m_iAmmo");
g_PlayerMarkedForward = new GlobalForward("FTT_OnClientMarked", ET_Ignore, Param_Cell, Param_Cell); g_PlayerMarkedForward = new GlobalForward("FTT_OnClientMarked", ET_Ignore, Param_Cell, Param_Cell);
// Load core things (trolls & phrases):
REPLACEMENT_PHRASES = new StringMap(); REPLACEMENT_PHRASES = new StringMap();
LoadPhrases(); LoadPhrases();
SetupTrolls(); SetupTrolls();
// Witch target overwrite stuff:
GameData data = new GameData("l4d2_behavior"); GameData data = new GameData("l4d2_behavior");
StartPrepSDKCall(SDKCall_Raw); StartPrepSDKCall(SDKCall_Raw);
@ -60,9 +62,8 @@ public void OnPluginStart() {
hAutoPunish = CreateConVar("sm_ftt_autopunish_action", "0", "Setup automatic punishment of players. Add bits together\n0=Disabled, 1=Tank magnet, 2=Special magnet, 4=Swarm, 8=InstantVomit", FCVAR_NONE, true, 0.0); hAutoPunish = CreateConVar("sm_ftt_autopunish_action", "0", "Setup automatic punishment of players. Add bits together\n0=Disabled, 1=Tank magnet, 2=Special magnet, 4=Swarm, 8=InstantVomit", FCVAR_NONE, true, 0.0);
hAutoPunishExpire = CreateConVar("sm_ftt_autopunish_expire", "0", "How many minutes of gametime until autopunish is turned off? 0 for never.", FCVAR_NONE, true, 0.0); hAutoPunishExpire = CreateConVar("sm_ftt_autopunish_expire", "0", "How many minutes of gametime until autopunish is turned off? 0 for never.", FCVAR_NONE, true, 0.0);
hMagnetChance = CreateConVar("sm_ftt_magnet_chance", "1.0", "% of the time that the magnet will work on a player.", FCVAR_NONE, true, 0.0, true, 1.0); hMagnetChance = CreateConVar("sm_ftt_magnet_chance", "1.0", "% of the time that the magnet will work on a player.", FCVAR_NONE, true, 0.0, true, 1.0);
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"); hMagnetTargetMode = CreateConVar("sm_ftt_magnet_targetting", "6", "How does the specials target players. Add bits together\n0=Incapped are ignored, 1=Specials targets incapped, 2=Tank targets incapped 4=Witch targets incapped");
hShoveFailChance = CreateConVar("sm_ftt_shove_fail_chance", "0.65", "The % chance that a shove fails", FCVAR_NONE, true, 0.0, true, 1.0); hShoveFailChance = CreateConVar("sm_ftt_shove_fail_chance", "0.65", "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); 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_ftl", Command_ListTheTrolls, ADMFLAG_KICK, "Lists all the trolls currently ingame.");
@ -77,7 +78,9 @@ public void OnPluginStart() {
RegAdminCmd("sm_insta", Command_InstaSpecial, ADMFLAG_KICK, "Spawns a special that targets them, close to them."); RegAdminCmd("sm_insta", Command_InstaSpecial, ADMFLAG_KICK, "Spawns a special that targets them, close to them.");
RegAdminCmd("sm_instaface", Command_InstaSpecialFace, ADMFLAG_KICK, "Spawns a special that targets them, right in their face."); RegAdminCmd("sm_instaface", Command_InstaSpecialFace, ADMFLAG_KICK, "Spawns a special that targets them, right in their face.");
RegAdminCmd("sm_inface", Command_InstaSpecialFace, ADMFLAG_KICK, "Spawns a special that targets them, right in their face."); RegAdminCmd("sm_inface", Command_InstaSpecialFace, ADMFLAG_KICK, "Spawns a special that targets them, right in their face.");
RegAdminCmd("sm_noob", Command_MarkNoob, ADMFLAG_KICK, "Marks a player as a noob. stored in a database");
HookEvent("player_spawn", Event_PlayerSpawn);
HookEvent("player_disconnect", Event_PlayerDisconnect); HookEvent("player_disconnect", Event_PlayerDisconnect);
HookEvent("player_death", Event_PlayerDeath); HookEvent("player_death", Event_PlayerDeath);
HookEvent("triggered_car_alarm", Event_CarAlarm); HookEvent("triggered_car_alarm", Event_CarAlarm);
@ -86,6 +89,8 @@ public void OnPluginStart() {
AddNormalSoundHook(view_as<NormalSHook>(SoundHook)); AddNormalSoundHook(view_as<NormalSHook>(SoundHook));
AutoExecConfig(true, "l4d2_feedthetrolls"); AutoExecConfig(true, "l4d2_feedthetrolls");
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// CVAR CHANGES // CVAR CHANGES
@ -103,11 +108,12 @@ public void Change_ThrowInterval(ConVar convar, const char[] oldValue, const cha
// METHODS - Old methods, some are also in feedthetrolls/misc.inc // METHODS - Old methods, some are also in feedthetrolls/misc.inc
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void ThrowAllItems(int victim) { void ThrowAllItems(int victim) {
float vicPos[3], destPos[3]; float vicPos[3], destPos[3];
int clients[4]; int clients[4];
GetClientAbsOrigin(victim, vicPos); GetClientAbsOrigin(victim, vicPos);
//Find a bot to throw to //Find a survivor to throw to (grabs the first nearest non-self survivor)
int clientCount = GetClientsInRange(vicPos, RangeType_Visibility, clients, sizeof(clients)); int clientCount = GetClientsInRange(vicPos, RangeType_Visibility, clients, sizeof(clients));
for(int i = 0; i < clientCount; i++) { for(int i = 0; i < clientCount; i++) {
if(clients[i] != victim) { if(clients[i] != victim) {
@ -126,7 +132,6 @@ void ThrowAllItems(int victim) {
WritePackFloat(pack, destPos[2]); WritePackFloat(pack, destPos[2]);
WritePackCell(pack, slot); WritePackCell(pack, slot);
WritePackCell(pack, victim); WritePackCell(pack, victim);
} }
} }
@ -164,18 +169,15 @@ bool IsPlayerFarDistance(int client, float distance) {
stock int GetPrimaryReserveAmmo(int client) { stock int GetPrimaryReserveAmmo(int client) {
int weapon = GetPlayerWeaponSlot(client, 0); int weapon = GetPlayerWeaponSlot(client, 0);
if(weapon > -1) { if(weapon > 0) {
int primaryAmmoType = GetEntProp(weapon, Prop_Send, "m_iPrimaryAmmoType"); return GetEntProp(client, Prop_Send, "m_iAmmo", _, GetEntProp(weapon, Prop_Send, "m_iPrimaryAmmoType"));
return GetEntData(client, g_iAmmoTable + (primaryAmmoType * 4));
} }
return -1; return -1;
} }
stock bool SetPrimaryReserveAmmo(int client, int amount) { stock bool SetPrimaryReserveAmmo(int client, int amount) {
int weapon = GetPlayerWeaponSlot(client, 0); int weapon = GetPlayerWeaponSlot(client, 0);
if(weapon > -1) { if(weapon > -1) {
int primaryAmmoType = GetEntProp(weapon, Prop_Send, "m_iPrimaryAmmoType"); SetEntProp(client, Prop_Send, "m_iAmmo", amount, _, GetEntProp(weapon, Prop_Send, "m_iPrimaryAmmoType"));
SetEntData(client, g_iAmmoTable + (primaryAmmoType * 4), amount);
return true;
} }
return false; return false;
} }