summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornavewindre <nw@moneybot.cc>2023-12-03 04:36:03 +0100
committernavewindre <nw@moneybot.cc>2023-12-03 04:36:03 +0100
commit38f1140c11724da05a23a10385061200b907cf6e (patch)
tree0a25c91da964e8b64c8584cd53f847679f317f46
parent2cb2a356c012cc34af811f26e16d26b11e663768 (diff)
stats
-rw-r--r--sourcemod-1.5-dev/scripting/ljstats.sp23
-rw-r--r--sourcemod-1.5-dev/scripting/stats.sp1127
2 files changed, 1138 insertions, 12 deletions
diff --git a/sourcemod-1.5-dev/scripting/ljstats.sp b/sourcemod-1.5-dev/scripting/ljstats.sp
index e9d535b..8167430 100644
--- a/sourcemod-1.5-dev/scripting/ljstats.sp
+++ b/sourcemod-1.5-dev/scripting/ljstats.sp
@@ -17,7 +17,7 @@
#define LJTOP_DIR "configs/ljstats/"
#define LJTOP_FILE "ljtop.txt"
-#define LJTOP_NUM_ENTRIES 500
+#define LJTOP_NUM_ENTRIES 1024
#define LJSOUND_NUM 5
#define MAX_STRAFES 50
#define BHOP_TIME 0.3
@@ -33,7 +33,7 @@
#define BJ_HEIGHT_DELTA_MAX 2.0
#define LAJ_HEIGHT_DELTA_MIN -6.0
#define LAJ_HEIGHT_DELTA_MAX 0.0
-#define JB_HEIGHT_DELTA_MIN -4
+#define JB_HEIGHT_DELTA_MIN -4.0
#define JB_HEIGHT_DELTA_MAX 1.0
#define HUD_HINT_SIZE 256
#define STRAFE_TRAINER_TICKS 9
@@ -680,8 +680,8 @@ public DB_LoadLJTop_Callback(Handle:owner, Handle:hndl, String:error[], any:pack
if(it[iTable] > LJTOP_NUM_ENTRIES - 1)
{
- LogError("Too many rows for table %s", table);
- return;
+ //LogError("Too many rows for table %s", table);
+ continue;
}
if (iTable == -1)
@@ -1158,7 +1158,8 @@ public OnClientCookiesCached(client)
GetClientCookie(client, g_hCookieLJEnabled, strCookie, sizeof(strCookie));
- g_PlayerStates[client][bLJEnabled] = bool:StringToInt(strCookie);
+ g_PlayerStates[client][bLJEnabled] = true;
+ //g_PlayerStates[client][bLJEnabled] = bool:StringToInt(strCookie);
GetClientCookie(client, g_hCookieBlockMode, strCookie, sizeof(strCookie));
g_PlayerStates[client][bBlockMode] = bool:StringToInt(strCookie);
@@ -1208,8 +1209,8 @@ ShowSettingsPanel(client)
AddMenuItem(hMenu, "tpmenu", "Show TP menu");
- Format(buf, sizeof(buf), "LJ stats: %s", g_PlayerStates[client][bLJEnabled] ? "On" : "Off");
- AddMenuItem(hMenu, "ljenabled", buf);
+ Format(buf, sizeof(buf), "Show top stats");
+ AddMenuItem(hMenu, "ljtop", buf);
Format(buf, sizeof(buf), "Beam: %s", g_PlayerStates[client][bBeam] ? "On" : "Off");
AddMenuItem(hMenu, "beam", buf);
@@ -1273,11 +1274,9 @@ public SettingsMenuHandler(Handle:hMenu, MenuAction:ma, client, nItem)
if(!strcmp(strInfo, "tpmenu")) {
Command_CheckpointPanel(client, 0);
}
- else if(!strcmp(strInfo, "ljenabled"))
+ else if(!strcmp(strInfo, "ljtop"))
{
- g_PlayerStates[client][bLJEnabled] = !g_PlayerStates[client][bLJEnabled];
- SetCookie(client, g_hCookieLJEnabled, g_PlayerStates[client][bLJEnabled]);
- PrintToChat(client, "LJ stats are now %s", g_PlayerStates[client][bLJEnabled] ? "on" : "off");
+ DisplayMenu(g_hLJTopMainMenu, client, MENU_TIME_FOREVER);
ShowSettingsPanel(client);
}
else if(!strcmp(strInfo, "beam"))
@@ -2044,7 +2043,7 @@ LJTopLoad(const String:strPath[])
if(nEntry >= LJTOP_NUM_ENTRIES)
{
- PrintToServer("[LJTop] Too many entries for table %d; ignoring line", nTable);
+ //PrintToServer("[LJTop] Too many entries for table %d; ignoring line", nTable);
continue;
}
diff --git a/sourcemod-1.5-dev/scripting/stats.sp b/sourcemod-1.5-dev/scripting/stats.sp
new file mode 100644
index 0000000..47030d4
--- /dev/null
+++ b/sourcemod-1.5-dev/scripting/stats.sp
@@ -0,0 +1,1127 @@
+#include <sourcemod>
+#include <sdktools>
+#include <clientprefs>
+#include <sdkhooks>
+#include <smlib>
+#include <morecolors>
+#include <cstrike>
+
+#pragma semicolon 1
+#define STATSTOP_NUM_ENTRIES 1024
+
+public Plugin:myinfo = {
+ name = "networkheaven playerstats",
+ author = "networkheaven.net",
+ description = "",
+ version = "aye",
+}
+
+
+enum LJTOP_TABLE
+{
+ LT_LJ,
+ LT_SWLJ,
+ LT_BWLJ,
+ LT_CJ,
+ LT_BJ,
+ LT_LAJ,
+ LT_WJ,
+ LT_JB,
+ LT_END
+}
+
+new String:g_strLJTopTags[LT_END][] =
+{
+ "lj",
+ "swlj",
+ "bwlj",
+ "cj",
+ "bj",
+ "laj",
+ "wj",
+ "jb"
+};
+
+new g_rankPointsNeeded[] = {
+ 0,
+ 1000,
+ 2500,
+ 5000,
+ 9000,
+ 10000,
+ 15000,
+ 25000
+};
+
+enum PlayerRanks {
+ PR_NOOB,
+ PR_BEGINNER,
+ PR_INTERMEDIATE,
+ PR_SEASONED,
+ PR_OVER9K,
+ PR_EXPERIENCED,
+ PR_GAMER,
+ PR_PRO,
+ PR_END
+};
+
+new String:g_playerRanks[PR_END][] = {
+ "noob",
+ "beginner",
+ "intermediate",
+ "seasoned",
+ "over9k",
+ "experienced",
+ "gamer",
+ "pro"
+};
+
+new String:g_playerRankBracketColors[PR_END][] = {
+ "{default}",
+ "{teamcolor}",
+ "{teamcolor}",
+ "{arcana}",
+ "{fuchsia}",
+ "{lawngreen}",
+ "{unique}",
+ "{tomato}"
+};
+
+new String:g_playerRankColors[PR_END][] = {
+ "{default}",
+ "{default}",
+ "{teamcolor}",
+ "{arcana}",
+ "{fuchsia}",
+ "{lawngreen}",
+ "{unique}",
+ "{tomato}"
+};
+
+new String:g_playerRankColorsTop3[3][] = {
+ "{valve}",
+ "{unusual}",
+ "{maroon}"
+};
+
+enum PlayerStats {
+ plStatPos,
+ String:plName[64],
+ String:plSteamid[32],
+ plKills,
+ plDeaths,
+ Float:plKDRatio,
+ plPlaytime,
+ plAlivetime,
+ plTotalPoints,
+ plDeadtime,
+ Float:plLjtop,
+ plLjtopPos,
+ Float:plSwljtop,
+ plSwljtopPos,
+ Float:plBwljtop,
+ plBwljtopPos,
+ Float:plBhtop,
+ plBhtopPos,
+ Float:plCjtop,
+ plCjtopPos,
+ Float:plLajtop,
+ plLajtopPos,
+ Float:plWjtop,
+ plWjtopPos,
+ Float:plJbtop,
+ plJbtopPos,
+ plRoundwins,
+ plRoundlosses
+};
+
+
+new Handle:nh_warmup = INVALID_HANDLE;
+new Handle:g_statsDB = INVALID_HANDLE;
+new Handle:g_ljDB = INVALID_HANDLE;
+new g_LJTopMax[LT_END] = { 0, ... };
+new g_statsTOP = 0;
+new g_playerStats[MAXPLAYERS+1][PlayerStats];
+new g_playerTop[STATSTOP_NUM_ENTRIES][PlayerStats];
+
+public OnPluginStart() {
+ CreateTimer( 1.0, Timer_PlaytimeTick, _ );
+ RegConsoleCmd( "sm_stats", Command_Stats, "shows stats" );
+ RegAdminCmd( "sm_savestats", Command_SaveStats, ADMFLAG_ROOT, "saves stats" );
+ ResetPlayerStates();
+
+ CreateTimer( 1.0, Timer_PlaytimeTick, _, TIMER_REPEAT );
+}
+
+
+public OnMapStart() {
+ ResetPlayerStates();
+ LoadLJDB();
+ LoadStatsDB();
+}
+
+public OnMapEnd() {
+ SaveStatsDB();
+}
+
+public OnClientDisconnect( client ) {
+ SaveStatsDBForPlayer( client );
+}
+
+public FindKDTopIndex( Float:kd ) {
+ if( !kd )
+ return g_statsTOP;
+
+ if( kd > g_playerTop[0][plKDRatio] )
+ return 0;
+
+ if( g_statsTOP > 0 && kd < g_playerTop[g_statsTOP - 1][plKDRatio] )
+ return g_statsTOP;
+
+ for( new i = 0; i < 3; ++i ) {
+ if( g_playerTop[i][plKDRatio] > kd )
+ return i;
+ }
+
+ new i = g_statsTOP / 2;
+ new denominator = 4;
+ new bool:flip = false;
+
+ for( ;; ) {
+ if( g_playerTop[i][plKDRatio] > kd && g_playerTop[i + 1][plKDRatio] < kd )
+ return i;
+ else if( g_playerTop[i][plKDRatio] > kd )
+ flip = false;
+ else
+ flip = true;
+
+ if( denominator < g_statsTOP )
+ denominator *= 2;
+
+ if( flip )
+ i += (g_statsTOP / denominator);
+ else
+ i -= (g_statsTOP / denominator);
+ }
+}
+
+public ResetPlayerState( i ) {
+ g_playerStats[i][plStatPos] = -1;
+
+ g_playerStats[i][plKills] = 0;
+ g_playerStats[i][plDeaths] = 0;
+ g_playerStats[i][plPlaytime] = 0;
+ g_playerStats[i][plAlivetime] = 0;
+ g_playerStats[i][plDeadtime] = 0;
+ g_playerStats[i][plRoundwins] = 0;
+ g_playerStats[i][plRoundlosses] = 0;
+ g_playerStats[i][plKDRatio] = 0.0;
+ g_playerStats[i][plTotalPoints] = 0;
+
+ g_playerStats[i][plLjtop] = 0.0;
+ g_playerStats[i][plBhtop] = 0.0;
+ g_playerStats[i][plCjtop] = 0.0;
+ g_playerStats[i][plLajtop] = 0.0;
+ g_playerStats[i][plWjtop] = 0.0;
+ g_playerStats[i][plJbtop] = 0.0;
+ g_playerStats[i][plBwljtop] = 0.0;
+ g_playerStats[i][plSwljtop] = 0.0;
+
+ g_playerStats[i][plLjtopPos] = 999999;
+ g_playerStats[i][plBhtopPos] = 999999;
+ g_playerStats[i][plCjtopPos] = 999999;
+ g_playerStats[i][plLajtopPos] = 999999;
+ g_playerStats[i][plWjtopPos] = 999999;
+ g_playerStats[i][plJbtopPos] = 999999;
+ g_playerStats[i][plBwljtopPos] = 999999;
+ g_playerStats[i][plSwljtopPos] = 999999;
+}
+
+public ResetPlayerStates() {
+ for( new i = 0; i <= MaxClients; ++i ) {
+ ResetPlayerState( i );
+ }
+
+ for( new i = 0; i < STATSTOP_NUM_ENTRIES; ++i ) {
+ g_playerTop[i][plStatPos] = -1;
+
+ g_playerTop[i][plKills] = 0;
+ g_playerTop[i][plDeaths] = 0;
+ g_playerTop[i][plPlaytime] = 0;
+ g_playerTop[i][plAlivetime] = 0;
+ g_playerTop[i][plDeadtime] = 0;
+ g_playerTop[i][plRoundwins] = 0;
+ g_playerTop[i][plRoundlosses] = 0;
+ g_playerTop[i][plKDRatio] = 0.0;
+ g_playerTop[i][plTotalPoints] = 0;
+
+ g_playerTop[i][plLjtop] = 0.0;
+ g_playerTop[i][plBhtop] = 0.0;
+ g_playerTop[i][plCjtop] = 0.0;
+ g_playerTop[i][plLajtop] = 0.0;
+ g_playerTop[i][plWjtop] = 0.0;
+ g_playerTop[i][plJbtop] = 0.0;
+ g_playerTop[i][plBwljtop] = 0.0;
+ g_playerTop[i][plSwljtop] = 0.0;
+
+ g_playerTop[i][plLjtopPos] = 999999;
+ g_playerTop[i][plBhtopPos] = 999999;
+ g_playerTop[i][plCjtopPos] = 999999;
+ g_playerTop[i][plLajtopPos] = 999999;
+ g_playerTop[i][plWjtopPos] = 999999;
+ g_playerTop[i][plJbtopPos] = 999999;
+ g_playerTop[i][plBwljtopPos] = 999999;
+ g_playerTop[i][plSwljtopPos] = 999999;
+ }
+}
+
+public OnClientPutInServer( client ) {
+ ResetPlayerState( client );
+ LoadLJDB();
+ LoadStatsDBForUser( client );
+}
+
+LJTOP_TABLE:GetLJTopTable( const String:table[] ) {
+ for( new LJTOP_TABLE:j; j < LT_END; j++ ) {
+ if( !strcmp(g_strLJTopTags[j], table) ) {
+ return j;
+ }
+ }
+
+ return LJTOP_TABLE:-1;
+}
+
+public LoadLJDataForSteamID( String:_steamid[], table, Float:distance, pos ) {
+ new String:playerSteamID[32];
+
+ new i = 0;
+ for( new i2 = 1; i2 < MaxClients; ++i2 ) {
+ if( !IsClientConnected( i2 ) || !IsClientInGame( i2 ) || IsFakeClient( i2 ) )
+ continue;
+
+ GetClientAuthString( i2, playerSteamID, sizeof(playerSteamID) );
+
+ if( !strcmp( playerSteamID, _steamid ) ) {
+ i = i2;
+ break;
+ }
+ }
+
+ if( !i )
+ return;
+
+ if( GetPlayerRecordPosition( i, table ) > pos ) {
+ switch( LJTOP_TABLE:table ) {
+ case LT_LJ: { g_playerStats[i][plLjtop] = distance; g_playerStats[i][plLjtopPos] = pos; }
+ case LT_BJ: { g_playerStats[i][plBhtop] = distance; g_playerStats[i][plBhtopPos] = pos; }
+ case LT_CJ: { g_playerStats[i][plCjtop] = distance; g_playerStats[i][plCjtopPos] = pos; }
+ case LT_LAJ: { g_playerStats[i][plLajtop] = distance; g_playerStats[i][plLajtopPos] = pos; }
+ case LT_WJ: { g_playerStats[i][plWjtop] = distance; g_playerStats[i][plWjtopPos] = pos; }
+ case LT_JB: { g_playerStats[i][plJbtop] = distance; g_playerStats[i][plJbtopPos] = pos; }
+ case LT_BWLJ: { g_playerStats[i][plBwljtop] = distance; g_playerStats[i][plBwljtopPos] = pos; }
+ case LT_SWLJ: { g_playerStats[i][plSwljtop] = distance; g_playerStats[i][plSwljtopPos] = pos; }
+ }
+ }
+}
+
+public LoadLJDBCallback( Handle:owner, Handle:hndl, String:error[], any:pack ) {
+ if( hndl == INVALID_HANDLE ) {
+ LogError( "LoadLJDB failed: %s", error );
+ return;
+ }
+
+ new rows = SQL_GetRowCount( hndl );
+
+ new it[LT_END] = { 0, ... };
+ for(new i = 0; i < rows; i++)
+ {
+ SQL_FetchRow(hndl);
+
+ decl String:table[16], String:steamid[32];
+ SQL_FetchStringByName( hndl, "ljtable", table, sizeof(table) );
+ new iTable = _:GetLJTopTable(table);
+
+ if( iTable == -1 ) {
+ LogError("DB_LoadLJTop: Invalid table %s", table);
+ continue;
+ }
+
+ g_LJTopMax[iTable] = it[iTable];
+
+ SQL_FetchStringByName(hndl, "steamid", steamid, sizeof(steamid));
+ new Float:dist = SQL_FetchFloatByName(hndl, "distance");
+ LoadLJDataForSteamID( steamid, iTable, dist, it[iTable] + 1 );
+ it[iTable]++;
+ }
+}
+
+public LoadLJDB() {
+ if( g_ljDB != INVALID_HANDLE ) {
+ CloseHandle(g_ljDB);
+ }
+
+ decl String:error[255];
+ g_ljDB = SQL_Connect("ljstats", true, error, sizeof(error));
+
+ if( g_ljDB == INVALID_HANDLE) {
+ LogError(error);
+ }
+
+ SQL_TQuery(g_ljDB, LoadLJDBCallback, "SELECT * FROM ljtop ORDER BY distance DESC");
+}
+
+public Float:GetLJScore( client, table ) {
+ new pos = 0;
+ new Float:multiplier = 1.0;
+
+ switch( LJTOP_TABLE:table ) {
+ case LT_LJ: { pos = g_playerStats[client][plLjtopPos]; multiplier = 1.2; }
+ case LT_CJ: { pos = g_playerStats[client][plCjtopPos]; multiplier = 1.2; }
+ case LT_BJ: { pos = g_playerStats[client][plBhtopPos]; multiplier = 1.0; }
+ case LT_JB: { pos = g_playerStats[client][plJbtopPos]; multiplier = 1.0; }
+ case LT_LAJ: { pos = g_playerStats[client][plLajtopPos]; multiplier = 0.8; }
+ case LT_BWLJ: { pos = g_playerStats[client][plBwljtopPos]; multiplier = 0.8; }
+ case LT_SWLJ: { pos = g_playerStats[client][plSwljtopPos]; multiplier = 0.8; }
+ case LT_WJ: { pos = g_playerStats[client][plWjtopPos]; multiplier = 0.8; }
+ }
+
+ if( pos == 0 )
+ return 0.0;
+
+ new Float:score = 0.0;
+ if( pos == 1 )
+ score = 1000.0;
+ else if( pos == 2 )
+ score = 750.0;
+ else if( pos == 3 )
+ score = 500.0;
+
+ new Float:div = Float:g_LJTopMax[table];
+ if( div < 1.0 )
+ div = 1.0;
+ score += (500 - (Float:pos / div * 500)) * multiplier;
+ return score;
+}
+
+public Float:GetKDScore( client ) {
+ new Float:points = 0.0;
+
+ new Float:kd = g_playerStats[client][plKDRatio];
+ new kdPlacement = FindKDTopIndex( kd ) + 1;
+ if( kdPlacement == 1 )
+ points += 1000;
+ else if( kdPlacement == 2 )
+ points += 750;
+ else if( kdPlacement == 3)
+ points += 500;
+
+ new Float:num = Float:kdPlacement;
+ new Float:den = Float:g_statsTOP;
+ if( den < 1.0 )
+ den = 1.0;
+
+ points += 500 - (num / den * 500);
+ return points;
+}
+
+public Float:GetPlayerPoints( client ) {
+ new Float:points = 0.0;
+
+ points += g_playerStats[client][plKills] * 1;
+ points -= g_playerStats[client][plDeaths] * 0.9;
+ points += g_playerStats[client][plRoundwins] * 0.5;
+ points -= g_playerStats[client][plRoundlosses] * 0.5;
+ points += GetLJScore( client, _:LT_LJ );
+ points += GetLJScore( client, _:LT_CJ );
+ points += GetLJScore( client, _:LT_BJ );
+ points += GetLJScore( client, _:LT_JB );
+ points += GetLJScore( client, _:LT_LAJ );
+ points += GetLJScore( client, _:LT_BWLJ );
+ points += GetLJScore( client, _:LT_SWLJ );
+ points += GetLJScore( client, _:LT_WJ );
+ points += GetKDScore( client );
+
+ if( points < 0 )
+ points = 0.0;
+
+ return points;
+}
+
+public UpdatePlayerPoints( client ) {
+ g_playerStats[client][plTotalPoints] = RoundFloat( GetPlayerPoints( client ) );
+}
+
+public LJTOP_TABLE:HasRecord( client ) {
+ if( g_playerStats[client][plLjtopPos] <= 3 )
+ return LT_LJ;
+ if( g_playerStats[client][plCjtopPos] <= 3 )
+ return LT_CJ;
+ if( g_playerStats[client][plWjtopPos] <= 3 )
+ return LT_WJ;
+ if( g_playerStats[client][plBhtopPos] <= 3 )
+ return LT_BJ;
+ if( g_playerStats[client][plJbtopPos] <= 3 )
+ return LT_JB;
+ if( g_playerStats[client][plLajtopPos] <= 3 )
+ return LT_LAJ;
+ if( g_playerStats[client][plBwljtopPos] <= 3 )
+ return LT_BWLJ;
+ if( g_playerStats[client][plSwljtopPos] <= 3 )
+ return LT_SWLJ;
+
+ return LT_END;
+}
+
+public GetPlayerRecordPosition( client, table ) {
+ switch( LJTOP_TABLE:table ) {
+ case LT_LJ: { return g_playerStats[client][plLjtopPos]; }
+ case LT_CJ: { return g_playerStats[client][plCjtopPos]; }
+ case LT_BJ: { return g_playerStats[client][plBhtopPos]; }
+ case LT_JB: { return g_playerStats[client][plJbtopPos]; }
+ case LT_LAJ: { return g_playerStats[client][plLajtopPos]; }
+ case LT_SWLJ: { return g_playerStats[client][plSwljtopPos]; }
+ case LT_BWLJ: { return g_playerStats[client][plBwljtopPos]; }
+ case LT_WJ: { return g_playerStats[client][plWjtopPos]; }
+ }
+
+ return -1;
+}
+
+public SaveStatsForClient( iClient, Handle:hndl ) {
+ g_playerStats[iClient][plKills] = SQL_FetchIntByName( hndl, "kills" );
+ g_playerStats[iClient][plDeaths] = SQL_FetchIntByName( hndl, "deaths" );
+ g_playerStats[iClient][plKDRatio] = SQL_FetchFloatByName( hndl, "kdratio" );
+ g_playerStats[iClient][plPlaytime] = SQL_FetchIntByName( hndl, "playtime" );
+ g_playerStats[iClient][plAlivetime] = SQL_FetchIntByName( hndl, "alivetime" );
+ g_playerStats[iClient][plDeadtime] = SQL_FetchIntByName( hndl, "deadtime" );
+ g_playerStats[iClient][plLjtop] = SQL_FetchFloatByName( hndl, "ljtop" );
+ g_playerStats[iClient][plLjtopPos] = SQL_FetchIntByName( hndl, "ljtoppos" );
+ g_playerStats[iClient][plSwljtop] = SQL_FetchFloatByName( hndl, "swljtop" );
+ g_playerStats[iClient][plSwljtopPos] = SQL_FetchIntByName( hndl, "swljtoppos" );
+ g_playerStats[iClient][plBwljtop] = SQL_FetchFloatByName( hndl, "bwljtop" );
+ g_playerStats[iClient][plBwljtopPos] = SQL_FetchIntByName( hndl, "bwljtoppos" );
+ g_playerStats[iClient][plCjtop] = SQL_FetchFloatByName( hndl, "cjtop" );
+ g_playerStats[iClient][plCjtopPos] = SQL_FetchIntByName( hndl, "cjtoppos" );
+ g_playerStats[iClient][plLajtop] = SQL_FetchFloatByName( hndl, "lajtop" );
+ g_playerStats[iClient][plLajtopPos] = SQL_FetchIntByName( hndl, "lajtoppos" );
+ g_playerStats[iClient][plWjtop] = SQL_FetchFloatByName( hndl, "wjtop" );
+ g_playerStats[iClient][plWjtopPos] = SQL_FetchIntByName( hndl, "wjtoppos" );
+ g_playerStats[iClient][plJbtop] = SQL_FetchFloatByName( hndl, "jbtop" );
+ g_playerStats[iClient][plJbtopPos] = SQL_FetchIntByName( hndl, "jbtoppos" );
+ g_playerStats[iClient][plRoundwins] = SQL_FetchIntByName( hndl, "roundwins" );
+ g_playerStats[iClient][plRoundlosses] = SQL_FetchIntByName( hndl, "roundlosses" );
+
+ decl String:name[64];
+ SQL_FetchStringByName( hndl, "name", name, sizeof(name) );
+ strcopy( g_playerTop[iClient][plName], sizeof(name), name );
+ decl String:steamid[32];
+ SQL_FetchStringByName( hndl, "steamid", steamid, sizeof(steamid) );
+ strcopy( g_playerTop[iClient][plSteamid], sizeof(steamid), steamid );
+
+ UpdatePlayerPoints( iClient );
+}
+
+public SaveStatsForTop( iClient, Handle:hndl ) {
+ g_playerTop[iClient][plKills] = SQL_FetchIntByName( hndl, "kills" );
+ g_playerTop[iClient][plDeaths] = SQL_FetchIntByName( hndl, "deaths" );
+ g_playerTop[iClient][plKDRatio] = SQL_FetchFloatByName( hndl, "kdratio" );
+ g_playerTop[iClient][plPlaytime] = SQL_FetchIntByName( hndl, "playtime" );
+ g_playerTop[iClient][plAlivetime] = SQL_FetchIntByName( hndl, "alivetime" );
+ g_playerTop[iClient][plDeadtime] = SQL_FetchIntByName( hndl, "deadtime" );
+ g_playerTop[iClient][plLjtop] = SQL_FetchFloatByName( hndl, "ljtop" );
+ g_playerTop[iClient][plLjtopPos] = SQL_FetchIntByName( hndl, "ljtoppos" );
+ g_playerTop[iClient][plSwljtop] = SQL_FetchFloatByName( hndl, "swljtop" );
+ g_playerTop[iClient][plSwljtopPos] = SQL_FetchIntByName( hndl, "swljtoppos" );
+ g_playerTop[iClient][plBwljtop] = SQL_FetchFloatByName( hndl, "bwljtop" );
+ g_playerTop[iClient][plBwljtopPos] = SQL_FetchIntByName( hndl, "bwljtoppos" );
+ g_playerTop[iClient][plCjtop] = SQL_FetchFloatByName( hndl, "cjtop" );
+ g_playerTop[iClient][plCjtopPos] = SQL_FetchIntByName( hndl, "cjtoppos" );
+ g_playerTop[iClient][plLajtop] = SQL_FetchFloatByName( hndl, "lajtop" );
+ g_playerTop[iClient][plLajtopPos] = SQL_FetchIntByName( hndl, "lajtoppos" );
+ g_playerTop[iClient][plWjtop] = SQL_FetchFloatByName( hndl, "wjtop" );
+ g_playerTop[iClient][plWjtopPos] = SQL_FetchIntByName( hndl, "wjtoppos" );
+ g_playerTop[iClient][plJbtop] = SQL_FetchFloatByName( hndl, "jbtop" );
+ g_playerTop[iClient][plJbtopPos] = SQL_FetchIntByName( hndl, "jbtoppos" );
+ g_playerTop[iClient][plRoundwins] = SQL_FetchIntByName( hndl, "roundwins" );
+ g_playerTop[iClient][plRoundlosses] = SQL_FetchIntByName( hndl, "roundlosses" );
+ g_playerTop[iClient][plTotalPoints] = SQL_FetchIntByName( hndl, "totalpoints" );
+
+ decl String:name[64];
+ SQL_FetchStringByName( hndl, "name", name, sizeof(name) );
+ strcopy( g_playerTop[iClient][plName], sizeof(name), name );
+ decl String:steamid[32];
+ SQL_FetchStringByName( hndl, "steamid", steamid, sizeof(steamid) );dd
+ strcopy( g_playerTop[iClient][plSteamid], sizeof(steamid), steamid );
+}
+
+public LoadStatsDBCallback( Handle:owner, Handle:hndl, String:error[], any:pack ) {
+ if( hndl == INVALID_HANDLE ) {
+ LogError( "LoadStatsDB failed: %s", error );
+ return;
+ }
+
+ g_statsTOP = SQL_GetRowCount( hndl );
+ for( new i = 0; i < g_statsTOP; i++ ) {
+ SQL_FetchRow( hndl );
+
+ decl String:steamid[32];
+ SQL_FetchStringByName( hndl, "steamid", steamid, sizeof(steamid) );
+ new iClient = 0;
+ for( new i2 = 1; i2 < GetMaxClients(); ++i2 ) {
+ if( !IsClientConnected( i2 ) || !IsClientInGame( i2 ) )
+ continue;
+
+ new String:playerSteamID[32];
+ GetClientAuthString( i2, playerSteamID, sizeof(playerSteamID) );
+ if( !strcmp( playerSteamID, steamid ) ) {
+ iClient = i2;
+ break;
+ }
+ }
+
+ if( iClient != 0 ) {
+ SaveStatsForClient( iClient, hndl );
+ strcopy( g_playerStats[iClient][plSteamid], sizeof(steamid), steamid );
+
+ if( !pack )
+ g_playerStats[iClient][plStatPos] = i;
+ }
+
+ if( i >= STATSTOP_NUM_ENTRIES - 1 || !!pack )
+ continue;
+
+ g_playerTop[i][plStatPos] = i;
+ SaveStatsForTop( i, hndl );
+ }
+}
+
+public CreateStatsDBCallback( Handle:owner, Handle:hndl, String:error[], any:pack ) {
+ if( hndl == INVALID_HANDLE ) {
+ LogError( "CreateStatsDB failed: %s", error );
+ return;
+ }
+
+ SQL_TQuery(g_statsDB, LoadStatsDBCallback, "SELECT * FROM playerstats ORDER BY totalpoints DESC");
+}
+
+public LoadStatsDB() {
+ if( g_statsDB != INVALID_HANDLE ) {
+ CloseHandle(g_statsDB);
+ }
+
+ decl String:error[255];
+ g_statsDB = SQL_Connect("playerstats", true, error, sizeof(error));
+
+ if( g_statsDB == INVALID_HANDLE) {
+ LogError(error);
+ }
+
+ SQL_TQuery(g_statsDB, CreateStatsDBCallback, "CREATE TABLE IF NOT EXISTS playerstats (steamid VARCHAR(32) NOT NULL, name VARCHAR(64) NOT NULL, kills INT NOT NULL, deaths INT NOT NULL, kdratio FLOAT NOT NULL, totalpoints INT NOT NULL, playtime INT NOT NULL, alivetime INT NOT NULL, deadtime INT NOT NULL, ljtop FLOAT NOT NULL, ljtoppos INT NOT NULL, swljtop FLOAT NOT NULL, swljtoppos INT NOT NULL, bwljtop FLOAT NOT NULL, bwljtoppos INT NOT NULL, cjtop FLOAT NOT NULL, cjtoppos INT NOT NULL, lajtop FLOAT NOT NULL, lajtoppos INT NOT NULL, wjtop FLOAT NOT NULL, wjtoppos INT NOT NULL, jbtop FLOAT NOT NULL, jbtoppos INT NOT NULL, roundwins INT NOT NULL, roundlosses INT NOT NULL, PRIMARY KEY (steamid))");
+}
+
+public LoadStatsDBForUser( client ) {
+ if( g_statsDB == INVALID_HANDLE ) {
+ LogMessage( "db invalid" );
+ return;
+ }
+
+ if( !IsClientConnected( client ) || !IsClientInGame( client ) || IsFakeClient( client ) ) {
+ LogMessage( "client not connected" );
+ return;
+ }
+
+ decl String:steamid[32];
+ GetClientAuthString( client, steamid, sizeof(steamid) );
+ for( new i = 0; i < g_statsTOP; ++i ) {
+ if( !strcmp( g_playerTop[i][plSteamid], steamid ) ) {
+ g_playerStats[client][plKills] = g_playerTop[i][plKills];
+ g_playerStats[client][plDeaths] = g_playerTop[i][plDeaths];
+ g_playerStats[client][plKDRatio] = g_playerTop[i][plKDRatio];
+ g_playerStats[client][plPlaytime] = g_playerTop[i][plPlaytime];
+ g_playerStats[client][plAlivetime] = g_playerTop[i][plAlivetime];
+ g_playerStats[client][plDeadtime] = g_playerTop[i][plDeadtime];
+ g_playerStats[client][plLjtop] = g_playerTop[i][plLjtop];
+ g_playerStats[client][plLjtopPos] = g_playerTop[i][plLjtopPos];
+ g_playerStats[client][plSwljtop] = g_playerTop[i][plSwljtop];
+ g_playerStats[client][plSwljtopPos] = g_playerTop[i][plSwljtopPos];
+ g_playerStats[client][plBwljtop] = g_playerTop[i][plBwljtop];
+ g_playerStats[client][plBwljtopPos] = g_playerTop[i][plBwljtopPos];
+ g_playerStats[client][plCjtop] = g_playerTop[i][plCjtop];
+ g_playerStats[client][plCjtopPos] = g_playerTop[i][plCjtopPos];
+ g_playerStats[client][plLajtop] = g_playerTop[i][plLajtop];
+ g_playerStats[client][plLajtopPos] = g_playerTop[i][plLajtopPos];
+ g_playerStats[client][plWjtop] = g_playerTop[i][plWjtop];
+ g_playerStats[client][plWjtopPos] = g_playerTop[i][plWjtopPos];
+ g_playerStats[client][plJbtop] = g_playerTop[i][plJbtop];
+ g_playerStats[client][plJbtopPos] = g_playerTop[i][plJbtopPos];
+ g_playerStats[client][plRoundwins] = g_playerTop[i][plRoundwins];
+ g_playerStats[client][plRoundlosses] = g_playerTop[i][plRoundlosses];
+
+ decl String:name[64];
+ strcopy( name, sizeof(name), g_playerTop[i][plName] );
+ strcopy( g_playerStats[client][plName], sizeof(name), name );
+
+ g_playerStats[client][plStatPos] = i;
+ }
+ }
+
+ decl String:query[1024];
+ Format( query, sizeof(query), "SELECT * FROM playerstats WHERE steamid='%s'", steamid );
+
+ SQL_TQuery(g_statsDB, LoadStatsDBCallback, query, true );
+}
+
+public SaveStatsDBCallback( Handle:owner, Handle:hndl, String:error[], any:pack ) {
+ if( hndl == INVALID_HANDLE || error[0] != '\0' ) {
+ LogError( "SaveStatsDB failed: %s", error );
+ return;
+ }
+}
+
+public SaveStatsDBForPlayer( client ) {
+ UpdatePlayerPoints( client );
+ if( g_statsDB == INVALID_HANDLE )
+ return;
+
+ if( IsFakeClient( client ) )
+ return;
+
+ decl String:steamid[32];
+ if( !GetClientAuthString( client, steamid, sizeof(steamid) ) )
+ return;
+
+ decl String:name[64];
+ GetClientName( client, name, sizeof(name) );
+
+ decl nIndex;
+ while((nIndex = FindCharInString(name, ';')) != -1) {
+ name[nIndex] = '-';
+ }
+
+ decl String:query[1024];
+ new i = client;
+ // actually fucking cursed
+ Format( query, sizeof(query), "INSERT OR REPLACE INTO playerstats (name, kills, deaths, kdratio, totalpoints, playtime, alivetime, deadtime, ljtop, ljtoppos, swljtop, swljtoppos, bwljtop, bwljtoppos, cjtop, cjtoppos, lajtop, lajtoppos, wjtop, wjtoppos, jbtop, jbtoppos, roundwins, roundlosses, steamid) VALUES ('%s', %d, %d, %f, %d, %d, %d, %d, %f, %d, %f, %d, %f, %d, %f, %d, %f, %d, %f, %d, %f, %d, %d, %d, '%s')",
+ name,
+ g_playerStats[i][plKills],
+ g_playerStats[i][plDeaths],
+ g_playerStats[i][plKDRatio],
+ g_playerStats[i][plTotalPoints],
+ g_playerStats[i][plPlaytime],
+ g_playerStats[i][plAlivetime],
+ g_playerStats[i][plDeadtime],
+ g_playerStats[i][plLjtop],
+ g_playerStats[i][plLjtopPos],
+ g_playerStats[i][plSwljtop],
+ g_playerStats[i][plSwljtopPos],
+ g_playerStats[i][plBwljtop],
+ g_playerStats[i][plBwljtopPos],
+ g_playerStats[i][plCjtop],
+ g_playerStats[i][plCjtopPos],
+ g_playerStats[i][plLajtop],
+ g_playerStats[i][plLajtopPos],
+ g_playerStats[i][plWjtop],
+ g_playerStats[i][plWjtopPos],
+ g_playerStats[i][plJbtop],
+ g_playerStats[i][plJbtopPos],
+ g_playerStats[i][plRoundwins],
+ g_playerStats[i][plRoundlosses],
+ steamid
+ );
+
+ SQL_TQuery(g_statsDB, SaveStatsDBCallback, query );
+}
+
+public SaveStatsDB() {
+ if( g_statsDB == INVALID_HANDLE )
+ return;
+
+ for( new i = 1; i < MaxClients; ++i ) {
+ if( !IsClientConnected( i ) || !IsClientInGame( i ) || IsFakeClient( i ) )
+ continue;
+
+ SaveStatsDBForPlayer( i );
+ }
+}
+
+public Action:OnClientSayCommand( client, const String:command[], const String:args[] ) {
+ new String:fullOut[512];
+
+ new bool:dead = !IsPlayerAlive( client );
+ new bool:teamchat = strcmp( command, "say_team" ) == 0;
+ if( dead )
+ Format( fullOut, sizeof(fullOut), "*DEAD* " );
+
+ if( teamchat ) {
+ new team = GetClientTeam( client );
+ if( team < 2 )
+ Format( fullOut, sizeof(fullOut), "%s(SPEC) ", fullOut );
+ else if( team == 2 )
+ Format( fullOut, sizeof(fullOut), "%s(Terrorist) ", fullOut );
+ else if( team == 3 )
+ Format( fullOut, sizeof(fullOut), "%s(Counter-Terrorist) ", fullOut );
+ }
+
+ new LJTOP_TABLE:recordTable = HasRecord( client );
+ new pos = GetPlayerRecordPosition( client, _:recordTable );
+
+ if( g_playerStats[client][plStatPos] <= 2 && g_playerStats[client][plStatPos] > -1 ) {
+ new statpos = g_playerStats[client][plStatPos] + 1;
+
+ new String:color[16];
+ strcopy( color, sizeof(color), g_playerRankColorsTop3[statpos - 1] );
+
+ Format( fullOut, sizeof(fullOut), "%s{unique}[%s#%d{unique}] ", fullOut, color, statpos );
+ }
+ else if( recordTable != LT_END && pos > 0 ) {
+ new String:color[16];
+ strcopy( color, sizeof(color), g_playerRankColorsTop3[pos - 1] );
+ new String:tableName[16];
+ strcopy( tableName, sizeof(tableName), g_strLJTopTags[_:recordTable] );
+
+ Format( fullOut, sizeof(fullOut), "%s{black}[%s%s #%d{black}] ", fullOut, color, tableName, pos );
+ }
+ else {
+ new Float:score = GetPlayerPoints( client );
+ new rank = 0;
+ for( new i = 0; i < sizeof( g_playerRanks ); ++i ) {
+ if( score > g_rankPointsNeeded[i] )
+ rank = i;
+ else break;
+ }
+
+ new String:rankString[16];
+ strcopy( rankString, sizeof(rankString), g_playerRanks[rank] );
+ new String:bracketColor[16];
+ strcopy( bracketColor, sizeof(bracketColor), g_playerRankBracketColors[rank] );
+ new String:color[16];
+ strcopy( color, sizeof(color), g_playerRankColors[rank] );
+
+ Format( fullOut, sizeof(fullOut), "%s%s[%s%s%s]", fullOut, bracketColor, color, rankString, bracketColor );
+ }
+
+ new String:name[64];
+ GetClientName( client, name, sizeof(name) );
+ Format( fullOut, sizeof(fullOut), "%s{teamcolor}%s {default}: ", fullOut, name );
+ Format( fullOut, sizeof(fullOut), "%s%s", fullOut, args );
+
+ if( !teamchat )
+ CPrintToChatAllEx( client, fullOut );
+ else {
+ for( new i = 1; i < MaxClients; ++i ) {
+ if( !IsClientConnected( i ) || !IsClientInGame( i ) )
+ continue;
+ if( GetClientTeam( i ) != GetClientTeam( client ) )
+ continue;
+ CPrintToChatEx( i, client, fullOut );
+ }
+ }
+
+ return Plugin_Handled;
+}
+
+public Action:Command_SaveStats( client, args ) {
+ SaveStatsDB();
+ CPrintToChat( client, "{green}Stats saved!" );
+
+ return Plugin_Handled;
+}
+
+public Action:Timer_SendMsg4( Handle: timer, any: client ) {
+ new String:chatOutput[1024];
+ Format( chatOutput, sizeof(chatOutput), "%s\n", chatOutput );
+ if( g_playerStats[client][plStatPos] > -1 ) {
+ new String:color[16];
+ if( g_playerStats[client][plStatPos] <= 2 )
+ strcopy( color, sizeof(color), g_playerRankColorsTop3[g_playerStats[client][plStatPos]] );
+ else {
+ new score = g_playerStats[client][plTotalPoints];
+ new rank = 0;
+ for( new i = 0; i < sizeof( g_playerRanks ); ++i ) {
+ if( score > g_rankPointsNeeded[i] )
+ rank = i;
+ else break;
+ }
+ strcopy( color, sizeof(color), g_playerRankColors[rank] );
+ }
+ Format( chatOutput, sizeof(chatOutput), "%s{white}You are ranked %s#%d{default}/{green}%d {default}\n", chatOutput, color, g_playerStats[client][plStatPos] + 1, g_statsTOP );
+ }
+ Format( chatOutput, sizeof(chatOutput), "%s{white}Total points {default}: {green}%d\n", chatOutput, g_playerStats[client][plTotalPoints] );
+
+ CPrintToChatEx( client, client, chatOutput );
+}
+
+public Action:Timer_SendMsg3( Handle: timer, any: client ) {
+ new String:chatOutput[1024];
+ if( g_playerStats[client][plBhtop] > 0 )
+ Format( chatOutput, sizeof(chatOutput), "%s{white}BH Top {default}: {green}%0.2f (#%d/%d) {default}(%0.0fpts)\n", chatOutput, g_playerStats[client][plBhtop], g_playerStats[client][plBhtopPos], g_LJTopMax[LT_BJ] + 1, GetLJScore( client, _:LT_BJ ) );
+ else
+ Format( chatOutput, sizeof(chatOutput), "%s{white}BH Top {default}: {default}N/A\n", chatOutput );
+
+ if( g_playerStats[client][plJbtop] > 0 )
+ Format( chatOutput, sizeof(chatOutput), "%s{white}JB Top {default}: {green}%0.2f (#%d/%d) {default}(%0.0fpts)\n", chatOutput, g_playerStats[client][plJbtop], g_playerStats[client][plJbtopPos], g_LJTopMax[LT_JB] + 1, GetLJScore( client, _:LT_JB ) );
+ else
+ Format( chatOutput, sizeof(chatOutput), "%s{white}JB Top {default}: {default}N/A\n", chatOutput );
+
+ if( g_playerStats[client][plLajtop] > 0 )
+ Format( chatOutput, sizeof(chatOutput), "%s{white}LAJ Top {default}: {green}%0.2f (#%d/%d) {default}(%0.0fpts)\n", chatOutput, g_playerStats[client][plLajtop], g_playerStats[client][plLajtopPos], g_LJTopMax[LT_LAJ] + 1, GetLJScore( client, _:LT_LAJ ) );
+ else
+ Format( chatOutput, sizeof(chatOutput), "%s{white}LAJ Top {default}: {default}N/A\n", chatOutput );
+
+ if( g_playerStats[client][plWjtop] > 0 )
+ Format( chatOutput, sizeof(chatOutput), "%s{white}WJ Top {default}: {green}%0.2f (#%d/%d) {default}(%0.0fpts)\n", chatOutput, g_playerStats[client][plWjtop], g_playerStats[client][plWjtopPos], g_LJTopMax[LT_WJ] + 1, GetLJScore( client, _:LT_WJ ) );
+ else
+ Format( chatOutput, sizeof(chatOutput), "%s{white}WJ Top {default}: {default}N/A\n", chatOutput );
+
+ CPrintToChatEx( client, client, chatOutput );
+ CreateTimer( 0.1, Timer_SendMsg4, client, TIMER_FLAG_NO_MAPCHANGE );
+
+ return Plugin_Continue;
+}
+
+public Action:Timer_SendMsg2( Handle: timer, any: client ) {
+ new String:chatOutput[1024];
+ Format( chatOutput, sizeof(chatOutput), "" );
+ if( g_playerStats[client][plLjtop] > 0 )
+ Format( chatOutput, sizeof(chatOutput), "%s{white}LJ Top {default}: {green}%0.2f (#%d/%d) {default}(%0.0fpts)\n", chatOutput, g_playerStats[client][plLjtop], g_playerStats[client][plLjtopPos], g_LJTopMax[LT_LJ] + 1, GetLJScore( client, _:LT_LJ ) );
+ else
+ Format( chatOutput, sizeof(chatOutput), "%s{white}LJ Top {default}: {default}N/A\n", chatOutput );
+
+ if( g_playerStats[client][plSwljtop] > 0 )
+ Format( chatOutput, sizeof(chatOutput), "%s{white}SWLJ Top {default}: {green}%0.2f (#%d/%d) {default}(%0.0fpts)\n", chatOutput, g_playerStats[client][plSwljtop], g_playerStats[client][plSwljtopPos], g_LJTopMax[LT_SWLJ] + 1, GetLJScore( client, _:LT_SWLJ ) );
+ else
+ Format( chatOutput, sizeof(chatOutput), "%s{white}SWLJ Top {default}: {default}N/A\n", chatOutput );
+
+ if( g_playerStats[client][plBwljtop] > 0 )
+ Format( chatOutput, sizeof(chatOutput), "%s{white}BWLJ Top {default}: {green}%0.2f (#%d/%d) {default}(%0.0fpts)\n", chatOutput, g_playerStats[client][plBwljtop], g_playerStats[client][plBwljtopPos], g_LJTopMax[LT_BWLJ] + 1, GetLJScore( client, _:LT_BWLJ ) );
+ else
+ Format( chatOutput, sizeof(chatOutput), "%s{white}BWLJ Top {default}: {default}N/A\n", chatOutput );
+ if( g_playerStats[client][plCjtop] > 0 )
+ Format( chatOutput, sizeof(chatOutput), "%s{white}CJ Top {default}: {green}%0.2f (#%d/%d) {default}(%0.0fpts)\n", chatOutput, g_playerStats[client][plCjtop], g_playerStats[client][plCjtopPos], g_LJTopMax[LT_CJ] + 1, GetLJScore( client, _:LT_CJ ) );
+ else
+ Format( chatOutput, sizeof(chatOutput), "%s{white}CJ Top {default}: {default}N/A\n", chatOutput );
+
+ CPrintToChatEx( client, client, chatOutput );
+
+ CreateTimer( 0.1, Timer_SendMsg3, client, TIMER_FLAG_NO_MAPCHANGE );
+ return Plugin_Continue;
+}
+
+public Action:Timer_SendMsg( Handle: Timer, any: client ) {
+ new String:chatOutput[1024];
+
+ Format( chatOutput, sizeof(chatOutput), "%s{white}Kills {default}: {green}%d {default}(%dpts)\n", chatOutput, g_playerStats[client][plKills], g_playerStats[client][plKills] / 2 );
+ Format( chatOutput, sizeof(chatOutput), "%s{white}Deaths {default}: {green}%d {default}(-%dpts)\n", chatOutput, g_playerStats[client][plDeaths], g_playerStats[client][plDeaths] / 2 );
+
+ new Float:kdScore = GetKDScore( client );
+ Format( chatOutput, sizeof(chatOutput), "%s{white}K/D Ratio {default}: {green}%0.2f {default}(%dpts)\n\n", chatOutput, g_playerStats[client][plKDRatio], RoundFloat( kdScore ) );
+
+ CPrintToChatEx( client, client, chatOutput );
+
+ CreateTimer( 0.1, Timer_SendMsg2, client, TIMER_FLAG_NO_MAPCHANGE );
+}
+
+public DisplayClientStatsToSelf( client ) {
+ UpdatePlayerPoints( client );
+ new String:steamid[32];
+ GetClientAuthString( client, steamid, sizeof(steamid) );
+ new String:name[64];
+ GetClientName( client, name, sizeof(name) );
+
+ new String:chatOutput[1024];
+ Format( chatOutput, sizeof(chatOutput), "{teamcolor}%s{default}'s ({green}%s{default}) stats:\n", name, steamid );
+ new playtime = g_playerStats[client][plPlaytime];
+ new hours = playtime / 3600;
+ new minutes = playtime / 60;
+ new seconds = playtime % 60;
+ Format( chatOutput, sizeof(chatOutput), "%s{white}Playtime {default}: {green}%dh %dm %ds\n", chatOutput, hours, minutes, seconds );
+ new alivetime = g_playerStats[client][plAlivetime];
+ hours = alivetime / 3600;
+ minutes = alivetime / 60;
+ seconds = alivetime % 60;
+ Format( chatOutput, sizeof(chatOutput), "%s{white}Alive time {default}: {green}%dh %dm %ds\n", chatOutput, hours, minutes, seconds );
+ new deadtime = g_playerStats[client][plDeadtime];
+ hours = deadtime / 3600;
+ minutes = deadtime / 60;
+ seconds = deadtime % 60;
+ Format( chatOutput, sizeof(chatOutput), "%s{white}Dead time {default}: {green}%dh %dm %ds\n", chatOutput, hours, minutes, seconds );
+
+/*
+ Format( chatOutput, sizeof(chatOutput), "%s\n", chatOutput);
+ Format( chatOutput, sizeof(chatOutput), "%s{teamcolor}Round wins: {default}%d (%dpts)\n", chatOutput, g_playerStats[client][plRoundwins], g_playerStats[client][plRoundwins] / 2 );
+ Format( chatOutput, sizeof(chatOutput), "%s{teamcolor}Round losses: {default}%d (-%dpts)\n", chatOutput, g_playerStats[client][plRoundlosses], g_playerStats[client][plRoundlosses] / 2 );
+*/
+
+ CPrintToChatEx( client, client, chatOutput );
+ CreateTimer( 0.1, Timer_SendMsg, client, TIMER_FLAG_NO_MAPCHANGE );
+}
+
+public DisplayClientStats( client, target ) {
+ UpdatePlayerPoints( client );
+ new String:chatOutput[1024];
+ new String:name[64];
+ new String:steamId[32];
+ GetClientName( client, name, sizeof(name) );
+ GetClientAuthString( client, steamId, sizeof(steamId) );
+
+ if( g_playerStats[client][plStatPos] > -1 ) {
+ new String:color[16];
+ if( g_playerStats[client][plStatPos] <= 2 )
+ strcopy( color, sizeof(color), g_playerRankColorsTop3[g_playerStats[client][plStatPos]] );
+ else {
+ new score = g_playerStats[client][plTotalPoints];
+ new rank = 0;
+ for( new i = 0; i < sizeof( g_playerRanks ); ++i ) {
+ if( score > g_rankPointsNeeded[i] )
+ rank = i;
+ else break;
+ }
+ strcopy( color, sizeof(color), g_playerRankColors[rank] );
+ }
+ Format( chatOutput, sizeof(chatOutput), "%s{teamcolor}%s {default}({green}%s{default}) is ranked %s#%d{default}/{green}%d {default}\n", chatOutput, name, steamId, color, g_playerStats[client][plStatPos] + 1, g_statsTOP );
+ }
+ Format( chatOutput, sizeof(chatOutput), "%s{teamcolor}%s{default}'s points : {green}%d\n", chatOutput, name, g_playerStats[client][plTotalPoints] );
+
+ CPrintToChatEx( target, client, chatOutput );
+}
+
+public DisplayTopStats( client, target ) {
+ new String:chatOutput[1024];
+ new String:name[64];
+ new String:steamId[32];
+ new String:color[16];
+ strcopy( name, sizeof(name), g_playerTop[client][plName] );
+ strcopy( steamId, sizeof(steamId), g_playerTop[client][plSteamid] );
+
+ new pos = client;
+ if( pos <= 2 )
+ strcopy( color, sizeof(color), g_playerRankColorsTop3[pos] );
+ else {
+ new score = g_playerTop[client][plTotalPoints];
+ new rank = 0;
+ for( new i = 0; i < sizeof( g_playerRanks ); ++i ) {
+ if( score > g_rankPointsNeeded[i] )
+ rank = i;
+ else break;
+ }
+ strcopy( color, sizeof(color), g_playerRankColors[rank] );
+ }
+ Format( chatOutput, sizeof(chatOutput), "%s{white}%s {default}({green}%s{default}) is ranked %s#%d{default}/{green}%d {default}\n", chatOutput, name, steamId, color, pos + 1, g_statsTOP );
+ Format( chatOutput, sizeof(chatOutput), "%s{white}%s{default}'s points : {green}%d\n", chatOutput, name, g_playerTop[client][plTotalPoints] );
+
+ CPrintToChat( target, chatOutput );
+}
+
+public Action:Command_Stats( client, args ) {
+ if( client <= 0 )
+ return Plugin_Handled;
+
+ if( args == 0 ) {
+ DisplayClientStatsToSelf( client );
+ }
+ else if( args == 1 ) {
+ decl String:arg[128];
+ GetCmdArg( 1, arg, sizeof(arg) );
+
+ new top = StringToInt( arg );
+ if( top > 0 && top < g_statsTOP + 1 ) {
+ if( top > g_statsTOP ) {
+ CPrintToChat( client, "{fuchsia}There are only {green}%d {fuchsia}players in the database.", g_statsTOP );
+ return Plugin_Handled;
+ }
+
+ DisplayTopStats( top - 1, client );
+ return Plugin_Handled;
+ }
+
+ for( new i = 1; i < GetMaxClients(); ++i ) {
+ if( !IsClientConnected( i ) || !IsClientInGame( i ) || IsFakeClient( i ) ) {
+ continue;
+ }
+
+ new String:name[64];
+ GetClientName( i, name, sizeof(name) );
+ if( !strcmp( name, arg, false ) ) {
+ DisplayClientStats( i, client );
+ return Plugin_Handled;
+ }
+ }
+
+ CPrintToChat( client, "{fuchsia}Player not found." );
+ }
+ else {
+ CPrintToChat( client, "{fuchsia}Usage: /stats or /stats [player] or /stats [1-1000]" );
+ }
+
+ return Plugin_Handled;
+}
+
+new timerCount;
+public Action:Timer_PlaytimeTick( Handle: timer, any: unused ) {
+ for( new i = 1; i < MaxClients; ++i ) {
+ if( !IsClientConnected( i ) || !IsClientInGame( i ) || IsFakeClient( i ) )
+ continue;
+
+ g_playerStats[i][plPlaytime]++;
+ if( IsPlayerAlive( i ) )
+ g_playerStats[i][plAlivetime]++;
+ else if( GetClientTeam( i ) > 1 )
+ g_playerStats[i][plDeadtime]++;
+ }
+
+ if( ++timerCount > 60 ) {
+ timerCount = 0;
+ SaveStatsDB();
+ }
+}
+
+public Action:Event_PlayerDeath( Handle:event, const String:name[], bool:dontBroadcast ) {
+ if( nh_warmup == INVALID_HANDLE ) {
+ nh_warmup = FindConVar( "nh_warmup" );
+ }
+
+ new dm = GetConVarInt( nh_warmup ) != 0;
+ if( dm )
+ return Plugin_Continue;
+
+ new killeruid = GetEventInt( event, "attacker" );
+ new targetuid = GetEventInt( event, "userid" );
+
+ if( !killeruid || !targetuid )
+ return Plugin_Continue;
+
+ new killer = GetClientOfUserId( killeruid );
+ new _target = GetClientOfUserId( targetuid );
+
+ if( !killer || !_target )
+ return Plugin_Continue;
+
+ if( killer && IsClientConnected( killer ) && !IsFakeClient( killer ) && !IsFakeClient( _target ) ) {
+ LogMessage( "killer kills: %d", g_playerStats[killer][plKills] );
+ g_playerStats[killer][plKills]++;
+ }
+ if( _target && IsClientConnected( _target ) && !IsFakeClient( _target ) ) {
+ g_playerStats[_target][plDeaths]++;
+ LogMessage( "target deaths: %d", g_playerStats[_target][plDeaths] );
+ }
+
+ new killerKills = g_playerStats[killer][plKills];
+ new killerDeaths = g_playerStats[killer][plDeaths];
+ new targetKills = g_playerStats[_target][plKills];
+ new targetDeaths = g_playerStats[_target][plDeaths];
+
+ if( targetDeaths <= 0 )
+ targetDeaths = 1;
+ if( killerDeaths <= 0 )
+ killerDeaths = 1;
+
+ g_playerStats[killer][plKDRatio] = Float:killerKills / Float:killerDeaths;
+ g_playerStats[_target][plKDRatio] = Float:targetKills / Float:targetDeaths;
+
+ if( !IsFakeClient( killer ) )
+ SaveStatsDBForPlayer( killer );
+ if( !IsFakeClient( _target ) )
+ SaveStatsDBForPlayer( _target );
+
+ return Plugin_Continue;
+} \ No newline at end of file