ftt: Refactor

This commit is contained in:
Jackzie 2021-09-23 14:14:14 -05:00
parent 72cac56b1a
commit e6811228fa
No known key found for this signature in database
GPG key ID: 76DF30177DC69DB4
9 changed files with 1200 additions and 1191 deletions

View file

@ -0,0 +1,372 @@
public void OnPluginEnd() {
UnhookEntityOutput("func_button", "OnPressed", Event_ButtonPress);
}
public void OnMapEnd() {
UnhookEntityOutput("func_button", "OnPressed", Event_ButtonPress);
}
public void OnMapStart() {
AddFileToDownloadsTable("sound/custom/meow1.mp3");
PrecacheSound("custom/meow1.mp3");
lastButtonUser = -1;
HookEntityOutput("func_button", "OnPressed", Event_ButtonPress);
CreateTimer(MAIN_TIMER_INTERVAL_S, Timer_Main, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
PrecacheSound("player/footsteps/clown/concrete1.wav");
//CreateTimer(30.0, Timer_AutoPunishCheck, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
}
public void OnClientPutInServer(int client) {
g_PendingBanTroll[client] = false;
SDKHook(client, SDKHook_OnTakeDamage, Event_TakeDamage);
}
public void OnClientAuthorized(int client, const char[] auth) {
if(!IsFakeClient(client)) {
strcopy(steamids[client], 64, auth);
}
}
public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
if(g_PendingBanTroll[client]) {
g_PendingBanTroll[client] = false;
if(!IsFakeClient(client) && GetUserAdmin(client) == INVALID_ADMIN_ID) {
BanIdentity(steamids[client], 0, BANFLAG_AUTHID, "TrollMarked", "ftt", 0);
}
}
steamids[client][0] = '\0';
ActiveTrolls[client] = 0;
g_iAttackerTarget[client] = 0;
}
public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
g_iAttackerTarget[client] = 0;
}
public Action Event_WeaponReload(int weapon) {
int client = GetEntPropEnt(weapon, Prop_Send, "m_hOwner");
if(IsTrollActive(client, "GunJam")) {
float dec = GetRandomFloat(0.0, 1.0);
if(FloatCompare(dec, 0.50) == -1) { //10% chance gun jams
return Plugin_Stop;
}
}
return Plugin_Continue;
}
public Action Event_ButtonPress(const char[] output, int entity, int client, float delay) {
if(client > 0 && client <= MaxClients) {
lastButtonUser = client;
}
return Plugin_Continue;
}
public void Event_PanicEventCreate(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
if(client) {
lastButtonUser = client;
}
}
public void Event_CarAlarm(Event event, const char[] name, bool dontBroadcast) {
int user = event.GetInt("userid");
int client = GetClientOfUserId(user);
if(client) {
PrintToChatAll("%N has alerted the horde!", client);
L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", user, 15000);
}
//Ignore car alarms for autopunish
lastButtonUser = -1;
}
public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
// =========================
// OVERRIDE VICTIM
// =========================
if(hMagnetChance.FloatValue < GetRandomFloat()) return Plugin_Continue;
L4D2Infected class = view_as<L4D2Infected>(GetEntProp(attacker, Prop_Send, "m_zombieClass"));
int existingTarget = GetClientOfUserId(g_iAttackerTarget[attacker]);
if(existingTarget > 0 && IsPlayerAlive(existingTarget) && (hMagnetTargetMode.IntValue & 1 != 1 || !IsPlayerIncapped(existingTarget))) {
if(class == L4D2Infected_Tank && (hMagnetTargetMode.IntValue % 2 != 2 || !IsPlayerIncapped(existingTarget))) {
curTarget = existingTarget;
return Plugin_Changed;
}else if(hMagnetTargetMode.IntValue & 1 != 1 || !IsPlayerIncapped(existingTarget)) {
curTarget = existingTarget;
return Plugin_Changed;
}
}
float closestDistance, survPos[3], spPos[3];
GetClientAbsOrigin(attacker, spPos);
int closestClient = -1;
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
//Ignore incapped players if turned on:
if(IsPlayerIncapped(i)) {
if((class == L4D2Infected_Tank && hMagnetTargetMode.IntValue & 2 == 2) || hMagnetTargetMode.IntValue & 1 == 1 ) continue;
}
if(class == L4D2Infected_Tank && IsTrollActive(i, "TankMagnet") || (class != L4D2Infected_Tank && IsTrollActive(i, "SpecialMagnet"))) {
GetClientAbsOrigin(i, survPos);
float dist = GetVectorDistance(survPos, spPos, true);
if(closestClient == -1 || dist < closestDistance) {
closestDistance = dist;
closestClient = i;
}
}
}
}
if(closestClient > 0) {
g_iAttackerTarget[attacker] = GetClientUserId(closestClient);
curTarget = closestClient;
return Plugin_Changed;
}
return Plugin_Continue;
}
public Action L4D2_OnEntityShoved(int client, int entity, int weapon, float vecDir[3], bool bIsHighPounce) {
if(client > 0 && client <= MaxClients && IsTrollActive(client, "NoShove") && hShoveFailChance.FloatValue > GetRandomFloat()) {
return Plugin_Handled;
}
return Plugin_Continue;
}
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) {
if(sArgs[0] == '@') return Plugin_Continue;
if(IsTrollActive(client, "Honk")) {
static char strings[32][7];
int words = ExplodeString(sArgs, " ", strings, sizeof(strings), 5);
for(int i = 0; i < words; i++) {
if(GetRandomFloat() <= 0.8) strings[i] = "honk";
else strings[i] = "squeak";
}
int length = 7 * words;
char[] message = new char[length];
ImplodeStrings(strings, 32, " ", message, length);
CPrintToChatAll("{blue}%N {default}: %s", client, message);
PrintToServer("%N: %s", client, sArgs);
return Plugin_Handled;
}else if(IsTrollActive(client, "iCantSpellNoMore")) {
int type = GetRandomInt(1, trollKV.Size + 8);
char letterSrc, replaceChar;
switch(type) {
case 1: {
letterSrc = 'e';
replaceChar = 'b';
}
case 2: {
letterSrc = 't';
replaceChar = 'e';
}
case 3: {
letterSrc = 'i';
replaceChar = 'e';
}
case 4: {
letterSrc = 'a';
replaceChar = 's';
}
case 5: {
letterSrc = 'u';
replaceChar = 'i';
}
case 6: {
letterSrc = '.';
replaceChar = '/';
}
case 7: {
letterSrc = 'm';
replaceChar = 'n';
}
case 8: {
letterSrc = 'n';
replaceChar = 'm';
}
case 9: {
letterSrc = 'l';
replaceChar = 'b';
}
case 10: {
letterSrc = 'l';
replaceChar = 'b';
}
case 11: {
letterSrc = 'h';
replaceChar = 'j';
}
case 12: {
letterSrc = 'o';
replaceChar = 'i';
}
case 13: {
letterSrc = 'e';
replaceChar = 'r';
}
default:
return Plugin_Continue;
}
int strLength = strlen(sArgs);
char[] newMessage = new char[strLength + 20];
int n = 0;
while (sArgs[n] != '\0') {
if(sArgs[n] == letterSrc) {
newMessage[n] = replaceChar;
}else{
newMessage[n] = sArgs[n];
}
n++;
}
PrintToServer("%N: %s", client, sArgs);
CPrintToChatAll("{blue}%N {default}: %s", client, newMessage);
return Plugin_Handled;
}else if(IsTrollActive(client, "NoProfanity")) {
//TODO: Check all replacement words, if none were replaced then do full word
//TODO: Lowercase .getstring
static char strings[32][MAX_PHRASE_LENGTH];
ArrayList phrases;
bool foundWord = false;
int words = ExplodeString(sArgs, " ", strings, 32, MAX_PHRASE_LENGTH);
for(int i = 0; i < words; i++) {
if(REPLACEMENT_PHRASES.GetValue(strings[i], phrases) && phrases.Length > 0) {
foundWord = true;
int c = phrases.GetString(GetRandomInt(0, phrases.Length - 1), strings[i], MAX_PHRASE_LENGTH);
PrintToServer("replacement: %s (%d)", strings[i], c);
}
}
int length = MAX_PHRASE_LENGTH * words;
char[] message = new char[length];
if(foundWord) {
ImplodeStrings(strings, 32, " ", message, length);
} else {
REPLACEMENT_PHRASES.GetValue("_Full Message Phrases", phrases);
phrases.GetString(GetRandomInt(0, phrases.Length - 1), message, MAX_PHRASE_LENGTH);
}
CPrintToChatAll("{blue}%N {default}: %s", client, message);
PrintToServer("%N: %s", client, sArgs);
return Plugin_Handled;
}
return Plugin_Continue;
}
public Action Event_ItemPickup(int client, int weapon) {
if(IsTrollActive(client, "NoPickup")) {
return Plugin_Stop;
}else{
static char wpnName[64];
GetEdictClassname(weapon, wpnName, sizeof(wpnName));
if(StrContains(wpnName, "rifle") > -1
|| StrContains(wpnName, "smg") > -1
|| StrContains(wpnName, "weapon_grenade_launcher") > -1
|| StrContains(wpnName, "sniper") > -1
|| StrContains(wpnName, "shotgun") > -1
) {
//If 4: Only UZI, if 5: Can't switch.
if(IsTrollActive(client, "UziRules")) {
static char currentWpn[32];
GetClientWeaponName(client, 0, currentWpn, sizeof(currentWpn));
if(StrEqual(wpnName, "weapon_smg", true)) {
return Plugin_Continue;
} else if(StrEqual(currentWpn, "weapon_smg", true)) {
return Plugin_Stop;
}else{
int flags = GetCommandFlags("give");
SetCommandFlags("give", flags & ~FCVAR_CHEAT);
FakeClientCommand(client, "give smg");
SetCommandFlags("give", flags);
return Plugin_Stop;
}
}else if(IsTrollActive(client, "PrimaryDisable")) {
return Plugin_Stop;
}
return Plugin_Continue;
}else{
return Plugin_Continue;
}
}
}
public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2]) {
if(g_bPendingItemGive[client] && !(buttons & IN_ATTACK2)) {
int target = GetClientAimTarget(client, true);
if(target > -1) {
buttons |= IN_ATTACK2;
RequestFrame(StopItemGive, client);
return Plugin_Changed;
}
return Plugin_Continue;
}
return Plugin_Continue;
}
public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) {
//Stop FF from marked:
if(attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker) && IsPlayerAlive(attacker)) {
if(g_PendingBanTroll[attacker] && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) {
return Plugin_Stop;
}
if(IsTrollActive(attacker, "DamageBoost")) {
damage * 2;
return Plugin_Changed;
}
}
return Plugin_Continue;
}
public Action SoundHook(int[] clients, int& numClients, char sample[PLATFORM_MAX_PATH], int& entity, int& channel, float& volume, int& level, int& pitch, int& flags, char[] soundEntry, int& seed) {
if(lastButtonUser > -1 && StrEqual(sample, "npc/mega_mob/mega_mob_incoming.wav")) {
PrintToConsoleAll("CRESCENDO STARTED BY %N", lastButtonUser);
#if defined DEBUG
PrintToChatAll("CRESCENDO STARTED BY %N", lastButtonUser);
#endif
lastCrescendoUser = lastButtonUser;
if(IsPlayerFarDistance(lastButtonUser, AUTOPUNISH_FLOW_MIN_DISTANCE)) {
NotifyAllAdmins("Autopunishing player %N for activation of event far from team", lastButtonUser);
ShowActivity(0, "activated autopunish for crescendo activator %N (auto)", lastButtonUser);
ActivateAutoPunish(lastButtonUser);
}
lastButtonUser = -1;
}else if(numClients > 0 && entity > 0 && entity <= MaxClients) {
if(StrContains(sample, "survivor\\voice") > -1) {
if(IsTrollActive(entity, "Honk")) {
strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav");
return Plugin_Changed;
} else if(IsTrollActive(entity, "VocalizeGag")) {
return Plugin_Handled;
} else if(IsTrollActive(entity, "Meow")) {
strcopy(sample, sizeof(sample), "custom/meow1.mp3");
return Plugin_Changed;
}
}
}
return Plugin_Continue;
}
public Action Event_WitchVictimSet(Event event, const char[] name, bool dontBroadcast) {
int witch = event.GetInt("witchid");
float closestDistance, survPos[3], witchPos[3];
GetEntPropVector(witch, Prop_Send, "m_vecOrigin", witchPos);
int closestClient = -1;
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
//Ignore incapped players if hWitchIgnoreIncapp turned on:
if(IsPlayerIncapped(i) && !hWitchTargetIncapp.BoolValue) {
continue;
}
if(IsTrollActive(i, "WitchMagnet")) {
GetClientAbsOrigin(i, survPos);
float dist = GetVectorDistance(survPos, witchPos, true);
if(closestClient == -1 || dist < closestDistance) {
closestDistance = dist;
closestClient = i;
}
}
}
}
if(closestClient > 0) {
DataPack pack;
CreateDataTimer(0.1, Timer_NextWitchSet, pack);
pack.WriteCell(GetClientUserId(closestClient));
pack.WriteCell(witch);
CreateDataTimer(0.2, Timer_NextWitchSet, pack);
pack.WriteCell(GetClientUserId(closestClient));
pack.WriteCell(witch);
}
}

