Merge branch 'master' of github.com:Jackzmc/sourcemod-plugins

This commit is contained in:
Jackz 2023-08-15 18:53:04 -05:00
commit 6ab22e8a60
No known key found for this signature in database
GPG key ID: E0BBD94CF657F603
5 changed files with 106 additions and 121 deletions

Binary file not shown.

View file

@ -2,9 +2,12 @@
#define DEBUG
#define PLUGIN_VERSION "0.00"
#define UPDATE_INTERVAL 6.0
#define UPDATE_INTERVAL_SLOW 15.0
// Update intervals (only sends when > 0 players)
// The update interval when there are active viewers
#define UPDATE_INTERVAL 5.0
// The update interval when there are no viewers on.
// We still need to poll to know how many viewers are watching
#define UPDATE_INTERVAL_SLOW 20.0
#include <sourcemod>
#include <sdktools>
@ -18,9 +21,9 @@ public Plugin myinfo =
{
name = "Admin Panel",
author = "Jackz",
description = "",
version = PLUGIN_VERSION,
url = ""
description = "Plugin to integrate with admin panel",
version = "1.0.0",
url = "https://github.com/jackzmc/l4d2-admin-dash"
};
ConVar cvar_debug;
@ -82,10 +85,10 @@ public void OnPluginStart()
#define DATE_FORMAT "%F at %I:%M %p"
Action Command_PanelStatus(int client, int args) {
ReplyToCommand(client, "Active: %b", updateTimer != null);
ReplyToCommand(client, "Last Error Code: %d", lastErrorCode);
ReplyToCommand(client, "#Players: %d", numberOfPlayers);
ReplyToCommand(client, "Update Interval: %0f s", fastUpdateMode ? UPDATE_INTERVAL : UPDATE_INTERVAL_SLOW);
char buffer[32];
ReplyToCommand(client, "Last Error Code: %d", lastErrorCode);
if(lastSuccessTime > 0)
FormatTime(buffer, sizeof(buffer), DATE_FORMAT, lastSuccessTime);
else
@ -99,7 +102,7 @@ void TryStartTimer(bool fast = true) {
fastUpdateMode = fast;
float interval = fast ? UPDATE_INTERVAL : UPDATE_INTERVAL_SLOW;
updateTimer = CreateTimer(interval, Timer_PostStatus, _, TIMER_REPEAT);
PrintToServer("[AdminPanel] Timer created, updating every %.1f seconds", interval);
PrintToServer("[AdminPanel] Updating every %.1f seconds", interval);
}
}
@ -205,7 +208,7 @@ void Callback_PostStatus(HTTPResponse response, any value, const char[] error) {
PrintToServer("[AdminPanel] Response: OK/204");
// We have subscribers, kill timer and recreate it in fast mode (if not already):
if(!fastUpdateMode) {
PrintToServer("[AdminPanel] We have subscribers, increasing interval");
PrintToServer("[AdminPanel] Switching to fast update interval for active viewers.");
if(updateTimer != null)
delete updateTimer;
TryStartTimer(true);
@ -215,7 +218,7 @@ void Callback_PostStatus(HTTPResponse response, any value, const char[] error) {
lastErrorCode = 0;
// We have no subscribers, kill timer and recreate it in slow mode (if not already):
if(fastUpdateMode) {
PrintToServer("[AdminPanel] No subscribers, decreasing interval");
PrintToServer("[AdminPanel] Switching to slow update interval, no viewers");
if(updateTimer != null)
delete updateTimer;
TryStartTimer(false);
@ -366,6 +369,7 @@ JSONObject GetPlayer(int client) {
player.SetInt("joinTime", playerJoinTime[client]);
player.SetInt("permHealth", GetEntProp(client, Prop_Send, "m_iHealth"));
if(team == 2) {
// Include idle players (player here is their idle bot)
if(IsFakeClient(client)) {
int idlePlayer = L4D_GetIdlePlayerOfBot(client);
if(idlePlayer > 0) {

View file

@ -559,6 +559,19 @@ stock void PrintChatToAdmins(const char[] format, any ...) {
}
PrintToServer("%s", buffer);
}
stock void CPrintChatToAdmin(const char[] format, any ...) {
char buffer[254];
VFormat(buffer, sizeof(buffer), format, 2);
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i)) {
AdminId admin = GetUserAdmin(i);
if(admin != INVALID_ADMIN_ID) {
CPrintToChat(i, "%s", buffer);
}
}
}
PCrintToServer("%s", buffer);
}
stock bool IsValidAdmin(int client, const char[] flags) {
int ibFlags = ReadFlagString(flags);
if ((GetUserFlagBits(client) & ibFlags) == ibFlags) {
@ -567,21 +580,7 @@ stock bool IsValidAdmin(int client, const char[] flags) {
return true;
}
return false;
}
stock void NotifyAllAdmins(const char[] format, any ...) {
char buffer[254];
VFormat(buffer, sizeof(buffer), format, 2);
for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i)) {
AdminId admin = GetUserAdmin(i);
if(admin != INVALID_ADMIN_ID && admin.ImmunityLevel > 0) {
PrintToChat(i, "%s", buffer);
}
}
}
PrintToServer("%s", buffer);
}
}
stock float GetNearestEntityDistance(int originEntity, char[] classname) {
float compareVec[3], entityVecOrigin[3];

View file

@ -10,6 +10,7 @@
#include <sdkhooks>
#include <jutils>
#include <left4dhooks>
#include <multicolors>
enum {
Immune_None,
@ -18,15 +19,6 @@ enum {
}
bool lateLoaded, isFinaleEnding;
// bool isPlayerTroll[MAXPLAYERS+1], isUnderAttack[MAXPLAYERS+1];
// ImmunityFlag immunityFlags[MAXPLAYERS+1];
// int iJoinTime[MAXPLAYERS+1];
// int iIdleStartTime[MAXPLAYERS+1];
// int iLastFFTime[MAXPLAYERS+1];
// int iJumpAttempts[MAXPLAYERS+1];
// float playerTotalDamageFF[MAXPLAYERS+1];
// float autoFFScaleFactor[MAXPLAYERS+1];
enum struct PlayerData {
int joinTime;
@ -107,6 +99,7 @@ public void OnPluginStart() {
AutoExecConfig(true, "l4d2_tkstopper");
HookEvent("finale_vehicle_ready", Event_FinaleVehicleReady);
HookEvent("finale_start", Event_FinaleStart);
HookEvent("player_team", Event_PlayerDisconnect);
HookEvent("charger_carry_start", Event_ChargerCarry);
@ -140,7 +133,7 @@ public void OnPluginStart() {
}
LoadTranslations("common.phrases");
}
public void Event_GamemodeChange(ConVar cvar, const char[] oldValue, const char[] newValue) {
void Event_GamemodeChange(ConVar cvar, const char[] oldValue, const char[] newValue) {
cvar.GetString(gamemode, sizeof(gamemode));
if(StrEqual(gamemode, "coop")) {
isEnabled = true;
@ -151,55 +144,17 @@ public void Event_GamemodeChange(ConVar cvar, const char[] oldValue, const char[
///////////////////////////////////////////////////////////////////////////////
// Special Infected Events
///////////////////////////////////////////////////////////////////////////////
public Action Event_ChargerCarry(Event event, const char[] name, bool dontBroadcast) {
int userid = event.GetInt("victim");
int victim = GetClientOfUserId(userid);
if(victim) {
if(StrEqual(name, "charger_carry_start")) {
pData[victim].underAttack = true;
} else {
CreateTimer(1.0, Timer_StopSpecialAttackImmunity, userid);
}
}
return Plugin_Continue;
Action Event_ChargerCarry(Event event, const char[] name, bool dontBroadcast) {
return SetUnderAttack("charger_carry_start");
}
public Action Event_HunterPounce(Event event, const char[] name, bool dontBroadcast) {
int userid = event.GetInt("victim");
int victim = GetClientOfUserId(userid);
if(victim) {
if(StrEqual(name, "lunge_pounce")) {
pData[victim].underAttack = true;
} else {
CreateTimer(1.0, Timer_StopSpecialAttackImmunity, userid);
}
}
return Plugin_Continue;
Action Event_HunterPounce(Event event, const char[] name, bool dontBroadcast) {
return SetUnderAttack(event, "lunge_pounce");
}
public Action Event_SmokerChoke(Event event, const char[] name, bool dontBroadcast) {
int userid = event.GetInt("victim");
int victim = GetClientOfUserId(userid);
if(victim) {
if(StrEqual(name, "choke_start")) {
pData[victim].underAttack = true;
} else {
CreateTimer(1.0, Timer_StopSpecialAttackImmunity, userid);
}
}
return Plugin_Continue;
Action Event_SmokerChoke(Event event, const char[] name, bool dontBroadcast) {
return SetUnderAttack("choke_start");
}
public Action Event_JockeyRide(Event event, const char[] name, bool dontBroadcast) {
int userid = event.GetInt("victim");
int victim = GetClientOfUserId(userid);
if(victim) {
if(StrEqual(name, "jockey_ride")) {
pData[victim].underAttack = true;
} else {
CreateTimer(1.0, Timer_StopSpecialAttackImmunity, userid);
}
}
return Plugin_Continue;
Action Event_JockeyRide(Event event, const char[] name, bool dontBroadcast) {
return SetUnderAttack("jockey_ride");
}
Action Timer_StopSpecialAttackImmunity(Handle h, int userid) {
@ -209,6 +164,19 @@ Action Timer_StopSpecialAttackImmunity(Handle h, int userid) {
}
return Plugin_Continue;
}
Action SetUnderAttack(Event event, const char[] checkString) {
int userid = event.GetInt("victim");
int victim = GetClientOfUserId(userid);
if(victim) {
if(StrEqual(name, checkString)) {
pData[victim].underAttack = true;
} else {
CreateTimer(1.0, Timer_StopSpecialAttackImmunity, userid);
}
}
return Plugin_Continue;
}
///////////////////////////////////////////////////////////////////////////////
// IDLE
///////////////////////////////////////////////////////////////////////////////
@ -233,16 +201,14 @@ public Action Event_PlayerToBot(Event event, char[] name, bool dontBroadcast) {
///////////////////////////////////////////////////////////////////////////////
// Misc events
///////////////////////////////////////////////////////////////////////////////
public void Event_FinaleVehicleReady(Event event, const char[] name, bool dontBroadcast) {
void Event_FinaleVehicleReady(Event event, const char[] name, bool dontBroadcast) {
isFinaleEnding = true;
for(int i = 1; i <= MaxClients; i++) {
if(pData[i].isTroll && IsClientConnected(i) && IsClientInGame(i)) {
PrintChatToAdmins("Note: %N is still marked as troll and will be banned after this game. Use \"/ignore <player> tk\" to ignore them.", i);
}
}
WarnStillMarked();
PrintToServer("[TKStopper] Escape vehicle active, 2x rff in effect");
}
void Event_FinaleStart(Event event, const char[] name, bool dontBroadcast) {
WarnStillMarked();
}
public void OnMapEnd() {
isFinaleEnding = false;
}
@ -272,13 +238,17 @@ public void OnClientDisconnect(int client) {
}
// Only clear things when they fully left on their own accord:
public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) {
void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) {
if(!event.GetBool("disconnect") || !isEnabled) return;
int client = GetClientOfUserId(event.GetInt("userid"));
if(client > 0 && event.GetInt("team") <= 2) {
if (pData[client].isTroll && !IsFakeClient(client)) {
BanClient(client, hBanTime.IntValue, BANFLAG_AUTO | BANFLAG_AUTHID, "Excessive FF (Auto)", "Excessive Friendly Fire", "TKStopper");
if(hBanTime.IntValue > 0)
CPrintChatToAdmins("{olive}%N{default} has been banned for %d minutes (marked as troll). If this was a mistake, you can discard their ban from the admin panel at {yellow}https://admin.jackz.me", client, hBanTime.IntValue);
else
CPrintChatToAdmins("{olive}%N{default} has been permanently banned (marked as troll). If this was a mistake, you can discard their ban from the admin panel at {yellow}https://admin.jackz.me", client);
pData[client].isTroll = false;
}
@ -286,7 +256,7 @@ public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroa
float minutesSinceiLastFFTime = GetLastFFMinutes(client);
float activeRate = GetActiveRate(client);
PrintToConsoleAll("[TKStopper] FF Summary for %N:", client);
PrintToConsoleAll("\t\t%.2f TK-FF buffer (%.2f total ff, %d freq.) | %.3f (buf %f) rFF rate | lastff %.1f min ago | %d suicide jumps",
PrintToConsoleAll("\t%.2f TK-FF buffer (%.2f total ff, %d freq.) | %.3f (buf %f) rFF rate | lastff %.1f min ago | %d suicide jumps",
pData[client].TKDamageBuffer,
pData[client].totalDamageFF,
pData[client].totalFFCount,
@ -306,7 +276,7 @@ public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroa
}
}
public Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype, int& weapon, float damageForce[3], float damagePosition[3]) {
Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype, int& weapon, float damageForce[3], float damagePosition[3]) {
if(isEnabled && damage > 0.0 && victim <= MaxClients && attacker <= MaxClients && attacker > 0 && victim > 0) {
if(GetClientTeam(victim) != GetClientTeam(attacker) || attacker == victim)
return Plugin_Continue;
@ -352,15 +322,15 @@ public Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, flo
if(pData[victim].jumpAttempts > hSuicideLimit.IntValue) {
if(hSuicideAction.IntValue == 1) {
LogMessage("[NOTICE] Kicking %N for suicide attempts", victim, hBanTime.IntValue);
NotifyAllAdmins("[Notice] Kicking %N for suicide attempts", victim, hBanTime.IntValue);
PrintToChatAdmins("[Notice] Kicking %N for suicide attempts", victim, hBanTime.IntValue);
KickClient(victim, "Troll");
} else if(hSuicideAction.IntValue == 2) {
LogMessage("[NOTICE] Banning %N for suicide attempts for %d minutes.", victim, hBanTime.IntValue);
NotifyAllAdmins("[Notice] Banning %N for suicide attempts for %d minutes.", victim, hBanTime.IntValue);
PrintToChatAdmins("[Notice] Banning %N for suicide attempts for %d minutes.", victim, hBanTime.IntValue);
BanClient(victim, hBanTime.IntValue, BANFLAG_AUTO | BANFLAG_AUTHID, "Suicide fall attempts", "Troll", "TKStopper");
} else if(hSuicideAction.IntValue == 3) {
LogMessage("[NOTICE] %N will be banned for suicide attempts for %d minutes. ", victim, hBanTime.IntValue);
NotifyAllAdmins("[Notice] %N will be banned for suicide attempts for %d minutes. Use \"/ignore <player> tk\" to make them immune.", victim, hBanTime.IntValue);
PrintToChatAdmins("[Notice] %N will be banned for suicide attempts for %d minutes. Use \"/ignore <player> tk\" to make them immune.", victim, hBanTime.IntValue);
pData[victim].isTroll = true;
}
}
@ -427,15 +397,15 @@ public Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, flo
if(!pData[attacker].pendingAction) {
if(hTKAction.IntValue == 1) {
LogMessage("[TKStopper] Kicking %N for excessive FF (%.2f HP)", attacker, pData[attacker].TKDamageBuffer);
NotifyAllAdmins("[Notice] Kicking %N for excessive FF (%.2f HP)", attacker, pData[attacker].TKDamageBuffer);
PrintToChatAdmins("[Notice] Kicking %N for excessive FF (%.2f HP)", attacker, pData[attacker].TKDamageBuffer);
KickClient(attacker, "Excessive FF");
} else if(hTKAction.IntValue == 2) {
LogMessage("[TKStopper] Banning %N for excessive FF (%.2f HP) for %d minutes.", attacker, pData[attacker].TKDamageBuffer, hBanTime.IntValue);
NotifyAllAdmins("[Notice] Banning %N for excessive FF (%.2f HP) for %d minutes.", attacker, pData[attacker].TKDamageBuffer, hBanTime.IntValue);
PrintToChatAdmins("[Notice] Banning %N for excessive FF (%.2f HP) for %d minutes.", attacker, pData[attacker].TKDamageBuffer, hBanTime.IntValue);
BanClient(attacker, hBanTime.IntValue, BANFLAG_AUTO | BANFLAG_AUTHID, "Excessive FF (Auto)", "Excessive Friendly Fire (Automatic)", "TKStopper");
} else if(hTKAction.IntValue == 3) {
LogMessage("[TKStopper] %N will be banned for FF on disconnect (%.2f HP) for %d minutes. ", attacker, pData[attacker].TKDamageBuffer, hBanTime.IntValue);
NotifyAllAdmins("[Notice] %N will be banned for FF on disconnect (%.2f HP) for %d minutes. Use \"/ignore <player> tk\" to make them immune.", attacker, pData[attacker].TKDamageBuffer, hBanTime.IntValue);
CPrintToChatAdmins("[Notice] %N will be banned for %d minutes for attempted teamkilling (%.2f HP) when they disconnect. Use {olive}/ignore <player> tk{default} to make them immune.", attacker, hBanTime.IntValue, pData[attacker].TKDamageBuffer);
pData[attacker].isTroll = true;
}
pData[attacker].pendingAction = true;
@ -482,7 +452,7 @@ public Action Event_OnTakeDamage(int victim, int& attacker, int& inflictor, flo
/// COMMANDS
public Action Command_TKInfo(int client, int args) {
Action Command_TKInfo(int client, int args) {
int time = GetTime();
if(!isEnabled) {
ReplyToCommand(client, "Warn: Plugin is disabled in current gamemode (%s)", gamemode);
@ -509,28 +479,28 @@ public Action Command_TKInfo(int client, int args) {
return Plugin_Handled;
}
int target = target_list[0];
ReplyToCommand(client, "FF Review for '%N':", target);
CReplyToCommand(client, "FF Review for {yellow}%N", target);
if(pData[target].isTroll) {
ReplyToCommand(client, "- will be banned on disconnect for TK -", target);
CReplyToCommand(client, "{olive}- will be banned on disconnect for TK -", target);
}
if(pData[target].immunityFlags == Immune_TK) {
ReplyToCommand(client, "Immunity: Teamkiller Detection", target);
CReplyToCommand(client, "Immunity: {yellow}Teamkiller Detection", target);
} else if(pData[target].immunityFlags == Immune_RFF) {
ReplyToCommand(client, "Immunity: Auto reverse-ff", target);
CReplyToCommand(client, "Immunity: {yellow}Auto reverse-ff", target);
} else if(view_as<int>(pData[target].immunityFlags) > 0) {
ReplyToCommand(client, "Immunity: Teamkiller Detection, Auto reverse-ff", target);
CReplyToCommand(client, "Immunity: {yellow}Teamkiller Detection, Auto reverse-ff", target);
} else {
ReplyToCommand(client, "Immunity: (none, use /ignore <player> [immunity] to toggle)", target);
CReplyToCommand(client, "Immunity: (none, use {green}/ignore <player> [immunity]{default} to toggle)", target);
}
float minutesSinceiLastFFTime = GetLastFFMinutes(target);
float activeRate = GetActiveRate(target);
ReplyToCommand(client, "FF Frequency: %d (active %d, %d forgotten)", pData[target].totalFFCount, pData[target].ffCount, (pData[target].totalFFCount - pData[target].ffCount));
ReplyToCommand(client, "Total FF Damage: %.1f HP (%.1f min ago last ff)", pData[target].totalDamageFF, minutesSinceiLastFFTime);
CReplyToCommand(client, "FF Frequency: {yellow}%d {default}(recent: %d, %d forgiven)", pData[target].totalFFCount, pData[target].ffCount, (pData[target].totalFFCount - pData[target].ffCount));
CReplyToCommand(client, "Total FF Damage: {yellow}%.1f HP{default} (last fff %.1f min ago)", pData[target].totalDamageFF, minutesSinceiLastFFTime);
if(~pData[target].immunityFlags & Immune_TK)
ReplyToCommand(client, "Recent FF (TKDetectBuff): %.1f", pData[target].TKDamageBuffer);
CReplyToCommand(client, "Recent FF (TKDetectBuffer): {yellow}%.1f", pData[target].TKDamageBuffer);
if(~pData[target].immunityFlags & Immune_RFF)
ReplyToCommand(client, "Auto Reverse-FF: %.1fx return rate", activeRate);
ReplyToCommand(client, "Attempted suicide jumps: %d", pData[target].jumpAttempts);
CReplyToCommand(client, "Auto Reverse-FF: {yellow}%.1fx return rate", activeRate);
CReplyToCommand(client, "Attempted suicide jumps: {yellow}%d", pData[target].jumpAttempts);
} else {
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i)) {
@ -557,25 +527,25 @@ public Action Command_TKInfo(int client, int args) {
}
public Action Command_IgnorePlayer(int client, int args) {
Action Command_IgnorePlayer(int client, int args) {
char arg1[32], arg2[16];
GetCmdArg(1, arg1, sizeof(arg1));
GetCmdArg(2, arg2, sizeof(arg2));
if(args < 2) {
ReplyToCommand(client, "Usage: sm_ignore <player> <tk/teamkill/rff/reverseff>");
CReplyToCommand(client, "Usage: {yellow}sm_ignore <player> <tk|teamkill / rff|reverseff>");
return Plugin_Handled;
}
int flags = 0;
if(StrEqual(arg2, "tk") || StrEqual(arg2, "teamkill")) {
flags = Immune_TK;
} else if(StrEqual(arg2, "all") || StrEqual(arg2, "a")) {
} else if(arg2[0] == 'a') {
flags = Immune_TK | Immune_RFF;
} else if(StrEqual(arg2, "reverseff") || StrEqual(arg2, "rff")) {
flags = Immune_RFF;
} else {
ReplyToCommand(client, "Usage: sm_ignore <player> <tk/teamkill/rff/reverseff>");
CReplyToCommand(client, "Usage: {yellow}sm_ignore <player> <tk|teamkill / rff|reverseff>");
return Plugin_Handled;
}
@ -607,10 +577,10 @@ public Action Command_IgnorePlayer(int client, int args) {
if (flags & Immune_TK) {
if (pData[target].immunityFlags & Immune_TK) {
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);
CShowActivity2(client, "[FTT] ", "{yellow}%N has re-enabled teamkiller detection for {olive}%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);
CShowActivity2(client, "[FTT] ", "{yellow}%N has ignored teamkiller detection for {olive}%N", client, target);
}
pData[target].immunityFlags ^= Immune_TK;
}
@ -620,7 +590,7 @@ public Action Command_IgnorePlayer(int client, int args) {
LogAction(client, target, "\"%L\" re-enabled auto reverse friendly-fire for \"%L\"", client, target);
} else {
LogAction(client, target, "\"%L\" disabled auto reverse friendly-fire for \"%L\"", client, target);
ShowActivity2(client, "[FTT] ", "%N has disabled auto reverse friendly-fire for %N", client, target);
CShowActivity2(client, "[FTT] ", "{yellow}%N has disabled auto reverse friendly-fire for {olive}%N", client, target);
pData[target].autoRFFScaleFactor = 0.0;
}
pData[target].immunityFlags ^= Immune_RFF;
@ -654,9 +624,9 @@ void GetImmunityFlagName(int flag, char[] buffer, int bufferLength) {
if(flag == Immune_RFF) {
strcopy(buffer, bufferLength, "Reverse Friendly-Fire");
} else if(flag == Immune_TK) {
strcopy(buffer, bufferLength, "Reverse Friendly-Fire");
strcopy(buffer, bufferLength, "Teamkiller Detection");
} else {
strcopy(buffer, bufferLength, "-unknown flag-");
strcopy(buffer, bufferLength, "-error: unknown flag-");
}
}
@ -674,6 +644,13 @@ void _CheckNative(int target, int flag) {
ThrowNativeError(SP_ERROR_NATIVE, "Flag is invalid");
}
}
void WarnStillMarked() {
for(int i = 1; i <= MaxClients; i++) {
if(pData[i].isTroll && IsClientConnected(i) && IsClientInGame(i)) {
CPrintChatToAdmins("Note: {yellow}%N is still marked as troll and will be banned after this game. Use {olive}/ignore <player> tk{default} to ignore them.", i);
}
}
}
/// STOCKS
float GetLastFFMinutes(int client) {

View file

@ -5,7 +5,7 @@
#define PLUGIN_VERSION "1.0"
#define MAX_PLAYER_HISTORY 25
#define MAX_NOTES_TO_SHOW 10
#define MAX_NOTES_TO_SHOW 5
#define DATABASE_CONFIG_NAME "stats"
#include <sourcemod>
@ -374,7 +374,7 @@ public void Event_FirstSpawn(Event event, const char[] name, bool dontBroadcast)
if(client > 0 && client <= MaxClients && !IsFakeClient(client)) {
static char auth[32];
GetClientAuthId(client, AuthId_Steam2, auth, sizeof(auth));
DB.Format(query, sizeof(query), "SELECT notes.content, stats_users.last_alias, markedBy FROM `notes` JOIN stats_users ON markedBy = stats_users.steamid WHERE notes.`steamid` = '%s'", auth);
DB.Format(query, sizeof(query), "SELECT notes.content, stats_users.last_alias, markedBy FROM `notes` JOIN stats_users ON markedBy = stats_users.steamid WHERE notes.`steamid` = '%s' ORDER BY id ASC", auth);
DB.Query(DB_FindNotes, query, GetClientUserId(client));
}
}
@ -417,7 +417,9 @@ public void DB_FindNotes(Database db, DBResultSet results, const char[] error, a
CPrintChatToAdmins("{yellow}> Notes for %N", client);
int actions = 0;
int repP = 0, repN = 0;
int count = 0;
while(results.FetchRow()) {
count++;
DBResult result;
results.FetchString(0, reason, sizeof(reason));
results.FetchString(1, noteCreator, sizeof(noteCreator), result);
@ -432,10 +434,13 @@ public void DB_FindNotes(Database db, DBResultSet results, const char[] error, a
repP++;
} else if(StrEqual(reason, "-rep")) {
repN++;
} else {
} else if(count < MAX_NOTES_TO_SHOW) {
CPrintChatToAdmins(" {olive}%s: {default}%s", noteCreator, reason);
}
}
if(count >= MAX_NOTES_TO_SHOW) {
CPrintChatToAdmins(" ... and {olive}%d {default}more", MAX_NOTES_COUNT - count);
}
if(actions > 0) {
CPrintChatToAdmins(" > {olive}%d Auto Actions Applied", actions);