lol changes

This commit is contained in:
Jackzie 2021-10-03 15:23:51 -05:00
parent f756ec3100
commit 440808c0c5
No known key found for this signature in database
GPG key ID: 1E834FE36520537A
21 changed files with 868 additions and 301 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,261 @@
#pragma semicolon 1
#pragma newdecls required
//#define DEBUG
#define PLUGIN_VERSION "1.0"
#include <sourcemod>
#include <sdktools>
//#include <sdkhooks>
public Plugin myinfo =
{
name = "Admin Activity Log",
author = "jackzmc",
description = "",
version = PLUGIN_VERSION,
url = ""
};
enum struct Log {
char name[32];
char clientSteamID[32];
char targetSteamID[32];
char message[256];
int timestamp;
}
// Plugin data
static ArrayList logs;
static Database g_db;
static char serverID[64];
static Handle pushTimer;
static ConVar hLogCvarChanges;
static char lastMap[64];
//Plugin related
static bool lateLoaded;
static EngineVersion g_Game;
//L4d2 Specific
static char L4D2_ZDifficulty[16];
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
CreateNative("ActivityMonitor_AddLog", Native_AddLog);
lateLoaded = late;
return APLRes_Success;
}
public void OnPluginStart() {
g_Game = GetEngineVersion();
logs = new ArrayList(sizeof(Log));
if(!SQL_CheckConfig("activitymonitor")) {
SetFailState("No database entry for 'activitymonitor'; no database to connect to.");
} else if(!ConnectDB()) {
SetFailState("Failed to connect to database.");
}
hLogCvarChanges = CreateConVar("sm_activitymonitor_log_cvar", "0", "Should this plugin log cvar changes (when using sm_cvar from console)");
ConVar hServerID = CreateConVar("sm_activitymonitor_id", "", "The name to use for the 'server' column");
hServerID.GetString(serverID, sizeof(serverID));
hServerID.AddChangeHook(CVAR_ServerIDChanged);
HookEvent("player_first_spawn", Event_Connection);
HookEvent("player_disconnect", Event_Connection);
if(g_Game == Engine_Left4Dead2 || g_Game == Engine_Left4Dead) {
HookEvent("player_incapacitated", Event_L4D2_Incapped);
HookEvent("player_death", Event_L4D2_Death);
ConVar zDifficulty = FindConVar("z_difficulty");
zDifficulty.GetString(L4D2_ZDifficulty, sizeof(L4D2_ZDifficulty));
CVAR_DifficultyChanged(zDifficulty, "", L4D2_ZDifficulty);
zDifficulty.AddChangeHook(CVAR_DifficultyChanged);
}
if(!lateLoaded) {
AddLog("INFO", "", "", "Server has started up");
}
pushTimer = CreateTimer(60.0, Timer_PushLogs, _, TIMER_REPEAT);
// AutoExecConfig(true, "activitymonitor");
}
public void OnMapStart() {
static char curMap[64];
GetCurrentMap(curMap, sizeof(curMap));
if(!StrEqual(lastMap, curMap)) {
strcopy(lastMap, sizeof(lastMap), curMap);
if(g_Game == Engine_Left4Dead2 || g_Game == Engine_Left4Dead)
Format(curMap, sizeof(curMap), "Map changed to %s (%s)", curMap, L4D2_ZDifficulty);
else
Format(curMap, sizeof(curMap), "Map changed to %s", curMap);
AddLog("INFO", "", "", curMap);
}
TriggerTimer(pushTimer, true);
}
public void CVAR_ServerIDChanged(ConVar convar, const char[] oldValue, const char[] newValue) {
strcopy(serverID, sizeof(serverID), newValue);
}
public void CVAR_DifficultyChanged(ConVar convar, const char[] oldValue, const char[] newValue) {
if(StrEqual(newValue, "Hard", false)) strcopy(L4D2_ZDifficulty, sizeof(L4D2_ZDifficulty), "Advanced");
else if(StrEqual(newValue, "Impossible", false)) strcopy(L4D2_ZDifficulty, sizeof(L4D2_ZDifficulty), "Expert");
else {
strcopy(L4D2_ZDifficulty, sizeof(L4D2_ZDifficulty), newValue);
// CVAR value could be lowercase 'normal', convert to 'Normal'
L4D2_ZDifficulty[0] = CharToUpper(L4D2_ZDifficulty[0]);
}
}
bool ConnectDB() {
char error[255];
g_db = SQL_Connect("activitymonitor", true, error, sizeof(error));
if (g_db == null) {
LogError("Database error %s", error);
delete g_db;
return false;
} else {
PrintToServer("[ACTM] Connected to database \"activitymonitor\"");
SQL_LockDatabase(g_db);
SQL_FastQuery(g_db, "SET NAMES \"UTF8mb4\"");
SQL_UnlockDatabase(g_db);
g_db.SetCharset("utf8mb4");
return true;
}
}
public Action Timer_PushLogs(Handle h) {
static char query[1024];
static Log log;
int length = logs.Length;
if(length > 0) {
for(int i = 0; i < length; i++) {
logs.GetArray(i, log, sizeof(log));
g_db.Format(query, sizeof(query), "INSERT INTO `activity_log` (`timestamp`, `server`, `type`, `client`, `target`, `message`) VALUES (%d, NULLIF('%s', ''), '%s', NULLIF('%s', ''), NULLIF('%s', ''), NULLIF('%s', ''))",
log.timestamp,
serverID,
log.name,
log.clientSteamID,
log.targetSteamID,
log.message
);
g_db.Query(SQL_Callback, query, _, DBPrio_Low);
}
// Incase a new item was added while pushing, don't clear it:
logs.Resize(logs.Length - length);
}
}
public void SQL_Callback(Database db, DBResultSet results, const char[] error, any data) {
if(results == null) PrintToServer("[ACTM] Log error: %s", error);
}
public void Event_Connection(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
if(client > 0 && !IsFakeClient(client)) {
static char clientName[32];
GetClientAuthId(client, AuthId_Steam2, clientName, sizeof(clientName));
if((name[7] == 'f')) {
//connection
AddLog("JOIN", clientName, "", "");
} else {
AddLog("QUIT", clientName, "", "");
}
}
}
public Action OnLogAction(Handle source, Identity identity, int client, int target, const char[] message) {
// Ignore cvar changed msgs (from server.cfg)
if(client == 0 && !hLogCvarChanges.BoolValue && strcmp(message[31], "changed cvar") >= 0) return Plugin_Continue;
static char clientName[32], targetName[32];
if(client == 0) clientName = "Server";
else if(client > 0) GetClientAuthId(client, AuthId_Steam2, clientName, sizeof(clientName));
else clientName[0] = '\0';
if(target > 0 && !IsFakeClient(target)) GetClientAuthId(target, AuthId_Steam2, targetName, sizeof(targetName));
else targetName[0] = '\0';
AddLog("ACTION", clientName, targetName, message);
return Plugin_Continue;
}
public void OnClientSayCommand_Post(int client, const char[] command, const char[] sArgs) {
if(client > 0 && !IsFakeClient(client)) {
static char clientName[32];
GetClientAuthId(client, AuthId_Steam2, clientName, sizeof(clientName));
AddLog("CHAT", clientName, "", sArgs);
}
}
public void Event_L4D2_Death(Event event, const char[] name, bool dontBroadcast) {
int victim = GetClientOfUserId(event.GetInt("userid"));
int attacker = GetClientOfUserId(event.GetInt("attacker"));
if(victim > 0 && GetClientTeam(victim) == 2) { //victim is a survivor
static char victimName[32], attackerName[32];
if(IsFakeClient(victim)) GetClientName(victim, victimName, sizeof(victimName));
else GetClientAuthId(victim, AuthId_Steam2, victimName, sizeof(victimName));
if(attacker > 0) {
if(IsFakeClient(attacker)) GetClientName(attacker, attackerName, sizeof(attackerName));
else GetClientAuthId(attacker, AuthId_Steam2, attackerName, sizeof(attackerName));
AddLogCustom("STATE", attackerName, victimName, "\"%L\" killed \"%L\"", attacker, victim);
} else {
AddLogCustom("STATE", "", victimName, "\"%L\" died", victim);
}
}
}
//Jackz was incapped by Jockey
//Jackz was incapped (by world/zombie)
//Jackz was incapped by Disgruntled Pea
//Ellis was incapped [by ...]
public void Event_L4D2_Incapped(Event event, const char[] name, bool dontBroadcast) {
int victim = GetClientOfUserId(event.GetInt("userid"));
int attacker = GetClientOfUserId(event.GetInt("attacker"));
if(victim > 0 && GetClientTeam(victim) == 2) {
static char victimName[32], attackerName[32];
if(IsFakeClient(victim)) GetClientName(victim, victimName, sizeof(victimName));
else GetClientAuthId(victim, AuthId_Steam2, victimName, sizeof(victimName));
if(attacker > 0) {
if(IsFakeClient(attacker)) GetClientName(attacker, attackerName, sizeof(attackerName));
else GetClientAuthId(attacker, AuthId_Steam2, attackerName, sizeof(attackerName));
AddLogCustom("STATE", attackerName, victimName, "\"%L\" incapped \"%L\"", attacker, victim);
} else {
AddLogCustom("STATE", "", victimName, "\"%L\" was incapped", victim);
}
}
}
void AddLog(const char[] type, const char[] clientName, const char[] targetName, const char[] message) {
if(StrEqual(clientName, "Bot")) return;
Log log;
strcopy(log.name, sizeof(log.name), type);
strcopy(log.clientSteamID, sizeof(log.clientSteamID), clientName);
strcopy(log.targetSteamID, sizeof(log.targetSteamID), targetName);
strcopy(log.message, sizeof(log.message), message);
log.timestamp = GetTime();
logs.PushArray(log);
}
void AddLogCustom(const char[] type, const char[] clientName, const char[] targetName, const char[] format, any ...) {
static char message[254];
if(StrEqual(clientName, "Bot")) return;
VFormat(message, sizeof(message), format, 5);
AddLog(type, clientName, targetName, message);
}
public any Native_AddLog(Handle plugin, int numParams) {
char type[32], clientName[32], targetName[32], message[256];
if(GetNativeString(1, type, sizeof(type)) != SP_ERROR_NONE) return false;
if(GetNativeString(2, clientName, sizeof(clientName)) != SP_ERROR_NONE) return false;
if(GetNativeString(3, targetName, sizeof(targetName)) != SP_ERROR_NONE) return false;
if(GetNativeString(4, message, sizeof(message)) != SP_ERROR_NONE) return false;
AddLog(type, clientName, targetName, message);
return true;
}

