· 6 years ago · Jul 26, 2019, 02:06 PM
1#include amxmodx
2#include amxmisc
3#include colorchat
4#include dhudmessage
5#include sqlx
6#define Maximum_Players 32
7
8enum _:Colors
9{
10 print_team_default,
11 print_team_red,
12 print_team_blue,
13 print_team_grey
14};
15
16stock const TeamName [Colors] [ ] =
17{
18 "UNASSIGNED",
19 "TERRORIST",
20 "CT",
21 "SPECTATOR"
22};
23
24#define SQL_Server ""
25#define SQL_Person ""
26#define SQL_Password ""
27#define SQL_Database "ZombieOutStanding_Stats_Db"
28
29#define Date_Format "%d.%m.%Y @ %H:%M" /** %d is day, %m is month, %Y is year, %H is hour and %M is minute. */
30
31#define Errors_File "ZombieOutStanding_Stats_Error.log" /** Where the errors should be logged */
32
33
34new g_iMenu, g_cQuery[256]
35
36#define Chat_Tag "[Zombie OutStanding]"
37#define Chat_Tag_Color 4 /** 1 for yellow, 3 for team color and 4 for green. */
38#define Chat_Message_For_Victim 1 /** Chat messages for victim. Use 0 to disable. */
39#define Chat_Message_For_Killer 1 /** Chat messages for killer. Use 0 to disable */
40#define Chat_Detailed_Rank 1 /** Also includes Kills, Deaths, headShots and KpD ratio. */
41
42#define Score_Start 1000 /** Score to start with. */
43#define Score_For_Suicide 5 /** Loses 5 points if committing suicide. */
44#define Score_For_Kill 5 /** Gets 5 points if committing normal kill. */
45#define Score_For_Head_Shot 10 /** Gets 10 points if committing headshot kill. */
46#define Score_For_Death 3 /** Loses 3 points if getting killed. */
47
48#define Name_Kick_Reason "Stop changing your name that fast."
49#define Name_Change_Interval 7.5 /** Seconds between changing names. */
50
51#define Task_Update_Time 23785321 /** Random offset. */
52#define Task_Id_Update_Time (Id - Task_Update_Time) /** TaskId - Offset returns player's Id. */
53
54#define Seconds_In_Minute 60
55#define Seconds_In_Hour 3600
56#define Seconds_In_Day 86400
57#define Seconds_In_Week 604800
58
59enum timeUnit
60{
61 timeUnit_None = 0,
62 timeUnit_Seconds,
63 timeUnit_Minutes,
64 timeUnit_Hours,
65 timeUnit_Days,
66 timeUnit_Weeks,
67 timeUnit_Count
68};
69
70static Handle:g_Tuple = Empty_Handle;
71
72static g_Query[1024] = { 0, ... };
73static g_Name[Maximum_Players + 1][64];
74static g_Steam[Maximum_Players + 1][64];
75static g_Ip[Maximum_Players + 1][64];
76static g_seenString[Maximum_Players + 1][64];
77static g_timeString[Maximum_Players + 1][64];
78
79static g_Time[Maximum_Players + 1] = { 0, ... };
80static g_Score[Maximum_Players + 1] = { 0, ... };
81static g_Seen[Maximum_Players + 1] = { 0, ... };
82static g_Kills[Maximum_Players + 1] = { 0, ... };
83static g_Deaths[Maximum_Players + 1] = { 0, ... };
84static g_headShots[Maximum_Players + 1] = { 0, ... };
85static g_kmdValue[Maximum_Players + 1] = { 0, ... };
86
87static Float:g_kpdRatio[Maximum_Players + 1] = { 0.0, ... };
88
89static g_maxPlayers = 0;
90static g_recordsCount = 0;
91
92AddCommas ( iNum , szOutput[] , iLen )
93{
94 new szTmp [17] , iOutputPos , iNumPos , iNumLen;
95
96 iNumLen = num_to_str( iNum , szTmp , charsmax( szTmp ) );
97
98 if ( iNumLen <= 3 )
99 {
100 iOutputPos += copy ( szOutput [iOutputPos] , iLen , szTmp );
101 }
102 else
103 {
104 while ( ( iNumPos < iNumLen ) && ( iOutputPos < iLen ) )
105 {
106 szOutput[ iOutputPos++ ] = szTmp[ iNumPos++ ];
107
108 if ( ( iNumLen - iNumPos ) && !( ( iNumLen - iNumPos ) % 3 ) )
109
110 szOutput[ iOutputPos++ ] = ',';
111 }
112
113 szOutput[ iOutputPos ] = EOS;
114 }
115
116 return iOutputPos;
117}
118
119
120computeTimeLength(Time, timeUnit:unitType, Output[], outputSize)
121{
122 static Weeks = 0, Days = 0, Hours = 0, Minutes = 0, Seconds = 0, \
123 maxElementId = 0, timeElement[5][64], Length = 0;
124
125 if (Time > 0)
126 {
127 maxElementId = 0;
128
129 switch (unitType)
130 {
131 case timeUnit_Seconds: Seconds = Time;
132 case timeUnit_Minutes: Seconds = Time * Seconds_In_Minute;
133 case timeUnit_Hours: Seconds = Time * Seconds_In_Hour;
134 case timeUnit_Days: Seconds = Time * Seconds_In_Day;
135 case timeUnit_Weeks: Seconds = Time * Seconds_In_Week;
136 }
137
138 Weeks = Seconds / Seconds_In_Week;
139 Seconds -= (Weeks * Seconds_In_Week);
140
141 Days = Seconds / Seconds_In_Day;
142 Seconds -= (Days * Seconds_In_Day);
143
144 Hours = Seconds / Seconds_In_Hour;
145 Seconds -= (Hours * Seconds_In_Hour);
146
147 Minutes = Seconds / Seconds_In_Minute;
148 Seconds -= (Minutes * Seconds_In_Minute);
149
150 if (Weeks > 0)
151 formatex(timeElement[maxElementId++], charsmax(timeElement[]), "%d w", Weeks);
152
153 if (Days > 0)
154 formatex(timeElement[maxElementId++], charsmax(timeElement[]), "%d d", Days);
155
156 if (Hours > 0)
157 formatex(timeElement[maxElementId++], charsmax(timeElement[]), "%d h", Hours);
158
159 if (Minutes > 0)
160 formatex(timeElement[maxElementId++], charsmax(timeElement[]), "%d m", Minutes);
161
162 if (Seconds > 0)
163 formatex(timeElement[maxElementId++], charsmax(timeElement[]), "%d s", Seconds);
164
165 switch (maxElementId)
166 {
167 case 1: Length = formatex(Output, outputSize, "%s", timeElement[0]);
168 case 2: Length = formatex(Output, outputSize, "%s %s", timeElement[0], timeElement[1]);
169 case 3: Length = formatex(Output, outputSize, "%s %s %s", timeElement[0], timeElement[1], \
170 timeElement[2]);
171 case 4: Length = formatex(Output, outputSize, "%s %s %s %s", timeElement[0], timeElement[1], \
172 timeElement[2], timeElement[3]);
173 case 5: Length = formatex(Output, outputSize, "%s %s %s %s %s", timeElement[0], timeElement[1], \
174 timeElement[2], timeElement[3], timeElement[4]);
175 }
176
177 return Length;
178 }
179
180 Length = formatex(Output, outputSize, "0 m");
181
182 return Length;
183}
184
185bool:isValidPlayer(Player)
186{
187 return bool:(Player >= 1 && Player <= g_maxPlayers);
188}
189
190resetPlayer(Player)
191{
192 static timeNow = 0;
193
194 if (isValidPlayer(Player) && !is_user_bot(Player) && !is_user_hltv(Player))
195 {
196 timeNow = get_systime();
197
198 /**
199 * -----------------------------------------------------
200 * Players
201 * -----------------------------------------------------
202 * Name
203 * Steam
204 * Ip
205 * Score
206 * Kills
207 * Deaths
208 * headShots
209 * Time - The time spent in minutes.
210 * timeString - Formatted as a string.
211 * Seen - get_systime() stamp.
212 * seenString - get_systime() stamp formatted as a time string including date.
213 * kpdRatio - Kills/ Deaths ratio.
214 * kmdValue - Kills - Deaths value.
215 */
216
217 g_Score[Player] = Score_Start;
218 g_Kills[Player] = 0;
219 g_Deaths[Player] = 0;
220 g_headShots[Player] = 0;
221 g_Time[Player] = 0;
222 computeTimeLength(g_Time[Player], timeUnit_Minutes, g_timeString[Player], charsmax(g_timeString[]));
223 g_Seen[Player] = timeNow;
224 format_time(g_seenString[Player], charsmax(g_seenString[]), Date_Format);
225 g_kpdRatio[Player] = 0.0;
226 g_kmdValue[Player] = 0;
227 }
228}
229
230Float:computeKpdRatio(Player)
231{
232 if (isValidPlayer(Player) && is_user_connected(Player) && \
233 is_user_bot(Player) == 0 && is_user_hltv(Player) == 0)
234 {
235 if (g_Deaths[Player] == 0)
236 {
237 return float(g_Kills[Player]);
238 }
239
240 else
241 {
242 return float(g_Kills[Player] / g_Deaths[Player]);
243 }
244 }
245
246 return 0.0;
247}
248
249computeKmdValue(Player)
250{
251 if (isValidPlayer(Player) && is_user_connected(Player) && \
252 is_user_bot(Player) == 0 && is_user_hltv(Player) == 0)
253 {
254 return g_Kills[Player] - g_Deaths[Player];
255 }
256
257 return 0;
258}
259
260/**
261* Updates player's rank statistics.
262*/
263updateRank(Client)
264{
265 if (isValidPlayer(Client) && is_user_connected(Client) && \
266 is_user_bot(Client) == 0 && is_user_hltv(Client) == 0)
267 {
268 /**
269 * -----------------------------------------------------
270 * Players
271 * -----------------------------------------------------
272 * Name
273 * Steam
274 * Ip
275 * Score
276 * Kills
277 * Deaths
278 * headShots
279 * Time - The time spent in minutes.
280 * timeString - Formatted as a string.
281 * Seen - get_systime() stamp.
282 * seenString - get_systime() stamp formatted as a time string including date.
283 * kpdRatio - Kills/ Deaths ratio.
284 * kmdValue - Kills - Deaths value.
285 */
286 formatex(g_Query, charsmax(g_Query), "UPDATE Players SET Ip = '%s', Score = %d, Kills = %d, Deaths = %d, \
287 headShots = %d, Seen = %d, seenString = '%s', kpdRatio = %f, kmdValue = %d WHERE Name = '%s';", \
288 g_Ip[Client], g_Score[Client], g_Kills[Client], g_Deaths[Client], g_headShots[Client], \
289 g_Seen[Client], g_seenString[Client], g_kpdRatio[Client], g_kmdValue[Client], g_Name[Client]);
290
291 SQL_ThreadQuery(g_Tuple, "emptyFunction", g_Query);
292 }
293}
294
295public plugin_natives()
296{
297 /**
298 * NewStats
299 */
300 register_library("NewStats");
301
302 /** Returns 0 if it fails. */
303 register_native("NewStats_GetStats", "NewStats_GetStats");
304
305 /** Returns 0 if it fails. Returns how many players were selected otherwise. */
306 register_native("NewStats_GetTop15", "NewStats_GetTop15");
307}
308
309/**
310* Retrieves the name of the best 15 players.
311*
312* Returns 0 if it fails. Returns how many players have been selected otherwise.
313* If there are not 15 ranked players yet, it might return values like 1, 2, 3 and so on.
314* Example of use:
315*
316* new totalPlayers = NewStats_GetTop15(...);
317*
318* And then you can get the rank statistics for each.
319*
320* =====================================================================================
321*
322* native NewStats_GetTop15(_n1[], _n2[], _n3[], _n4[], _n5[], _n6[], _n7[], _n8[], \
323* _n9[], _n10[], _n11[], _n12[], _n13[], _n14[], _n15[]);
324*
325*/
326public NewStats_GetTop15(pluginId, parametersCount)
327{
328 static Name[15][64], Total, Error[256], errorId, Handle:Connection, \
329 Handle:Query, Iterator;
330
331 Connection = SQL_Connect(g_Tuple, errorId, Error, charsmax(Error));
332
333 if (errorId)
334 {
335 log_to_file(Errors_File, "NewStats_GetTop15() failed because SQL has encountered an error.");
336 log_to_file(Errors_File, "The error is listed below.");
337 log_to_file(Errors_File, "[%d] %s", errorId, Error);
338
339 return 0;
340 }
341
342 Query = SQL_PrepareQuery(Connection, "SELECT Name FROM Players ORDER BY kmdValue DESC LIMIT 15;");
343 SQL_Execute(Query);
344
345 if (SQL_NumResults(Query) == 0)
346 {
347 SQL_FreeHandle(Query);
348 SQL_FreeHandle(Connection);
349
350 return 0;
351 }
352
353 Total = 0;
354
355 while (SQL_MoreResults(Query))
356 {
357 SQL_ReadResult(Query, 0, Name[Total++], charsmax(Name[]));
358
359 SQL_NextRow(Query);
360 }
361
362 SQL_FreeHandle(Query);
363 SQL_FreeHandle(Connection);
364
365 for (Iterator = 0; Iterator < Total; Iterator++)
366 set_string(Iterator + 1, Name[Iterator], charsmax(Name[]));
367
368 return Total;
369}
370
371/**
372* Retrieves information of a player by name.
373*
374* Returns 0 if it fails. If the name of the player does not exists and so on.
375* Returns 1 otherwise.
376* These values are all strings. You can then convert them to numbers and so on.
377* Example of use:
378*
379* new Name[64] = "Hattrick";
380* Steam[64], Ip[64], Score[16], Rank[16];
381* new Success = NewStats_GetStats(Name, Steam, Ip, Score, ...);
382*
383* if (Success)
384* {
385* server_print("Player %s's score is %s. Or numeric, %d.", Name, Score, str_to_num(Score));
386* }
387*
388* =====================================================================================
389*
390* native NewStats_GetStats(const Name[], Steam[], Ip[], Score[], Kills[], \
391* Deaths[], headShots[], Time[], timeString[], Seen[], seenString[], \
392* kpdRatio[], kmdValue[], Rank[], totalPositions[]);
393*
394*/
395public NewStats_GetStats(pluginId, parametersCount)
396{
397 static Name[64], Error[256], errorId, Handle:Connection, Handle:Query, Kills[16], Deaths[16], \
398 headShots[16], Score[16], Ip[64], Steam[64], Time[16], timeString[64], Seen[16], \
399 seenString[64], kpdRatio[16], kmdValue[16], Kills_i, Deaths_i, headShots_i, Score_i, \
400 Time_i, Seen_i, Float:kpdRatio_f, kmdValue_i, Rank[16], Rank_i, totalPositions[16];
401
402 get_string(1, Name, charsmax(Name));
403
404 replace_all(Name, charsmax(Name), "`", "*");
405 replace_all(Name, charsmax(Name), "'", "*");
406 replace_all(Name, charsmax(Name), "\", "*");
407
408 /**
409 * -----------------------------------------------------
410 * Players
411 * -----------------------------------------------------
412 * Name
413 * Steam
414 * Ip
415 * Score
416 * Kills
417 * Deaths
418 * headShots
419 * Time - The time spent in minutes.
420 * timeString - Formatted as a string.
421 * Seen - get_systime() stamp.
422 * seenString - get_systime() stamp formatted as a time string including date.
423 * kpdRatio - Kills/ Deaths ratio.
424 * kmdValue - Kills - Deaths value.
425 */
426 Connection = SQL_Connect(g_Tuple, errorId, Error, charsmax(Error));
427
428 if (errorId)
429 {
430 log_to_file(Errors_File, "NewStats_GetStats() failed because SQL has encountered an error.");
431 log_to_file(Errors_File, "The error is listed below.");
432 log_to_file(Errors_File, "[%d] %s", errorId, Error);
433
434 return 0;
435 }
436
437 formatex(g_Query, charsmax(g_Query), "SELECT Steam, Ip, Score, Kills, Deaths, headShots, \
438 Time, timeString, Seen, seenString, kpdRatio, kmdValue FROM Players WHERE Name = '%s';", Name);
439
440 Query = SQL_PrepareQuery(Connection, g_Query);
441 SQL_Execute(Query);
442
443 if (SQL_NumResults(Query) == 0)
444 {
445 SQL_FreeHandle(Query);
446 SQL_FreeHandle(Connection);
447
448 return 0;
449 }
450
451 SQL_ReadResult(Query, 0, Steam, charsmax(Steam));
452 SQL_ReadResult(Query, 1, Ip, charsmax(Ip));
453 Score_i = SQL_ReadResult(Query, 2);
454 num_to_str(Score_i, Score, charsmax(Score));
455 Kills_i = SQL_ReadResult(Query, 3);
456 num_to_str(Kills_i, Kills, charsmax(Kills));
457 Deaths_i = SQL_ReadResult(Query, 4);
458 num_to_str(Deaths_i, Deaths, charsmax(Deaths));
459 headShots_i = SQL_ReadResult(Query, 5);
460 num_to_str(headShots_i, headShots, charsmax(headShots));
461 Time_i = SQL_ReadResult(Query, 6);
462 num_to_str(Time_i, Time, charsmax(Time));
463 SQL_ReadResult(Query, 7, timeString, charsmax(timeString));
464 Seen_i = SQL_ReadResult(Query, 8);
465 num_to_str(Seen_i, Seen, charsmax(Seen));
466 SQL_ReadResult(Query, 9, seenString, charsmax(seenString));
467 SQL_ReadResult(Query, 10, kpdRatio_f);
468 float_to_str(kpdRatio_f, kpdRatio, charsmax(kpdRatio));
469 kmdValue_i = SQL_ReadResult(Query, 11);
470 num_to_str(kmdValue_i, kmdValue, charsmax(kmdValue));
471
472 SQL_FreeHandle(Query);
473
474 set_string(2, Steam, charsmax(Steam));
475 set_string(3, Ip, charsmax(Ip));
476 set_string(4, Score, charsmax(Score));
477 set_string(5, Kills, charsmax(Kills));
478 set_string(6, Deaths, charsmax(Deaths));
479 set_string(7, headShots, charsmax(headShots));
480 set_string(8, Time, charsmax(Time));
481 set_string(9, timeString, charsmax(timeString));
482 set_string(10, Seen, charsmax(Seen));
483 set_string(11, seenString, charsmax(seenString));
484 set_string(12, kpdRatio, charsmax(kpdRatio));
485 set_string(13, kmdValue, charsmax(kmdValue));
486
487 formatex(g_Query, charsmax(g_Query), "SELECT DISTINCT kmdValue FROM Players \
488 WHERE kmdValue >= %d ORDER BY kmdValue ASC;", kmdValue_i);
489
490 Query = SQL_PrepareQuery(Connection, g_Query);
491 SQL_Execute(Query);
492
493 Rank_i = SQL_NumResults(Query);
494 num_to_str(Rank_i, Rank, charsmax(Rank));
495
496 SQL_FreeHandle(Query);
497 SQL_FreeHandle(Connection);
498
499 set_string(14, Rank, charsmax(Rank));
500
501 num_to_str(g_recordsCount, totalPositions, charsmax(totalPositions));
502 set_string(15, totalPositions, charsmax(totalPositions));
503
504 return 1;
505}
506
507public plugin_init()
508{
509 register_event("DeathMsg", "OnDeathMsg", "a");
510
511 g_Tuple = SQL_MakeDbTuple(SQL_Server, SQL_Person, SQL_Password, SQL_Database);
512
513 if (g_Tuple == Empty_Handle)
514 {
515 g_Tuple = SQL_MakeDbTuple(SQL_Server, SQL_Person, SQL_Password, SQL_Database);
516
517 if (g_Tuple == Empty_Handle)
518 {
519 log_to_file(Errors_File, "SQL_MakeDbTuple() failed @ plugin_init()");
520
521 return set_fail_state("SQL_MakeDbTuple() failed @ plugin_init()");
522 }
523 }
524
525 /**
526 * -----------------------------------------------------
527 * Players
528 * -----------------------------------------------------
529 * Name
530 * Steam
531 * Ip
532 * Score
533 * Kills
534 * Deaths
535 * headShots
536 * Time - The time spent in minutes.
537 * timeString - Formatted as a string.
538 * Seen - get_systime() stamp.
539 * seenString - get_systime() stamp formatted as a time string including date.
540 * kpdRatio - Kills/ Deaths ratio.
541 * kmdValue - Kills - Deaths value.
542 */
543 SQL_ThreadQuery(g_Tuple, "emptyFunction", "CREATE TABLE IF NOT EXISTS Players \
544 (Name TEXT, Steam TEXT, Ip TEXT, Score NUMERIC, Kills NUMERIC, Deaths NUMERIC, \
545 headShots NUMERIC, Time NUMERIC, timeString TEXT, Seen NUMERIC, seenString TEXT, kpdRatio FLOAT, \
546 kmdValue NUMERIC);");
547
548 SQL_ThreadQuery(g_Tuple, "recordsCount", "SELECT Kills FROM Players");
549
550 g_maxPlayers = get_maxplayers();
551
552 return PLUGIN_CONTINUE;
553}
554
555public recordsCount(failState, Handle:Query, Error[], errorId, Data[], dataSize, Float:queueTime)
556{
557 if (failState != 0 || errorId != 0)
558 {
559 log_to_file(Errors_File, "SQL_ThreadQuery() failed @ recordsCount()");
560 log_to_file(Errors_File, "[%d] %s", errorId, Error);
561 }
562
563 else if (queueTime > 15.0)
564 {
565 log_to_file(Errors_File, "SQL_ThreadQuery() @ recordsCount() : This query took 15.0 seconds. \
566 Talk to the game host company tell them the MySQL database works too slow.");
567 }
568
569 g_recordsCount = SQL_NumResults(Query);
570}
571
572public client_command(Client)
573{
574 static Command[32] = { 0, ... }, Argument[32] = { 0, ... }, \
575 queryData[32] = { 0, ... };
576
577 if (is_user_connected(Client) && !is_user_bot(Client) && !is_user_hltv(Client))
578 {
579 read_argv(0, Command, charsmax(Command));
580 read_argv(1, Argument, charsmax(Argument));
581
582 if (equali(Command, "Say", 3))
583 {
584 if (equali(Argument, "Rank", 4) || equali(Argument, "/Rank", 5))
585 {
586 num_to_str(Client, queryData, charsmax(queryData));
587
588 formatex(g_Query, charsmax(g_Query), "SELECT DISTINCT kmdValue \
589 FROM Players WHERE kmdValue >= %d ORDER BY kmdValue ASC;", g_kmdValue[Client]);
590
591 SQL_ThreadQuery(g_Tuple, "printRankChat", g_Query, queryData, sizeof(queryData));
592 }
593
594 else if (equali(Argument, "Top", 3) || equali(Argument, "/Top", 4))
595 {
596
597 }
598 }
599 }
600}
601
602public emptyFunction(failState, Handle:Query, Error[], errorId, Data[], dataSize, Float:queueTime)
603{
604 if (failState != 0 || errorId != 0)
605 {
606 log_to_file(Errors_File, "SQL_ThreadQuery() failed @ emptyFunction()");
607 log_to_file(Errors_File, "[%d] %s", errorId, Error);
608 }
609
610 else if (queueTime > 15.0)
611 {
612 log_to_file(Errors_File, "SQL_ThreadQuery() @ emptyFunction() : This query took 15.0 seconds. \
613 Talk to the game host company tell them the MySQL database works too slow.");
614 }
615
616 /**
617 * Query is now executed.
618 */
619}
620
621public OnDeathMsg()
622{
623 /**
624 * -----------------------------------------------------
625 * Players
626 * -----------------------------------------------------
627 * Name
628 * Steam
629 * Ip
630 * Score
631 * Kills
632 * Deaths
633 * headShots
634 * Time - The time spent in minutes.
635 * timeString - Formatted as a string.
636 * Seen - get_systime() stamp.
637 * seenString - get_systime() stamp formatted as a time string including date.
638 * kpdRatio - Kills/ Deaths ratio.
639 * kmdValue - Kills - Deaths value.
640 */
641
642 static Killer = 0, Victim = 0, bool:headShot = false, Weapon[64] = { 0, ... }, \
643 victimIp[64] = { 0, ... }, killerIp[64] = { 0, ... }, timeNow = 0, bool:killerValid = false, \
644 bool:victimValid = false, bool:victimBOT = false, bool:killerBOT = false;
645 //lcheck();
646
647 Killer = read_data(1);
648 Victim = read_data(2);
649 headShot = bool:read_data(3);
650 read_data(4, Weapon, charsmax(Weapon));
651 ucfirst(Weapon);
652 timeNow = get_systime();
653 killerValid = isValidPlayer(Killer);
654 victimValid = isValidPlayer(Victim);
655 killerBOT = killerValid && is_user_bot(Killer) ? true : false;
656 victimBOT = victimValid && is_user_bot(Victim) ? true : false;
657
658 /**
659 * Committed suicide with weapon, Killer is valid.
660 */
661 if (Killer == Victim && killerValid && !killerBOT)
662 {
663 get_user_ip(Victim, victimIp, charsmax(victimIp), 1 /** No port. */);
664
665 g_Deaths[Victim]++;
666 g_Seen[Victim] = timeNow;
667 format_time(g_seenString[Victim], charsmax(g_seenString[]), Date_Format);
668 formatex(g_Ip[Victim], charsmax(g_Ip), "%s", victimIp);
669 g_Score[Victim] -= Score_For_Suicide;
670 g_kpdRatio[Victim] = computeKpdRatio(Victim);
671 g_kmdValue[Victim] = computeKmdValue(Victim);
672
673 updateRank(Victim);
674 }
675
676 /**
677 * Committed suicide by world, Killer is not a player.
678 */
679 else if (victimValid && !victimBOT && !killerBOT && \
680 (!killerValid || equali(Weapon, "World", 5 /** May be "WorldSpawn". */)))
681 {
682 get_user_ip(Victim, victimIp, charsmax(victimIp), 1 /** No port. */);
683
684 g_Deaths[Victim]++;
685 g_Seen[Victim] = timeNow;
686 format_time(g_seenString[Victim], charsmax(g_seenString[]), Date_Format);
687 formatex(g_Ip[Victim], charsmax(g_Ip), "%s", victimIp);
688 g_Score[Victim] -= Score_For_Suicide;
689 g_kpdRatio[Victim] = computeKpdRatio(Victim);
690 g_kmdValue[Victim] = computeKmdValue(Victim);
691
692 updateRank(Victim);
693 }
694
695 /**
696 * Normal kill.
697 */
698 else if (killerValid && victimValid && !killerBOT && !victimBOT)
699 {
700 get_user_ip(Victim, victimIp, charsmax(victimIp), 1 /** No port. */);
701 get_user_ip(Killer, killerIp, charsmax(killerIp), 1 /** No port. */);
702
703 g_Deaths[Victim]++;
704 g_Kills[Killer]++;
705
706 if (headShot)
707 {
708 g_headShots[Killer]++;
709
710 g_Score[Killer] += Score_For_Head_Shot;
711 }
712
713 else
714 {
715 g_Score[Killer] += Score_For_Kill;
716 }
717
718 g_Seen[Victim] = timeNow;
719 g_Seen[Killer] = timeNow;
720 format_time(g_seenString[Victim], charsmax(g_seenString[]), Date_Format);
721 format_time(g_seenString[Killer], charsmax(g_seenString[]), Date_Format);
722 formatex(g_Ip[Victim], charsmax(g_Ip), "%s", victimIp);
723 formatex(g_Ip[Killer], charsmax(g_Ip), "%s", killerIp);
724 g_Score[Victim] -= Score_For_Death;
725 g_kpdRatio[Victim] = computeKpdRatio(Victim);
726 g_kpdRatio[Killer] = computeKpdRatio(Killer);
727 g_kmdValue[Victim] = computeKmdValue(Victim);
728 g_kmdValue[Killer] = computeKmdValue(Killer);
729
730 updateRank(Victim);
731 updateRank(Killer);
732 }
733}
734
735public client_disconnect(Client)
736{
737 if (isValidPlayer(Client) && is_user_bot(Client) == 0 && is_user_hltv(Client) == 0)
738 {
739 resetPlayer(Client);
740
741 if (task_exists(Client + Task_Update_Time))
742 {
743 remove_task(Client + Task_Update_Time);
744 }
745 }
746}
747
748public client_putinserver(Client)
749{
750 static queryData[32] = { 0, ... };
751
752 if (isValidPlayer(Client) && is_user_bot(Client) == 0 && is_user_hltv(Client) == 0)
753 {
754 resetPlayer(Client);
755
756 num_to_str(Client, queryData, charsmax(queryData));
757
758 get_user_name(Client, g_Name[Client], charsmax(g_Name[]));
759 replace_all(g_Name[Client], charsmax(g_Name[]), "`", "*");
760 replace_all(g_Name[Client], charsmax(g_Name[]), "'", "*");
761 replace_all(g_Name[Client], charsmax(g_Name[]), "\", "*");
762
763 get_user_authid(Client, g_Steam[Client], charsmax(g_Steam[]));
764 get_user_ip(Client, g_Ip[Client], charsmax(g_Ip[]), 1);
765
766 /**
767 * -----------------------------------------------------
768 * Players
769 * -----------------------------------------------------
770 * Name
771 * Steam
772 * Ip
773 * Score
774 * Kills
775 * Deaths
776 * headShots
777 * Time - The time spent in minutes.
778 * timeString - Formatted as a string.
779 * Seen - get_systime() stamp.
780 * seenString - get_systime() stamp formatted as a time string including date.
781 * kpdRatio - Kills/ Deaths ratio.
782 * kmdValue - Kills - Deaths value.
783 */
784 formatex(g_Query, charsmax(g_Query), "SELECT Score, Kills, Deaths, headShots, Time, timeString, \
785 Seen, seenString, kpdRatio, kmdValue FROM Players WHERE Name = '%s';", g_Name[Client]);
786
787 SQL_ThreadQuery(g_Tuple, "retrieveOrCreatePlayer", g_Query, queryData, sizeof(queryData));
788 }
789}
790
791public retrieveOrCreatePlayer(failState, Handle:Query, Error[], errorId, Data[], dataSize, Float:queueTime)
792{
793 static Client = 0;
794
795 if (failState != 0 || errorId != 0)
796 {
797 log_to_file(Errors_File, "SQL_ThreadQuery() failed @ retrieveOrCreatePlayer()");
798 log_to_file(Errors_File, "[%d] %s", errorId, Error);
799 }
800
801 else if (queueTime > 15.0)
802 {
803 log_to_file(Errors_File, "SQL_ThreadQuery() @ retrieveOrCreatePlayer() : This query took 15.0 seconds. \
804 Talk to the game host company tell them the MySQL database works too slow.");
805 }
806
807 Client = str_to_num(Data);
808
809 if (is_user_connected(Client) == 1 && is_user_bot(Client) == 0 && is_user_hltv(Client) == 0)
810 {
811 resetPlayer(Client);
812
813 /**
814 * -----------------------------------------------------
815 * Players
816 * -----------------------------------------------------
817 * Name
818 * Steam
819 * Ip
820 * Score
821 * Kills
822 * Deaths
823 * headShots
824 * Time - The time spent in minutes.
825 * timeString - formatted time spent
826 * Seen - get_systime() stamp
827 * seenString - get_systime() stamp formatted as time string
828 * kpdRatio - Kills/ Deaths ratio
829 * kmdValue - Kills - Deaths value
830 */
831
832 switch (SQL_NumResults(Query))
833 {
834 case 0:
835 {
836 formatex(g_Query, charsmax(g_Query), "INSERT INTO Players VALUES ('%s', \
837 '%s', '%s', %d, %d, %d, %d, %d, '%s', %d, '%s', %f, %d);", g_Name[Client], \
838 g_Steam[Client], g_Ip[Client], g_Score[Client], g_Kills[Client], \
839 g_Deaths[Client], g_headShots[Client], g_Time[Client], g_timeString[Client], g_Seen[Client], \
840 g_seenString[Client], g_kpdRatio[Client], g_kmdValue[Client]);
841
842 SQL_ThreadQuery(g_Tuple, "emptyFunction", g_Query);
843
844 g_recordsCount++;
845 }
846
847 default:
848 {
849 g_Score[Client] = SQL_ReadResult(Query, 0);
850 g_Kills[Client] = SQL_ReadResult(Query, 1);
851 g_Deaths[Client] = SQL_ReadResult(Query, 2);
852 g_headShots[Client] = SQL_ReadResult(Query, 3);
853 g_Time[Client] = SQL_ReadResult(Query, 4);
854 SQL_ReadResult(Query, 5, g_timeString[Client], charsmax(g_timeString[]));
855 g_Seen[Client] = SQL_ReadResult(Query, 6);
856 SQL_ReadResult(Query, 7, g_seenString[Client], charsmax(g_seenString[]));
857 SQL_ReadResult(Query, 8, g_kpdRatio[Client]);
858 g_kmdValue[Client] = SQL_ReadResult(Query, 9);
859 }
860 }
861
862 set_task(11.0, "rankPrepared", Client);
863 set_task(120.0, "timeUpdate", Client + Task_Update_Time, .flags = "b"); /** Every 2 minutes. */
864 }
865}
866
867public timeUpdate(Id)
868{
869 if (is_user_connected(Task_Id_Update_Time) && \
870 !is_user_bot(Task_Id_Update_Time) && !is_user_hltv(Task_Id_Update_Time))
871 {
872 g_Time[Task_Id_Update_Time] += 2; /** 2 minutes. */
873
874 computeTimeLength(g_Time[Task_Id_Update_Time], \
875 timeUnit_Minutes, g_timeString[Task_Id_Update_Time], charsmax(g_timeString[]));
876
877 formatex(g_Query, charsmax(g_Query), \
878 "UPDATE Players SET Time = %d, timeString = '%s' WHERE Name = '%s';", \
879 g_Time[Task_Id_Update_Time], g_timeString[Task_Id_Update_Time], g_Name[Task_Id_Update_Time]);
880
881 SQL_ThreadQuery(g_Tuple, "emptyFunction", g_Query);
882 }
883}
884
885public client_infochanged(Client)
886{
887 static Name[64] = { 0, ... }, queryData[32] = { 0, ... }, \
888 Float:finalChange[33] = { 0.0, ... }, Float:gameTime = 0.0;
889
890 if (is_user_connected(Client) == 1 && is_user_bot(Client) == 0 && is_user_hltv(Client) == 0)
891 {
892 get_user_info(Client, "name", Name, charsmax(Name));
893
894 replace_all(Name, charsmax(Name), "`", "*");
895 replace_all(Name, charsmax(Name), "'", "*");
896 replace_all(Name, charsmax(Name), "\", "*");
897
898 if (equali(Name, g_Name[Client]) == 0)
899 {
900 resetPlayer(Client);
901
902 gameTime = get_gametime();
903
904 if (gameTime < finalChange[Client])
905 {
906 server_cmd("kick #%d %s", get_user_userid(Client), Name_Kick_Reason);
907 }
908
909 else
910 {
911 finalChange[Client] = gameTime + Name_Change_Interval;
912
913 num_to_str(Client, queryData, charsmax(queryData));
914
915 formatex(g_Name[Client], charsmax(g_Name[]), "%s", Name);
916
917 get_user_authid(Client, g_Steam[Client], charsmax(g_Steam[]));
918 get_user_ip(Client, g_Ip[Client], charsmax(g_Ip[]), 1);
919
920 /**
921 * -----------------------------------------------------
922 * Players
923 * -----------------------------------------------------
924 * Name
925 * Steam
926 * Ip
927 * Score
928 * Kills
929 * Deaths
930 * headShots
931 * Time - The time spent in minutes.
932 * timeString - formatted time spent
933 * Seen - get_systime() stamp
934 * seenString - get_systime() stamp formatted as time string
935 * kpdRatio - Kills/ Deaths ratio
936 * kmdValue - Kills - Deaths value
937 */
938 formatex(g_Query, charsmax(g_Query), "SELECT Score, Kills, Deaths, headShots, \
939 Time, timeString, Seen, seenString, kpdRatio, kmdValue FROM Players WHERE Name = '%s';", \
940 g_Name[Client]);
941
942 SQL_ThreadQuery(g_Tuple, "retrieveOrCreatePlayer", g_Query, queryData, sizeof(queryData));
943 }
944 }
945 }
946}
947
948public rankPrepared(Client)
949{
950 static queryData[32] = { 0, ... };
951
952 if (is_user_connected(Client) == 1 && is_user_bot(Client) == 0 && is_user_hltv(Client) == 0)
953 {
954 set_dhudmessage ( 0, 255, 0, 0.03, 0.60, 2, 6.0, 2.0 );
955 show_dhudmessage(Client, "You are now ranked!");
956
957 num_to_str(Client, queryData, charsmax(queryData));
958
959 formatex(g_Query, charsmax(g_Query), "SELECT DISTINCT kmdValue \
960 FROM Players WHERE kmdValue >= %d ORDER BY kmdValue ASC;", g_kmdValue[Client]);
961
962 SQL_ThreadQuery(g_Tuple, "showRank", g_Query, queryData, sizeof(queryData));
963 }
964}
965
966public showRank(failState, Handle:Query, Error[], errorId, Data[], dataSize, Float:queueTime)
967{
968 static Client = 0, Rank = 0, rankString[16], recordsString[16], scoreString[16], \
969 killsString[16], deathsString[16], headShotsString[16];
970
971 if (failState != 0 || errorId != 0)
972 {
973 log_to_file(Errors_File, "SQL_ThreadQuery() failed @ showRank()");
974 log_to_file(Errors_File, "[%d] %s", errorId, Error);
975 }
976
977 else if (queueTime > 15.0)
978 {
979 log_to_file(Errors_File, "SQL_ThreadQuery() @ showRank() : This query took 15.0 seconds. \
980 Talk to the game host company tell them the MySQL database works too slow.");
981 }
982
983 Client = str_to_num(Data);
984
985 if (is_user_connected(Client) == 1 && is_user_bot(Client) == 0 && is_user_hltv(Client) == 0)
986 {
987 Rank = SQL_NumResults(Query);
988
989 AddCommas(Rank, rankString, charsmax(rankString));
990 AddCommas(g_recordsCount, recordsString, charsmax(recordsString));
991 AddCommas(g_Kills[Client], killsString, charsmax(killsString));
992 AddCommas(g_Deaths[Client], deathsString, charsmax(deathsString));
993 AddCommas(g_Score[Client], scoreString, charsmax(scoreString));
994 AddCommas(g_headShots[Client], headShotsString, charsmax(headShotsString));
995
996 new HostName [64]; get_cvar_string ( "hostname", HostName, charsmax ( HostName ) );
997
998 set_dhudmessage ( 0, 255, 0, 0.05, 0.22, 2, 0.02, 1.0, 0.05, 6.0 );
999 show_dhudmessage ( Client, "Welcome, %s^nRank: %s of %s Score: %d^nKills: %s Deaths: %s KPD: %0.2f^nOnline: %s^nWe hope you enjoy!",
1000 g_Name[Client], rankString, recordsString, g_Score[Client] = Score_Start, \
1001 killsString, deathsString, g_kpdRatio[Client], g_timeString[Client]);
1002
1003
1004 set_dhudmessage(149, 103, 200, 0.03, 0.5, 2, 2.0, 3.0)
1005 show_dhudmessage ( Client, "%s^nDon't forget to add us to your favourites!",HostName);
1006 }
1007}
1008
1009public printRankChat(failState, Handle:Query, Error[], errorId, Data[], dataSize, Float:queueTime)
1010{
1011 static cScore[15];
1012 static cDeaths[15];
1013 static cKills[15];
1014 static cTotal[15];
1015 static cRank[15];
1016 static Rank;
1017 static iPlayer;
1018 iPlayer = str_to_num(Data);
1019 Rank = SQL_NumResults(Query);
1020 AddCommas(Rank, cRank, 15);
1021 AddCommas(g_recordsCount, cTotal, 15);
1022 AddCommas(g_Deaths[iPlayer], cDeaths, 15);
1023 AddCommas(g_Kills[iPlayer], cKills, 15);
1024 AddCommas(g_Score[iPlayer], cScore, 15);
1025 g_iMenu = menu_create("Ranking", "EmptyPanel", 0);
1026 formatex(g_cQuery, 255, "Rank: %s of %s Score: %s", cRank, cTotal, cScore);
1027 menu_additem(g_iMenu, g_cQuery, "1", 0, -1);
1028 if (failState != 0 || errorId != 0)
1029 {
1030 log_to_file(Errors_File, "SQL_ThreadQuery() failed @ printRankChat()");
1031 log_to_file(Errors_File, "[%d] %s", errorId, Error);
1032 }
1033 else if (queueTime > 15.0)
1034 {
1035 log_to_file(Errors_File, "SQL_ThreadQuery() @ printRankChat() : This query took 15.0 seconds. \
1036 Talk to the game host company tell them the MySQL database works too slow.");
1037 }
1038 formatex(g_cQuery, 255, "Kills: %s Deaths: %s KPD: %0.2f", cKills, cDeaths, g_kpdRatio[iPlayer]);
1039 menu_additem(g_iMenu, g_cQuery, "2", 0, -1);
1040 formatex(g_cQuery, 255, "Online: %s", g_timeString[iPlayer]);
1041 menu_additem(g_iMenu, g_cQuery, "3", 0, -1);
1042 menu_setprop(g_iMenu, 6, -1);
1043 menu_display(iPlayer, g_iMenu, 0);
1044
1045 client_print_color(0, print_team_grey, "^4[Zombie Outstanding]^3 %s^1's rank is^4 %s^1 of ^4%s^1 --^3 %0.2f KPD", g_Name[iPlayer], cRank, cTotal, g_kpdRatio[iPlayer]);
1046 return 0;
1047}
1048
1049public EmptyPanel(iPlayer, iMenu, iItem)
1050{
1051 return 0;
1052}
1053
1054stock client_print_color ( id, iColor = print_team_default, const Msg [ ], any:... )
1055{
1056 if ( id && !is_user_connected ( id ) ) return 0;
1057
1058 if ( iColor > print_team_grey ) iColor = print_team_default;
1059
1060 new Message [192];
1061
1062 if ( iColor == print_team_default )
1063
1064 Message [0] = 0x04;
1065 else
1066 Message [0] = 0x03;
1067
1068
1069 new iParams = numargs ( )
1070
1071 if ( id )
1072 {
1073 if ( iParams == 3 )
1074
1075 copy ( Message [1], charsmax ( Message ) -1, Msg );
1076 else
1077 vformat ( Message [1], charsmax ( Message ) -1, Msg, 4 );
1078
1079 if ( iColor )
1080 {
1081 new GetTeam [11]; get_user_team ( id, GetTeam, charsmax ( GetTeam ) );
1082
1083 SendTeamInfo ( id, id, TeamName [iColor] );
1084
1085 SendSayText ( id, id, Message );
1086
1087 SendTeamInfo ( id, id, GetTeam );
1088 }
1089 else
1090 SendSayText ( id, id, Message );
1091 }
1092 else
1093 {
1094 new iPlayers [32], iNum; get_players ( iPlayers, iNum, "ch" );
1095
1096 if ( !iNum ) return 0;
1097
1098 new iFool = iPlayers [0];
1099
1100 if ( iParams == 3 )
1101
1102 copy ( Message [1], charsmax ( Message ) -1, Msg );
1103 else
1104 vformat ( Message [1], charsmax ( Message ) -1, Msg, 4 );
1105
1106 if ( iColor )
1107 {
1108 new GetTeam [11]; get_user_team ( iFool, GetTeam, charsmax ( GetTeam ) );
1109
1110 SendTeamInfo ( 0, iFool, TeamName [iColor] );
1111
1112 SendSayText ( 0, iFool, Message);
1113
1114 SendTeamInfo ( 0, iFool, GetTeam );
1115 }
1116 else
1117 SendSayText ( 0, iFool, Message );
1118 }
1119
1120 return 1;
1121}
1122
1123stock SendTeamInfo ( iReceiver, iPlayerId, GetTeam [] )
1124{
1125 static iTeamInfo = 0;
1126
1127 if ( !iTeamInfo )
1128
1129 iTeamInfo = get_user_msgid ( "TeamInfo" );
1130
1131 message_begin ( iReceiver ? MSG_ONE_UNRELIABLE : MSG_BROADCAST, iTeamInfo, .player = iReceiver );
1132
1133 write_byte ( iPlayerId );
1134
1135 write_string ( GetTeam );
1136
1137 message_end ( );
1138}
1139
1140stock SendSayText ( iReceiver, iPlayerId, Message [ ] )
1141{
1142 static iSayText = 0;
1143
1144 if ( !iSayText )
1145
1146 iSayText = get_user_msgid ( "SayText" );
1147
1148 message_begin ( iReceiver ? MSG_ONE_UNRELIABLE : MSG_BROADCAST, iSayText, .player = iReceiver );
1149
1150 write_byte ( iPlayerId );
1151
1152 write_string ( Message );
1153
1154 message_end ( );
1155}