View file

@ -4,21 +4,34 @@
//#define DEBUG 1
enum TrollModifier {
TrollMod_None = 0,
TrollMod_InstantFire = 1,
TrollMod_Repeat = 2
TrollMod_Instant = 1,
TrollMod_Constant = 2
}
enum struct Troll {
char name[32];
char description[128];
bool runsOnce;
int flags;
void GetID(char[] name, int length) {
strcopy(name, length, this.name);
ReplaceString(name, MAX_TROLL_NAME_LENGTH, " ", "", false);
}
bool HasMod(TrollMod mod) {
return ((this.flags >> view_as<int>(mod)) & 1) == view_as<int>(mod);
}
// Gets the default modifier to use
TrollModifier GetDefaultMod() {
// If the flags is equal to the 2^n flag, then it must be the only flag:
if(this.flags == TrollMod_Instant) return TrollMod_Instant;
else if(this.flags == TrollMod_Constant) return TrollMod_Constant;
else return -1;
}
}
Troll Trolls[MAX_TROLLS+1];
@ -27,11 +40,21 @@ int ActiveTrolls[MAXPLAYERS+1];
StringMap trollKV;
char trollIds[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH];
int SetupTroll(const char[] name, const char description[128], bool hasMods) {
void ResetClient(int victim, bool wipe = true) {
if(wipe) ActiveTrolls[victim] = 0;
SetEntityGravity(victim, 1.0);
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
SDKUnhook(victim, SDKHook_WeaponCanUse, Event_ItemPickup);
int wpn = GetClientWeaponEntIndex(victim, 0);
if(wpn > -1)
SDKUnhook(wpn, SDKHook_Reload, Event_WeaponReload);
}
int SetupTroll(const char[] name, const char description[128], int flags) {
static int i = 0;
strcopy(Trolls[i].name, MAX_TROLL_NAME_LENGTH, name);
strcopy(Trolls[i].description, 128, description);
Trolls[i].runsOnce = !hasMods;
Trolls[i].flags = flags;
static char key[MAX_TROLL_NAME_LENGTH];
strcopy(key, MAX_TROLL_NAME_LENGTH, name);
ReplaceString(key, MAX_TROLL_NAME_LENGTH, " ", "", false);
@ -207,31 +230,31 @@ void DisableTroll(int client, const char[] troll) {
void SetupTrolls() {
trollKV = new StringMap();
SetupTroll("Reset Troll", "Resets the user, removes all troll effects", false);
SetupTroll("Special Magnet", "Attracts ALL specials to any alive target with this troll enabled", false);
SetupTroll("Tank Magnet", "Attracts ALL tanks to any alive target with this troll enabled", false);
SetupTroll("Witch Magnet", "All witches when startled will target any player with this troll", false);
SetupTroll("Vomit Player", "Shortcut to sm_vomitplayer. vomits the player.", false);
SetupTroll("ThrowItAll", "Player throws all their items at nearby player, periodically", true);
SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", false);
SetupTroll("No Profanity", "Replaces some words with random phrases", false);
SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", false);
SetupTroll("UziRules", "Picking up a weapon gives them a UZI instead", false);
SetupTroll("Slow Speed", "Sets player speed to 0.8x of normal speed", false);
SetupTroll("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", false);
SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", false);
SetupTroll("PrimaryDisable", "Player cannot pickup any weapons, only melee/pistols", true);
SetupTroll("Clusmy", "Player drops axe periodically or on demand", true);
SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", false);
SetupTroll("KillMeSoftly", "Make player eat or waste pills whenever possible", false);
SetupTroll("GunJam", "On reload, small chance their gun gets jammed - Can't reload.", false);
SetupTroll("NoPickup", "Prevents a player from picking up ANY (new) item. Use ThrowItAll to make them drop", true);
SetupTroll("Honk", "Honk", false);
SetupTroll("No Shove", "Prevents a player from shoving", false);
SetupTroll("Damage Boost", "Makes a player take more damage than normal", false);
SetupTroll("Temp Health Quick Drain", "Makes a player's temporarily health drain very quickly", false);
SetupTroll("Slow Drain", "Will make the player slowly lose health over time", false);
SetupTroll("CameTooEarly", "When they shoot, random chance they empty whole clip", true);
SetupTroll("Reset Troll", "Resets the user, removes all troll effects", TrollMod_Instant);
SetupTroll("Special Magnet", "Attracts ALL specials to any alive target with this troll enabled", TrollMod_Constant);
SetupTroll("Tank Magnet", "Attracts ALL tanks to any alive target with this troll enabled", TrollMod_Constant);
SetupTroll("Witch Magnet", "All witches when startled will target any player with this troll", TrollMod_Constant);
SetupTroll("Vomit Player", "Shortcut to sm_vomitplayer. vomits the player.", TrollMod_Instant);
SetupTroll("ThrowItAll", "Player throws all their items at nearby player, periodically", TrollMod_Instant | TrollMod_Constant);
SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant);
SetupTroll("No Profanity", "Replaces some words with random phrases", TrollMod_Constant);
SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", TrollMod_Instant);
SetupTroll("UziRules", "Picking up a weapon gives them a UZI instead", TrollMod_Constant);
SetupTroll("Slow Speed", "Sets player speed to 0.8x of normal speed", TrollMod_Constant);
SetupTroll("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", TrollMod_Constant);
SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", TrollMod_Instant);
SetupTroll("PrimaryDisable", "Player cannot pickup any weapons, only melee/pistols", TrollMod_Constant);
SetupTroll("Clusmy", "Player drops axe periodically or on demand", TrollMod_Instant | TrollMod_Constant);
SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", TrollMod_Instant);
SetupTroll("KillMeSoftly", "Make player eat or waste pills whenever possible", TrollMod_Instant | TrollMod_Constant);
SetupTroll("GunJam", "On reload, small chance their gun gets jammed - Can't reload.", TrollMod_Constant);
SetupTroll("NoPickup", "Prevents a player from picking up ANY (new) item. Use ThrowItAll to make them drop", TrollMod_Constant);
SetupTroll("Honk", "Honk", TrollMod_Constant);
SetupTroll("No Shove", "Prevents a player from shoving", TrollMod_Constant);
SetupTroll("Damage Boost", "Makes a player take more damage than normal", TrollMod_Constant);
SetupTroll("Temp Health Quick Drain", "Makes a player's temporarily health drain very quickly", TrollMod_Constant);
SetupTroll("Slow Drain", "Will make the player slowly lose health over time", TrollMod_Constant);
SetupTroll("CameTooEarly", "When they shoot, random chance they empty whole clip", TrollMod_Constant);
SetupTroll("Meow", "Makes the player meow", false);
//INFO: UP MAX_TROLLS when adding new trolls!
}

View file

@ -0,0 +1,348 @@
public Action Command_InstaSpecial(int client, int args) {
if(args < 1) {
Menu menu = new Menu(Insta_PlayerHandler);
menu.SetTitle("Choose a player");
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
static char userid[8], display[16];
Format(userid, sizeof(userid), "%d|0", GetClientUserId(i));
GetClientName(i, display, sizeof(display));
menu.AddItem(userid, display);
}
}
menu.ExitButton = true;
menu.Display(client, 0);
} else {
char arg1[32], arg2[32] = "jockey";
GetCmdArg(1, arg1, sizeof(arg1));
if(args >= 2) {
GetCmdArg(2, arg2, sizeof(arg2));
}
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MaxClients,
COMMAND_FILTER_ALIVE,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
int specialType = GetSpecialType(arg2);
static float pos[3];
if(specialType == -1) {
ReplyToCommand(client, "Unknown special \"%s\"", arg2);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++) {
int target = target_list[i];
if(GetClientTeam(target) == 2) {
SpawnSpecialNear(target, specialType);
}else{
ReplyToTargetError(client, target_count);
}
}
ShowActivity(client, "spawned Insta-%s™ near %s", arg2, target_name);
}
return Plugin_Handled;
}
public Action Command_InstaSpecialFace(int client, int args) {
if(args < 1) {
Menu menu = new Menu(Insta_PlayerHandler);
menu.SetTitle("Choose a player");
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
static char userid[8], display[16];
Format(userid, sizeof(userid), "%d|1", GetClientUserId(i));
GetClientName(i, display, sizeof(display));
menu.AddItem(userid, display);
}
}
menu.ExitButton = true;
menu.Display(client, 0);
} else {
char arg1[32], arg2[32] = "jockey";
GetCmdArg(1, arg1, sizeof(arg1));
if(args >= 2) {
GetCmdArg(2, arg2, sizeof(arg2));
}
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MaxClients,
COMMAND_FILTER_ALIVE,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
int specialType = GetSpecialType(arg2);
static float pos[3];
if(specialType == -1) {
ReplyToCommand(client, "Unknown special \"%s\"", arg2);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++) {
int target = target_list[i];
if(GetClientTeam(target) == 2) {
SpawnSpecialInFace(target, specialType);
}else{
ReplyToTargetError(client, target_count);
}
}
ShowActivity(client, "spawned Insta-%s™ on %s", arg2, target_name);
}
return Plugin_Handled;
}
public Action Command_WitchAttack(int client, int args) {
if(args < 1) {
ReplyToCommand(client, "Usage: sm_witch_attack <user>");
} else {
char arg1[32];
GetCmdArg(1, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
1,
COMMAND_FILTER_ALIVE | COMMAND_FILTER_NO_MULTI, /* Only allow alive players */
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
int target = target_list[0];
if(GetClientTeam(target) == 2) {
int witch = INVALID_ENT_REFERENCE;
while ((witch = FindEntityByClassname(witch, "witch")) != INVALID_ENT_REFERENCE) {
SetWitchTarget(witch, target);
ShowActivity(client, "all witches target %s", target_name);
}
}else{
ReplyToTargetError(client, target_count);
}
}
return Plugin_Handled;
}
public Action Command_FeedTheCrescendoTroll(int client, int args) {
if(lastCrescendoUser > -1) {
ActivateAutoPunish(lastCrescendoUser);
ReplyToCommand(client, "Activated auto punish on %N", lastCrescendoUser);
ShowActivity(client, "activated autopunish for crescendo activator %N",lastCrescendoUser);
}else{
ReplyToCommand(client, "No player could be found to autopunish.");
}
return Plugin_Handled;
}
public Action Command_ResetUser(int client, int args) {
if(args < 1) {
ReplyToCommand(client, "Usage: sm_ftr <user(s)>");
}else{
char arg1[32];
GetCmdArg(1, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MAXPLAYERS,
COMMAND_FILTER_CONNECTED, /* Only allow alive players */
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++) {
if(ActiveTrolls[target_list[i]] > 0) {
ResetClient(target_list[i], true);
ShowActivity(client, "reset troll effects on \"%N\". ", target_list[i]);
}
}
}
return Plugin_Handled;
}
public Action Command_ApplyUser(int client, int args) {
if(args < 2) {
Menu menu = new Menu(ChoosePlayerHandler);
menu.SetTitle("Choose a player");
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
static char userid[8], display[16];
Format(userid, sizeof(userid), "%d", GetClientUserId(i));
GetClientName(i, display, sizeof(display));
menu.AddItem(userid, display);
}
}
menu.ExitButton = true;
menu.Display(client, 0);
}else{
char arg1[32], arg2[32], arg3[8];
GetCmdArg(1, arg1, sizeof(arg1));
GetCmdArg(2, arg2, sizeof(arg2));
GetCmdArg(3, arg3, sizeof(arg3));
bool silent = StrEqual(arg3, "silent") || StrEqual(arg3, "quiet") || StrEqual(arg3, "mute");
static char name[MAX_TROLL_NAME_LENGTH];
if(!GetTrollID(StringToInt(arg2), name)) {
ReplyToCommand(client, "Not a valid mode. Must be greater than 0. Usage: sm_fta [player] [mode]. Use sm_ftr <player> to reset.");
}else{
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MAXPLAYERS,
0,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++) {
if(IsClientInGame(target_list[i]) && GetClientTeam(target_list[i]) == 2)
ApplyTroll(target_list[i], name, client, TrollMod_Instant, silent);
}
}
}
return Plugin_Handled;
}
public Action Command_ListModes(int client, int args) {
static char name[MAX_TROLL_NAME_LENGTH];
static Troll troll;
for(int i = 0; i <= MAX_TROLLS; i++) {
GetTrollByKeyIndex(i, troll);
ReplyToCommand(client, "%d. %s - %s", i, troll.name, troll.description);
}
return Plugin_Handled;
}
public Action Command_ListTheTrolls(int client, int args) {
int count = 0;
//TODO: Update
char[][] modeListArr = new char[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH];
static char modeList[255];
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && ActiveTrolls[i] > 0) {
int modeCount = 0;
static char name[MAX_TROLL_NAME_LENGTH];
for(int j = 1; j <= MAX_TROLLS; j++) {
GetTrollID(j, name);
if(IsTrollActive(i, name)) {
strcopy(modeListArr[modeCount], MAX_TROLL_NAME_LENGTH, name);
modeCount++;
}
}
ImplodeStrings(modeListArr, modeCount, ", ", modeList, sizeof(modeList));
ReplyToCommand(client, "%N | %s", i, modeList);
count++;
}
}
if(count == 0) {
ReplyToCommand(client, "No clients have a mode applied.");
}
return Plugin_Handled;
}
public Action Command_MarkPendingTroll(int client, int args) {
if(args == 0) {
Menu menu = new Menu(ChooseMarkedTroll);
menu.SetTitle("Choose a troll to mark");
static char userid[8], display[16];
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
AdminId admin = GetUserAdmin(i);
if(admin == INVALID_ADMIN_ID) {
Format(userid, sizeof(userid), "%d", GetClientUserId(i));
GetClientName(i, display, sizeof(display));
menu.AddItem(userid, display);
}else{
ReplyToCommand(client, "%N is an admin cannot be marked.", i);
}
}
}
menu.ExitButton = true;
menu.Display(client, 0);
} else {
char arg1[32];
GetCmdArg(1, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
1,
COMMAND_FILTER_NO_MULTI , /* Only allow alive players */
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
int target = target_list[0];
if(GetClientTeam(target) == 2) {
ToggleMarkPlayer(client, target);
}else{
ReplyToCommand(client, "Player does not exist or is not a survivor.");
}
}
return Plugin_Handled;
}
public Action Command_FeedTheTrollMenu(int client, int args) {
ReplyToCommand(client, "sm_ftl - Lists all the active trolls on players");
ReplyToCommand(client, "sm_ftm - Lists all available troll modes & descriptions");
ReplyToCommand(client, "sm_ftr - Resets target users' of their trolls");
ReplyToCommand(client, "sm_fta - Applies a troll mode on targets");
ReplyToCommand(client, "sm_ftt - Opens this menu");
ReplyToCommand(client, "sm_ftc - Will apply a punishment to last crescendo activator");
ReplyToCommand(client, "sm_mark - Marks the user to be banned on disconnect, prevents their FF.");
return Plugin_Handled;
}

