· 5 years ago · May 31, 2020, 09:12 AM
1#include <amxmodx>
2#include <engine>
3#include <fakemeta>
4#include <reapi>
5#include <geoip>
6#include <sqlx>
7#include <speedrun>
8#include <box_system>
9
10new const PluginName [] = "GoldSrc Speedrun [STATS]"
11new const PluginVersion [] = ""
12new const PluginAuthor [] = "Icebeam / sQN"
13
14new const PREFIX[] = "^4[GoldSrc]";
15
16new const DATABASE[] = "addons/amxmodx/data/speedrun_stats.db";
17
18enum _:PlayerData
19{
20 Connected, Authorized, PlayerIndex, TimerStarted, TimerStopped, Float:StartRun
21};
22enum _:PlayerStats
23{
24 SyncHud, Jumps, Strafes, Attempt
25};
26enum _:Style
27{
28 Speedrun, Training, Challenge
29};
30enum _:Categories
31{
32 R_100_FPS, R_200_FPS, R_250_FPS, R_333_FPS, R_500_FPS, R_1000_FPS,
33 DJ_100_FPS, DJ_200_FPS, DJ_250_FPS, DJ_333_FPS, DJ_500_FPS, DJ_1000_FPS,
34 LG_100_FPS, LG_200_FPS, LG_250_FPS, LG_333_FPS, LG_500_FPS, LG_1000_FPS,
35 CS, HCS, LG_CS, LG_HCS, FR2K, FR3K, FR4K, FR6K, FR
36};
37new _:Category_Names[][] =
38{
39 "100 FPS", "200 FPS", "250 FPS", "333 FPS", "500 FPS", "1000 FPS",
40 "DJ + 100 FPS", "DJ + 200 FPS", "DJ + 250 FPS", "DJ + 333 FPS", "DJ + 500 FPS", "DJ + 1000 FPS",
41 "LG + 100 FPS", "LG + 200 FPS", "LG + 250 FPS", "LG + 333 FPS", "LG + 500 FPS", "LG + 1000 FPS",
42 "Crazy Speed", "Hard Crazy Speed", "LG + Crazy Speed", "LG + Hard Crazy Speed", "2K Run", "3K Run",
43 "4K Run", "6K Run", "Fastrun"
44}
45
46new PlayerInfo[33][PlayerData];
47new PlayerHud[33][PlayerStats];
48/*
49enum _:DBStats
50{
51 PersonalBest[33][Categories],
52 PersonalJumps[33][Categories]
53
54}
55*/
56new PersonalBest[33][Categories];
57new PersonalJumps[33][Categories]
58new PersonalStrafes[33][Categories]
59new WorldRecord[Categories];
60
61new g_SpeedrunTop, g_RecordsTop, g_DetailedTop;
62
63new bool:StrafingAw[33], bool:StrafingSd[33], bool:TurningLeft[33], bool:TurningRight[33];
64new Float:MaxSpeed[33], Float:OldAngles[33], Float:OldSpeed[33]
65new GoodSync[33], SyncFrames[33], StrafeFrames[33][14], StrafeGoodSync[33][14];
66
67// [ SQL ]
68new Handle:g_hTuple, g_szQuery[512];
69new g_szMapName[32];
70new g_iMapIndex;
71new g_SyncHud;
72
73public plugin_init()
74{
75 register_plugin(PluginName, PluginVersion, PluginAuthor);
76
77 register_saycmd("top", "Command_TopMenu", -1, "");
78 register_saycmd("top15", "Command_TopMenu", -1, "");
79
80 g_SyncHud = CreateHudSyncObj();
81 set_task(0.1, "Task_ShowHud", 1337, .flags = "b");
82
83 RegisterHookChain(RG_CBasePlayer_Jump, "HC_CheckStartTimer", false);
84 RegisterHookChain(RG_CBasePlayer_Duck, "HC_CheckStartTimer", false);
85 RegisterHookChain(RG_CBasePlayer_Spawn, "HC_CBasePlayer_Spawn_Post", true);
86 RegisterHookChain(RG_CBasePlayer_PreThink, "HC_CBasePlayer_PreThink", true);
87
88 SQL_Init();
89}
90
91public plugin_natives()
92{
93 register_native("get_user_wr", "_get_user_wr", 1);
94 register_native("get_user_pb", "_get_user_pb", 1);
95 register_native("start_timer", "_start_timer", 1);
96 register_native("stop_timer", "_stop_timer", 1);
97}
98
99SQL_Init() {
100 SQL_SetAffinity("sqlite");
101
102 if(!file_exists(DATABASE))
103 {
104 new file = fopen(DATABASE, "w");
105 if(!file)
106 {
107 new szMsg[128]; formatex(szMsg, charsmax(szMsg), "%s file not found and cant be created.", DATABASE);
108 set_fail_state(szMsg);
109 }
110 fclose(file);
111 }
112
113 g_hTuple = SQL_MakeDbTuple("", "", "", DATABASE, 0);
114
115 formatex(g_szQuery, charsmax(g_szQuery),
116 "CREATE TABLE IF NOT EXISTS `runners`( \
117 id INTEGER PRIMARY KEY,\
118 steamid TEXT NOT NULL, \
119 nickname TEXT NOT NULL, \
120 ip TEXT NOT NULL, \
121 nationality TEXT NULL)");
122
123 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
124
125 formatex(g_szQuery, charsmax(g_szQuery),
126 "CREATE TABLE IF NOT EXISTS `maps`( \
127 mid INTEGER PRIMARY KEY,\
128 mapname TEXT NOT NULL UNIQUE)")
129
130 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
131
132 formatex(g_szQuery, charsmax(g_szQuery),
133 "CREATE TABLE IF NOT EXISTS `results`( \
134 id INTEGER NOT NULL, \
135 mid INTEGER NOT NULL, \
136 category INTEGER NOT NULL, \
137 time INTEGER NOT NULL, \
138 jumps INTEGER NOT NULL, \
139 strafes INTEGER NOT NULL, \
140 recorddate DATETIME NULL, \
141 FOREIGN KEY(id) REFERENCES `runners`(id) ON DELETE CASCADE, \
142 FOREIGN KEY(mid) REFERENCES `maps`(mid) ON DELETE CASCADE, \
143 PRIMARY KEY(id, mid, category))");
144
145 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
146
147 set_task(1.0, "DelayedLoadMapInfo");
148}
149
150public DelayedLoadMapInfo()
151{
152 get_mapname(g_szMapName, charsmax(g_szMapName));
153 formatex(g_szQuery, charsmax(g_szQuery), "SELECT mid FROM `maps` WHERE mapname='%s'", g_szMapName);
154 SQL_ThreadQuery(g_hTuple, "Query_LoadMapHandle", g_szQuery);
155}
156
157public Query_LoadMapHandle(failstate, Handle:query, error[], errnum, data[], size)
158{
159 if(failstate != TQUERY_SUCCESS)
160 {
161 log_amx("SQL error[LoadMapHandle]: %s", error); return;
162 }
163
164 if(SQL_MoreResults(query))
165 {
166 g_iMapIndex = SQL_ReadResult(query, 0);
167 }
168 else
169 {
170 formatex(g_szQuery, charsmax(g_szQuery), "INSERT INTO `maps`(mapname) VALUES ('%s')", g_szMapName);
171 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
172
173 formatex(g_szQuery, charsmax(g_szQuery), "SELECT mid FROM `maps` WHERE mapname='%s'", g_szMapName);
174 SQL_ThreadQuery(g_hTuple, "Query_LoadMapHandle", g_szQuery);
175 }
176
177 if(g_iMapIndex)
178 {
179 for(new i = 1; i <= 32; i++)
180 {
181 if(PlayerInfo[i][Connected]) ClientAuthorization(i);
182 }
183 for(new i; i < Categories; i++)
184 {
185 ShowTop(0, i);
186 }
187 }
188}
189
190public Query_IngnoredHandle(failstate, Handle:query, error[], errnum, data[], size)
191{
192 if(failstate != TQUERY_SUCCESS)
193 {
194 log_amx("SQL error[IngnoredHandle]: %s", error); return;
195 }
196}
197
198public client_connect(id)
199{
200 PlayerInfo[id][Authorized] = false;
201 PlayerInfo[id][TimerStarted] = false;
202 PlayerInfo[id][TimerStopped] = false;
203 PlayerInfo[id][PlayerIndex] = 0;
204
205 PlayerHud[id][Jumps] = 0
206 PlayerHud[id][Strafes] = 0
207 PlayerHud[id][Attempt] = 0
208
209 GoodSync[id] = 0
210 SyncFrames[id] = 0
211}
212
213public client_putinserver(id)
214{
215 if(!is_user_bot(id) && !is_user_hltv(id))
216 {
217 PlayerInfo[id][Connected] = true;
218 ClientAuthorization(id);
219 }
220}
221
222ClientAuthorization(id)
223{
224 if(!g_iMapIndex) return;
225
226 new szAuth[32]; get_user_authid(id, szAuth, charsmax(szAuth));
227
228 new data[1]; data[0] = id;
229 formatex(g_szQuery, charsmax(g_szQuery), "SELECT id, ip, nationality FROM `runners` WHERE steamid='%s'", szAuth);
230 SQL_ThreadQuery(g_hTuple, "Query_LoadRunnerInfoHandler", g_szQuery, data, sizeof(data));
231}
232
233public Query_LoadRunnerInfoHandler(failstate, Handle:query, error[], errnum, data[], size)
234{
235 if(failstate != TQUERY_SUCCESS)
236 {
237 log_amx("SQL error[LoadRunnerInfo]: %s",error); return;
238 }
239
240 new id = data[0];
241 if(!is_user_connected(id)) return;
242
243 new szCode[5];
244
245 if(SQL_MoreResults(query))
246 {
247 client_authorized_db(id, SQL_ReadResult(query, 0));
248
249 SQL_ReadResult(query, 2, szCode, 1);
250
251 if(szCode[0] == 0)
252 {
253 new szIP[32]; get_user_ip(id, szIP, charsmax(szIP), 1);
254
255 get_nationality(id, szIP, szCode);
256 formatex(g_szQuery, charsmax(g_szQuery), "UPDATE `runners` SET nationality='%s' WHERE id=%d", szCode, PlayerInfo[id][PlayerIndex]);
257 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
258 }
259 }
260 else
261 {
262 new szAuth[32]; get_user_authid(id, szAuth, charsmax(szAuth));
263 new szIP[32]; get_user_ip(id, szIP, charsmax(szIP), 1);
264 new szName[64]; get_user_name(id, szName, charsmax(szName));
265 SQL_PrepareString(szName, szName, 63);
266
267 get_nationality(id, szIP, szCode);
268
269 formatex(g_szQuery, charsmax(g_szQuery), "INSERT INTO `runners` (steamid, nickname, ip, nationality) VALUES ('%s', '%s', '%s', '%s')", szAuth, szName, szIP, szCode);
270 SQL_ThreadQuery(g_hTuple, "Query_InsertRunnerHandle", g_szQuery, data, size);
271 }
272}
273
274public Query_InsertRunnerHandle(failstate, Handle:query, error[], errnum, data[], size)
275{
276 if(failstate != TQUERY_SUCCESS)
277 {
278 log_amx("SQL error[InsertRunner]: %s",error); return;
279 }
280
281 new id = data[0];
282 if(!is_user_connected(id)) return;
283
284 client_authorized_db(id , SQL_GetInsertId(query));
285}
286
287client_authorized_db(id, pid)
288{
289 PlayerInfo[id][PlayerIndex] = pid;
290 PlayerInfo[id][Authorized] = true;
291
292 arrayset(PersonalBest[id], 0, sizeof(PersonalBest[]));
293
294 LoadRunnerData(id);
295}
296
297LoadRunnerData(id)
298{
299 if(!PlayerInfo[id][Authorized]) return;
300
301 new data[1]; data[0] = id;
302
303 formatex(g_szQuery, charsmax(g_szQuery), "SELECT * FROM `results` WHERE id=%d AND mid=%d", PlayerInfo[id][PlayerIndex], g_iMapIndex);
304 SQL_ThreadQuery(g_hTuple, "Query_LoadDataHandle", g_szQuery, data, sizeof(data));
305}
306
307public Query_LoadDataHandle(failstate, Handle:query, error[], errnum, data[], size)
308{
309 if(failstate != TQUERY_SUCCESS)
310 {
311 log_amx("SQL Insert error: %s",error); return;
312 }
313
314 new id = data[0];
315 if(!is_user_connected(id)) return;
316
317 while(SQL_MoreResults(query))
318 {
319 new category = SQL_ReadResult(query, 2);
320 PersonalBest[id][category] = SQL_ReadResult(query, 3);
321 PersonalJumps[id][category] = SQL_ReadResult(query, 4);
322 PersonalStrafes[id][category] = SQL_ReadResult(query, 5);
323
324 SQL_NextRow(query);
325 }
326}
327
328public client_disconnected(id)
329{
330 PlayerInfo[id][Authorized] = false;
331 PlayerInfo[id][Connected] = false;
332}
333
334public SR_PlayerOnStart(id)
335{
336 HC_CBasePlayer_Spawn_Post(id);
337}
338
339public HC_CBasePlayer_Spawn_Post(id)
340{
341 PlayerInfo[id][TimerStarted] = false;
342
343 PlayerHud[id][Jumps] = 0;
344 PlayerHud[id][Strafes] = 0;
345}
346
347public Task_ShowHud()
348{
349 new Float:fSpeed, Float:fVelocity[3], iSpecMode;
350
351 for(new id = 1, target; id <= 32; id++)
352 {
353 iSpecMode = get_entvar(id, var_iuser1);
354 target = (iSpecMode == 1 || iSpecMode == 2 || iSpecMode == 4) ? get_entvar(id, var_iuser2) : id;
355 get_entvar(target, var_velocity, fVelocity);
356
357 if(PlayerInfo[id][TimerStarted] && !PlayerInfo[id][TimerStopped] && is_user_alive(id))
358 {
359 set_hudmessage(255, 255, 255, -1.0, 0.7, 0, _, 0.1, _, _, 2);
360 ShowSyncHudMsg(target, g_SyncHud, "%d^nTime: %d:%02d^n Jumps: %d^n Strafes: %i^nSpeed: %3.0f", PlayerHud[id][Attempt], get_running_time(id) / 60000,
361 (get_running_time(id) / 1000) % 60, PlayerHud[id][Jumps], PlayerHud[id][Strafes], vector_length(fVelocity));
362 }
363 }
364}
365
366public HC_CBasePlayer_PreThink(id)
367{
368 new buttons = get_entvar(id, var_button);
369 new flags = get_entvar(id, var_flags);
370
371 static bool:OnGround; OnGround = bool:(flags & FL_ONGROUND);
372 static Float:fAngles[3]; get_entvar(id, var_angles, fAngles);
373
374 if(buttons & IN_JUMP)
375 {
376 if(flags & FL_ONGROUND)
377 {
378 PlayerHud[id][Jumps]++
379 }
380 }
381
382 TurningRight[id] = false;
383 TurningLeft[id] = false;
384
385 if(fAngles[1] < OldAngles[id])
386 {
387 TurningRight[id] = true;
388 }
389 else if(fAngles[1] > OldAngles[id])
390 {
391 TurningLeft[id] = true;
392 }
393
394 OldAngles[id] = fAngles[1];
395
396 if(OnGround) return HC_SUPERCEDE;
397
398 static Float:fVelocity[3]; get_entvar(id, var_velocity, fVelocity);
399 static Float:fSpeed; fSpeed = floatsqroot(fVelocity[0] * fVelocity[0] + fVelocity[1] * fVelocity[1]);
400
401 if(TurningLeft[id] || TurningRight[id])
402 {
403 if(!StrafingAw[id] && ((buttons & IN_FORWARD) || (buttons & IN_MOVELEFT)) && !(buttons & IN_MOVERIGHT) && !(buttons & IN_BACK))
404 {
405 StrafingAw[id] = true;
406 StrafingSd[id] = false;
407
408 PlayerHud[id][Strafes]++
409 }
410 else if(!StrafingSd[id] && ((buttons & IN_BACK) || (buttons & IN_MOVERIGHT)) && !(buttons & IN_MOVELEFT) && !(buttons & IN_FORWARD))
411 {
412 StrafingAw[id] = false;
413 StrafingSd[id] = true;
414 PlayerHud[id][Strafes]++
415 }
416 }
417
418 if(MaxSpeed[id] < fSpeed)
419 {
420 MaxSpeed[id] = fSpeed;
421 }
422
423 if(OldSpeed[id] < fSpeed)
424 {
425 GoodSync[id]++;
426 }
427
428 OldSpeed[id] = fSpeed;
429
430 SyncFrames[id]++;
431
432 return HC_CONTINUE;
433}
434
435public Command_TopMenu(id)
436{
437 if(!PlayerInfo[id][Authorized] || is_flooding(id)) return PLUGIN_HANDLED;
438
439 g_SpeedrunTop = menu_create("\rSpeedrun \d> Top", "Toplist_Handler");
440
441 menu_additem(g_SpeedrunTop, "Current category^n", "1");
442
443 menu_additem(g_SpeedrunTop, "100 FPS", "2");
444 menu_additem(g_SpeedrunTop, "200 FPS", "3");
445 menu_additem(g_SpeedrunTop, "250 FPS", "4");
446 menu_additem(g_SpeedrunTop, "333 FPS", "5");
447 menu_additem(g_SpeedrunTop, "500 FPS", "6");
448 menu_additem(g_SpeedrunTop, "1000 FPS", "7");
449 menu_additem(g_SpeedrunTop, "Crazy Speed", "8");
450 menu_additem(g_SpeedrunTop, "Hard Crazy Speed", "9");
451 menu_additem(g_SpeedrunTop, "LG + CS", "10");
452
453 menu_display(id, g_SpeedrunTop, 0);
454
455 return PLUGIN_HANDLED;
456}
457
458public Toplist_Handler(id, menu, item)
459{
460 if(item == MENU_EXIT)
461 {
462 menu_destroy(menu);
463 return PLUGIN_HANDLED;
464 }
465
466 switch(item)
467 {
468 case 0:ShowTop(id, get_user_category(id))
469 case 1:ShowTop(id, R_100_FPS)
470 case 2:ShowTop(id, R_200_FPS)
471 case 3:ShowTop(id, R_250_FPS)
472 case 4:ShowTop(id, R_333_FPS)
473 case 5:ShowTop(id, R_500_FPS)
474 case 6:ShowTop(id, R_1000_FPS)
475 case 7:client_print(id, print_chat, "top cs")
476 case 8:client_print(id, print_chat, "top hcs")
477 case 9:client_print(id, print_chat, "lg + cs")
478
479 }
480
481 set_task(2.0, "DelayedTop", id)
482 engclient_print(id, engprint_center, "Top loading...")
483
484 return PLUGIN_HANDLED;
485}
486
487public DelayedTop(id)
488{
489 menu_display(id, g_RecordsTop);
490}
491
492public RecMenu_Handler(id, menu, item)
493{
494 if(!is_user_connected(id) || item == MENU_EXIT)
495 {
496 menu_destroy(menu);
497 return PLUGIN_HANDLED;
498 }
499
500 new dummy, szInfo[128], argName[32], argAuthid[32], argTime[32], argJumps[32], argStrafes[32], argRecDate[32]
501
502 menu_item_getinfo(menu, item, dummy, szInfo, charsmax(szInfo), _, _, dummy)
503 parse(szInfo, argName, charsmax(argName), argAuthid, charsmax(argAuthid), argTime, charsmax(argTime), argJumps, charsmax(argJumps), argStrafes, charsmax(argStrafes), argRecDate, charsmax(argRecDate))
504
505 new title[64] = ""; format(title, charsmax(title), "\rSpeedrun \d> Record Stats")
506 g_DetailedTop = menu_create(title, "InfoMenu_Handler")
507
508 new TextName[64] = "";format(TextName, charsmax(TextName), "Name: \y%s", argName)
509 new TextAuthid[64] = "";format(TextAuthid, charsmax(TextAuthid), "SteamID: \y%s", argAuthid)
510 new TextTime[64] = "";format(TextTime, charsmax(TextTime), "Time:\y %s", argTime)
511 new TextJump[64] = "";format(TextJump, charsmax(TextJump), "Jumps:\y %s", argJumps)
512 new TextStrafe[64] = "";format(TextStrafe, charsmax(TextStrafe), "Strafes:\y %s", argStrafes)
513 new TextRecDate[64] = "";format(TextRecDate, charsmax(TextRecDate), "Record Date:\y %s", argRecDate)
514
515 menu_additem(g_DetailedTop, TextName)
516 menu_additem(g_DetailedTop, TextAuthid)
517 menu_additem(g_DetailedTop, TextTime)
518 menu_additem(g_DetailedTop, TextJump)
519 menu_additem(g_DetailedTop, TextStrafe)
520 menu_additem(g_DetailedTop, TextRecDate)
521 menu_additem(g_DetailedTop, "\dPlayer Stats (not available yet)^n\w")
522
523 menu_setprop(g_DetailedTop, MPROP_PERPAGE, 0);
524 menu_setprop(g_DetailedTop, MPROP_EXIT, MEXIT_NEVER);
525
526 menu_display(id, g_DetailedTop);
527
528 return PLUGIN_HANDLED;
529}
530public InfoMenu_Handler(id, menu, item)
531{
532 if(!is_user_connected(id) || item == MENU_EXIT)
533 {
534 menu_destroy(menu);
535 return PLUGIN_HANDLED;
536 }
537
538 menu_display(id, g_RecordsTop);
539
540 return PLUGIN_HANDLED;
541}
542
543public HC_CheckStartTimer(id)
544{
545 if(PlayerInfo[id][Authorized] && !PlayerInfo[id][TimerStarted])
546 {
547 StartTimer(id);
548 }
549}
550public box_stop_touch(box, id, const szClass[])
551{
552 if(PlayerInfo[id][Authorized] && !PlayerInfo[id][TimerStarted])
553 {
554 StartTimer(id);
555 }
556}
557
558StartTimer(id)
559{
560 if(get_user_style(id) != Speedrun) return;
561
562 PlayerInfo[id][TimerStarted] = true;
563 PlayerInfo[id][TimerStopped] = false;
564 PlayerInfo[id][StartRun] = _:get_gametime();
565
566 PlayerHud[id][Jumps] = 0;
567 PlayerHud[id][Strafes] = 0;
568 PlayerHud[id][Attempt]++
569}
570
571public box_start_touch(box, id, const szClass[])
572{
573 if(!is_user_alive(id))
574 return PLUGIN_CONTINUE;
575
576 if(equal(szClass, "finish"))
577 {
578 if(!PlayerInfo[id][TimerStopped])
579 {
580 StopTimer(id);
581 }
582 }
583 return PLUGIN_CONTINUE;
584}
585
586StopTimer(id)
587{
588 PlayerInfo[id][TimerStopped] = true;
589
590 new RunTime = get_running_time(id);
591 new Jump = get_player_jumps(id);
592 new Strafe = get_player_strafes(id);
593 new Category = get_user_category(id);
594 new Attempt = get_player_attempt(id)
595
596 new PrintTime[32]; get_formated_time(RunTime, PrintTime, charsmax(PrintTime));
597 new PrintTime2[32]; get_formated_time(RunTime - WorldRecord[Category], PrintTime2, charsmax(PrintTime2));
598 new PrintTime3[32]; get_formated_time(WorldRecord[Category], PrintTime3, charsmax(PrintTime3));
599 new PrintTime4[32]; get_formated_time(WorldRecord[Category] - RunTime, PrintTime4, charsmax(PrintTime4));
600
601 if(Category >= DJ_100_FPS && Category <= LG_1000_FPS)
602 {
603 client_print(id, print_chat, "not saved")
604 return;
605 }
606
607 //set_hudmessage(255, 255, 255, -1.0, 0.7, 3, 120.0, 120.0, _, _, 2);
608 //ShowSyncHudMsg(id, g_SyncHud, "%s^n^n%s^n Jumps: %d^n Strafes: %i^n Speed: N/A", Category_Names[Category], PrintTime, PlayerHud[id][Jumps], PlayerHud[id][Strafes])
609
610 if(PersonalBest[id][Category] == 0)
611 {
612 SaveRunnerData(id, Category, RunTime, Jump, Strafe);
613 }
614 else if(PersonalBest[id][Category] > RunTime)
615 {
616 get_formated_time(PersonalBest[id][Category] - RunTime, PrintTime4, charsmax(PrintTime4));
617
618 client_print_color(id, print_team_red, "^4[%s - Attempt: #%d]^1 // Time: ^4%s^1 // PB: ^4-%s!^1 // WR: ^3+%s", Category_Names[Category], PlayerHud[id][Attempt], PrintTime, PrintTime4, PrintTime2);
619
620 //set_hudmessage(255, 40, 40, -1.0, 0.7, 0, _, 120.0, _, _, 2);
621 //ShowSyncHudMsg(id, g_SyncHud, "%s^n^n%s^n Jumps: %d^n Strafes: %i^n Speed: N/A", Category_Names[Category], PrintTime, PlayerHud[id][Jumps], PlayerHud[id][Strafes])
622
623 SaveRunnerData(id, Category, RunTime, Jump, Strafe);
624 }
625 else if(PersonalBest[id][Category] < RunTime)
626 {
627 get_formated_time(RunTime - PersonalBest[id][Category], PrintTime4, charsmax(PrintTime4));
628
629 client_print_color(id, print_team_red, "^3[%s - Attempt: #%d]^1 // Time: ^3%s^1 // PB: ^3+%s^1 // WR: ^3+%s", Category_Names[Category], PlayerHud[id][Attempt], PrintTime, PrintTime4, PrintTime2);
630 }
631 else
632 {
633 client_print_color(id, print_team_default, "^4PB: Own record equal!");
634 }
635
636 if(WorldRecord[Category] == 0 || WorldRecord[Category] > RunTime)
637 {
638 WorldRecord[Category] = RunTime;
639
640 new Name[32]; get_user_name(id, Name, charsmax(Name));
641 get_formated_time(RunTime, PrintTime, charsmax(PrintTime));
642
643 client_print_color(0, print_team_red, " ")
644 client_print_color(0, print_team_red, " ")
645 client_print_color(0, print_team_red, " ")
646 client_print_color(0, print_team_red, " ")
647 client_print_color(0, print_team_red, "^3%s^1 set a new record on ^3%s^1 improving by ^4[-%s!]^1. New WR: ^3[%s]^1", Name, Category_Names[Category], PrintTime4, PrintTime);
648 }
649 /*
650 if(g_iBestTimeofMap[category] != 0 && g_iBestTimeofMap[category] < iTime)
651 {
652 get_formated_time(iTime - g_iBestTimeofMap[category], szTime, charsmax(szTime));
653 console_print(id, "%s Map record: +%s!", g_szCategory[category], szTime);
654 }
655
656 ExecuteForward(g_fwFinished, g_iReturn, id, iTime, record);
657 */
658}
659
660public SaveRunnerData(id, Category, RunTime, Jump, Strafe)
661{
662 if(!PlayerInfo[id][Authorized]) return;
663
664 if(get_user_style(id) == Training) return;
665
666 new query_type = PersonalBest[id][Category] ? 1 : 0;
667
668 PersonalBest[id][Category] = RunTime;
669 PersonalJumps[id][Category] = Jump;
670 PersonalStrafes[id][Category] = Strafe;
671
672 new RecordTime[32]; get_time("%d-%m-%Y %H:%M:%S", RecordTime, charsmax(RecordTime));
673
674 if(query_type)
675 {
676 formatex(g_szQuery, charsmax(g_szQuery), "UPDATE `results` SET time=%d, jumps=%d, strafes=%i, recorddate='%s' WHERE id=%d AND mid=%d AND category=%d",
677 RunTime, Jump, Strafe, RecordTime, PlayerInfo[id][PlayerIndex], g_iMapIndex, Category);
678 }
679 else
680 {
681 formatex(g_szQuery, charsmax(g_szQuery), "INSERT INTO `results` VALUES (%d, %d, %d, %d, %d, %i, '%s')",
682 PlayerInfo[id][PlayerIndex], g_iMapIndex, Category, RunTime, Jump, Strafe, RecordTime);
683 }
684
685 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
686}
687
688ShowTop(id, category)
689{
690 if(!WorldRecord[category])
691 {
692 engclient_print(id, engprint_center, "Records not found.")
693 }
694
695 formatex(g_szQuery, charsmax(g_szQuery), "SELECT nickname, steamid, time, jumps, strafes, recorddate FROM `results` JOIN `runners` ON `runners`.id=`results`.id WHERE mid=%d AND category=%d AND time ORDER BY time ASC LIMIT 100",
696 g_iMapIndex, category);
697
698 new data[2]; data[0] = id; data[1] = category;
699 SQL_ThreadQuery(g_hTuple, "Query_LoadTop15Handle", g_szQuery, data, sizeof(data));
700}
701public Query_LoadTop15Handle(failstate, Handle:query, error[], errnum, data[], size)
702{
703 if(failstate != TQUERY_SUCCESS)
704 {
705 log_amx("SQL error[LoadTop15]: %s",error); return;
706 }
707
708 new id = data[0];
709 if(!is_user_connected(id) && id != 0) return;
710
711 new category = data[1];
712
713 new title[64] = ""; format(title, charsmax(title), "\rSpeedrun \d> Top %s", Category_Names[category])
714 g_RecordsTop = menu_create(title, "RecMenu_Handler");
715
716 new szData[256];
717 new szPosition[2];
718 new iPosition = 1;
719
720 new iTime, iJumps, iStrafes, szName[32], szAuthid[32], szTime[32], szRecDate[64], szInfo[128]
721
722 while(SQL_MoreResults(query))
723 {
724 SQL_ReadResult(query, 0, szName, 31);
725 SQL_ReadResult(query, 1, szAuthid, 31);
726 iTime = SQL_ReadResult(query, 2);
727 iJumps = SQL_ReadResult(query, 3);
728 iStrafes = SQL_ReadResult(query, 4);
729 SQL_ReadResult(query, 5, szRecDate, 31);
730
731 get_formated_time(iTime, szTime, 31);
732 num_to_str(iPosition, szPosition, charsmax(szPosition));
733
734 WorldRecord[category] = iTime;
735
736 formatex(szData, charsmax(szData), "\r#%s\w - %s - \y%s", szPosition, szName, szTime);
737 formatex(szInfo, charsmax(szInfo), "%s %s %s %d %i %s", szName, szAuthid, szTime, iJumps, iStrafes, szRecDate)
738
739 menu_additem(g_RecordsTop, szData, szInfo);
740
741 if(id == 0) return;
742
743 ++iPosition;
744
745 SQL_NextRow(query);
746 }
747
748 menu_setprop(g_RecordsTop, MPROP_NEXTNAME, "Next");
749 menu_setprop(g_RecordsTop, MPROP_BACKNAME, "Previous");
750 menu_setprop(g_RecordsTop, MPROP_EXITNAME, "Exit");
751}
752
753get_running_time(id)
754{
755 return floatround((get_gametime() - PlayerInfo[id][StartRun]) * 1000, floatround_ceil);
756}
757get_player_jumps(id)
758{
759 return PlayerHud[id][Jumps];
760}
761get_player_strafes(id)
762{
763 return PlayerHud[id][Strafes];
764}
765get_player_attempt(id)
766{
767 return PlayerHud[id][Attempt]
768}
769get_formated_time(RunTime, PrintTime[], size)
770{
771 formatex(PrintTime, size, "%d:%02d.%03d", RunTime / 60000, (RunTime / 1000) % 60, RunTime % 1000);
772}
773get_nationality(id, const szIP[], szCode[5])
774{
775 new szTemp[3];
776 if(geoip_code2_ex(szIP, szTemp))
777 {
778 copy(szCode, 4, szTemp);
779 }
780 else
781 {
782 get_user_info(id, "lang", szCode, 2);
783 SQL_PrepareString(szCode, szCode, 4);
784 }
785}
786
787public Float:_get_user_wr(id, category)
788{
789 category = get_user_category(id)
790 return WorldRecord[category]
791}
792
793public Float:_get_user_pb(id, category)
794{
795 category = get_user_category(id)
796 return PersonalBest[id][category]
797}
798
799public _start_timer(id)
800{
801 return PlayerInfo[id][StartRun] = get_gametime();
802}
803
804public _stop_timer(id)
805{
806 return PlayerInfo[id][StartRun] = -1.0
807}
808
809bool:is_flooding(id)
810{
811 static Float:fAntiFlood[33];
812 new bool:fl = false;
813 new Float:fNow = get_gametime();
814
815 if((fNow-fAntiFlood[id]) < 1.0) fl = true;
816
817 fAntiFlood[id] = fNow;
818 return fl;
819}
820
821stock SQL_PrepareString(const szQuery[], szOutPut[], size)
822{
823 copy(szOutPut, size, szQuery);
824 replace_all(szOutPut, size, "'", "\'");
825 replace_all(szOutPut,size, "`", "\`");
826 replace_all(szOutPut,size, "\\", "\\\\");
827}