View file

@ -0,0 +1,6 @@
#if defined _activitymonitor_included_
#endinput
#endif
#define _activitymonitor_included_
native bool AddLog(const char[] type, const char[] clientName, const char[] targetName, const char[] message);

View file

@ -1,5 +1,6 @@
#define MAX_TROLL_NAME_LENGTH 32
#define MAX_TROLL_FLAG_LENGTH 32
#define MAX_TROLLS 28
//#define DEBUG 1
@ -9,47 +10,103 @@ enum trollModifier {
TrollMod_Constant = 2
}
enum struct Troll {
char name[MAX_TROLL_NAME_LENGTH];
char description[128];
bool runsOnce;
int flags;
int categoryID;
char _id[MAX_TROLL_NAME_LENGTH];
void GetID(char[] name) {
strcopy(name, MAX_TROLL_NAME_LENGTH, this.name);
ReplaceString(name, MAX_TROLL_NAME_LENGTH, " ", "", false);
}
bool HasMod(trollModifier mod) {
return ((this.flags >> (view_as<int>(mod)) - 1) & 1) == 1;
}
// 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 == view_as<int>(TrollMod_Instant)) return TrollMod_Instant;
else if(this.flags == view_as<int>(TrollMod_Constant)) return TrollMod_Constant;
else return TrollMod_Invalid;
}
void Activate(int victim, int activator, trollModifier modifier, bool silent = false) {
ApplyTroll(victim, this._id, activator, modifier, silent);
}
enum trollFlag {
Flag_1 = 1,
Flag_2 = 4,
Flag_3 = 8,
Flag_4 = 16,
Flag_5 = 32
}
Troll Trolls[MAX_TROLLS+1];
int ActiveTrolls[MAXPLAYERS+1];
StringMap trollKV;
char trollIds[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH];
enum struct Troll {
int id;
char name[MAX_TROLL_NAME_LENGTH];
char description[128];
int mods;
int enabledFlags;
int categoryID;
int activeFlagClients[MAXPLAYERS+1];
ArrayList flagNames;
bool HasMod(trollModifier mod) {
return ((this.mods >> (view_as<int>(mod)) - 1) & 1) == 1;
}
bool GetFlagName(trollFlag flag, char[] buffer, int maxlength) {
if(this.flagNames == null) return false;
this.flagNames.GetString(view_as<int>(flag), buffer, maxlength);
return true;
}
int AddFlag(const char[] name) {
if(this.flagNames == null) this.flagNames = new ArrayList(MAX_TROLL_FLAG_LENGTH);
int index = this.flagNames.PushString(name);
index = RoundFloat(Pow(2.0, float(index)));
this.enabledFlags |= index;
return index;
}
bool HasFlags() {
return this.enabledFlags > 0 && this.flagNames != null;
}
// 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.mods == view_as<int>(TrollMod_Instant)) return TrollMod_Instant;
else if(this.mods == view_as<int>(TrollMod_Constant)) return TrollMod_Constant;
else return TrollMod_Invalid;
}
bool IsFlagActive(int client, trollFlag flag) {
if(ActiveTrolls[client] > 0 && IsTrollActive(client, this.name) && this.enabledFlags > 0 && this.activeFlagClients[client] >= 0) {
return ((this.activeFlagClients[client] >> view_as<int>(flag)) & 1) == 1;
}
return false;
}
bool IsFlagNameActive(int client, const char[] flagName) {
static char buffer[MAX_TROLL_FLAG_LENGTH];
for(int i = 0; i < this.flagNames.Length; i++) {
this.flagNames.GetString(i, buffer, sizeof(buffer));
if(StrEqual(buffer, flagName, false)) return this.IsFlagActive(client, view_as<trollFlag>(i));
}
return false;
}
void Activate(int client, int activator, trollModifier modifier = TrollMod_Invalid, int flags = 0) {
if(modifier == TrollMod_Invalid) modifier = this.GetDefaultMod();
ApplyTroll(client, this.name, activator, modifier, false, flags);
}
void Toggle(int client, int flags) {
ToggleTroll(client, this.name, flags);
}
void Enable(int client, int flags) {
EnableTroll(client, this.name, flags);
}
void Disable(int client) {
DisableTroll(client, this.name);
}
}
Troll Trolls[MAX_TROLLS+1];
void ResetClient(int victim, bool wipe = true) {
if(wipe) ActiveTrolls[victim] = 0;
if(wipe) {
ActiveTrolls[victim] = 0;
}
SetEntityGravity(victim, 1.0);
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
SDKUnhook(victim, SDKHook_WeaponCanUse, Event_ItemPickup);
@ -57,24 +114,24 @@ void ResetClient(int victim, bool wipe = true) {
if(wpn > -1)
SDKUnhook(wpn, SDKHook_Reload, Event_WeaponReload);
}
ArrayList categories;
static int categoryID = 0;
int SetupTroll(const char[] name, const char description[128], int flags) {
if(flags == 0) {
static int categoryID = -1;
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;
Trolls[i].id = i;
strcopy(Trolls[i].name, MAX_TROLL_NAME_LENGTH, name);
strcopy(Trolls[i].description, 128, description);
Trolls[i].categoryID = categoryID;
Trolls[i].flags = flags;
static char key[MAX_TROLL_NAME_LENGTH];
strcopy(key, MAX_TROLL_NAME_LENGTH, name);
ReplaceString(key, MAX_TROLL_NAME_LENGTH, " ", "", false);
strcopy(trollIds[i], MAX_TROLL_NAME_LENGTH, key);
strcopy(Trolls[i]._id, MAX_TROLL_NAME_LENGTH, key);
trollKV.SetValue(key, i);
Trolls[i].mods = mods;
strcopy(trollIds[i], MAX_TROLL_NAME_LENGTH, name);
trollKV.SetValue(name, i);
return i++;
}
// Gets the Troll enum struct via name
@ -87,6 +144,13 @@ int GetTroll(const char[] name, Troll troll) {
}
return -1;
}
int GetTrollIndex(const char[] name) {
static int i = 0;
if(trollKV.GetValue(name, i)) {
return i;
}
return -1;
}
// Gets the Troll enum struct via key index
// Returns index of troll enum
int GetTrollByKeyIndex(int index, Troll troll) {
@ -102,70 +166,86 @@ bool GetTrollID(int index, char name[MAX_TROLL_NAME_LENGTH]) {
return true;
}
void ToggleTroll(int client, const char[] name) {
void ToggleTroll(int client, const char[] name, int flags = 0) {
static Troll troll;
int index = GetTroll(name, troll);
ActiveTrolls[client] ^= 1 << view_as<int>(index);
troll.activeFlagClients[client] = flags;
}
void ApplyTroll(int victim, const char[] name, int activator, trollModifier modifier, bool silent = false) {
void ApplyTroll(int victim, const char[] name, int activator, trollModifier modifier, bool silent = false, int flags = 0) {
static Troll troll;
int trollIndex = GetTroll(name, troll);
if(trollIndex == -1) {
PrintToServer("[FTT] %N attempted to apply unknown troll: %s", activator, name);
return;
}
if(GetClientTeam(victim) == 1) {
//Victim is spectating, find its bot
victim = FindIdlePlayerBot(victim);
}
if(!ApplyAffect(victim, name, activator, modifier)) {
if(!ApplyAffect(victim, troll, activator, modifier, flags)) {
return;
}
if(!silent) {
if(IsTrollActive(victim, name)) {
ShowActivity(activator, "deactivated troll \"%s\" on %N. ", troll.name, victim);
if(IsTrollActive(victim, troll.name)) {
ShowActivityEx(activator, "[FTT] ", "deactivated troll \"%s\" on %N. ", troll.name, victim);
LogAction(activator, victim, "\"%L\" deactivated troll \"%s\" on \"%L\"", activator, troll.name, victim);
} else {
if(modifier == TrollMod_Constant)
ShowActivity(activator, "activated constant troll \"%s\" for %N. ", troll.name, victim);
else
ShowActivity(activator, "activated troll \"%s\" for %N. ", troll.name, victim);
if(modifier == TrollMod_Constant) {
ShowActivityEx(activator, "[FTT] ", "activated constant troll \"%s\" for %N. ", troll.name, victim);
} else {
ShowActivityEx(activator, "[FTT] ", "activated troll \"%s\" for %N. ", troll.name, victim);
}
LogAction(activator, victim, "\"%L\" activated troll \"%s\" for \"%L\"", activator, troll.name, victim);
}
}
if(modifier == TrollMod_Constant) {
ActiveTrolls[victim] ^= 1 << trollIndex;
}
troll.activeFlagClients[victim] = flags;
}
bool ApplyAffect(int victim, const char[] name, int activator, trollModifier modifier) {
if(StrEqual(name, "ResetTroll")) {
ShowActivity(activator, "reset troll effects for %N. ", victim);
bool ApplyAffect(int victim, Troll troll, int activator, trollModifier modifier, int flags) {
bool isActive = IsTrollActiveByRawID(victim, troll.id);
if(StrEqual(troll.name, "Reset User")) {
LogAction(activator, victim, "\"%L\" reset all troll effects for \"%L\"", activator, victim);
ShowActivityEx(activator, "[FTT] ", "reset troll effects for %N. ", victim);
ActiveTrolls[victim] = 0;
troll.activeFlagClients[victim] = 0;
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
SetEntityGravity(victim, 1.0);
return false;
} else if(StrEqual(name, "SlowSpeed"))
} else if(StrEqual(troll.name, "Slow Speed"))
if(isActive)
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
else
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 0.8);
else if(StrEqual(name, "HigherGravity"))
else if(StrEqual(troll.name, "Higher Gravity"))
if(isActive)
SetEntityGravity(victim, 1.0);
else
SetEntityGravity(victim, 1.3);
else if(StrEqual(name, "HalfPrimaryAmmo")) {
else if(StrEqual(troll.name, "Half Primary Ammo")) {
int current = GetPrimaryReserveAmmo(victim);
SetPrimaryReserveAmmo(victim, current / 2);
} else if(StrEqual(name, "UziRules")) {
DisableTroll(victim, "NoPickup");
DisableTroll(victim, "PrimaryDisable");
} else if(StrEqual(troll.name, "UziRules")) {
DisableTroll(victim, "No Pickup");
DisableTroll(victim, "Primary Disable");
SDKHook(victim, SDKHook_WeaponCanUse, Event_ItemPickup);
} else if(StrEqual(name, "PrimaryDisable")) {
} else if(StrEqual(troll.name, "Primary Disable")) {
DisableTroll(victim, "UziRules");
DisableTroll(victim, "NoPickup");
DisableTroll(victim, "No Pickup");
SDKHook(victim, SDKHook_WeaponCanUse, Event_ItemPickup);
} else if(StrEqual(name, "NoPickup")) {
} else if(StrEqual(troll.name, "No Pickup")) {
DisableTroll(victim, "UziRules");
DisableTroll(victim, "PrimaryDisable");
DisableTroll(victim, "Primary Disable");
SDKHook(victim, SDKHook_WeaponCanUse, Event_ItemPickup);
} else if(StrEqual(name, "CameTooEarly")) {
} else if(StrEqual(troll.name, "CameTooEarly")) {
ReplyToCommand(activator, "This troll mode is not implemented.");
} else if(StrEqual(name, "KillMeSoftly")) {
} else if(StrEqual(troll.name, "KillMeSoftly")) {
static char wpn[32];
GetClientWeaponName(victim, 4, wpn, sizeof(wpn));
if(StrEqual(wpn, "weapon_adrenaline") || StrEqual(wpn, "weapon_pain_pills")) {
@ -177,44 +257,43 @@ bool ApplyAffect(int victim, const char[] name, int activator, trollModifier mod
}
//TODO: Implement TrollMod_Constant
return false;
} else if(StrEqual(name, "ThrowItAll")) {
} else if(StrEqual(troll.name, "Throw It All")) {
if(modifier == TrollMod_Instant)
ThrowAllItems(victim);
if(hThrowTimer == INVALID_HANDLE && modifier == TrollMod_Constant) {
hThrowTimer = CreateTimer(hThrowItemInterval.FloatValue, Timer_ThrowTimer, _, TIMER_REPEAT);
}
} else if(StrEqual(name, "Swarm")) {
} else if(StrEqual(troll.name, "Swarm")) {
if(modifier == TrollMod_Instant) {
L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", victim, 15000);
}else if(modifier == TrollMod_Constant) {
}else{
ReplyToCommand(activator, "Invalid modifier for mode.");
return false;
}
} else if(StrEqual(name, "GunJam")) {
return true;
} else if(StrEqual(troll.name, "Gun Jam")) {
int wpn = GetClientWeaponEntIndex(victim, 0);
if(wpn > -1)
SDKHook(wpn, SDKHook_Reload, Event_WeaponReload);
else
else {
ReplyToCommand(activator, "Victim does not have a primary weapon.");
} else if(StrEqual(name, "VomitPlayer"))
return false;
}
} else if(StrEqual(troll.name, "Vomit Player"))
L4D_CTerrorPlayer_OnVomitedUpon(victim, victim);
else if(StrEqual(name, "InfaceSpecial")) {
else if(StrEqual(troll.name, "Inface Special")) {
FakeClientCommand(victim, "sm_inface");
return false;
} else if(StrEqual(name, "InstaSpecial")) {
} else if(StrEqual(troll.name, "Insta Special")) {
FakeClientCommand(victim, "sm_insta");
return false;
} else {
#if defined DEBUG
PrintToServer("[FTT] Possibly invalid troll, no action: %s", name);
PrintToServer("[FTT] Possibly invalid troll, no action: %s", troll.name);
ReplyToCommand(activator, "[FTT/Debug] If nothing occurs, this troll possibly was not implemented correctly. ");
#endif
}
return true;
}
bool IsTrollActive(int client, const char[] troll) {
if(ActiveTrolls[client] == 0) return false;
static int i = 0;
@ -225,9 +304,15 @@ bool IsTrollActive(int client, const char[] troll) {
return false; //errors instead but compiler no like
}
void EnableTroll(int client, const char[] troll) {
bool IsTrollActiveByRawID(int client, int id) {
if(ActiveTrolls[client] == 0) return false;
return ((ActiveTrolls[client] >> id) & 1) == 1;
}
void EnableTroll(int client, const char[] troll, int flags = 0) {
if(!IsTrollActive(client, troll)) {
ToggleTroll(client, troll);
ToggleTroll(client, troll, flags);
}
}
@ -243,47 +328,3 @@ void SetCategory(const char[] newCat) {
void GetCategory(int category, char[] buffer, int size) {
categories.GetString(category, buffer, size);
}
void SetupTrolls() {
trollKV = new StringMap();
categories = new ArrayList(ByteCountToCells(16));
SetupTroll("Reset Troll", "Resets the user, removes all troll effects", TrollMod_Instant);
SetCategory("Magnet / Horde");
SetupTroll("Special Magnet", "Attracts ALL specials to any alive target with this troll enabled", TrollMod_Constant);
SetupTroll("Tank Magnet", "Attracts ALL tanks to any alive target with this troll enabled", TrollMod_Constant);
SetupTroll("Witch Magnet", "All witches when startled will target any player with this troll", TrollMod_Constant);
SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", TrollMod_Instant | TrollMod_Constant);
SetupTroll("Vomit Player", "Shortcut to sm_vomitplayer. vomits the player.", TrollMod_Instant);
SetupTroll("Inface Special", "Shortcut to sm_inface", TrollMod_Instant);
SetupTroll("Insta Special", "Shortcut to sm_insta", TrollMod_Instant);
SetCategory("Items");
SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant);
SetupTroll("Bad Throw", "Player drops throwables on throw, and biles/molotovs themselves", TrollMod_Constant);
SetupTroll("No Pickup", "Prevents a player from picking up ANY (new) item. Use ThrowItAll to make them drop", TrollMod_Constant);
SetupTroll("UziRules", "Picking up a weapon gives them a UZI instead", TrollMod_Constant);
SetupTroll("Primary Disable", "Player cannot pickup any weapons, only melee/pistols", TrollMod_Constant);
SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", TrollMod_Instant);
SetCategory("Chat");
SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", TrollMod_Instant);
SetupTroll("No Profanity", "Replaces some words with random phrases", TrollMod_Constant);
SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant);
SetupTroll("Honk", "Honk", TrollMod_Constant);
SetupTroll("Meow", "Makes the player meow", TrollMod_Constant);
SetCategory("Health");
SetupTroll("Damage Boost", "Makes a player take more damage than normal", TrollMod_Constant);
SetupTroll("Temp Health Quick Drain", "Makes a player's temporarily health drain very quickly", TrollMod_Constant);
SetupTroll("Slow Drain", "Will make the player slowly lose health over time", TrollMod_Constant);
SetupTroll("KillMeSoftly", "Make player eat or waste pills whenever possible", TrollMod_Instant | TrollMod_Constant);
SetCategory("Misc");
SetupTroll("Gun Jam", "On reload, small chance their gun gets jammed - Can't reload.", TrollMod_Constant);
SetupTroll("Slow Speed", "Sets player speed to 0.8x of normal speed", TrollMod_Constant);
SetupTroll("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", TrollMod_Constant);
SetupTroll("No Shove", "Prevents a player from shoving", TrollMod_Constant);
SetupTroll("CameTooEarly", "When they shoot, random chance they empty whole clip", TrollMod_Constant);
//INFO: UP MAX_TROLLS when adding new trolls!
}

View file

@ -41,15 +41,22 @@ public Action Command_InstaSpecial(int client, int args) {
ReplyToCommand(client, "Unknown special \"%s\"", arg2);
return Plugin_Handled;
}
int successes = 0;
for (int i = 0; i < target_count; i++) {
int target = target_list[i];
if(GetClientTeam(target) == 2) {
SpawnSpecialNear(target, specialType);
if(SpawnSpecialNear(target, specialType)) {
LogAction(client, target, "\"%L\" spawned Insta-%s™ nearby \"%L\"", client, arg2, target);
successes++;
} else {
ReplyToCommand(client, "[FTT] Could not spawn %s near %s", arg2, target_name);
}
}else{
ReplyToTargetError(client, target_count);
}
}
ShowActivity(client, "spawned Insta-%s™ near %s", arg2, target_name);
if(successes > 0)
ShowActivityEx(client, "[FTT] ", "spawned Insta-%s™ near %s", arg2, target_name);
}
@ -99,15 +106,22 @@ public Action Command_InstaSpecialFace(int client, int args) {
ReplyToCommand(client, "Unknown special \"%s\"", arg2);
return Plugin_Handled;
}
int successes = 0;
for (int i = 0; i < target_count; i++) {
int target = target_list[i];
if(GetClientTeam(target) == 2) {
SpawnSpecialInFace(target, specialType);
if(SpawnSpecialInFace(target, specialType)) {
LogAction(client, target, "\"%L\" spawned Insta-%s™ at player \"%L\"", client, arg2, target);
successes++;
} else {
ReplyToCommand(client, "[FTT] Could not spawn %s on %s", arg2, target_name);
}
}else{
ReplyToTargetError(client, target_count);
}
}
ShowActivity(client, "spawned Insta-%s™ on %s", arg2, target_name);
if(successes > 0)
ShowActivityEx(client, "[FTT] ", "spawned Insta-%s™ on %s", arg2, target_name);
}
return Plugin_Handled;
}
@ -143,7 +157,8 @@ public Action Command_WitchAttack(int client, int args) {
while ((witch = FindEntityByClassname(witch, "witch")) != INVALID_ENT_REFERENCE) {
SetWitchTarget(witch, target);
ShowActivity(client, "all witches target %s", target_name);
ShowActivityEx(client, "[FTT] ", "set all witches to target %s", target_name);
LogAction(client, target, "\"%L\" set all witches to attack \"%L\"", client, target);
}
}else{
ReplyToTargetError(client, target_count);
@ -157,7 +172,8 @@ 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);
LogAction(client, lastCrescendoUser, "\"%L\" autopunished crescendo rusher \"%L\"", client, lastCrescendoUser);
ShowActivityEx(client, "[FTT] ", "activated autopunish for crescendo activator %N",lastCrescendoUser);
}else{
ReplyToCommand(client, "No player could be found to autopunish.");
}
@ -191,7 +207,8 @@ public Action Command_ResetUser(int client, int args) {
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]);
LogAction(client, target_list[i], "\"%L\" reset all troll effects for \"%L\"", client, target_list[i]);
ShowActivityEx(client, "[FTT] ", "reset troll effects for \"%N\". ", target_list[i]);
}
}
}
@ -199,52 +216,30 @@ public Action Command_ResetUser(int client, int args) {
}
public Action Command_ApplyUser(int client, int args) {
if(args < 2) {
Menu menu = new Menu(ChoosePlayerHandler);
menu.SetTitle("Choose a player to troll");
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
static char userid[8], display[16];
Format(userid, sizeof(userid), "%d", GetClientUserId(i));
GetClientName(i, display, sizeof(display));
menu.AddItem(userid, display);
}
}
menu.ExitButton = true;
menu.Display(client, 0);
if(args < 1) {
ShowTrollMenu(client);
}else{
char arg1[32], arg2[32], arg3[8];
char arg1[32];
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;
static char target_name[MAX_TARGET_LENGTH];
int target_list[1], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MAXPLAYERS,
0,
1,
COMMAND_FILTER_NO_MULTI,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
) {
&& target_list[0] > 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);
}
}
SetupCategoryMenu(client, target_list[0]);
}
return Plugin_Handled;
}
@ -272,9 +267,8 @@ public Action Command_ListTheTrolls(int client, int args) {
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);
if(trollIds[j][0] != '\0' && IsTrollActive(i, trollIds[j])) {
strcopy(modeListArr[modeCount], MAX_TROLL_NAME_LENGTH, trollIds[j]);
modeCount++;
}
}