View file

@ -0,0 +1,141 @@
public int Insta_PlayerHandler(Menu menu, MenuAction action, int client, int param2) {
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
static char str[2][8];
ExplodeString(info, "|", str, 2, 8, false);
int userid = StringToInt(str[0]);
int instaMode = StringToInt(str[1]);
Menu spMenu = new Menu(Insta_SpecialHandler);
spMenu.SetTitle("Choose a Insta-Special™");
for(int i = 1; i <= 6; i++) {
static char id[8];
Format(id, sizeof(id), "%d|%d|%d", userid, instaMode, i);
spMenu.AddItem(id, SPECIAL_NAMES[i-1]);
}
spMenu.ExitButton = true;
spMenu.Display(client, 0);
} else if (action == MenuAction_End)
delete menu;
}
public int Insta_SpecialHandler(Menu menu, MenuAction action, int client, int param2) {
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
static char str[3][8];
ExplodeString(info, "|", str, 3, 8, false);
int target = GetClientOfUserId(StringToInt(str[0]));
bool inFace = StrEqual(str[1], "1");
int special = StringToInt(str[2]);
if(inFace) {
SpawnSpecialInFace(target, special);
ShowActivity(client, "spawned Insta-%s™ near %N", SPECIAL_NAMES[special-1], target);
} else {
SpawnSpecialNear(target, special);
ShowActivity(client, "spawned Insta-%s™ near %N", SPECIAL_NAMES[special-1], target);
}
} else if (action == MenuAction_End)
delete menu;
}
public int ChooseMarkedTroll(Menu menu, MenuAction action, int activator, int param2) {
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
int target = GetClientOfUserId(StringToInt(info));
ToggleMarkPlayer(activator, target);
} else if (action == MenuAction_End)
delete menu;
}
public int ChoosePlayerHandler(Menu menu, MenuAction action, int param1, int param2) {
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
int userid = StringToInt(info);
Menu trollMenu = new Menu(ChooseModeMenuHandler);
trollMenu.SetTitle("Choose a troll mode");
//TODO: Update
static char id[8];
static char name[MAX_TROLL_NAME_LENGTH];
for(int i = 0; i <= MAX_TROLLS; i++) {
GetTrollID(i, name);
// int trollIndex = GetTrollByKeyIndex(i, troll);
// Pass key index
Format(id, sizeof(id), "%d|%d", userid, i);
trollMenu.AddItem(id, name);
}
trollMenu.ExitButton = true;
trollMenu.Display(param1, 0);
} else if (action == MenuAction_End)
delete menu;
}
public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int param2) {
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
static char str[2][8];
ExplodeString(info, "|", str, 2, 8, false);
int userid = StringToInt(str[0]);
int client = GetClientOfUserId(userid);
int keyIndex = StringToInt(str[1]);
static Troll troll;
static char trollID[MAX_TROLL_NAME_LENGTH];
GetTrollByKeyIndex(keyIndex, troll);
troll.GetID(trollID, MAX_TROLL_NAME_LENGTH);
//If troll has multiple flags, prompt:
if(troll.HasMode(TrollMod_Instant) && troll.HasMode
(TrollMod_Constant)) {
Menu modiferMenu = new Menu(ChooseTrollModiferHandler);
modiferMenu.SetTitle("Choose Troll Modifer Option");
static char singleUse[16], multiUse[16], bothUse[16];
Format(singleUse, sizeof(singleUse), "%d|%d|1", userid, keyIndex);
Format(multiUse, sizeof(multiUse), "%d|%d|2", userid, keyIndex);
Format(bothUse, sizeof(bothUse), "%d|%d|3", userid, keyIndex);
modiferMenu.AddItem(singleUse, "Activate once");
modiferMenu.AddItem(multiUse, "Activate Periodically");
modiferMenu.AddItem(bothUse, "Activate Periodically & Instantly");
modiferMenu.ExitButton = true;
modiferMenu.Display(param1, 0);
} else {
ApplyTroll(client, trollID, param1, troll.GetDefaultMod());
}
} else if (action == MenuAction_End)
delete menu;
}
public int ChooseTrollModiferHandler(Menu menu, MenuAction action, int param1, int param2) {
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
static char str[3][8];
ExplodeString(info, "|", str, 3, 8, false);
int client = GetClientOfUserId(StringToInt(str[0]));
int keyIndex = StringToInt(str[1]);
static Troll troll;
static char trollID[MAX_TROLL_NAME_LENGTH];
GetTrollByKeyIndex(keyIndex, troll);
troll.GetID(trollID, MAX_TROLL_NAME_LENGTH);
int modifier = StringToInt(str[2]);
if(modifier == 2 || modifier == 3)
ApplyTroll(client, trollID, param1, TrollMod_Repeat);
else
ApplyTroll(client, trollID, param1, TrollMod_InstantFire);
} else if (action == MenuAction_End)
delete menu;
}
public void StopItemGive(int client) {
g_bPendingItemGive[client] = false;
}

