#include <amxmodx>
#include <engine>
#include <sqlx>
#include <player_stats>
#define MYSQL_HOST "127.0.0.1"
#define MYSQL_USER ""
#define MYSQL_PASS ""
#define MYSQL_DBDB ""
#define UpdateStatsType 2
// 1 - Odswiez statystyki gracza (ofiary / zabojcy) po zabiciu
// Jesli twoja BazaDanych jest gowniana uzyj tego
//
// 2 - Aktualizuj statystyki wszystkich graczy podczas timera , lub podczas zapytania /top15 /rank etc.
// Как по мне, ŃĐ°ĐĽŃ‹Đą адекватный ŃпоŃоб :)
//
// 3 - Zabtualizuj statystyki graczy po zabiciu kogos
// Statystyki sa dokladniejsze od UpdateStatsType 1 i UpdateStatsType 2, ale ciezsze
// Uzyj tego jesli potrzebujesz dokladniejszych danych, a twoja BD poradzi sobie z takim obciazeniem
//
// Конечно же обновление и при диŃконнекте!
#define FreqUpdateByTime 20.0
// Aktualizuj czestotliwosc dla UpdateStatsType 2
// Jesli nie korzystasz z web zakomenduj to
#define PrunedDays 10
// Ile dni zajmuje usuniecie gracza z bazy danych od ostatniego polaczenia
#define AntiFloodSecs 20
// Ochrona przed floodowaniem bazy danych
// СпаŃает от идиотов, которые долбят ŃŃ‚Đ°Ń‚Ń ĐżĐľŃтоянно, вызывая лаги
// W skrocie blokuje cweli co napierdalaja status w konsole
#define SendMeAndHpOnDeath
// Wyslij info do ofiary o say /me i say /hp
#define KillAssist 50
// Liczenie asyst
// name1 + name2 by max damage
// Liczba - minimalne obrazena ma byc liczona asysta
new const g_arrViewSkills[][] =
{
"L-", "LS", "L+", "M-", "MS", "M+", "H-", "HS", "H+", "P-", "PS", "P+", "G"
};
new const g_arrItemSkills[] =
{
0, 60, 75, 85, 100, 115, 130, 140, 150, 165, 180, 195, 210
};
new const g_arrBodyParts[HIT_RIGHTLEG + 1][] =
{
"W cialo", "W glowe", "W klate", "W brzuch", "W lewa reke", "W prawa reke", "W lewa noge", "W prawa noge"
};
enum GetStatsStates
{
StatsNone = 666,
StatsRank,
StatsRankStats,
StatsTop15,
StatsMe,
StatsHp
};
enum _:QueryStates
{
LoadPlayer,
SavePlayer,
ResetStats,
RemoveLols
};
enum _:PlayerData
{
Frags,
Deaths,
HS,
Damage,
Shots,
Hits,
bPlanted,
bDefused,
bExploded,
#if defined KillAssist
aPlayers,
#endif
CLEAR_DATA,
#if defined KillAssist
aDamage[33],
#endif
Damage2,
LastHit,
KillerId,
KillerName[32],
Float:fDistance,
Float:fHpKiller,
Float:fApKiller,
Float:Skill,
hBox[HIT_RIGHTLEG + 1],
GameTime,
LastGetStats, // ochrona przed flood BazyDanych
AuthId[25] // cash steamID
};
#if !defined MAX_PLAYERS
const MAX_PLAYERS = 32;
#endif
#if AMXX_VERSION_NUM < 183
#include <colorchat>
#define replace_string replace_all
#define client_disconnected client_disconnect
new MaxClients;
#endif
const MAX_QUERY_LENGTH = 1000;
new g_arrPlayerData[MAX_PLAYERS + 1][PlayerData];
new Handle:g_hSqlTuple;
new g_szQuery[MAX_QUERY_LENGTH], data[3];
new g_szAllPlayersUpdateQuery[18000];
new g_iLastUpdate;
new bool:g_bMySqlConnection,
bool:g_bResetStats;
#define IsUserValid(%0) (1 <= %0 <= MaxClients)
RegisterCmds()
{
register_srvcmd("remove_stats", "SrvCMD_RemoveStats");
register_clcmd("say /rank", "clCMD_SayRank");
register_clcmd("say /rankstats", "clCMD_SayRankStats");
register_clcmd("say /top15", "clCMD_SayTop15");
register_clcmd("say /me", "clCMD_SayMe");
register_clcmd("say /hp", "clCMD_SayHp");
}
RegisterEvents()
{
register_event("Damage", "eventDamage", "b", "2!0");
register_event("DeathMsg", "eventDeathMsg", "a", "1>0");
register_event("CurWeapon", "eventCurWeapon", "be", "1=1", "3>-1");
register_event("BarTime", "eventBarTimePlant", "be", "1=3");
register_event("BarTime", "eventBarTimeDefuse", "be", "1!3");
register_event("TextMsg", "eventBombPlanted", "a", "2=#Bomb_Planted");
register_event("TextMsg", "eventBombDefused", "a", "2=#Bomb_Defused");
register_event("TextMsg", "eventBombTargetBombed", "a", "2=#Target_Bombed");
register_event("HLTV", "ResetDamage", "a", "1=0", "2=0");
register_logevent("UpdateAllStats", 2, "1=Round_End");
}
public plugin_natives()
{
register_library("PlayerStats");
register_native("ps_remove_player", "native_ps_remove_player", 1);
register_native("ps_setinfo_player", "native_ps_setinfo_player", 1);
register_native("ps_get_player_damage", "native_ps_get_player_damage", 1);
register_native("ps_get_player_gametime", "native_ps_get_player_gametime", 1);
}
public plugin_init()
{
register_plugin("Players MySQL Stats", "1.2", "neugomon");
RegisterCmds();
RegisterEvents();
#if defined FreqUpdateByTime && UpdateStatsType == 2
set_task(FreqUpdateByTime, "UpdateAllStats", 13333, .flags = "b");
#endif
#if AMXX_VERSION_NUM < 183
MaxClients = get_maxplayers();
#endif
}
public plugin_cfg()
{
SQL_SetAffinity("mysql");
g_hSqlTuple = SQL_MakeDbTuple(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DBDB, 1);
#if AMXX_VERSION_NUM >= 183
SQL_SetCharset(g_hSqlTuple, "utf8");
#endif
CheckMySQLConnection();
}
/*
public plugin_end()
UpdateAllStats(0, StatsNone);
*/
public client_putinserver(id)
{
if(!g_bMySqlConnection || g_bResetStats)
return;
arrayset(g_arrPlayerData[id], 0, PlayerData);
#if defined KillAssist
arrayset(_:g_arrPlayerData[id][aDamage], 0, sizeof g_arrPlayerData[][aDamage]);
#endif
data[0] = LoadPlayer;
data[1] = id;
get_user_authid(id, g_arrPlayerData[id][AuthId], charsmax(g_arrPlayerData[][AuthId]));
formatex(g_szQuery, charsmax(g_szQuery), "SELECT `skill`, `harray`, `gametime` FROM `players_stats` WHERE `authid` = '%s'", g_arrPlayerData[id][AuthId]);
SQL_ThreadQuery(g_hSqlTuple, "SqlQueryHandler", g_szQuery, data, sizeof(data));
}
public client_disconnected(id)
{
if(g_bMySqlConnection && !g_bResetStats)
{
g_arrPlayerData[id][GameTime] += get_user_time(id, 1);
UpdateStats(id, false);
}
}
public eventCurWeapon(id)
{
static plClips[33], plWeapon[33];
static weapon, clips;
weapon = read_data(2);
clips = read_data(3);
if(plClips[id] > clips && weapon == plWeapon[id])
g_arrPlayerData[id][Shots]++;
plWeapon[id] = weapon;
plClips[id] = clips;
}
public eventDamage(id)
{
if(IsUserValid(id))
{
static hitplace, attacker;
attacker = get_user_attacker(id, 0, hitplace);
if(IsUserValid(attacker) && attacker != id)
{
g_arrPlayerData[attacker][hBox][hitplace]++;
g_arrPlayerData[attacker][Hits]++;
static dmg; dmg = read_data(2);
g_arrPlayerData[attacker][Damage] += dmg;
g_arrPlayerData[attacker][Damage2] += dmg;
g_arrPlayerData[attacker][LastHit] = hitplace;
#if defined KillAssist
g_arrPlayerData[attacker][aDamage][id] += dmg;
#endif
}
}
}
public eventDeathMsg()
{
new killer = read_data(1);
new victim = read_data(2);
if(killer != victim)
{
g_arrPlayerData[killer][Frags]++;
if(read_data(3) == HIT_HEAD)
g_arrPlayerData[killer][HS]++;
new Float:delta = 1.0 / (1.0 + floatpower(10.0, (g_arrPlayerData[killer][Skill] - g_arrPlayerData[victim][Skill]) / 100.0));
g_arrPlayerData[killer][Skill] += (g_arrPlayerData[killer][Frags] < 100) ? (delta * 2.0) : (delta * 1.5);
g_arrPlayerData[victim][Skill] -= (g_arrPlayerData[victim][Frags] < 100) ? (delta * 2.0) : (delta * 1.5);
g_arrPlayerData[victim][fHpKiller] = _:entity_get_float(killer, EV_FL_health);
g_arrPlayerData[victim][fApKiller] = _:entity_get_float(killer, EV_FL_armorvalue);
g_arrPlayerData[victim][fDistance] = is_user_connected(victim) ? (_:(entity_range(killer, victim) / 32.0)) : (_:0.0);
g_arrPlayerData[victim][KillerId] = killer;
get_user_name(killer, g_arrPlayerData[victim][KillerName], charsmax(g_arrPlayerData[][KillerName]));
#if defined SendMeAndHpOnDeath
GetStats(victim, StatsMe);
GetStats(victim, StatsHp);
#endif
#if defined KillAssist
new iBestPlayer;
for(new i = 1, maxDamage = KillAssist; i <= MaxClients; i++)
{
if(g_arrPlayerData[i][aDamage][victim] > maxDamage)
{
maxDamage = g_arrPlayerData[i][aDamage][victim];
iBestPlayer = i;
}
}
if(iBestPlayer != killer && is_user_connected(iBestPlayer))
{
g_arrPlayerData[iBestPlayer][aPlayers]++;
new szNameVictim[32];
get_user_name(victim, szNameVictim, charsmax(szNameVictim));
client_print_color(
iBestPlayer,
print_team_default,
"^1[^4Stats^1] Pomogles ^3%s ^1zabic ^3%s ^1zadales ^3%d^4dmg^1.",
g_arrPlayerData[victim][KillerName],
szNameVictim,
g_arrPlayerData[iBestPlayer][aDamage][victim]
);
}
#endif
}
g_arrPlayerData[victim][Deaths]++;
#if UpdateStatsType == 1
if(g_bMySqlConnection && !g_bResetStats)
{
UpdateStats(killer, false);
if(killer != victim)
UpdateStats(victim, false);
}
#endif
#if UpdateStatsType == 3
UpdateAllStats(0, StatsNone);
#endif
}
new g_planter, g_defuser;
public eventBombPlanted() g_arrPlayerData[g_planter][bPlanted]++;
public eventBombDefused() g_arrPlayerData[g_defuser][bDefused]++;
public eventBombTargetBombed()g_arrPlayerData[g_planter][bExploded]++;
public eventBarTimePlant(id) g_planter = id;
public eventBarTimeDefuse(id) g_defuser = id;
public SrvCMD_RemoveStats()
{
if(!g_bMySqlConnection)
{
log_amx("[Remove Stats] SQL Connection Error! Stats reset FAILED!");
return PLUGIN_HANDLED;
}
if(g_bResetStats)
{
log_amx("[Remove Stats] Stats already removed!");
return PLUGIN_HANDLED;
}
data[0] = ResetStats;
SQL_ThreadQuery(g_hSqlTuple, "SqlQueryHandler", "TRUNCATE `players_stats`", data, sizeof(data));
return PLUGIN_HANDLED;
}
public ResetDamage()
{
for(new i = 1; i <= MaxClients; i++)
{
g_arrPlayerData[i][Damage2] = 0;
g_arrPlayerData[i][KillerId] = 0;
#if defined KillAssist
arrayset(_:g_arrPlayerData[i][aDamage], 0, sizeof g_arrPlayerData[][aDamage]);
#endif
}
}
public UpdateAllStats(index, GetStatsStates:type)
{
if(!g_bMySqlConnection || g_bResetStats)
return;
new systime = get_systime();
if(index == 13333 && systime - g_iLastUpdate < 10)
return;
g_iLastUpdate = systime;
g_szAllPlayersUpdateQuery[0] = EOS;
new players[32], pnum;
get_players(players, pnum);
for(new i; i < pnum; i++)
UpdateStats(players[i], true);
data[0] = SavePlayer;
data[1] = index;
data[2] = any:type;
if(g_szAllPlayersUpdateQuery[0] == EOS)
SqlQueryHandler(TQUERY_SUCCESS, Empty_Handle, "", 0, data, sizeof(data));
else SQL_ThreadQuery(g_hSqlTuple, "SqlQueryHandler", g_szAllPlayersUpdateQuery, data, sizeof(data));
}
public clCMD_SayRank(id)
return GetStats(id, StatsRank);
public clCMD_SayRankStats(id)
return GetStats(id, StatsRankStats);
public clCMD_SayTop15(id)
return GetStats(id, StatsTop15);
public clCMD_SayMe(id)
return GetStats(id, StatsMe);
public clCMD_SayHp(id)
return GetStats(id, StatsHp);
public SqlQueryHandler(querystate, Handle:query, err[], errcode, dt[], datasize)
{
if(querystate == TQUERY_SUCCESS)
{
new id = dt[1];
switch(QueryStates:dt[0])
{
case LoadPlayer:
{
if(SQL_NumResults(query))
{
SQL_ReadResult(query, 0, g_arrPlayerData[id][Skill]);
new hArray[128]; SQL_ReadResult(query, 1, hArray, charsmax(hArray));
g_arrPlayerData[id][GameTime] = SQL_ReadResult(query, 2);
if(strlen(hArray))
{
new arr[HIT_RIGHTLEG + 1][10];
replace_string(hArray, charsmax(hArray), ":", " ");
if(parse(hArray,
arr[HIT_GENERIC], charsmax(arr[]),
arr[HIT_HEAD], charsmax(arr[]),
arr[HIT_CHEST], charsmax(arr[]),
arr[HIT_STOMACH], charsmax(arr[]),
arr[HIT_LEFTARM], charsmax(arr[]),
arr[HIT_RIGHTARM], charsmax(arr[]),
arr[HIT_LEFTLEG], charsmax(arr[]),
arr[HIT_RIGHTLEG], charsmax(arr[])
) == sizeof arr
)
{
for(new i; i < sizeof arr; i++)
g_arrPlayerData[id][hBox][i] = str_to_num(arr[i]);
}
}
}
else g_arrPlayerData[id][Skill] = _:100.0;
}
case SavePlayer:
{
if(GetStatsStates:dt[2] > StatsNone)
{
switch(GetStatsStates:dt[2])
{
#if defined KillAssist
case StatsRank, StatsRankStats:
formatex(g_szQuery, charsmax(g_szQuery),
"SELECT (SELECT COUNT(*) FROM `players_stats` WHERE `skill` > (SELECT `skill` FROM `players_stats` WHERE `authid` = '%s')) AS `rank`, \
(SELECT COUNT(*) FROM `players_stats`) AS `statsnum`, `frags`, `deaths`, `hits`, `shots`, `damage`, `hs`, `skill`, `assists` FROM `players_stats` WHERE `authid` = '%s'",
g_arrPlayerData[id][AuthId], g_arrPlayerData[id][AuthId]
);
case StatsTop15:
formatex(g_szQuery, charsmax(g_szQuery), "SELECT `nick`, `frags`, `deaths`, `hs`, `shots`, `hits`, `skill`, `assists` FROM `players_stats` ORDER BY `skill` DESC LIMIT 15");
#else
case StatsRank, StatsRankStats:
formatex(g_szQuery, charsmax(g_szQuery),
"SELECT (SELECT COUNT(*) FROM `players_stats` WHERE `skill` > (SELECT `skill` FROM `players_stats` WHERE `authid` = '%s')) AS `rank`, \
(SELECT COUNT(*) FROM `players_stats`) AS `statsnum`, `frags`, `deaths`, `hits`, `shots`, `damage`, `hs`, `skill` FROM `players_stats` WHERE `authid` = '%s'",
g_arrPlayerData[id][AuthId], g_arrPlayerData[id][AuthId]
);
case StatsTop15:
formatex(g_szQuery, charsmax(g_szQuery), "SELECT `nick`, `frags`, `deaths`, `hs`, `shots`, `hits`, `skill` FROM `players_stats` ORDER BY `skill` DESC LIMIT 15");
#endif
}
data[0] = any:dt[2];
data[1] = id;
SQL_ThreadQuery(g_hSqlTuple, "SqlQueryHandler", g_szQuery, data, sizeof(data));
}
}
case ResetStats:
{
log_amx("[Reset Stats] Stats successfully reset!");
log_amx("[Reset Stats] Restart Map...");
g_bResetStats = true;
server_cmd("restart");
}
case RemoveLols:
{
new prun = SQL_AffectedRows(query);
if(prun)
log_amx("[Pruned Players] Removed %d players!", prun);
}
/*
ТŃŃ‚ типа начинаютŃŃŹ выводы инфы... :D
*/
case StatsRank:
{
if(!SQL_NumResults(query))
client_print_color(id, 0, "^1[^4Stats^1] Brak danych z MySQL.");
else
{
new iFrags = SQL_ReadResult(query, 2);
new iDeaths = SQL_ReadResult(query, 3);
new iHits = SQL_ReadResult(query, 4);
new Float:fSkill; SQL_ReadResult(query, 8, fSkill);
// spec symbol '%'
#if defined KillAssist
client_print_color(id, 0, "^1[^4Stats^1] Zajmujesz^3%d-е ^1miejsce z ^3%d^1, zabiles ^3%d^1, zadales ^3%d ^1raz [^4Eff ^3%.2f%^1|^4ĐCC ^3%.2f%^1|^4Skill ^3%s^1|^4Assyst ^3%d^1]",
SQL_ReadResult(query, 0) + 1, SQL_ReadResult(query, 1), iFrags, iHits, effec(iFrags, iDeaths), accuracy(iHits, SQL_ReadResult(query, 5)), g_arrViewSkills[get_skill(fSkill)], SQL_ReadResult(query, 9));
#else
client_print_color(id, 0, "^1[^4Stats^1] Zajmujesz ^3%d-е ^1miejsce z ^3%d^1, zabiles ^3%d^1, zadales ^3%d ^1raz [^4Eff ^3%.2f%^1|^4ACC ^3%.2f%^1|^4Skill ^3%s^1]",
SQL_ReadResult(query, 0) + 1, SQL_ReadResult(query, 1), iFrags, iHits, effec(iFrags, iDeaths), accuracy(iHits, SQL_ReadResult(query, 5)), g_arrViewSkills[get_skill(fSkill)]);
#endif
}
}
case StatsRankStats:
{
if(!SQL_NumResults(query))
client_print_color(id, 0, "^1[^4Stats^1] Brak danych z MySQL.");
else
{
new iFrags = SQL_ReadResult(query, 2);
new iDeaths = SQL_ReadResult(query, 3);
new iHits = SQL_ReadResult(query, 4);
new iShots = SQL_ReadResult(query, 5);
new Float:fSkill; SQL_ReadResult(query, 8, fSkill);
new buff[1535], len;
len += formatex(buff[len], charsmax(buff) - len, "<META http-equiv=Content-Type content='text/html;charset=UTF-8'><link href='http://stats.neugomon.ru/srv/stats.css' rel=stylesheet type=text/css>");
len += formatex(buff[len], charsmax(buff) - len, "<p>Ogolne statystyki gracza</p><table cellpadding=0><tr><td valign=top width=50%%><table cellspacing=0><tr><th colspan=2> Zajmujesz %d-ie miejsce na %d", SQL_ReadResult(query, 0) + 1, SQL_ReadResult(query, 1));
#if defined KillAssist
len += formatex(buff[len], charsmax(buff) - len, "<tr><td>Zabito<td>%d (w glowe: %d)<tr><td>Asysta<td>%d<tr><td>Smierci<td>%d<tr><td>Trafien<td>%d<tr><td>Strzalow<td>%d<tr><td>Od<td>%d<tr><td>Precyzja<td>%0.2f%%<tr><td>Efektywnosc<td>%0.2f%%<tr><td>Skill<td>%s</table>",
iFrags, SQL_ReadResult(query, 7), SQL_ReadResult(query, 9), iDeaths, iHits, iShots, SQL_ReadResult(query, 6), accuracy(iHits, iShots), effec(iFrags, iDeaths), g_arrViewSkills[get_skill(fSkill)]);
#else
len += formatex(buff[len], charsmax(buff) - len, "<tr><td>Zabito<td>%d (w glowe: %d)<tr><td>Smierci<td>%d<tr><td>Trafien<td>%d<tr><td>Strzalow<td>%d<tr><td>Od<td>%d<tr><td>Precyzja<td>%0.2f%%<tr><td>Efektywnosc<td>%0.2f%%<tr><td>Skill<td>%s</table>",
iFrags, SQL_ReadResult(query, 7), iDeaths, iHits, iShots, SQL_ReadResult(query, 6), accuracy(iHits, iShots), effec(iFrags, iDeaths), g_arrViewSkills[get_skill(fSkill)]);
#endif
len += formatex(buff[len], charsmax(buff) - len, "<td valign=top width=50%%><table cellspacing=0><tr><th colspan=2>Statystyki trafien");
for(new i; i < sizeof g_arrBodyParts; i++)
len += formatex(buff[len], charsmax(buff) - len, "<tr><td>%s<td>%d", g_arrBodyParts[i], g_arrPlayerData[id][hBox][i]);
formatex(buff[len], charsmax(buff) - len, "<tr><td height=15px><td></table>");
show_motd(id, buff, "Your stats");
}
}
case StatsTop15:
{
if(!SQL_NumResults(query))
client_print_color(id, 0, "^1[^4Stats^1] Brak danych z MySQL.");
else
{
new buff[1535], len, i, name[32], iFrags, iDeaths, iHits, iShots;
new OldLen, bool:IsCut;
len += formatex(buff[len], charsmax(buff) - len, "<META http-equiv=Content-Type content='text/html;charset=UTF-8'><link href='http://stats.neugomon.ru/srv/stats.css' rel=stylesheet type=text/css>");
#if defined KillAssist
len += formatex(buff[len], charsmax(buff) - len, "<table><tr><th>#<th>Nick<th>Frags<th>HS<th>Assists<th>Deaths<th>Shots<th>Hits<th>Eff<th>Acc<th>Skill</tr>");
#else
len += formatex(buff[len], charsmax(buff) - len, "<table><tr><th>#<th>Nick<th>Frags<th>HS<th>Deaths<th>Shots<th>Hits<th>Eff<th>Acc<th>Skill</tr>");
#endif
while(SQL_MoreResults(query))
{
SQL_ReadResult(query, 0, name, charsmax(name));
replace_string(name, charsmax(name), "<", "[");
replace_string(name, charsmax(name), ">", "]");
iFrags = SQL_ReadResult(query, 1);
iDeaths = SQL_ReadResult(query, 2);
iShots = SQL_ReadResult(query, 4);
iHits = SQL_ReadResult(query, 5);
new Float:fSkill; SQL_ReadResult(query, 6, fSkill);
OldLen = len;
#if defined KillAssist
len += formatex(buff[len], charsmax(buff) - len, "<tr><td>%d<td>%s<td>%d<td>%d<td>%d<td>%d<td>%d<td>%d<td>%.2f%%<td>%.2f%%<td>%s</tr>", ++i, name,
iFrags, SQL_ReadResult(query, 3), SQL_ReadResult(query, 7), iDeaths, iShots, iHits, effec(iFrags, iDeaths), accuracy(iHits, iShots), g_arrViewSkills[get_skill(fSkill)]);
#else
len += formatex(buff[len], charsmax(buff) - len, "<tr><td>%d<td>%s<td>%d<td>%d<td>%d<td>%d<td>%d<td>%.2f%%<td>%.2f%%<td>%s</tr>", ++i, name,
iFrags, SQL_ReadResult(query, 3), iDeaths, iShots, iHits, effec(iFrags, iDeaths), accuracy(iHits, iShots), g_arrViewSkills[get_skill(fSkill)]);
#endif
if(len + 9 >= charsmax(buff))
{
buff[OldLen] = 0;
IsCut = true;
break;
}
else SQL_NextRow(query);
}
formatex(buff[IsCut ? OldLen : len], charsmax(buff), "</table>");
show_motd(id, buff, "Top players");
}
}
}
}
else log_to_file("ps.log", "[State #%d] Error [#%d] %s", dt[0], errcode, err);
}
public CheckMySQLConnection()
{
static ErrNum;
new errcode, errstr[128];
if(SQL_Connect(g_hSqlTuple, errcode, errstr, charsmax(errstr)) == Empty_Handle)
{
if(++ErrNum == 3)
{
new error[190];
formatex(error, charsmax(error), "SQL Connection ERROR [#%d] %s", errcode, errstr);
set_fail_state(error);
}
else
{
g_bMySqlConnection = false;
set_task(3.0, "CheckMySQLConnection");
}
}
else
{
g_bMySqlConnection = true;
data[0] = RemoveLols;
formatex(
g_szQuery, charsmax(g_szQuery),
"DELETE FROM `players_stats` WHERE `last_connection` < (UNIX_TIMESTAMP(NOW()) - %d)",
(PrunedDays * 86400)
);
SQL_ThreadQuery(g_hSqlTuple, "SqlQueryHandler", g_szQuery, data, sizeof(data));
if(ErrNum)
{
new players[32], pnum;
get_players(players, pnum);
for(new i; i < pnum; i++)
if(!g_arrPlayerData[players[i]][AuthId][0])
client_putinserver(players[i]);
}
}
}
/* Natives */
public native_ps_remove_player(param[25])
{
if(!param[0])
return 0;
new errcode, errstr[128];
new Handle:QueryHandle = SQL_Connect(g_hSqlTuple, errcode, errstr, charsmax(errstr));
if(QueryHandle != Empty_Handle)
{
new id = get_id_by_auth(param);
if(id) arrayset(g_arrPlayerData[id], 0, PlayerData);
SQL_PrepareQuery(QueryHandle, "DELETE FROM `players_stats` WHERE `authid` = '%s'", param);
if(SQL_Execute(QueryHandle))
{ SQL_FreeHandle(QueryHandle); return 1; }
else { SQL_FreeHandle(QueryHandle); return 0; }
}
return 0;
}
public native_ps_setinfo_player(param[], SetParams:setparam, value)
{
if(!param[0] || setparam < FRAGS || value < 0)
return 0;
new errcode, errstr[128];
new Handle:QueryHandle = SQL_Connect(g_hSqlTuple, errcode, errstr, charsmax(errstr));
if(QueryHandle != Empty_Handle)
{
new row[10] = "";
switch(setparam)
{
case FRAGS: row = "frags";
case DEATHS:row = "deaths";
case HSs: row = "hs";
case DMG: row = "damage";
case SHOTS: row = "shots";
case HITS: row = "hits";
case BOMB_PLANTED: row = "bplanted";
case BOMB_DEFUSED: row = "bdefused";
case BOMB_EXPLODED:row = "bexploded";
case SKILL: row = "skill";
case GAME_TIME: row = "gametime";
}
SQL_PrepareQuery(QueryHandle, "UPDATE `players_stats` SET `%s` = '%d' WHERE `authid` = '%s'", row, value, param);
if(SQL_Execute(QueryHandle))
{ SQL_FreeHandle(QueryHandle); return 1; }
else { SQL_FreeHandle(QueryHandle); return 0; }
}
return 0;
}
public native_ps_get_player_damage(id, bool:bCheckConnect)
{
if(bCheckConnect && !is_user_connected(id))
return -1;
return g_arrPlayerData[id][Damage2];
}
public native_ps_get_player_gametime(id, bool:bCheckConnect)
{
if(bCheckConnect && !is_user_connected(id))
return -1;
return g_arrPlayerData[id][GameTime];
}
/* End Natives */
UpdateStats(id, bool:allupdate)
{
if(!g_arrPlayerData[id][Frags] && !g_arrPlayerData[id][Deaths])
return;
new name[64];
get_user_name(id, name, charsmax(name));
mysql_escape_string(name, charsmax(name));
new hArray[128];
for(new i = 1, len = formatex(hArray, charsmax(hArray), "%d", g_arrPlayerData[id][hBox][0]); i < sizeof g_arrPlayerData[][hBox]; i++)
len += formatex(hArray[len], charsmax(hArray) - len, ":%d", g_arrPlayerData[id][hBox][i]);
#if defined KillAssist
formatex(g_szQuery, charsmax(g_szQuery),
"INSERT INTO `players_stats` \
(`nick`, `authid`, `frags`, `assists`, `deaths`, `hs`, `damage`, `shots`, `hits`, `bplanted`, `bdefused`, `bexploded`, `skill`, `gametime`, `harray`, `last_connection`) \
VALUES ('%s', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%f', '%d', '%s', UNIX_TIMESTAMP(NOW())) \
ON DUPLICATE KEY UPDATE `nick` = '%s', `frags` = `frags` + '%d', `assists` = `assists` + '%d', `deaths` = `deaths` + '%d', `hs` = `hs` + '%d', \
`damage` = `damage` + '%d', `shots` = `shots` + '%d', `hits` = `hits` + '%d', \
`bplanted` = `bplanted` + '%d', `bdefused` = `bdefused` + '%d', `bexploded` = `bexploded` + '%d', \
`skill` = '%f', `gametime` = '%d', `harray` = '%s', `last_connection` = UNIX_TIMESTAMP(NOW()); ",
name, g_arrPlayerData[id][AuthId],
g_arrPlayerData[id][Frags],
g_arrPlayerData[id][aPlayers],
g_arrPlayerData[id][Deaths],
g_arrPlayerData[id][HS],
g_arrPlayerData[id][Damage],
g_arrPlayerData[id][Shots],
g_arrPlayerData[id][Hits],
g_arrPlayerData[id][bPlanted],
g_arrPlayerData[id][bDefused],
g_arrPlayerData[id][bExploded],
g_arrPlayerData[id][Skill],
g_arrPlayerData[id][GameTime],
hArray,
name,
g_arrPlayerData[id][Frags],
g_arrPlayerData[id][aPlayers],
g_arrPlayerData[id][Deaths],
g_arrPlayerData[id][HS],
g_arrPlayerData[id][Damage],
g_arrPlayerData[id][Shots],
g_arrPlayerData[id][Hits],
g_arrPlayerData[id][bPlanted],
g_arrPlayerData[id][bDefused],
g_arrPlayerData[id][bExploded],
g_arrPlayerData[id][Skill],
g_arrPlayerData[id][GameTime],
hArray
);
#else
formatex(g_szQuery, charsmax(g_szQuery),
"INSERT INTO `players_stats` \
(`nick`, `authid`, `frags`, `deaths`, `hs`, `damage`, `shots`, `hits`, `bplanted`, `bdefused`, `bexploded`, `skill`, `gametime`, `harray`, `last_connection`) \
VALUES ('%s', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%f', '%d', '%s', UNIX_TIMESTAMP(NOW())) \
ON DUPLICATE KEY UPDATE `nick` = '%s', `frags` = `frags` + '%d', `deaths` = `deaths` + '%d', `hs` = `hs` + '%d', \
`damage` = `damage` + '%d', `shots` = `shots` + '%d', `hits` = `hits` + '%d', \
`bplanted` = `bplanted` + '%d', `bdefused` = `bdefused` + '%d', `bexploded` = `bexploded` + '%d', \
`skill` = '%f', `gametime` = '%d', `harray` = '%s', `last_connection` = UNIX_TIMESTAMP(NOW()); ",
name, g_arrPlayerData[id][AuthId],
g_arrPlayerData[id][Frags],
g_arrPlayerData[id][Deaths],
g_arrPlayerData[id][HS],
g_arrPlayerData[id][Damage],
g_arrPlayerData[id][Shots],
g_arrPlayerData[id][Hits],
g_arrPlayerData[id][bPlanted],
g_arrPlayerData[id][bDefused],
g_arrPlayerData[id][bExploded],
g_arrPlayerData[id][Skill],
g_arrPlayerData[id][GameTime],
hArray,
name,
g_arrPlayerData[id][Frags],
g_arrPlayerData[id][Deaths],
g_arrPlayerData[id][HS],
g_arrPlayerData[id][Damage],
g_arrPlayerData[id][Shots],
g_arrPlayerData[id][Hits],
g_arrPlayerData[id][bPlanted],
g_arrPlayerData[id][bDefused],
g_arrPlayerData[id][bExploded],
g_arrPlayerData[id][Skill],
g_arrPlayerData[id][GameTime],
hArray
);
#endif
arrayset(g_arrPlayerData[id], 0, CLEAR_DATA);
if(allupdate)
add(g_szAllPlayersUpdateQuery, charsmax(g_szAllPlayersUpdateQuery), g_szQuery);
else
{
data[0] = SavePlayer;
data[1] = id;
data[2] = any:StatsNone;
SQL_ThreadQuery(g_hSqlTuple, "SqlQueryHandler", g_szQuery, data, sizeof(data));
}
}
GetStats(id, GetStatsStates:type)
{
switch(type)
{
case StatsMe:
{
switch(g_arrPlayerData[id][Damage2])
{
case 0: client_print_color(id, 0, "^1[^4SayMe^1] ^1Nikogo ^3nie ^1trafiles.");
default:client_print_color(id, 0, "^1[^4SayMe^1] ^1Zadales ^3%d ^1obrazenia. Ostatnie trafienie w ^3%s^1.", g_arrPlayerData[id][Damage2], g_arrBodyParts[g_arrPlayerData[id][LastHit]][2]);
}
}
case StatsHp:
{
switch(g_arrPlayerData[id][KillerId])
{
case 0: client_print_color(id, 0, "^1[^4SayHp^1] ^1Nie ^3zabiles ^1nikogo.");
default:client_print_color(id, g_arrPlayerData[id][KillerId], "^1[^4SayHp^1] ^1Zabil ciebie ^3%s ^1z dystansu ^3%.0f ^1metrow. Pozostalo ^3%.0f^4HP ^1 ^3%.0f^4AP", g_arrPlayerData[id][KillerName], g_arrPlayerData[id][fDistance], g_arrPlayerData[id][fHpKiller], g_arrPlayerData[id][fApKiller]);
}
}
default:
{
new systime = get_systime();
if(systime - g_arrPlayerData[id][LastGetStats] < AntiFloodSecs)
{
client_print_color(id, 0,
"^1[^4Stats^1] Komenda bedzie dostepna przez ^3%d ^1sek",
g_arrPlayerData[id][LastGetStats] + AntiFloodSecs - systime
);
}
else
{
g_arrPlayerData[id][LastGetStats] = systime;
#if UpdateStatsType == 2
UpdateAllStats(id, type);
#else
data[0] = SavePlayer;
data[1] = index;
data[2] = any:type;
SqlQueryHandler(TQUERY_SUCCESS, Empty_Handle, "", 0, data, sizeof(data));
#endif
}
}
}
return PLUGIN_HANDLED;
}
stock get_id_by_auth(auth[])
{
new players[32], pnum;
get_players(players, pnum, "ch");
for(new i; i < pnum; i++)
if(strcmp(g_arrPlayerData[players[i]][AuthId], auth) == 0)
return players[i];
return 0;
}
stock get_skill(Float:skill)
{
for(new i, sk = floatround(skill); i < sizeof g_arrViewSkills; i++)
{
if(i && g_arrItemSkills[i] > sk)
return i - 1;
else if((!i && g_arrItemSkills[i] > sk) || i == charsmax(g_arrViewSkills))
return i;
}
return 0;
}
stock Float:effec(kills, deaths)
return !kills ? (0.0) : (100.0 * float(kills) / float(kills + deaths));
stock Float:accuracy(hits, shots)
return !shots ? (0.0) : (100.0 * float(hits) / float(shots));
stock mysql_escape_string(output[], len)
{
static const szReplaceIn[][] = { "\\", "\0", "\n", "\r", "\x1a", "'", "^"" };
static const szReplaceOut[][] = { "\\\\", "\\0", "\\n", "\\r", "\Z", "\'", "\^"" };
for(new i; i < sizeof szReplaceIn; i++)
replace_string(output, len, szReplaceIn[i], szReplaceOut[i]);
}