View file

@ -43,7 +43,7 @@ public Action Event_PlayerDeath(Event event, const char[] name, bool dontBroadca
}
public Action Event_WeaponReload(int weapon) {
int client = GetEntPropEnt(weapon, Prop_Send, "m_hOwner");
if(IsTrollActive(client, "GunJam")) {
if(IsTrollActive(client, "Gun Jam")) {
float dec = GetRandomFloat(0.0, 1.0);
if(FloatCompare(dec, 0.50) == -1) { //10% chance gun jams
return Plugin_Stop;
@ -101,7 +101,7 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
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"))) {
if(class == L4D2Infected_Tank && IsTrollActive(i, "Tank Magnet") || (class != L4D2Infected_Tank && IsTrollActive(i, "Special Magnet"))) {
GetClientAbsOrigin(i, survPos);
float dist = GetVectorDistance(survPos, spPos, true);
if(closestClient == -1 || dist < closestDistance) {
@ -120,7 +120,7 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
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()) {
if(client > 0 && client <= MaxClients && IsTrollActive(client, "No Shove") && hShoveFailChance.FloatValue > GetRandomFloat()) {
return Plugin_Handled;
}
return Plugin_Continue;
@ -214,7 +214,7 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
PrintToServer("%N: %s", client, sArgs);
CPrintToChatAll("{blue}%N {default}: %s", client, newMessage);
return Plugin_Handled;
}else if(IsTrollActive(client, "NoProfanity")) {
}else if(IsTrollActive(client, "No Profanity")) {
static char strings[32][MAX_PHRASE_LENGTH];
ArrayList phrases;
bool foundWord = false;
@ -224,8 +224,7 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
phrases = GetPhrasesArray(strings[i]);
if(phrases != null && phrases.Length > 0) {
foundWord = true;
int c = phrases.GetString(GetRandomInt(0, phrases.Length - 1), strings[i], MAX_PHRASE_LENGTH);
PrintToServer("replacement: %s (%d)", strings[i], c);
phrases.GetString(GetRandomInt(0, phrases.Length - 1), strings[i], MAX_PHRASE_LENGTH);
}
}
int length = MAX_PHRASE_LENGTH * words;
@ -233,8 +232,11 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
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);
if(!fullMessagePhraseList) {
PrintToServer("[FTT] Error: Could not find full message phrases!!!");
return Plugin_Continue;
}
fullMessagePhraseList.GetString(GetRandomInt(0, fullMessagePhraseList.Length - 1), message, MAX_PHRASE_LENGTH);
}
CPrintToChatAll("{blue}%N {default}: %s", client, message);
PrintToServer("%N: %s", client, sArgs);
@ -244,7 +246,7 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
}
public Action Event_ItemPickup(int client, int weapon) {
if(IsTrollActive(client, "NoPickup")) {
if(IsTrollActive(client, "No Pickup")) {
return Plugin_Stop;
}else{
static char wpnName[64];
@ -270,7 +272,7 @@ public Action Event_ItemPickup(int client, int weapon) {
SetCommandFlags("give", flags);
return Plugin_Stop;
}
}else if(IsTrollActive(client, "PrimaryDisable")) {
}else if(IsTrollActive(client, "Primary Disable")) {
return Plugin_Stop;
}
return Plugin_Continue;
@ -290,6 +292,34 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
}
return Plugin_Continue;
}
static int invertedTrollIndex;
if(invertedTrollIndex <= 0) {
invertedTrollIndex = GetTrollIndex("Inverted Controls");
}
if(IsTrollActiveByRawID(client, invertedTrollIndex)) {
if(buttons & IN_MOVELEFT || buttons & IN_MOVERIGHT) {
vel[1] = -vel[1];
}
if(buttons & IN_FORWARD || buttons & IN_BACK) {
vel[0] = -vel[0];
}
if(buttons & IN_JUMP) {
buttons = buttons & ~IN_JUMP | IN_DUCK;
} else if(buttons & IN_DUCK) {
buttons = buttons & ~IN_DUCK | IN_JUMP;
}
if(buttons & IN_RUN) {
buttons = buttons & ~IN_RUN | IN_WALK;
} else if(buttons & IN_WALK) {
buttons = buttons & ~IN_WALK | IN_RUN;
}
if(buttons & IN_RELOAD) {
buttons = buttons & ~IN_RELOAD | IN_ATTACK2;
} else if(buttons & IN_ATTACK2) {
buttons = buttons & ~IN_ATTACK2 | IN_RELOAD;
}
return Plugin_Changed;
}
return Plugin_Continue;
}
@ -300,7 +330,7 @@ public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float&
return Plugin_Stop;
}
if(IsTrollActive(attacker, "DamageBoost")) {
if(IsTrollActive(attacker, "Damage Boost")) {
damage * 2;
return Plugin_Changed;
}
@ -318,7 +348,8 @@ public Action SoundHook(int[] clients, int& numClients, char sample[PLATFORM_MAX
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);
ShowActivityEx(0, "[FTT] ", "activated autopunish for crescendo activator %N (auto)", lastButtonUser);
LogAction(0, lastButtonUser, "\"%L\" automatic autopunish for crescendo activator \"%L\"", 0, lastButtonUser);
ActivateAutoPunish(lastButtonUser);
}
lastButtonUser = -1;
@ -327,7 +358,7 @@ public Action SoundHook(int[] clients, int& numClients, char sample[PLATFORM_MAX
if(IsTrollActive(entity, "Honk")) {
strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav");
return Plugin_Changed;
} else if(IsTrollActive(entity, "VocalizeGag")) {
} else if(IsTrollActive(entity, "Vocalize Gag")) {
return Plugin_Handled;
} else if(IsTrollActive(entity, "Meow")) {
strcopy(sample, sizeof(sample), "custom/meow1.mp3");
@ -351,7 +382,7 @@ public Action Event_WitchVictimSet(Event event, const char[] name, bool dontBroa
continue;
}
if(IsTrollActive(i, "WitchMagnet")) {
if(IsTrollActive(i, "Witch Magnet")) {
GetClientAbsOrigin(i, survPos);
float dist = GetVectorDistance(survPos, witchPos, true);
if(closestClient == -1 || dist < closestDistance) {
@ -384,7 +415,8 @@ void EntityCreateCallback(int entity) {
GetEntityClassname(entity, class, sizeof(class));
int entOwner = GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity");
if(entOwner > 0 && entOwner <= MaxClients && IsTrollActive(entOwner, "BadThrow")) {
if(entOwner > 0 && entOwner <= MaxClients) {
if(IsTrollActive(entOwner, "Bad Throw")) {
static float pos[3];
GetClientEyePosition(entOwner, pos);
if(StrContains(class, "vomitjar", true) > -1) {
@ -415,4 +447,17 @@ void EntityCreateCallback(int entity) {
SpawnItem("pipe_bomb", pos);
}
}
}
}
int FindClosestVisibleClient(int source) {
static float pos[3], ang[3];
GetClientEyePosition(source, pos);
GetClientEyeAngles(source, ang);
Handle handle = TR_TraceRayFilterEx(pos, ang, MASK_VISIBLE, RayType_Infinite, TraceEntityFilterPlayer, source);
return TR_GetEntityIndex(handle);
}
public bool TraceEntityFilterPlayer(int entity, int mask, any data) {
return data != entity && entity <= MaxClients && GetClientTeam(entity) == 2 && IsPlayerAlive(entity);
}

View file

@ -12,7 +12,7 @@ public int Insta_PlayerHandler(Menu menu, MenuAction action, int client, int par
Menu spMenu = new Menu(Insta_SpecialHandler);
spMenu.SetTitle("Choose a Insta-Special™");
for(int i = 1; i <= 6; i++) {
for(int i = 1; i <= 8; i++) {
Format(info, sizeof(info), "%d|%d|%d", userid, instaMode, i);
spMenu.AddItem(info, SPECIAL_NAMES[i-1]);
}
@ -33,11 +33,19 @@ public int Insta_SpecialHandler(Menu menu, MenuAction action, int client, int pa
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);
if(SpawnSpecialInFace(target, special)) {
LogAction(client, target, "\"%L\" spawned Insta-%s™ on \"%L\"", client, SPECIAL_NAMES[special-1], target);
ShowActivityEx(client, "[FTT] ", "spawned Insta-%s™ on %N", SPECIAL_NAMES[special-1], target);
} else {
SpawnSpecialNear(target, special);
ShowActivity(client, "spawned Insta-%s™ near %N", SPECIAL_NAMES[special-1], target);
ReplyToCommand(client, "Could not spawn special.");
}
} else {
if(SpawnSpecialNear(target, special)) {
LogAction(client, target, "\"%L\" spawned Insta-%s™ near \"%L\"", client, SPECIAL_NAMES[special-1], target);
ShowActivityEx(client, "[FTT] ", "spawned Insta-%s™ near %N", SPECIAL_NAMES[special-1], target);
} else {
ReplyToCommand(client, "Could not spawn special.");
}
}
} else if (action == MenuAction_End)
delete menu;
@ -66,25 +74,31 @@ public int ChoosePlayerHandler(Menu menu, MenuAction action, int param1, int par
delete menu;
}
static int iMenuVictimID[MAXPLAYERS+1];
public int ChooseCategoryHandler(Menu menu, MenuAction action, int param1, int param2) {
if (action == MenuAction_Select) {
if (action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
ShowTrollMenu(param1);
else if (action == MenuAction_Select) {
static char info[32];
menu.GetItem(param2, info, sizeof(info));
static char str[2][8];
ExplodeString(info, "|", str, 2, 8, false);
int userid = StringToInt(str[0]);
iMenuVictimID[param1] = userid;
int category = StringToInt(str[1]);
// Reset troll:
if(category == -1) {
ApplyTroll(GetClientOfUserId(userid), "Reset User", param1, TrollMod_Instant);
return;
}
Menu trollMenu = new Menu(ChooseModeMenuHandler);
GetCategory(category, info, sizeof(info));
Format(info, sizeof(info), "Category: %s", info);
trollMenu.SetTitle(info);
//TODO: Update
static Troll troll;
// add 'return' btn
Format(info, sizeof(info), "%d|-1", userid);
trollMenu.AddItem(info, "<= Go Back");
static Troll troll;
// Add all menus that have same category
for(int i = 0; i < trollKV.Size; i++) {
@ -95,30 +109,32 @@ public int ChooseCategoryHandler(Menu menu, MenuAction action, int param1, int p
}
}
trollMenu.ExitButton = true;
trollMenu.ExitBackButton = true;
trollMenu.Display(param1, 0);
} else if (action == MenuAction_End)
delete menu;
}
public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int param2) {
if (action == MenuAction_Select) {
static char info[16];
if (action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
if(iMenuVictimID[param1] == 0) {
ReplyToCommand(param1, "FTT: Could not acquire player");
}
SetupCategoryMenu(param1, iMenuVictimID[param1]);
}
} else if (action == MenuAction_Select) {
static char info[32];
menu.GetItem(param2, info, sizeof(info));
static char str[2][8];
ExplodeString(info, "|", str, 2, 8, false);
int userid = StringToInt(str[0]);
int client = GetClientOfUserId(userid);
int keyIndex = StringToInt(str[1]);
if(keyIndex == -1) {
SetupCategoryMenu(param1, userid);
return;
}
static Troll troll;
static char trollID[MAX_TROLL_NAME_LENGTH];
GetTrollByKeyIndex(keyIndex, troll);
troll.GetID(trollID);
//If troll has multiple flags, prompt:
if(StrEqual(trollID, "ThrowItAll")) {
if(StrEqual(troll.name, "Throw It All")) {
// Setup menu to call itself, but with an extra data point
Menu itmMenu = new Menu(ChooseClumsySlotHandler);
itmMenu.SetTitle("Choose Item To Throw");
@ -138,10 +154,11 @@ public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int p
itmMenu.Display(param1, 0);
} else if(troll.HasMod(TrollMod_Instant) && troll.HasMod(TrollMod_Constant)) {
Menu modiferMenu = new Menu(ChooseTrollModiferHandler);
modiferMenu.SetTitle("Choose Troll Modifer Option");
Format(info, sizeof(info), "%s: Choose Modifier", troll.name);
modiferMenu.SetTitle(info);
Format(info, sizeof(info), "%d|%d|1", userid, keyIndex);
modiferMenu.AddItem(info, "Activate once");
modiferMenu.AddItem(info, "Activate Once");
Format(info, sizeof(info), "%d|%d|2", userid, keyIndex);
modiferMenu.AddItem(info, "Activate Periodically");
Format(info, sizeof(info), "%d|%d|3", userid, keyIndex);
@ -150,7 +167,7 @@ public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int p
modiferMenu.ExitButton = true;
modiferMenu.Display(param1, 0);
} else {
ApplyTroll(client, trollID, param1, troll.GetDefaultMod());
troll.Activate(client, param1);
}
} else if (action == MenuAction_End)
delete menu;
@ -164,15 +181,19 @@ public int ChooseClumsySlotHandler(Menu menu, MenuAction action, int param1, int
ExplodeString(info, "|", str, 2, 8, false);
int client = GetClientOfUserId(StringToInt(str[0]));
int slot = StringToInt(str[1]);
PrintToChatAll("%d", slot);
if(slot == -1) {
if(client == 0) {
ReplyToCommand(param1, "FTT: Could not acquire player");
return;
}else if(slot == -1) {
for(int i = 0; i <= 4; i++) {
ThrowItemToClosestPlayer(client, i);
}
} else {
ThrowItemToClosestPlayer(client, slot);
}
ShowActivity(param1, "activated troll \"Throw It All\" for %N. ", client);
LogAction(param1, client, "\"%L\" activated troll \"Throw It all\" for \"%L\"", param1, client);
ShowActivityEx(param1, "[FTT] ", "activated troll \"Throw It All\" for %N. ", client);
} else if (action == MenuAction_End)
delete menu;
}
@ -187,15 +208,18 @@ public int ChooseTrollModiferHandler(Menu menu, MenuAction action, int param1, i
int keyIndex = StringToInt(str[1]);
int flags = StringToInt(str[2]);
if(client == 0) {
ReplyToCommand(param1, "FTT: Could not acquire player");
return;
}
static Troll troll;
GetTrollByKeyIndex(keyIndex, troll);
if(flags == 1 || flags == 3)
troll.Activate(client, param1, TrollMod_Instant);
// ApplyTroll(client, trollID, param1, TrollMod_Instant);
if(flags == 2 || flags == 3)
troll.Activate(client, param1, TrollMod_Constant);
// ApplyTroll(client, trollID, param1, TrollMod_Constant);
} else if (action == MenuAction_End)
delete menu;
}
@ -206,13 +230,37 @@ public void StopItemGive(int client) {
void SetupCategoryMenu(int client, int victimUserID) {
Menu categoryMenu = new Menu(ChooseCategoryHandler);
categoryMenu.SetTitle("Choose a troll category");
static char category[16], id[8];
static char category[64], id[8];
Format(category, sizeof(category), "%N: Choose troll category", GetClientOfUserId(victimUserID));
categoryMenu.SetTitle(category);
Format(id, sizeof(id), "%d|-1", victimUserID);
categoryMenu.AddItem(id, "Reset User");
for(int i = 0; i < categories.Length; i++) {
categories.GetString(i, category, sizeof(category));
Format(id, sizeof(id), "%d|%d", victimUserID, i);
categoryMenu.AddItem(id, category);
}
categoryMenu.ExitButton = true;
categoryMenu.ExitBackButton = true;
categoryMenu.Display(client, 0);
}
void ShowTrollMenu(int client) {
Menu menu = new Menu(ChoosePlayerHandler);
menu.SetTitle("Choose a player to troll");
static char userid[8], display[32];
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
IntToString(GetClientUserId(i), userid, sizeof(userid));
int specClient = GetSpectatorClient(i);
if(specClient > 0)
Format(display, sizeof(display), "%N (Idle)", specClient);
else
GetClientName(i, display, sizeof(display));
menu.AddItem(userid, display);
}
}
menu.ExitButton = true;
menu.Display(client, 0);
}

View file

@ -1,13 +1,14 @@
#define AUTOPUNISH_FLOW_MIN_DISTANCE 5000.0
#define AUTOPUNISH_MODE_COUNT 3
// #define DEBUG_PHRASE_LOAD 1
void ActivateAutoPunish(int client) {
if(hAutoPunish.IntValue & 2 == 2)
ApplyTroll(lastButtonUser, "SpecialMagnet", 0, TrollMod_Constant);
ApplyTroll(lastButtonUser, "Special Magnet", 0, TrollMod_Constant);
if(hAutoPunish.IntValue & 1 == 1)
ApplyTroll(lastButtonUser, "TankMagnet", 0, TrollMod_Constant);
ApplyTroll(lastButtonUser, "Tank Magnet", 0, TrollMod_Constant);
if(hAutoPunish.IntValue & 8 == 8)
ApplyTroll(lastButtonUser, "VomitPlayer", 0, TrollMod_Instant);
ApplyTroll(lastButtonUser, "Vomit Player", 0, TrollMod_Instant);
else if(hAutoPunish.IntValue & 4 == 4)
ApplyTroll(lastButtonUser, "Swarm", 0, TrollMod_Instant);
if(hAutoPunishExpire.IntValue > 0) {
@ -29,7 +30,8 @@ void SetWitchTarget(int witch, int target) {
bool ToggleMarkPlayer(int client, int target) {
if(g_PendingBanTroll[target]) {
g_PendingBanTroll[target] = false;
ShowActivity(client, "unmarked %N as troll", target);
LogAction(client, target, "\"%L\" unmarked \"%L\" as troll", client, target);
ShowActivityEx(client, "[FTT] ", "unmarked %N as troll", target);
return true;
}else{
AdminId admin_client = GetUserAdmin(client);
@ -41,7 +43,8 @@ bool ToggleMarkPlayer(int client, int target) {
Call_Finish();
g_PendingBanTroll[target] = true;
EnableTroll(target, "NoProfanity");
ShowActivity(client, "marked %N as troll", target);
LogAction(client, target, "\"%L\" marked \"%L\" as troll", client, target);
ShowActivityEx(client, "[FTT] ", "marked %N as troll", target);
return true;
}else{
ReplyToCommand(client, "cannot mark %N as troll as they are an admin.", target);
@ -68,6 +71,7 @@ stock bool IsPlayerIncapped(int client) {
#define MAX_PHRASES_PER_WORD 8
#define MAX_PHRASE_LENGTH 191
StringMap REPLACEMENT_PHRASES;
ArrayList fullMessagePhraseList;
/* Example:
exWord
{
@ -104,6 +108,13 @@ void LoadPhrases() {
phrases.PushString(phrase);
}
i = 0;
if(StrEqual(word, "_full message phrases")) {
fullMessagePhraseList = phrases.Clone();
continue;
}
#if defined DEBUG_PHRASE_LOAD
PrintToServer("Loaded %d phrases for word \"%s\"", phrases.Length, word);
#endif
REPLACEMENT_PHRASES.SetValue(word, phrases.Clone(), true);
} while (kv.GotoNextKey(false));
delete kv;
@ -193,7 +204,6 @@ bool IsAnyPlayerNear(int source, float range) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i) && i != source) {
GetClientAbsOrigin(i, pos2);
float dist = GetVectorDistance(pos1, pos2);
PrintToChatAll("%f <= %f: %b", dist, range, (dist <= range));
if(dist <= range) return true;
}
}
@ -202,7 +212,7 @@ bool IsAnyPlayerNear(int source, float range) {
void ThrowItemToClosestPlayer(int victim, int slot) {
int wpn = GetPlayerWeaponSlot(victim, slot);
if(slot != 1 || DoesClientHaveMelee(victim)) {
if(wpn > 0 && (slot != 1 || DoesClientHaveMelee(victim))) {
static float pos[3];
int clients[4];
GetClientAbsOrigin(victim, pos);
@ -229,3 +239,13 @@ void DropItem(int victim, int slot) {
}
}
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

@ -1,9 +1,9 @@
char SPECIAL_NAMES[][] = {
"Smoker", "Boomer", "Hunter", "Spitter", "Jockey", "Charger", "Witch"
"Smoker", "Boomer", "Hunter", "Spitter", "Jockey", "Charger", "Witch", "Tank"
};
stock int GetSpecialType(const char[] input) {
for(int i = 0; i < sizeof(SPECIAL_NAMES); i++) {
for(int i = 0; i < 8; i++) {
if(strcmp(SPECIAL_NAMES[i], input, false) == 0) return i + 1;
}
return -1;
@ -37,16 +37,18 @@ float GetIdealMinDistance(int specialType) {
}
bool SpawnSpecialInFace(int target, int specialType) {
if(specialType >= sizeof(SPECIAL_NAMES)) return false;
if(specialType > 8) return false;
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
if(specialType != 5 && specialType != 2) { //If not jockey/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);
if(!FindSuitablePosition(target, pos, testPos, minDistance, 100)) {
L4D_GetRandomPZSpawnPosition(target, specialType, 10, testPos);
}
pos = testPos;
} else { // Else spawn a little bit off, and above (above for jockeys)
pos[2] += 10.0;
@ -54,31 +56,49 @@ bool SpawnSpecialInFace(int target, int specialType) {
}
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;
return SpawnSpecialInternal(specialType, target, pos, NULL_VECTOR) > 0;
}
bool SpawnSpecialNear(int target, int specialType) {
if(specialType >= sizeof(SPECIAL_NAMES)) return false;
if(specialType > 8) return false;
static float pos[3];
if(L4D_GetRandomPZSpawnPosition(target, specialType, 10, pos)) {
int special = (specialType == 7) ? L4D2_SpawnWitch(pos, NULL_VECTOR) : L4D2_SpawnSpecial(specialType, pos, NULL_VECTOR);
if(special == -1) return false;
if(specialType == 7)
SetWitchTarget(special, target);
else
g_iAttackerTarget[special] = GetClientUserId(target);
return true;
return SpawnSpecialInternal(specialType, target, pos, NULL_VECTOR) > 0;
}
return false;
}
// doesnt seem to work with l4dhooks methods
void BypassLimit() {
int bot = CreateFakeClient("InfectedBot");
if (bot != 0) {
ChangeClientTeam(bot, 3);
CreateTimer(0.1, Timer_KickBot, bot);
}
}
int SpawnSpecialInternal(int type, int target, float pos[3], float ang[3]) {
if(type <= 6) {
// BypassLimit();
int special = L4D2_SpawnSpecial(type, pos, ang);
if(special != -1)
g_iAttackerTarget[special] = GetClientUserId(target);
return special;
}
else if(type == 7) {
int witch = L4D2_SpawnWitch(pos, ang);
if(witch != -1)
SetWitchTarget(witch, target);
return witch;
}
else if(type == 8) {
// BypassLimit();
int tank = L4D2_SpawnTank(pos, ang);
if(tank <= 0 || !IsClientConnected(tank)) return -1;
if(tank != -1)
g_iAttackerTarget[tank] = GetClientUserId(target);
return tank;
}
else return -1;
}

View file

@ -1,7 +1,8 @@
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")) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && IsTrollActive(i, "Throw It All")) {
ThrowAllItems(i);
count++;
}
@ -13,14 +14,14 @@ 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(IsTrollActive(i, "Slow Drain")) {
if(loop % 4 == 0) {
int hp = GetClientHealth(i);
if(hp > 50) {
SetEntProp(i, Prop_Send, "m_iHealth", hp - 1);
}
}
}else if(IsTrollActive(i, "TempHealthQuickDrain")) {
}else if(IsTrollActive(i, "Temp Health Quick Drain")) {
if(loop % 2 == 0) {
float bufferTime = GetEntPropFloat(i, Prop_Send, "m_healthBufferTime");
float buffer = GetEntPropFloat(i, Prop_Send, "m_healthBuffer");
@ -82,9 +83,9 @@ public Action Timer_ResetAutoPunish(Handle timer, int user) {
int client = GetClientOfUserId(user);
if(client) {
if(hAutoPunish.IntValue & 2 == 2)
DisableTroll(client, "SpecialMagnet");
DisableTroll(client, "Special Magnet");
if(hAutoPunish.IntValue & 1 == 1)
DisableTroll(client, "TankMagnet");
DisableTroll(client, "Tank Magnet");
}
}
@ -94,3 +95,9 @@ public Action Timer_NextWitchSet(Handle timer, DataPack pack) {
int witch = pack.ReadCell();
SetWitchTarget(witch, client);
}
public Action Timer_KickBot(Handle timer, int client) {
if(IsClientInGame(client) && (!IsClientInKickQueue(client))) {
if(IsFakeClient(client)) KickClient(client);
}
}

View file

@ -0,0 +1,48 @@
// UP THE VALUE 'MAX_TROLLS' in base.inc before adding new ones!
void SetupTrolls() {
trollKV = new StringMap();
categories = new ArrayList(ByteCountToCells(16));
SetupTroll("Reset User", "Resets the user, removes all troll effects", TrollMod_Instant);
SetCategory("Magnets");
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);
SetCategory("Infected");
SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", TrollMod_Instant | TrollMod_Constant);
SetupTroll("Vomit Player", "Shortcut to sm_vomitplayer. vomits the player.", TrollMod_Instant);
SetupTroll("Inface Special", "Shortcut to sm_inface", TrollMod_Instant);
SetupTroll("Insta Special", "Shortcut to sm_insta", TrollMod_Instant);
SetCategory("Items");
SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant);
SetupTroll("Bad Throw", "Player drops throwables on throw, and biles/molotovs themselves", TrollMod_Constant);
SetupTroll("No Pickup", "Prevents a player from picking up ANY (new) item. Use ThrowItAll to make them drop", TrollMod_Constant);
SetupTroll("UziRules", "Picking up a weapon gives them a UZI instead", TrollMod_Constant);
SetupTroll("Primary Disable", "Player cannot pickup any weapons, only melee/pistols", TrollMod_Constant);
SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", TrollMod_Instant);
SetCategory("Chat");
SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", TrollMod_Instant);
SetupTroll("No Profanity", "Replaces some words with random phrases", TrollMod_Constant);
SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant);
SetupTroll("Honk", "Honk", TrollMod_Constant);
SetupTroll("Meow", "Makes the player meow", TrollMod_Constant);
SetCategory("Health");
SetupTroll("Damage Boost", "Makes a player take more damage than normal", TrollMod_Constant);
SetupTroll("Temp Health Quick Drain", "Makes a player's temporarily health drain very quickly", TrollMod_Constant);
SetupTroll("Slow Drain", "Will make the player slowly lose health over time", TrollMod_Constant);
SetupTroll("KillMeSoftly", "Make player eat or waste pills whenever possible", TrollMod_Instant | TrollMod_Constant);
SetCategory("Misc");
SetupTroll("Gun Jam", "On reload, small chance their gun gets jammed - Can't reload.", TrollMod_Constant);
SetupTroll("Slow Speed", "Sets player speed to 0.8x of normal speed", TrollMod_Constant);
SetupTroll("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", TrollMod_Constant);
SetupTroll("No Shove", "Prevents a player from shoving", TrollMod_Constant);
SetupTroll("CameTooEarly", "When they shoot, random chance they empty whole clip", TrollMod_Constant);
SetupTroll("Inverted Controls", "Well, aint it obvious", TrollMod_Constant);
//INFO: UP MAX_TROLLS when adding new trolls!
}

View file

@ -29,9 +29,8 @@ bool bChooseVictimAvailable = false; //For charge player feature, is it availabl
int g_iAmmoTable; //Loads the ammo table to get ammo amounts
int gChargerVictim = -1; //For charge player feature
#include <feedthetrolls/base>
#include <feedthetrolls/trolls>
#include <feedthetrolls/specials>
#include <feedthetrolls/misc>
#include <feedthetrolls/commands>

View file

@ -581,3 +581,20 @@ stock void MakeEntityGlow(int entity, const int color[3], float distance = 1500.
SetEntProp(entity, Prop_Send, "m_nGlowRange", distance);
SetEntProp(entity, Prop_Send, "m_glowColorOverride", color[0] + (color[1] * 256) + (color[2] * 65536));
}
//Unless I'm dumb, this does not exist
stock void StringToLower(char[] str) {
int len = strlen(str);
for(int i = 0; i < len; i++) {
str[i] = CharToLower(str[i]);
}
}
stock int GetRealClient(int client) {
if(IsFakeClient(client)) {
int realPlayer = GetClientOfUserId(GetEntProp(client, Prop_Send, "m_humanSpectatorUserID"));
return realPlayer > 0 ? realPlayer : -1;
}else{
return client;
}
}

View file

@ -93,6 +93,9 @@ public void __pl_l4dh_SetNTVOptional()
MarkNativeAsOptional("L4D2_IsReachable");
MarkNativeAsOptional("L4D_HasPlayerControlledZombies");
MarkNativeAsOptional("L4D_PipeBombPrj");
MarkNativeAsOptional("L4D_MolotovPrj");
MarkNativeAsOptional("L4D2_VomitJarPrj");
MarkNativeAsOptional("L4D2_GrenadeLauncherPrj");
MarkNativeAsOptional("L4D2_ExecVScriptCode");
MarkNativeAsOptional("L4D2_GetVScriptOutput");
@ -301,6 +304,9 @@ public void __pl_l4dh_SetNTVOptional()
// ====================================================================================================
// VARIOUS ENUMS
// ====================================================================================================
// For the game mode native and forward.
enum
{
@ -311,6 +317,23 @@ enum
GAMEMODE_SCAVENGE = 8
}
// Provided by "BHaType":
// For the "L4D_State_Transition" native.
// X -> Y (means X state will become Y state on next frame or some seconds later)
enum
{
STATE_ACTIVE = 0,
STATE_WELCOME, // -> STATE_PICKING_TEAM
STATE_PICKING_TEAM,
STATE_PICKINGCLASS, // -> STATE_ACTIVE
STATE_DEATH_ANIM, // -> STATE_DEATH_WAIT_FOR_KEY
STATE_DEATH_WAIT_FOR_KEY, // -> STATE_OBSERVER_MODE
STATE_OBSERVER_MODE,
STATE_WAITING_FOR_RESCUE,
STATE_GHOST,
STATE_INTRO_CAMERA
}
@ -320,6 +343,7 @@ enum
// ====================================================================================================
// To find list: Search for "ACT_RESET" for example, in the server binary. XRef to the "ActivityList_RegisterSharedActivities" function. View in HexRays to see the full list of constants and values.
// These constants can be used in a plugins source code instead of hard coding the sequence number when working with the animation pre-hook.
// Only for Survivors, not Special Infected.
enum
{
L4D1_ACT_RESET,
@ -5128,7 +5152,6 @@ native int L4D_Dissolve(int entity);
* @brief Removes the boomer vomit effect from a player.
*
* @param client Client id of the player to remove the effect from
* @param vecAng Angular velocity vector, director to spin the projectile
*
* @noreturn
*/
@ -5271,6 +5294,41 @@ native bool L4D_HasPlayerControlledZombies();
*/
native int L4D_PipeBombPrj(int client, const float vecPos[3], const float vecAng[3]);
/**
* @brief Creates an activated Molotov projectile.
*
* @param client Client id to attribute the projectile to for damage credit
* @param vecPos Vector coordinate of the projectile on creation
* @param vecAng Vector velocity and direction of the projectile
*
* @return Entity index of the projectile
*/
native int L4D_MolotovPrj(int client, const float vecPos[3], const float vecAng[3]);
/**
* @brief Creates an activated VomitJar projectile.
*
* @param client Client id to attribute the projectile to for damage credit
* @param vecPos Vector coordinate of the projectile on creation
* @param vecAng Vector velocity and direction of the projectile
*
* @return Entity index of the projectile
*/
// L4D2 Only.
native int L4D2_VomitJarPrj(int client, const float vecPos[3], const float vecAng[3]);
/**
* @brief Creates an activated Grenade Launcher projectile.
*
* @param client Client id to attribute the projectile to for damage credit
* @param vecPos Vector coordinate of the projectile on creation
* @param vecAng Vector velocity and direction of the projectile
*
* @return Entity index of the projectile
*/
// L4D2 Only.
native int L4D2_GrenadeLauncherPrj(int client, const float vecPos[3], const float vecAng[3]);
/**
* @brief Creates a Spitter goo projectile.
*

View file

@ -193,17 +193,18 @@ public Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, flo
lastFF[attacker] = time;
if(playerTotalDamageFF[attacker] > hThreshold.IntValue && !IsFinaleEnding && isDamageDirect) {
LogAction(-1, attacker, "Excessive FF (%.2f HP)", playerTotalDamageFF[attacker]);
if(hAction.IntValue == 1) {
LogMessage("[NOTICE] Kicking %N for excessive FF (%f HP) for %d minutes.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
NotifyAllAdmins("[Notice] Kicking %N for excessive FF (%f HP) for %d minutes.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
LogMessage("[NOTICE] Kicking %N for excessive FF (%.2f HP) for %d minutes.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
NotifyAllAdmins("[Notice] Kicking %N for excessive FF (%.2f HP) for %d minutes.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
KickClient(attacker, "Excessive FF");
} else if(hAction.IntValue == 2) {
LogMessage("[NOTICE] Banning %N for excessive FF (%f HP) for %d minutes.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
NotifyAllAdmins("[Notice] Banning %N for excessive FF (%f HP) for %d minutes.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
LogMessage("[NOTICE] Banning %N for excessive FF (%.2f HP) for %d minutes.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
NotifyAllAdmins("[Notice] Banning %N for excessive FF (%.2f HP) for %d minutes.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
BanClient(attacker, hBanTime.IntValue, BANFLAG_AUTO | BANFLAG_AUTHID, "Excessive FF", "Excessive Friendly Fire", "TKStopper");
} else if(hAction.IntValue == 3) {
LogMessage("[NOTICE] %N will be banned for FF on disconnect (%f HP) for %d minutes. ", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
NotifyAllAdmins("[Notice] %N will be banned for FF on disconnect (%f HP) for %d minutes. Use /ignore <player> to make them immune.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
LogMessage("[NOTICE] %N will be banned for FF on disconnect (%.2f HP) for %d minutes. ", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
NotifyAllAdmins("[Notice] %N will be banned for FF on disconnect (%.2f HP) for %d minutes. Use /ignore <player> to make them immune.", attacker, playerTotalDamageFF[attacker], hBanTime.IntValue);
isPlayerTroll[attacker] = true;
}
damage = 0.0;
@ -254,8 +255,10 @@ public Action Command_IgnorePlayer(int client, int args) {
ReplyToCommand(client, "%N is an admin and is already immune.");
}else{
if(isImmune[target]) {
LogAction(client, target, "\"%L\" re-enabled teamkiller detection for \"%L\"", client, target);
ShowActivity2(client, "[FTT] ", "%N has re-enabled teamkiller detection for %N", client, target);
} else {
LogAction(client, target, "\"%L\" ignored teamkiller detection for \"%L\"", client, target);
ShowActivity2(client, "[FTT] ", "%N has ignored teamkiller detection for %N", client, target);
}
isImmune[target] = !isImmune[target];

View file

@ -15,6 +15,7 @@
#include <l4d2_behavior>
#include <ftt>
#include <multicolors>
#include <activitymonitor>
public Plugin myinfo =
@ -103,7 +104,6 @@ public void Change_ThrowInterval(ConVar convar, const char[] oldValue, const cha
//If a throw timer exists (someone has mode 11), destroy & recreate w/ new interval
if(hThrowTimer != INVALID_HANDLE) {
delete hThrowTimer;
PrintToServer("Reset new throw item timer");
hThrowTimer = CreateTimer(convar.FloatValue, Timer_ThrowTimer, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
}
}

View file

@ -40,7 +40,7 @@ public void OnPluginStart()
SwarmRadius = hSwarmDefaultRange.IntValue;
LoadTranslations("common.phrases");
RegAdminCmd("sm_swarm", Cmd_Swarm, ADMFLAG_ROOT, "sm_swarm [player] [range] - Zombies swarm player (or random if not set)");
RegAdminCmd("sm_swarm", Cmd_Swarm, ADMFLAG_CHEATS, "sm_swarm [player] [range] - Zombies swarm player (or random if not set)");
RegAdminCmd("sm_rush", Cmd_Swarm, ADMFLAG_ROOT, "sm_swarm [player] [range] - Zombies swarm player (or random if not set)");
RegAdminCmd("sm_rushmenu", Cmd_SwarmMenu, ADMFLAG_ROOT, "sm_swarmmenu - Open swarm menu");
RegAdminCmd("sm_rmenu", Cmd_SwarmMenu, ADMFLAG_ROOT, "sm_swarmmenu - Open swarm menu");