View file

@ -0,0 +1,109 @@
#define AUTOPUNISH_FLOW_MIN_DISTANCE 5000.0
#define AUTOPUNISH_MODE_COUNT 3
void ActivateAutoPunish(int client) {
if(hAutoPunish.IntValue & 2 == 2)
ApplyTroll(lastButtonUser, "SpecialMagnet", 0, TrollMod_Constant);
if(hAutoPunish.IntValue & 1 == 1)
ApplyTroll(lastButtonUser, "TankMagnet", 0, TrollMod_Constant);
if(hAutoPunish.IntValue & 8 == 8)
ApplyTroll(lastButtonUser, "VomitPlayer", 0, TrollMod_Instant);
else if(hAutoPunish.IntValue & 4 == 4)
ApplyTroll(lastButtonUser, "Swarm", 0, TrollMod_Instant);
if(hAutoPunishExpire.IntValue > 0) {
CreateTimer(60.0 * hAutoPunishExpire.FloatValue, Timer_ResetAutoPunish, GetClientOfUserId(lastButtonUser));
}
}
void SetWitchTarget(int witch, int target) {
Behavior behavior = Behavior(witch, WITCH_QUERY);
BehaviorAction action = behavior.CurrentAction.Last;
BehaviorAction newaction = view_as<BehaviorAction>(AllocateMemory(18556));
SDKCall(g_hWitchAttack, newaction, target);
IActionResult result; result.Init(CHANGE_TO, newaction);
result.ToAction(action);
}
bool ToggleMarkPlayer(int client, int target) {
if(g_PendingBanTroll[target]) {
g_PendingBanTroll[target] = false;
ShowActivity(client, "unmarked %N as troll", target);
return true;
}else{
AdminId admin_client = GetUserAdmin(client);
AdminId admin_target = GetUserAdmin(target);
if(admin_client != INVALID_ADMIN_ID && admin_target == INVALID_ADMIN_ID ) {
Call_StartForward(g_PlayerMarkedForward);
Call_PushCell(client);
Call_PushCell(target);
Call_Finish();
g_PendingBanTroll[target] = true;
ShowActivity(client, "marked %N as troll", target);
return true;
}else{
ReplyToCommand(client, "cannot mark %N as troll as they are an admin.", target);
return false;
}
}
}
stock int FindIdlePlayerBot(int client) {
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsFakeClient(i)) {
int user = GetEntProp(i, Prop_Send, "m_humanSpectatorUserID");
int bot = GetClientOfUserId(user);
return bot > 0 ? bot : client;
}
}
return client;
}
stock bool IsPlayerIncapped(int client) {
return GetEntProp(client, Prop_Send, "m_isIncapacitated") == 1;
}
#define MAX_PHRASES_PER_WORD 8
#define MAX_PHRASE_LENGTH 191
StringMap REPLACEMENT_PHRASES;
//TODO: Load from cfg
/* Example:
exWord
{
"1" "phrase1"
"2" "phrase2"
}
*/
void LoadPhrases() {
KeyValues kv = new KeyValues("Phrases");
ArrayList phrases = new ArrayList(ByteCountToCells(MAX_PHRASE_LENGTH));
char sPath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, sizeof(sPath), "data/ftt_phrases.cfg");
if(!FileExists(sPath) || !kv.ImportFromFile(sPath)) {
delete kv;
PrintToServer("[FTT] Could not load phrase list from data/ftt_phrases.cfg");
return;
}
static char word[32];
char phrase[MAX_PHRASE_LENGTH];
// Go through all the words:
kv.GotoFirstSubKey();
int i = 0;
static char buffer[4];
do {
kv.GetSectionName(word, sizeof(word));
phrases.Clear();
for(;;) {
IntToString(++i, buffer, sizeof(buffer));
kv.GetString(buffer, phrase, MAX_PHRASE_LENGTH, "_null");
if(strcmp(phrase, "_null") == 0) break;
phrases.PushString(phrase);
}
i = 0;
REPLACEMENT_PHRASES.SetValue(word, phrases.Clone(), true);
} while (kv.GotoNextKey(false));
delete kv;
}

View file

@ -0,0 +1,82 @@
char SPECIAL_NAMES[][] = {
"Smoker", "Boomer", "Hunter", "Spitter", "Jockey", "Charger", "Witch"
};
stock int GetSpecialType(const char[] input) {
for(int i = 0; i < sizeof(SPECIAL_NAMES); i++) {
if(strcmp(SPECIAL_NAMES[i], input, false) == 0) return i + 1;
}
return -1;
}
stock bool FindSuitablePosition(int target, const float pos[3], float outputPos[3], float minDistance = 19000.0, int tries = 100) {
outputPos = pos;
for(int i = tries; i > 0; i--) {
// int nav = L4D_GetNearestNavArea(pos);
// L4D_FindRandomSpot(nav, testPos);
// float dist = GetVectorDistance(testPos, pos, true);
outputPos[0] += GetRandomFloat(-30.0, 30.0);
outputPos[1] += GetRandomFloat(-30.0, 30.0);
float dist = GetVectorDistance(outputPos, pos, true);
if(dist >= minDistance && L4D2Direct_GetTerrorNavArea(outputPos) != Address_Null) { //5m^2
return true;
}
}
return false;
}
float GetIdealMinDistance(int specialType) {
switch(specialType) {
// /*Boomer*/ case 2: return 1200.0;
/*Charger*/ case 6: return 19000.0;
/*Smoker*/ case 1: return 20000.0;
default:
return 12000.0;
}
}
bool SpawnSpecialInFace(int target, int specialType) {
static float pos[3], ang[3];
static float testPos[3];
testPos = pos;
GetClientAbsOrigin(target, pos);
GetClientEyeAngles(target, ang);
if(specialType != 5 && specialType != 2) { //If charger/hunter, find a suitable area that is at least 5 m away
float minDistance = GetIdealMinDistance(specialType);
GetHorizontalPositionFromOrigin(pos, ang, minDistance, testPos);
FindSuitablePosition(target, pos, testPos, minDistance, 100);
pos = testPos;
} else { // Else spawn a little bit off, and above (above for jockeys)
pos[2] += 10.0;
pos[0] += 5.0;
}
pos[2] += 1.0;
NegateVector(ang);
int special = (specialType == 7) ? L4D2_SpawnWitch(pos, ang) : L4D2_SpawnSpecial(specialType, pos, ang);
if(special == -1) return false;
if(specialType == 7)
SetWitchTarget(special, target);
else
g_iAttackerTarget[special] = GetClientUserId(target);
if(specialType == 2) { //Kill boomer
ForcePlayerSuicide(special);
}
return true;
}
bool SpawnSpecialNear(int target, int specialType) {
static float pos[3];
if(L4D_GetRandomPZSpawnPosition(target, specialType, 10, pos)) {
int special = (specialType == 7) ? L4D2_SpawnWitch(pos, ZERO_VECTOR) : L4D2_SpawnSpecial(specialType, pos, ZERO_VECTOR);
if(special == -1) return false;
if(specialType == 7)
SetWitchTarget(special, target);
else
g_iAttackerTarget[special] = GetClientUserId(target);
return true;
}
return false;
}

View file

@ -0,0 +1,93 @@
public Action Timer_ThrowTimer(Handle timer) {
int count = 0;
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && IsTrollActive(i, "ThrowItAll")) {
ThrowAllItems(i);
count++;
}
}
return count > 0 ? Plugin_Continue : Plugin_Stop;
}
public Action Timer_Main(Handle timer) {
static int loop;
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i)) {
if(IsTrollActive(i, "SlowDrain")) {
if(loop % 4 == 0) {
int hp = GetClientHealth(i);
if(hp > 50) {
SetEntProp(i, Prop_Send, "m_iHealth", hp - 1);
}
}
}else if(IsTrollActive(i, "TempHealthQuickDrain")) {
if(loop % 2 == 0) {
float bufferTime = GetEntPropFloat(i, Prop_Send, "m_healthBufferTime");
float buffer = GetEntPropFloat(i, Prop_Send, "m_healthBuffer");
float tempHealth = GetTempHealth(i);
if(tempHealth > 0.0) {
PrintToConsole(i, "%f | %f %f", tempHealth, buffer, bufferTime);
//SetEntPropFloat(i, Prop_Send, "m_healthBuffer", buffer - 10.0);
SetEntPropFloat(i, Prop_Send, "m_healthBufferTime", bufferTime - 7.0);
}
}
}else if(IsTrollActive(i, "Swarm")) {
L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", GetClientUserId(i), 15000);
}
}
}
if(++loop >= 60) {
loop = 0;
}
return Plugin_Continue;
}
public Action Timer_GivePistol(Handle timer, int client) {
int flags = GetCommandFlags("give");
SetCommandFlags("give", flags & ~FCVAR_CHEAT);
FakeClientCommand(client, "give pistol");
SetCommandFlags("give", flags|FCVAR_CHEAT);
}
public Action Timer_ThrowWeapon(Handle timer, Handle pack) {
ResetPack(pack);
float dest[3];
dest[0] = ReadPackFloat(pack);
dest[1] = ReadPackFloat(pack);
dest[2] = ReadPackFloat(pack);
int slot = ReadPackCell(pack);
int victim = ReadPackCell(pack);
int wpnRef = GetPlayerWeaponSlot(victim, slot);
if(wpnRef != -1) {
int wpn = EntRefToEntIndex(wpnRef);
if(wpn != INVALID_ENT_REFERENCE) {
if(slot == 1) {
static char name[16];
GetEdictClassname(wpn, name, sizeof(name));
if(!StrEqual(name, "weapon_pistol", false)) {
SDKHooks_DropWeapon(victim, wpn, dest);
CreateTimer(0.2, Timer_GivePistol, victim);
}
}else
SDKHooks_DropWeapon(victim, wpn, dest);
}
}
}
public Action Timer_ResetAutoPunish(Handle timer, int user) {
int client = GetClientOfUserId(user);
if(client) {
if(hAutoPunish.IntValue & 2 == 2)
DisableTroll(client, "SpecialMagnet");
if(hAutoPunish.IntValue & 1 == 1)
DisableTroll(client, "TankMagnet");
}
}
public Action Timer_NextWitchSet(Handle timer, DataPack pack) {
pack.Reset();
int client = GetClientOfUserId(pack.ReadCell());
int witch = pack.ReadCell();
SetWitchTarget(witch, client);
}

View file

@ -1,9 +1,3 @@
#define AUTOPUNISH_FLOW_MIN_DISTANCE 5000.0
#define AUTOPUNISH_MODE_COUNT 3
// #define TROLL_MODE_COUNT 26
//
enum L4D2Infected
{
L4D2Infected_None = 0,
@ -37,204 +31,5 @@ int gChargerVictim = -1; //For charge player feature
float ZERO_VECTOR[3] = {0.0, 0.0, 0.0};
#include <feedthetrolls/base>
void ResetClient(int victim, bool wipe = true) {
if(wipe) ActiveTrolls[victim] = 0;
SetEntityGravity(victim, 1.0);
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
SDKUnhook(victim, SDKHook_WeaponCanUse, Event_ItemPickup);
int wpn = GetClientWeaponEntIndex(victim, 0);
if(wpn > -1)
SDKUnhook(wpn, SDKHook_Reload, Event_WeaponReload);
}
void ActivateAutoPunish(int client) {
if(hAutoPunish.IntValue & 2 == 2)
ApplyTroll(lastButtonUser, "SpecialMagnet", 0, TrollMod_None);
if(hAutoPunish.IntValue & 1 == 1)
ApplyTroll(lastButtonUser, "TankMagnet", 0, TrollMod_None);
if(hAutoPunish.IntValue & 8 == 8)
ApplyTroll(lastButtonUser, "VomitPlayer", 0, TrollMod_None);
else if(hAutoPunish.IntValue & 4 == 4)
ApplyTroll(lastButtonUser, "Swarm", 0, TrollMod_None);
if(hAutoPunishExpire.IntValue > 0) {
CreateTimer(60.0 * hAutoPunishExpire.FloatValue, Timer_ResetAutoPunish, GetClientOfUserId(lastButtonUser));
}
}
void SetWitchTarget(int witch, int target) {
Behavior behavior = Behavior(witch, WITCH_QUERY);
BehaviorAction action = behavior.CurrentAction.Last;
BehaviorAction newaction = view_as<BehaviorAction>(AllocateMemory(18556));
SDKCall(g_hWitchAttack, newaction, target);
IActionResult result; result.Init(CHANGE_TO, newaction);
result.ToAction(action);
}
bool ToggleMarkPlayer(int client, int target) {
if(g_PendingBanTroll[target]) {
g_PendingBanTroll[target] = false;
ShowActivity(client, "unmarked %N as troll", target);
return true;
}else{
AdminId admin_client = GetUserAdmin(client);
AdminId admin_target = GetUserAdmin(target);
if(admin_client != INVALID_ADMIN_ID && admin_target == INVALID_ADMIN_ID ) {
Call_StartForward(g_PlayerMarkedForward);
Call_PushCell(client);
Call_PushCell(target);
Call_Finish();
g_PendingBanTroll[target] = true;
ShowActivity(client, "marked %N as troll", target);
return true;
}else{
ReplyToCommand(client, "cannot mark %N as troll as they are an admin.", target);
return false;
}
}
}
stock int FindIdlePlayerBot(int client) {
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsFakeClient(i)) {
int user = GetEntProp(i, Prop_Send, "m_humanSpectatorUserID");
int bot = GetClientOfUserId(user);
return bot > 0 ? bot : client;
}
}
return client;
}
stock bool IsPlayerIncapped(int client) {
return GetEntProp(client, Prop_Send, "m_isIncapacitated") == 1;
}
char SPECIAL_NAMES[][] = {
"Smoker", "Boomer", "Hunter", "Spitter", "Jockey", "Charger", "Witch"
};
stock int GetSpecialType(const char[] input) {
for(int i = 0; i < sizeof(SPECIAL_NAMES); i++) {
if(strcmp(SPECIAL_NAMES[i], input, false) == 0) return i + 1;
}
return -1;
}
stock bool FindSuitablePosition(int target, const float pos[3], float outputPos[3], float minDistance = 19000.0, int tries = 100) {
outputPos = pos;
for(int i = tries; i > 0; i--) {
// int nav = L4D_GetNearestNavArea(pos);
// L4D_FindRandomSpot(nav, testPos);
// float dist = GetVectorDistance(testPos, pos, true);
outputPos[0] += GetRandomFloat(-30.0, 30.0);
outputPos[1] += GetRandomFloat(-30.0, 30.0);
float dist = GetVectorDistance(outputPos, pos, true);
if(dist >= minDistance && L4D2Direct_GetTerrorNavArea(outputPos) != Address_Null) { //5m^2
return true;
}
}
return false;
}
#define MAX_PHRASES_PER_WORD 8
#define MAX_PHRASE_LENGTH 191
StringMap REPLACEMENT_PHRASES;
//TODO: Load from cfg
/* Example:
exWord
{
"1" "phrase1"
"2" "phrase2"
}
*/
void LoadPhrases() {
KeyValues kv = new KeyValues("Phrases");
ArrayList phrases = new ArrayList(ByteCountToCells(MAX_PHRASE_LENGTH));
char sPath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, sizeof(sPath), "data/ftt_phrases.cfg");
if(!FileExists(sPath) || !kv.ImportFromFile(sPath)) {
delete kv;
PrintToServer("[FTT] Could not load phrase list from data/ftt_phrases.cfg");
return;
}
static char word[32];
char phrase[MAX_PHRASE_LENGTH];
// Go through all the words:
kv.GotoFirstSubKey();
int i = 0;
static char buffer[4];
do {
kv.GetSectionName(word, sizeof(word));
phrases.Clear();
for(;;) {
IntToString(++i, buffer, sizeof(buffer));
kv.GetString(buffer, phrase, MAX_PHRASE_LENGTH, "_null");
if(strcmp(phrase, "_null") == 0) break;
phrases.PushString(phrase);
}
i = 0;
REPLACEMENT_PHRASES.SetValue(word, phrases.Clone(), true);
} while (kv.GotoNextKey(false));
delete kv;
}
float GetIdealMinDistance(int specialType) {
switch(specialType) {
// /*Boomer*/ case 2: return 1200.0;
/*Charger*/ case 6: return 19000.0;
/*Smoker*/ case 1: return 20000.0;
default:
return 12000.0;
}
}
public Action Timer_Kill(Handle h, int client) {
AcceptEntityInput(client, "Kill");
}
//TODO: Add Insta-Witch
bool SpawnSpecialInFace(int target, int specialType) {
static float pos[3], ang[3];
static float testPos[3];
testPos = pos;
GetClientAbsOrigin(target, pos);
GetClientEyeAngles(target, ang);
if(specialType != 5 && specialType != 2) { //If charger/hunter, find a suitable area that is at least 5 m away
float minDistance = GetIdealMinDistance(specialType);
GetHorizontalPositionFromOrigin(pos, ang, minDistance, testPos);
FindSuitablePosition(target, pos, testPos, minDistance, 100);
pos = testPos;
} else { // Else spawn a little bit off, and above (above for jockeys)
pos[2] += 10.0;
pos[0] += 5.0;
}
pos[2] += 1.0;
NegateVector(ang);
int special = (specialType == 7) ? L4D2_SpawnWitch(pos, ang) : L4D2_SpawnSpecial(specialType, pos, ang);
if(special == -1) return false;
if(specialType == 7)
SetWitchTarget(special, target);
else
g_iAttackerTarget[special] = GetClientUserId(target);
if(specialType == 2) { //Kill boomer
ForcePlayerSuicide(special);
}
return true;
}
bool SpawnSpecialNear(int target, int specialType) {
static float pos[3];
if(L4D_GetRandomPZSpawnPosition(target, specialType, 10, pos)) {
int special = (specialType == 7) ? L4D2_SpawnWitch(pos, ZERO_VECTOR) : L4D2_SpawnSpecial(specialType, pos, ZERO_VECTOR);
if(special == -1) return false;
if(specialType == 7)
SetWitchTarget(special, target);
else
g_iAttackerTarget[special] = GetClientUserId(target);
return true;
}
return false;
}
#include <feedthetrolls/specials>
#include <feedthetrolls/misc>

View file

@ -102,385 +102,6 @@ public void OnPluginStart() {
// EVENTS
///////////////////////////////////////////////////////////////////////////////
public void OnPluginEnd() {
UnhookEntityOutput("func_button", "OnPressed", Event_ButtonPress);
}
public void OnMapEnd() {
UnhookEntityOutput("func_button", "OnPressed", Event_ButtonPress);
}
public void OnMapStart() {
AddFileToDownloadsTable("sound/custom/meow1.mp3");
PrecacheSound("custom/meow1.mp3");
lastButtonUser = -1;
HookEntityOutput("func_button", "OnPressed", Event_ButtonPress);
CreateTimer(MAIN_TIMER_INTERVAL_S, Timer_Main, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
PrecacheSound("player/footsteps/clown/concrete1.wav");
//CreateTimer(30.0, Timer_AutoPunishCheck, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
}
public void OnClientPutInServer(int client) {
g_PendingBanTroll[client] = false;
SDKHook(client, SDKHook_OnTakeDamage, Event_TakeDamage);
}
public void OnClientAuthorized(int client, const char[] auth) {
if(!IsFakeClient(client)) {
strcopy(steamids[client], 64, auth);
}
}
public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
if(g_PendingBanTroll[client]) {
g_PendingBanTroll[client] = false;
if(!IsFakeClient(client) && GetUserAdmin(client) == INVALID_ADMIN_ID) {
BanIdentity(steamids[client], 0, BANFLAG_AUTHID, "TrollMarked", "ftt", 0);
}
}
steamids[client][0] = '\0';
ActiveTrolls[client] = 0;
g_iAttackerTarget[client] = 0;
}
public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
g_iAttackerTarget[client] = 0;
}
public Action Event_WeaponReload(int weapon) {
int client = GetEntPropEnt(weapon, Prop_Send, "m_hOwner");
if(IsTrollActive(client, "GunJam")) {
float dec = GetRandomFloat(0.0, 1.0);
if(FloatCompare(dec, 0.50) == -1) { //10% chance gun jams
return Plugin_Stop;
}
}
return Plugin_Continue;
}
public Action Event_ButtonPress(const char[] output, int entity, int client, float delay) {
if(client > 0 && client <= MaxClients) {
lastButtonUser = client;
}
return Plugin_Continue;
}
public void Event_PanicEventCreate(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
if(client) {
lastButtonUser = client;
}
}
public void Event_CarAlarm(Event event, const char[] name, bool dontBroadcast) {
int user = event.GetInt("userid");
int client = GetClientOfUserId(user);
if(client) {
PrintToChatAll("%N has alerted the horde!", client);
L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", user, 15000);
}
//Ignore car alarms for autopunish
lastButtonUser = -1;
}
public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
// =========================
// OVERRIDE VICTIM
// =========================
if(hMagnetChance.FloatValue < GetRandomFloat()) return Plugin_Continue;
L4D2Infected class = view_as<L4D2Infected>(GetEntProp(attacker, Prop_Send, "m_zombieClass"));
int existingTarget = GetClientOfUserId(g_iAttackerTarget[attacker]);
if(existingTarget > 0 && IsPlayerAlive(existingTarget) && (hMagnetTargetMode.IntValue & 1 != 1 || !IsPlayerIncapped(existingTarget))) {
if(class == L4D2Infected_Tank && (hMagnetTargetMode.IntValue % 2 != 2 || !IsPlayerIncapped(existingTarget))) {
curTarget = existingTarget;
return Plugin_Changed;
}else if(hMagnetTargetMode.IntValue & 1 != 1 || !IsPlayerIncapped(existingTarget)) {
curTarget = existingTarget;
return Plugin_Changed;
}
}
float closestDistance, survPos[3], spPos[3];
GetClientAbsOrigin(attacker, spPos);
int closestClient = -1;
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
//Ignore incapped players if turned on:
if(IsPlayerIncapped(i)) {
if((class == L4D2Infected_Tank && hMagnetTargetMode.IntValue & 2 == 2) || hMagnetTargetMode.IntValue & 1 == 1 ) continue;
}
if(class == L4D2Infected_Tank && IsTrollActive(i, "TankMagnet") || (class != L4D2Infected_Tank && IsTrollActive(i, "SpecialMagnet"))) {
GetClientAbsOrigin(i, survPos);
float dist = GetVectorDistance(survPos, spPos, true);
if(closestClient == -1 || dist < closestDistance) {
closestDistance = dist;
closestClient = i;
}
}
}
}
if(closestClient > 0) {
g_iAttackerTarget[attacker] = GetClientUserId(closestClient);
curTarget = closestClient;
return Plugin_Changed;
}
return Plugin_Continue;
}
public Action L4D2_OnEntityShoved(int client, int entity, int weapon, float vecDir[3], bool bIsHighPounce) {
if(client > 0 && client <= MaxClients && IsTrollActive(client, "NoShove") && hShoveFailChance.FloatValue > GetRandomFloat()) {
return Plugin_Handled;
}
return Plugin_Continue;
}
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) {
if(sArgs[0] == '@') return Plugin_Continue;
if(IsTrollActive(client, "Honk")) {
static char strings[32][7];
int words = ExplodeString(sArgs, " ", strings, sizeof(strings), 5);
for(int i = 0; i < words; i++) {
if(GetRandomFloat() <= 0.8) strings[i] = "honk";
else strings[i] = "squeak";
}
int length = 7 * words;
char[] message = new char[length];
ImplodeStrings(strings, 32, " ", message, length);
CPrintToChatAll("{blue}%N {default}: %s", client, message);
PrintToServer("%N: %s", client, sArgs);
return Plugin_Handled;
}else if(IsTrollActive(client, "iCantSpellNoMore")) {
int type = GetRandomInt(1, trollKV.Size + 8);
char letterSrc, replaceChar;
switch(type) {
case 1: {
letterSrc = 'e';
replaceChar = 'b';
}
case 2: {
letterSrc = 't';
replaceChar = 'e';
}
case 3: {
letterSrc = 'i';
replaceChar = 'e';
}
case 4: {
letterSrc = 'a';
replaceChar = 's';
}
case 5: {
letterSrc = 'u';
replaceChar = 'i';
}
case 6: {
letterSrc = '.';
replaceChar = '/';
}
case 7: {
letterSrc = 'm';
replaceChar = 'n';
}
case 8: {
letterSrc = 'n';
replaceChar = 'm';
}
case 9: {
letterSrc = 'l';
replaceChar = 'b';
}
case 10: {
letterSrc = 'l';
replaceChar = 'b';
}
case 11: {
letterSrc = 'h';
replaceChar = 'j';
}
case 12: {
letterSrc = 'o';
replaceChar = 'i';
}
case 13: {
letterSrc = 'e';
replaceChar = 'r';
}
default:
return Plugin_Continue;
}
int strLength = strlen(sArgs);
char[] newMessage = new char[strLength + 20];
int n = 0;
while (sArgs[n] != '\0') {
if(sArgs[n] == letterSrc) {
newMessage[n] = replaceChar;
}else{
newMessage[n] = sArgs[n];
}
n++;
}
PrintToServer("%N: %s", client, sArgs);
CPrintToChatAll("{blue}%N {default}: %s", client, newMessage);
return Plugin_Handled;
}else if(IsTrollActive(client, "NoProfanity")) {
//TODO: Check all replacement words, if none were replaced then do full word
//TODO: Lowercase .getstring
static char strings[32][MAX_PHRASE_LENGTH];
ArrayList phrases;
bool foundWord = false;
int words = ExplodeString(sArgs, " ", strings, 32, MAX_PHRASE_LENGTH);
for(int i = 0; i < words; i++) {
if(REPLACEMENT_PHRASES.GetValue(strings[i], phrases) && phrases.Length > 0) {
foundWord = true;
int c = phrases.GetString(GetRandomInt(0, phrases.Length - 1), strings[i], MAX_PHRASE_LENGTH);
PrintToServer("replacement: %s (%d)", strings[i], c);
}
}
int length = MAX_PHRASE_LENGTH * words;
char[] message = new char[length];
if(foundWord) {
ImplodeStrings(strings, 32, " ", message, length);
} else {
REPLACEMENT_PHRASES.GetValue("_Full Message Phrases", phrases);
phrases.GetString(GetRandomInt(0, phrases.Length - 1), message, MAX_PHRASE_LENGTH);
}
CPrintToChatAll("{blue}%N {default}: %s", client, message);
PrintToServer("%N: %s", client, sArgs);
return Plugin_Handled;
}
return Plugin_Continue;
}
public Action Event_ItemPickup(int client, int weapon) {
if(IsTrollActive(client, "NoPickup")) {
return Plugin_Stop;
}else{
static char wpnName[64];
GetEdictClassname(weapon, wpnName, sizeof(wpnName));
if(StrContains(wpnName, "rifle") > -1
|| StrContains(wpnName, "smg") > -1
|| StrContains(wpnName, "weapon_grenade_launcher") > -1
|| StrContains(wpnName, "sniper") > -1
|| StrContains(wpnName, "shotgun") > -1
) {
//If 4: Only UZI, if 5: Can't switch.
if(IsTrollActive(client, "UziRules")) {
static char currentWpn[32];
GetClientWeaponName(client, 0, currentWpn, sizeof(currentWpn));
if(StrEqual(wpnName, "weapon_smg", true)) {
return Plugin_Continue;
} else if(StrEqual(currentWpn, "weapon_smg", true)) {
return Plugin_Stop;
}else{
int flags = GetCommandFlags("give");
SetCommandFlags("give", flags & ~FCVAR_CHEAT);
FakeClientCommand(client, "give smg");
SetCommandFlags("give", flags);
return Plugin_Stop;
}
}else if(IsTrollActive(client, "PrimaryDisable")) {
return Plugin_Stop;
}
return Plugin_Continue;
}else{
return Plugin_Continue;
}
}
}
public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2]) {
if(g_bPendingItemGive[client] && !(buttons & IN_ATTACK2)) {
int target = GetClientAimTarget(client, true);
if(target > -1) {
buttons |= IN_ATTACK2;
RequestFrame(StopItemGive, client);
return Plugin_Changed;
}
return Plugin_Continue;
}
return Plugin_Continue;
}
public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) {
//Stop FF from marked:
if(attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker) && IsPlayerAlive(attacker)) {
if(g_PendingBanTroll[attacker] && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) {
return Plugin_Stop;
}
if(IsTrollActive(attacker, "DamageBoost")) {
damage * 2;
return Plugin_Changed;
}
}
return Plugin_Continue;
}
public Action SoundHook(int[] clients, int& numClients, char sample[PLATFORM_MAX_PATH], int& entity, int& channel, float& volume, int& level, int& pitch, int& flags, char[] soundEntry, int& seed) {
if(lastButtonUser > -1 && StrEqual(sample, "npc/mega_mob/mega_mob_incoming.wav")) {
PrintToConsoleAll("CRESCENDO STARTED BY %N", lastButtonUser);
#if defined DEBUG
PrintToChatAll("CRESCENDO STARTED BY %N", lastButtonUser);
#endif
lastCrescendoUser = lastButtonUser;
if(IsPlayerFarDistance(lastButtonUser, AUTOPUNISH_FLOW_MIN_DISTANCE)) {
NotifyAllAdmins("Autopunishing player %N for activation of event far from team", lastButtonUser);
ShowActivity(0, "activated autopunish for crescendo activator %N (auto)", lastButtonUser);
ActivateAutoPunish(lastButtonUser);
}
lastButtonUser = -1;
}else if(numClients > 0 && entity > 0 && entity <= MaxClients) {
if(StrContains(sample, "survivor\\voice") > -1) {
if(IsTrollActive(entity, "Honk")) {
strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav");
return Plugin_Changed;
} else if(IsTrollActive(entity, "VocalizeGag")) {
return Plugin_Handled;
} else if(IsTrollActive(entity, "Meow")) {
strcopy(sample, sizeof(sample), "custom/meow1.mp3");
return Plugin_Changed;
}
}
}
return Plugin_Continue;
}
public Action Event_WitchVictimSet(Event event, const char[] name, bool dontBroadcast) {
int witch = event.GetInt("witchid");
float closestDistance, survPos[3], witchPos[3];
GetEntPropVector(witch, Prop_Send, "m_vecOrigin", witchPos);
int closestClient = -1;
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
//Ignore incapped players if hWitchIgnoreIncapp turned on:
if(IsPlayerIncapped(i) && !hWitchTargetIncapp.BoolValue) {
continue;
}
if(IsTrollActive(i, "WitchMagnet")) {
GetClientAbsOrigin(i, survPos);
float dist = GetVectorDistance(survPos, witchPos, true);
if(closestClient == -1 || dist < closestDistance) {
closestDistance = dist;
closestClient = i;
}
}
}
}
if(closestClient > 0) {
DataPack pack;
CreateDataTimer(0.1, Timer_NextWitchSet, pack);
pack.WriteCell(GetClientUserId(closestClient));
pack.WriteCell(witch);
CreateDataTimer(0.2, Timer_NextWitchSet, pack);
pack.WriteCell(GetClientUserId(closestClient));
pack.WriteCell(witch);
}
}
public Action Timer_NextWitchSet(Handle timer, DataPack pack) {
pack.Reset();
int client = GetClientOfUserId(pack.ReadCell());
int witch = pack.ReadCell();
SetWitchTarget(witch, client);
}
///////////////////////////////////////////////////////////////////////////////
// CVAR CHANGES
@ -499,591 +120,16 @@ public void Change_ThrowInterval(ConVar convar, const char[] oldValue, const cha
// COMMANDS
///////////////////////////////////////////////////////////////////////////////
public Action Command_InstaSpecial(int client, int args) {
if(args < 1) {
Menu menu = new Menu(Insta_PlayerHandler);
menu.SetTitle("Choose a player");
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
static char userid[8], display[16];
Format(userid, sizeof(userid), "%d|0", GetClientUserId(i));
GetClientName(i, display, sizeof(display));
menu.AddItem(userid, display);
}
}
menu.ExitButton = true;
menu.Display(client, 0);
} else {
char arg1[32], arg2[32] = "jockey";
GetCmdArg(1, arg1, sizeof(arg1));
if(args >= 2) {
GetCmdArg(2, arg2, sizeof(arg2));
}
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MaxClients,
COMMAND_FILTER_ALIVE,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
int specialType = GetSpecialType(arg2);
static float pos[3];
if(specialType == -1) {
ReplyToCommand(client, "Unknown special \"%s\"", arg2);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++) {
int target = target_list[i];
if(GetClientTeam(target) == 2) {
SpawnSpecialNear(target, specialType);
}else{
ReplyToTargetError(client, target_count);
}
}
ShowActivity(client, "spawned Insta-%s™ near %s", arg2, target_name);
}
return Plugin_Handled;
}
public Action Command_InstaSpecialFace(int client, int args) {
if(args < 1) {
Menu menu = new Menu(Insta_PlayerHandler);
menu.SetTitle("Choose a player");
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
static char userid[8], display[16];
Format(userid, sizeof(userid), "%d|1", GetClientUserId(i));
GetClientName(i, display, sizeof(display));
menu.AddItem(userid, display);
}
}
menu.ExitButton = true;
menu.Display(client, 0);
} else {
char arg1[32], arg2[32] = "jockey";
GetCmdArg(1, arg1, sizeof(arg1));
if(args >= 2) {
GetCmdArg(2, arg2, sizeof(arg2));
}
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MaxClients,
COMMAND_FILTER_ALIVE,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
int specialType = GetSpecialType(arg2);
static float pos[3];
if(specialType == -1) {
ReplyToCommand(client, "Unknown special \"%s\"", arg2);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++) {
int target = target_list[i];
if(GetClientTeam(target) == 2) {
SpawnSpecialInFace(target, specialType);
}else{
ReplyToTargetError(client, target_count);
}
}
ShowActivity(client, "spawned Insta-%s™ on %s", arg2, target_name);
}
return Plugin_Handled;
}
public Action Command_WitchAttack(int client, int args) {
if(args < 1) {
ReplyToCommand(client, "Usage: sm_witch_attack <user>");
} else {
char arg1[32];
GetCmdArg(1, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
1,
COMMAND_FILTER_ALIVE | COMMAND_FILTER_NO_MULTI, /* Only allow alive players */
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
int target = target_list[0];
if(GetClientTeam(target) == 2) {
int witch = INVALID_ENT_REFERENCE;
while ((witch = FindEntityByClassname(witch, "witch")) != INVALID_ENT_REFERENCE) {
SetWitchTarget(witch, target);
ShowActivity(client, "all witches target %s", target_name);
}
}else{
ReplyToTargetError(client, target_count);
}
}
return Plugin_Handled;
}
public Action Command_FeedTheCrescendoTroll(int client, int args) {
if(lastCrescendoUser > -1) {
ActivateAutoPunish(lastCrescendoUser);
ReplyToCommand(client, "Activated auto punish on %N", lastCrescendoUser);
ShowActivity(client, "activated autopunish for crescendo activator %N",lastCrescendoUser);
}else{
ReplyToCommand(client, "No player could be found to autopunish.");
}
return Plugin_Handled;
}
public Action Command_ResetUser(int client, int args) {
if(args < 1) {
ReplyToCommand(client, "Usage: sm_ftr <user(s)>");
}else{
char arg1[32];
GetCmdArg(1, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MAXPLAYERS,
COMMAND_FILTER_CONNECTED, /* Only allow alive players */
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++) {
if(ActiveTrolls[target_list[i]] > 0) {
ResetClient(target_list[i], true);
ShowActivity(client, "reset troll effects on \"%N\". ", target_list[i]);
}
}
}
return Plugin_Handled;
}
public Action Command_ApplyUser(int client, int args) {
if(args < 2) {
Menu menu = new Menu(ChoosePlayerHandler);
menu.SetTitle("Choose a player");
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
static char userid[8], display[16];
Format(userid, sizeof(userid), "%d", GetClientUserId(i));
GetClientName(i, display, sizeof(display));
menu.AddItem(userid, display);
}
}
menu.ExitButton = true;
menu.Display(client, 0);
}else{
char arg1[32], arg2[32], arg3[8];
GetCmdArg(1, arg1, sizeof(arg1));
GetCmdArg(2, arg2, sizeof(arg2));
GetCmdArg(3, arg3, sizeof(arg3));
bool silent = StrEqual(arg3, "silent") || StrEqual(arg3, "quiet") || StrEqual(arg3, "mute");
static char name[MAX_TROLL_NAME_LENGTH];
if(!GetTrollID(StringToInt(arg2), name)) {
ReplyToCommand(client, "Not a valid mode. Must be greater than 0. Usage: sm_fta [player] [mode]. Use sm_ftr <player> to reset.");
}else{
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MAXPLAYERS,
0,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++) {
if(IsClientInGame(target_list[i]) && GetClientTeam(target_list[i]) == 2)
ApplyTroll(target_list[i], name, client,TrollMod_None, silent);
}
}
}
return Plugin_Handled;
}
public Action Command_ListModes(int client, int args) {
static char name[MAX_TROLL_NAME_LENGTH];
static Troll troll;
for(int i = 0; i <= MAX_TROLLS; i++) {
GetTrollByKeyIndex(i, troll);
ReplyToCommand(client, "%d. %s - %s", i, troll.name, troll.description);
}
return Plugin_Handled;
}
public Action Command_ListTheTrolls(int client, int args) {
int count = 0;
//TODO: Update
char[][] modeListArr = new char[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH];
static char modeList[255];
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && ActiveTrolls[i] > 0) {
int modeCount = 0;
static char name[MAX_TROLL_NAME_LENGTH];
for(int j = 1; j <= MAX_TROLLS; j++) {
GetTrollID(j, name);
if(IsTrollActive(i, name)) {
strcopy(modeListArr[modeCount], MAX_TROLL_NAME_LENGTH, name);
modeCount++;
}
}
ImplodeStrings(modeListArr, modeCount, ", ", modeList, sizeof(modeList));
ReplyToCommand(client, "%N | %s", i, modeList);
count++;
}
}
if(count == 0) {
ReplyToCommand(client, "No clients have a mode applied.");
}
return Plugin_Handled;
}
public Action Command_MarkPendingTroll(int client, int args) {
if(args == 0) {
Menu menu = new Menu(ChooseMarkedTroll);
menu.SetTitle("Choose a troll to mark");
static char userid[8], display[16];
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
AdminId admin = GetUserAdmin(i);
if(admin == INVALID_ADMIN_ID) {
Format(userid, sizeof(userid), "%d", GetClientUserId(i));
GetClientName(i, display, sizeof(display));
menu.AddItem(userid, display);
}else{
ReplyToCommand(client, "%N is an admin cannot be marked.", i);
}
}
}
menu.ExitButton = true;
menu.Display(client, 0);
} else {
char arg1[32];
GetCmdArg(1, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
1,
COMMAND_FILTER_NO_MULTI , /* Only allow alive players */
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
int target = target_list[0];
if(GetClientTeam(target) == 2) {
ToggleMarkPlayer(client, target);
}else{
ReplyToCommand(client, "Player does not exist or is not a survivor.");
}
}
return Plugin_Handled;
}
public Action Command_FeedTheTrollMenu(int client, int args) {
ReplyToCommand(client, "sm_ftl - Lists all the active trolls on players");
ReplyToCommand(client, "sm_ftm - Lists all available troll modes & descriptions");
ReplyToCommand(client, "sm_ftr - Resets target users' of their trolls");
ReplyToCommand(client, "sm_fta - Applies a troll mode on targets");
ReplyToCommand(client, "sm_ftt - Opens this menu");
ReplyToCommand(client, "sm_ftc - Will apply a punishment to last crescendo activator");
ReplyToCommand(client, "sm_mark - Marks the user to be banned on disconnect, prevents their FF.");
return Plugin_Handled;
}
///////////////////////////////////////////////////////////////////////////////
// MENU HANDLER
///////////////////////////////////////////////////////////////////////////////
public int Insta_PlayerHandler(Menu menu, MenuAction action, int client, int param2) {
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
static char str[2][8];
ExplodeString(info, "|", str, 2, 8, false);
int userid = StringToInt(str[0]);
int instaMode = StringToInt(str[1]);
Menu spMenu = new Menu(Insta_SpecialHandler);
spMenu.SetTitle("Choose a Insta-Special™");
for(int i = 1; i <= 6; i++) {
static char id[8];
Format(id, sizeof(id), "%d|%d|%d", userid, instaMode, i);
spMenu.AddItem(id, SPECIAL_NAMES[i-1]);
}
spMenu.ExitButton = true;
spMenu.Display(client, 0);
} else if (action == MenuAction_End)
delete menu;
}
public int Insta_SpecialHandler(Menu menu, MenuAction action, int client, int param2) {
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
static char str[3][8];
ExplodeString(info, "|", str, 3, 8, false);
int target = GetClientOfUserId(StringToInt(str[0]));
bool inFace = StrEqual(str[1], "1");
int special = StringToInt(str[2]);
if(inFace) {
SpawnSpecialInFace(target, special);
ShowActivity(client, "spawned Insta-%s™ near %N", SPECIAL_NAMES[special-1], target);
} else {
SpawnSpecialNear(target, special);
ShowActivity(client, "spawned Insta-%s™ near %N", SPECIAL_NAMES[special-1], target);
}
} else if (action == MenuAction_End)
delete menu;
}
public int ChooseMarkedTroll(Menu menu, MenuAction action, int activator, int param2) {
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
int target = GetClientOfUserId(StringToInt(info));
ToggleMarkPlayer(activator, target);
} else if (action == MenuAction_End)
delete menu;
}
public int ChoosePlayerHandler(Menu menu, MenuAction action, int param1, int param2) {
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
int userid = StringToInt(info);
Menu trollMenu = new Menu(ChooseModeMenuHandler);
trollMenu.SetTitle("Choose a troll mode");
//TODO: Update
static char id[8];
static char name[MAX_TROLL_NAME_LENGTH];
for(int i = 0; i <= MAX_TROLLS; i++) {
GetTrollID(i, name);
// int trollIndex = GetTrollByKeyIndex(i, troll);
// Pass key index
Format(id, sizeof(id), "%d|%d", userid, i);
trollMenu.AddItem(id, name);
}
trollMenu.ExitButton = true;
trollMenu.Display(param1, 0);
} else if (action == MenuAction_End)
delete menu;
}
public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int param2) {
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
static char str[2][8];
ExplodeString(info, "|", str, 2, 8, false);
int userid = StringToInt(str[0]);
int client = GetClientOfUserId(userid);
int keyIndex = StringToInt(str[1]);
static Troll troll;
static char trollID[MAX_TROLL_NAME_LENGTH];
GetTrollByKeyIndex(keyIndex, troll);
troll.GetID(trollID, MAX_TROLL_NAME_LENGTH);
//If mode has an option to be single-time fired/continous/both, prompt:
if(!troll.runsOnce) {
Menu modiferMenu = new Menu(ChooseTrollModiferHandler);
modiferMenu.SetTitle("Choose Troll Modifer Option");
static char singleUse[16], multiUse[16], bothUse[16];
Format(singleUse, sizeof(singleUse), "%d|%d|1", userid, keyIndex);
Format(multiUse, sizeof(multiUse), "%d|%d|2", userid, keyIndex);
Format(bothUse, sizeof(bothUse), "%d|%d|3", userid, keyIndex);
modiferMenu.AddItem(singleUse, "Activate once");
modiferMenu.AddItem(multiUse, "Activate Periodically");
modiferMenu.AddItem(bothUse, "Activate Periodically & Instantly");
modiferMenu.ExitButton = true;
modiferMenu.Display(param1, 0);
} else {
ApplyTroll(client, trollID, param1, TrollMod_None);
}
} else if (action == MenuAction_End)
delete menu;
}
public int ChooseTrollModiferHandler(Menu menu, MenuAction action, int param1, int param2) {
if (action == MenuAction_Select) {
static char info[16];
menu.GetItem(param2, info, sizeof(info));
static char str[3][8];
ExplodeString(info, "|", str, 3, 8, false);
int client = GetClientOfUserId(StringToInt(str[0]));
int keyIndex = StringToInt(str[1]);
static Troll troll;
static char trollID[MAX_TROLL_NAME_LENGTH];
GetTrollByKeyIndex(keyIndex, troll);
troll.GetID(trollID, MAX_TROLL_NAME_LENGTH);
int modifier = StringToInt(str[2]);
if(modifier == 2 || modifier == 3)
ApplyTroll(client, trollID, param1, TrollMod_Repeat);
else
ApplyTroll(client, trollID, param1, TrollMod_InstantFire);
} else if (action == MenuAction_End)
delete menu;
}
public void StopItemGive(int client) {
g_bPendingItemGive[client] = false;
}
///////////////////////////////////////////////////////////////////////////////
// TIMERS
///////////////////////////////////////////////////////////////////////////////
public Action Timer_ThrowTimer(Handle timer) {
int count = 0;
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && IsTrollActive(i, "ThrowItAll")) {
ThrowAllItems(i);
count++;
}
}
return count > 0 ? Plugin_Continue : Plugin_Stop;
}
public Action Timer_Main(Handle timer) {
static int loop;
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i)) {
if(IsTrollActive(i, "SlowDrain")) {
if(loop % 4 == 0) {
int hp = GetClientHealth(i);
if(hp > 50) {
SetEntProp(i, Prop_Send, "m_iHealth", hp - 1);
}
}
}else if(IsTrollActive(i, "TempHealthQuickDrain")) {
if(loop % 2 == 0) {
float bufferTime = GetEntPropFloat(i, Prop_Send, "m_healthBufferTime");
float buffer = GetEntPropFloat(i, Prop_Send, "m_healthBuffer");
float tempHealth = GetTempHealth(i);
if(tempHealth > 0.0) {
PrintToConsole(i, "%f | %f %f", tempHealth, buffer, bufferTime);
//SetEntPropFloat(i, Prop_Send, "m_healthBuffer", buffer - 10.0);
SetEntPropFloat(i, Prop_Send, "m_healthBufferTime", bufferTime - 7.0);
}
}
}else if(IsTrollActive(i, "Swarm")) {
L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", GetClientUserId(i), 15000);
}
}
}
if(++loop >= 60) {
loop = 0;
}
return Plugin_Continue;
}
public Action Timer_GivePistol(Handle timer, int client) {
int flags = GetCommandFlags("give");
SetCommandFlags("give", flags & ~FCVAR_CHEAT);
FakeClientCommand(client, "give pistol");
SetCommandFlags("give", flags|FCVAR_CHEAT);
}
public Action Timer_ThrowWeapon(Handle timer, Handle pack) {
ResetPack(pack);
float dest[3];
dest[0] = ReadPackFloat(pack);
dest[1] = ReadPackFloat(pack);
dest[2] = ReadPackFloat(pack);
int slot = ReadPackCell(pack);
int victim = ReadPackCell(pack);
int wpnRef = GetPlayerWeaponSlot(victim, slot);
if(wpnRef != -1) {
int wpn = EntRefToEntIndex(wpnRef);
if(wpn != INVALID_ENT_REFERENCE) {
if(slot == 1) {
static char name[16];
GetEdictClassname(wpn, name, sizeof(name));
if(!StrEqual(name, "weapon_pistol", false)) {
SDKHooks_DropWeapon(victim, wpn, dest);
CreateTimer(0.2, Timer_GivePistol, victim);
}
}else
SDKHooks_DropWeapon(victim, wpn, dest);
}
}
}
public Action Timer_ResetAutoPunish(Handle timer, int user) {
int client = GetClientOfUserId(user);
if(client) {
if(hAutoPunish.IntValue & 2 == 2)
DisableTroll(client, "SpecialMagnet");
if(hAutoPunish.IntValue & 1 == 1)
DisableTroll(client, "TankMagnet");
}
}
// /////////////////////////////////////////////////////////////////////////////
// NATIVES & FORWARDS