· 6 years ago · Mar 17, 2019, 05:00 PM
1/*
2
3+--------------------------------------+
4| DeathRun Timer - 2015-2016 |
5| |
6| Author: |
7| deniS[MD] a.k.a icimaro1337 |
8| Credits: |
9| xPaw[EE] |
10| Mistrick[RU] |
11| Keniski[RU] |
12| Klippy[RS] |
13+--------------------------------------+
14
15*/
16
17#include <amxmodx>
18#include <engine>
19#include <hamsandwich>
20#include <nvault>
21#include <sqlx>
22#include <geoip>
23
24#pragma semicolon 1
25
26// Here you can configure main settings
27
28// #define COLORCHAT
29
30new const g_szPrefix[] = "[GamesBR]";
31
32const MAX_PLAYERS = 32;
33
34#define ADMIN_ACCESS ADMIN_CVAR
35
36// Here you stop
37
38#if defined COLORCHAT
39 #include <colorchat>
40#endif
41
42/* Macro */
43
44#define set_bit(%1,%2) (%1 |= (1<<%2))
45#define get_bit(%1,%2) (%1 & (1<<%2))
46#define clr_bit(%1,%2) (%1 &= ~(1<<%2))
47
48/* Macro */
49
50new const g_szVersion[] = "0.1";
51
52new const g_szTableName[] = "DEATHRUN_STATS";
53
54new g_pWebLink;
55
56new Handle:g_hSqlTuple;
57
58new bool:g_bSqlite;
59
60new g_szMapName[64];
61
62new Trie:g_tStarts, Trie:g_tStops;
63
64new bool:g_bTimerFound;
65
66enum _:eTimer
67{
68 START,
69 STOP
70};
71
72new g_szTimerModels[eTimer][] =
73{
74 "models/deathrun/timer/timer_start.mdl",
75 "models/deathrun/timer/timer_stop.mdl"
76};
77new g_szTimerName[eTimer][] =
78{
79 "Start",
80 "Stop"
81};
82
83new g_iTimer[eTimer];
84new Float:g_vTimerOrigin[eTimer][3];
85
86new g_iTimerAngles[eTimer];
87new Float:g_flTimerAngles[4] =
88{
89 0.0,
90 90.0,
91 180.0,
92 270.0
93};
94
95new g_iPlayerTimer[MAX_PLAYERS + 1];
96
97new g_bConnected, g_bAlive, g_bStarted;
98
99new Float:g_flStartTime[MAX_PLAYERS + 1], Float:g_flFinishTime[MAX_PLAYERS + 1];
100
101new g_iVault;
102
103new g_iMsgRoundTime;
104
105new g_iHudSyncObj;
106
107public plugin_precache()
108{
109 for (new i = 0; i < eTimer; i++)
110 precache_model(g_szTimerModels[i]);
111}
112public plugin_init()
113{
114 register_plugin("DeathRun Timer", g_szVersion, "deniS");
115
116 g_pWebLink = register_cvar("dr_timer_web_link", "http://177.54.156.124/web");
117
118 register_cvar("dr_timer_sql_host", "177.54.156.124");
119 register_cvar("dr_timer_sql_user", "tempo");
120 register_cvar("dr_timer_sql_pass", "Lu@30350783");
121 register_cvar("dr_timer_sql_db", "tempo");
122
123 get_mapname(g_szMapName, charsmax(g_szMapName));
124
125 g_tStarts = TrieCreate();
126 g_tStops = TrieCreate();
127
128 new i, iSize;
129
130 new const szStarts[][] =
131 {
132 "counter_start", "clockstartbutton", "firsttimerelay", "but_start", "counter_start_button",
133 "multi_start", "timer_startbutton", "start_timer_emi", "gogogo"
134 };
135 iSize = sizeof(szStarts);
136
137 for (i = 0; i < iSize; i++)
138 TrieSetCell(g_tStarts, szStarts[i], 1);
139
140 new const szStops[][] =
141 {
142 "counter_off", "clockstopbutton", "clockstop", "but_stop", "counter_stop_button",
143 "multi_stop", "stop_counter", "m_counter_end_emi"
144 };
145 iSize = sizeof(szStops);
146
147 for (i = 0; i < iSize; i++)
148 TrieSetCell(g_tStops, szStops[i], 1);
149
150 new iEntity = -1;
151
152 while ((iEntity = find_ent_by_class(iEntity, "func_button")) != 0)
153 {
154 new szTargetName[64];
155 entity_get_string(iEntity, EV_SZ_targetname, szTargetName, charsmax(szTargetName));
156
157 if (TrieKeyExists(g_tStarts, szTargetName) || TrieKeyExists(g_tStops, szTargetName))
158 {
159 if (!g_bTimerFound)
160 g_bTimerFound = true;
161
162 break;
163 }
164 }
165
166 if (!g_bTimerFound)
167 {
168 TrieDestroy(g_tStarts);
169 TrieDestroy(g_tStops);
170
171 new szFile[96];
172 formatex(szFile, charsmax(szFile), "deathrun/timer/%s", g_szMapName);
173
174 g_iVault = nvault_open(szFile);
175
176 LoadTimers();
177 }
178
179 iEntity = create_entity("info_target");
180
181 if (iEntity)
182 {
183 entity_set_float(iEntity, EV_FL_nextthink, get_gametime() + 0.5);
184 entity_set_string(iEntity, EV_SZ_classname, "_TimerThink");
185 register_think("_TimerThink", "TimerThink");
186 }
187
188 g_iMsgRoundTime = get_user_msgid("RoundTime");
189
190 RegisterHam(Ham_Spawn, "player", "HamSpawnPlayer_Post", true);
191 RegisterHam(Ham_Killed, "player", "HamKilledPlayer_Post", true);
192 RegisterHam(Ham_Use, "func_button", "HamUseFuncButton_Pre", false);
193
194 register_clcmd("say /timer", "ClCmdTimer");
195 register_clcmd("say_team /timer", "ClCmdTimer");
196
197 register_clcmd("say /top", "ClCmdBest");
198 register_clcmd("say_team /top", "ClCmdBest");
199
200 g_iHudSyncObj = CreateHudSyncObj();
201}
202public plugin_cfg()
203{
204 set_task(0.5, "DB_Init");
205}
206public DB_Init()
207{
208 state mysql;
209
210 new szDB[64];
211 get_cvar_string("dr_timer_sql_db", szDB, charsmax(szDB));
212
213 if (contain(szDB, ".") > 0)
214 {
215 state sqlite;
216
217 g_bSqlite = true;
218 }
219
220 SQL_Init();
221}
222SQL_Init()<mysql>
223{
224 new szHost[64], szUser[64], szPass[64], szDB[64];
225 get_cvar_string("dr_timer_sql_host", szHost, charsmax(szHost));
226 get_cvar_string("dr_timer_sql_user", szUser, charsmax(szUser));
227 get_cvar_string("dr_timer_sql_pass", szPass, charsmax(szPass));
228 get_cvar_string("dr_timer_sql_db", szDB, charsmax(szDB));
229
230 g_hSqlTuple = SQL_MakeDbTuple(szHost, szUser, szPass, szDB);
231
232 new szQuery[512];
233
234 formatex
235 (
236 szQuery, charsmax(szQuery),
237 "CREATE TABLE IF NOT EXISTS `%s` \
238 ( \
239 `ID` INT NOT NULL AUTO_INCREMENT, \
240 \
241 `MAPNAME` VARCHAR(64) NOT NULL, \
242 `AUTHID` VARCHAR(32) NOT NULL, \
243 `NICKNAME` VARCHAR(64) NOT NULL, \
244 `IP` VARCHAR(45) NOT NULL, \
245 `COUNTRY_FULL` VARCHAR(45) NOT NULL, \
246 `COUNTRY_SHORT` VARCHAR(3) NOT NULL, \
247 `TIME` DOUBLE NOT NULL, \
248 `DATE` DATETIME NOT NULL, \
249 \
250 PRIMARY KEY(`ID`) \
251 )",
252 g_szTableName
253 );
254
255 SQL_ThreadQuery(g_hSqlTuple, "Sql_IgnoredQuery_Handler", szQuery);
256}
257SQL_Init()<sqlite>
258{
259 SQL_SetAffinity("sqlite");
260
261 new szDataDir[128];
262 get_localinfo("amxx_datadir", szDataDir, charsmax(szDataDir));
263
264 new szDB[64];
265 get_cvar_string("dr_timer_sql_db", szDB, charsmax(szDB));
266
267 new szFile[196];
268 formatex(szFile, charsmax(szFile), "%s/%s", szDataDir, szDB);
269
270 if (!file_exists(szFile))
271 {
272 new fp = fopen(szFile, "w");
273
274 if (!fp)
275 {
276 log_amx("[%s] SQL_Init()<sqlite>: File ^"%s^" not found and can't be created!", g_szPrefix, szFile);
277 return;
278 }
279 else
280 fclose(fp);
281 }
282
283 g_hSqlTuple = SQL_MakeDbTuple("", "", "", szFile, 0);
284
285 new szQuery[512];
286
287 formatex
288 (
289 szQuery, charsmax(szQuery),
290 "CREATE TABLE IF NOT EXISTS `%s` \
291 ( \
292 `MAPNAME` TEXT NOT NULL, \
293 `AUTHID` TEXT NOT NULL, \
294 `NICKNAME` TEXT NOT NULL, \
295 `IP` TEXT NOT NULL, \
296 `COUNTRY_FULL` TEXT NOT NULL, \
297 `COUNTRY_SHORT` TEXT NOT NULL, \
298 `TIME` REAL NOT NULL, \
299 `DATE` DATETIME NOT NULL \
300 )",
301 g_szTableName
302 );
303
304 SQL_ThreadQuery(g_hSqlTuple, "Sql_IgnoredQuery_Handler", szQuery);
305}
306public client_putinserver(id)
307{
308 set_bit(g_bConnected, id);
309}
310public client_disconnect(id)
311{
312 clr_bit(g_bConnected, id);
313
314 if (get_bit(g_bAlive, id))
315 clr_bit(g_bAlive, id);
316
317 if (get_bit(g_bStarted, id))
318 clr_bit(g_bStarted, id);
319
320 if (g_flStartTime[id] != 0.0)
321 g_flStartTime[id] = 0.0;
322
323 if (g_flFinishTime[id] != 0.0)
324 g_flFinishTime[id] = 0.0;
325}
326public TimerThink(iEntity)
327{
328 if (iEntity)
329 entity_set_float(iEntity, EV_FL_nextthink, get_gametime() + 0.5);
330
331 for (new iAlivePlayer = 0; iAlivePlayer < MAX_PLAYERS; iAlivePlayer++)
332 {
333 if (get_bit(g_bConnected, iAlivePlayer) && get_bit(g_bAlive, iAlivePlayer) && get_bit(g_bStarted, iAlivePlayer))
334 {
335 new Float:flGameTime = get_gametime();
336
337 message_begin(MSG_ONE_UNRELIABLE, g_iMsgRoundTime, _, iAlivePlayer);
338 write_short(floatround(flGameTime - g_flStartTime[iAlivePlayer], floatround_floor) + 1);
339 message_end();
340
341 for (new iDeadPlayer = 0; iDeadPlayer < MAX_PLAYERS; iDeadPlayer++)
342 {
343 if (get_bit(g_bConnected, iDeadPlayer) && !get_bit(g_bAlive, iDeadPlayer) && entity_get_int(iDeadPlayer, EV_INT_iuser2) == iAlivePlayer && entity_get_int(iDeadPlayer, EV_INT_iuser1) == 4)
344 {
345 new iMinutes = floatround(g_flStartTime[iAlivePlayer] / 60.0, floatround_floor);
346 new iSeconds = floatround(g_flStartTime[iAlivePlayer] - iMinutes * 60, floatround_floor);
347
348 set_hudmessage(0, 255, 0, -1.0, 0.25, 0, _, 0.5, _, _, 1);
349 ShowSyncHudMsg(iDeadPlayer, g_iHudSyncObj, "%02d:%02d", iMinutes, iSeconds);
350 }
351 }
352 }
353 }
354}
355public HamSpawnPlayer_Post(id)
356{
357 set_bit(g_bAlive, id);
358
359 if (get_bit(g_bStarted, id))
360 {
361 clr_bit(g_bStarted, id);
362
363 g_flStartTime[id] = 0.0;
364 }
365}
366public HamKilledPlayer_Post(id)
367{
368 clr_bit(g_bAlive, id);
369
370 if (get_bit(g_bStarted, id))
371 {
372 clr_bit(g_bStarted, id);
373
374 g_flStartTime[id] = 0.0;
375 }
376}
377public HamUseFuncButton_Pre(iEntity, id)
378{
379 if (!get_bit(g_bAlive, id))
380 return(HAM_IGNORED);
381
382 if (g_bTimerFound)
383 {
384 new szTarget[32];
385 entity_get_string(iEntity, EV_SZ_target, szTarget, charsmax(szTarget));
386
387 if (TrieKeyExists(g_tStarts, szTarget))
388 Timer_Start(id);
389 else if (TrieKeyExists(g_tStops, szTarget))
390 Timer_Stop(id);
391 }
392 else
393 {
394 if (iEntity == g_iTimer[START])
395 Timer_Start(id);
396 else if (iEntity == g_iTimer[STOP])
397 Timer_Stop(id);
398 }
399
400 return(HAM_IGNORED);
401}
402Timer_Start(id)
403{
404 set_hudmessage(0, 0, 255, -1.0, 0.90, 0, _, 3.0, _, _, 1);
405
406 if (!get_bit(g_bStarted, id))
407 {
408 set_bit(g_bStarted, id);
409
410 ShowSyncHudMsg(id, g_iHudSyncObj, "Timer started!");
411 }
412 else
413 ShowSyncHudMsg(id, g_iHudSyncObj, "Timer re-started!");
414
415 g_flStartTime[id] = get_gametime();
416}
417Timer_Stop(id)
418{
419 if (!get_bit(g_bStarted, id))
420 return;
421
422 clr_bit(g_bStarted, id);
423
424 g_flFinishTime[id] = get_gametime() - g_flStartTime[id];
425
426 g_flStartTime[id] = 0.0;
427
428 message_begin(MSG_ONE_UNRELIABLE, g_iMsgRoundTime, _, id);
429 write_short(1);
430 message_end();
431
432 new szTime[17];
433 ClimbtimeToString(g_flFinishTime[id], szTime, charsmax(szTime));
434
435 #if defined COLORCHAT
436 ColorChat(id, RED, "^4[%s]^1 You finished map in^3 %s^1!", g_szPrefix, szTime);
437 #else
438 client_print(id, print_chat, "[%s] You finished map in %s!", g_szPrefix, szTime);
439 #endif
440
441 new iPlayers[MAX_PLAYERS], iNum;
442 get_players(iPlayers, iNum, "ch");
443
444 if (iNum)
445 {
446 new szName[32];
447 get_user_name(id, szName, charsmax(szName));
448
449 new iPlayer;
450
451 for (new i = 0; i < iNum; i++)
452 {
453 iPlayer = iPlayers[i];
454
455 if (iPlayer == id)
456 continue;
457
458 #if defined COLORCHAT
459 ColorChat(iPlayer, RED, "^4[%s]^3 %s^1 finished map in^3 %s^1!", g_szPrefix, szName, szTime);
460 #else
461 client_print(iPlayer, print_chat, "[%s] %s finished map in %s!", g_szPrefix, szName, szTime);
462 #endif
463 }
464 }
465
466 new szAuthID[32];
467 get_user_authid(id, szAuthID, charsmax(szAuthID));
468
469 new szQuery[512], cData[1]; cData[0] = id;
470
471 formatex
472 (
473 szQuery, charsmax(szQuery),
474 "SELECT \
475 `TIME` \
476 FROM \
477 `%s` \
478 WHERE \
479 `MAPNAME` = '%s' \
480 AND \
481 `AUTHID` = '%s'",
482 g_szTableName,
483 g_szMapName,
484 szAuthID
485 );
486
487 SQL_ThreadQuery(g_hSqlTuple, "Sql_QueryTop_Handler", szQuery, cData, sizeof(cData));
488}
489public Sql_QueryTop_Handler(iFailState, Handle:hQuery, szError[], iError, cData[], iSize)
490{
491 if (iFailState != TQUERY_SUCCESS)
492 {
493 log_amx("[%s] Sql_IgnoredQuery_Handler(): SQL_Error #%d - %s", g_szPrefix, iError, szError);
494 return;
495 }
496
497 new id = cData[0];
498
499 if (!get_bit(g_bConnected, id))
500 return;
501
502 new szAuthID[32], szName[64], szIP[32], szCountryFull[45], szCountryShort[3], szDate[32];
503 get_user_authid(id, szAuthID, charsmax(szAuthID));
504 get_user_name(id, szName, charsmax(szName));
505 get_user_ip(id, szIP, charsmax(szIP), 1);
506 geoip_country(szIP, szCountryFull, charsmax(szCountryFull));
507 geoip_code2(szIP, szCountryShort);
508 get_time("%Y%m%d%H%M%S", szDate, charsmax(szDate));
509
510 SQL_PrepareString(szName, szName, charsmax(szName));
511
512 new szQuery[512];
513
514 if (SQL_NumResults(hQuery))
515 {
516 new Float:flOldTime, Float:flResult, szTime[17];
517
518 SQL_ReadResult(hQuery, 0, flOldTime);
519
520 if (g_flFinishTime[id] < flOldTime)
521 {
522 flResult = flOldTime - g_flFinishTime[id];
523
524 ClimbtimeToString(flResult, szTime, charsmax(szTime));
525
526 #if defined COLORCHAT
527 ColorChat(id, RED, "^4[%s]^1 You improved your time for^3 %s^1 msec!", g_szPrefix, szTime);
528 #else
529 client_print(id, print_chat, "[%s] You improved your time for %s msec!", g_szPrefix, szTime);
530 #endif
531
532 formatex
533 (
534 szQuery, charsmax(szQuery),
535 "UPDATE `%s` \
536 SET \
537 `NICKNAME` = '%s', \
538 `IP` = '%s', \
539 `COUNTRY_FULL` = '%s', \
540 `COUNTRY_SHORT` = '%s', \
541 `TIME` = '%f', \
542 `DATE` = '%s' \
543 WHERE \
544 `MAPNAME` = '%s' \
545 AND \
546 `AUTHID` = '%s'",
547 g_szTableName,
548 szName,
549 szIP,
550 szCountryFull,
551 szCountryShort,
552 g_flFinishTime[id],
553 szDate,
554 g_szMapName,
555 szAuthID
556 );
557
558 SQL_ThreadQuery(g_hSqlTuple, "Sql_IgnoredQuery_Handler", szQuery);
559
560 formatex
561 (
562 szQuery, charsmax(szQuery),
563 "SELECT \
564 `AUTHID` \
565 FROM \
566 `%s` \
567 WHERE \
568 MAPNAME='%s' \
569 ORDER BY \
570 `TIME` \
571 LIMIT 15",
572 g_szTableName,
573 g_szMapName
574 );
575
576 SQL_ThreadQuery(g_hSqlTuple, "Sql_GetPlaceQuery_Handler", szQuery, cData, sizeof(cData[]));
577 }
578 else
579 {
580 flResult = g_flFinishTime[id] - flOldTime;
581
582 ClimbtimeToString(flResult, szTime, charsmax(szTime));
583
584 #if defined COLORCHAT
585 ColorChat(id, RED, "^4[%s]^1 You failed your time for^3 %s^1 msec!", g_szPrefix, szTime);
586 #else
587 client_print(id, print_chat, "[%s] You failed your time for %s msec!", g_szPrefix, szTime);
588 #endif
589 }
590 }
591 else
592 {
593 formatex
594 (
595 szQuery, charsmax(szQuery),
596 "INSERT INTO `%s` \
597 ( \
598 `MAPNAME`, \
599 `AUTHID`, \
600 `NICKNAME`, \
601 `IP`, \
602 `COUNTRY_FULL`, \
603 `COUNTRY_SHORT`, \
604 `TIME`, \
605 `DATE` \
606 ) \
607 \
608 VALUES \
609 ( \
610 '%s', \
611 '%s', \
612 '%s', \
613 '%s', \
614 '%s', \
615 '%s', \
616 '%f', \
617 '%s' \
618 )",
619 g_szTableName,
620 g_szMapName,
621 szAuthID,
622 szName,
623 szIP,
624 szCountryFull,
625 szCountryShort,
626 g_flFinishTime[id],
627 szDate
628 );
629
630 SQL_ThreadQuery(g_hSqlTuple, "Sql_IgnoredQuery_Handler", szQuery);
631
632 formatex
633 (
634 szQuery, charsmax(szQuery),
635 "SELECT \
636 `AUTHID` \
637 FROM \
638 `%s` \
639 WHERE \
640 MAPNAME='%s' \
641 ORDER BY \
642 `TIME` \
643 LIMIT 15",
644 g_szTableName,
645 g_szMapName
646 );
647
648 SQL_ThreadQuery(g_hSqlTuple, "Sql_GetPlaceQuery_Handler", szQuery, cData, sizeof(cData[]));
649 }
650
651 g_flFinishTime[id] = 0.0;
652}
653public Sql_GetPlaceQuery_Handler(iFailState, Handle:hQuery, szError, iError, cData[], iSize)
654{
655 if (iFailState != TQUERY_SUCCESS)
656 {
657 log_amx("[%s] Sql_GetPlaceQuery_Handler(): SQL_Error #%d - %s", g_szPrefix, iError, szError);
658 return;
659 }
660
661 new id = cData[0];
662
663 if (!get_bit(g_bConnected, id))
664 return;
665
666 new szAuthID[32];
667 get_user_authid(id, szAuthID, charsmax(szAuthID));
668
669 new i, szAuthID_SQL[32];
670
671 while(SQL_MoreResults(hQuery))
672 {
673 i++;
674
675 SQL_ReadResult(hQuery, 0, szAuthID_SQL, charsmax(szAuthID_SQL));
676
677 if (equal(szAuthID, szAuthID_SQL))
678 {
679 #if defined COLORCHAT
680 ColorChat(id, RED, "^4[%s]^1 You are now on^3 %d^1 place in map top!", g_szPrefix, i);
681 #else
682 client_print(id, print_chat, "[%s] You are now on %d place in map top!", g_szPrefix, i);
683 #endif
684
685 new iPlayers[MAX_PLAYERS], iNum;
686 get_players(iPlayers, iNum, "ch");
687
688 if (iNum)
689 {
690 new szName[32];
691 get_user_name(id, szName, charsmax(szName));
692
693 new iPlayer;
694
695 for (new i = 0; i < iNum; i++)
696 {
697 iPlayer = iPlayers[i];
698
699 if (iPlayer == id)
700 continue;
701
702 #if defined COLORCHAT
703 ColorChat(iPlayer, RED, "^4[%s]^3 %s^1 is now on^3 %d^1 place in map top!", g_szPrefix, szName, i);
704 #else
705 client_print(iPlayer, print_chat, "[%s] %s is now on %d place in map top!", g_szPrefix, szName, i);
706 #endif
707 }
708 }
709 break;
710 }
711 SQL_NextRow(hQuery);
712 }
713}
714public Sql_IgnoredQuery_Handler(iFailState, Handle:hQuery, szError[], iError, cData[], iSize)
715{
716 if (iFailState != TQUERY_SUCCESS)
717 {
718 log_amx("[%s] Sql_IgnoredQuery_Handler(): SQL_Error #%d - %s", g_szPrefix, iError, szError);
719 return;
720 }
721}
722public ClCmdBest(id)
723{
724 if (!g_bSqlite)
725 {
726 new szWebLink[128];
727 get_pcvar_string(g_pWebLink, szWebLink, charsmax(szWebLink));
728
729 new szMotd[256];
730 formatex(szMotd, charsmax(szMotd), "<META HTTP-EQUIV=^"REFRESH^" CONTENT=^"0;URL=%s/maptop.php?mapname=%s^">", szWebLink, g_szMapName);
731
732 show_motd(id, szMotd, "DR - Map Top");
733 }
734 else
735 {
736 new szQuery[512], cData[1]; cData[0] = id;
737
738 formatex
739 (
740 szQuery, charsmax(szQuery),
741 "SELECT \
742 `NICKNAME`, \
743 `TIME` \
744 FROM \
745 `%s` \
746 WHERE \
747 `MAPNAME` = '%s' \
748 ORDER BY \
749 `TIME` \
750 LIMIT 15",
751 g_szTableName,
752 g_szMapName
753 );
754
755 SQL_ThreadQuery(g_hSqlTuple, "Sql_LoadTopQuery_Handler", szQuery, cData, sizeof(cData));
756 }
757}
758public Sql_LoadTopQuery_Handler(iFailState, Handle:hQuery, szError, iError, cData[], iSize)
759{
760 if (iFailState != TQUERY_SUCCESS)
761 {
762 log_amx("[%s] Sql_GetPlaceQuery_Handler(): SQL_Error #%d - %s", g_szPrefix, iError, szError);
763 return;
764 }
765
766 new id = cData[0];
767
768 if (!get_bit(g_bConnected, id))
769 return;
770
771 new szMotd[1536], iSize = charsmax(szMotd);
772
773 new iLen = formatex
774 (
775 szMotd, iSize,
776 "<!DOCTYPE HTML> \
777 <html> \
778 <head> \
779 <style type=^"text/css^"> \
780 body \
781 { \
782 background: #000; \
783 margin: 8px; \
784 color: #FFB000; \
785 font: normal 16px/20px Verdana, Tahoma, sans-serif; \
786 text-align: center; \
787 } \
788 th:nth-child(2){ text-align: left; } \
789 td:nth-child(2){ text-align: left; } \
790 </style> \
791 </head> \
792 <body>"
793 );
794
795 iLen += formatex
796 (
797 szMotd[iLen], iSize - iLen,
798 "<table align=^"center^" width=^"90%%^"> \
799 <tr> \
800 <th width=^"5%%^">#</th>\
801 <th width=^"40%%^">Player</th>\
802 <th width=^"20%%^">Time</th>\
803 </tr> \
804 "
805 );
806
807 new i = 1;
808 new Float:flTime, szName[32], szTime[32];
809
810 while (SQL_MoreResults(hQuery))
811 {
812 SQL_ReadResult(hQuery, 0, szName, 31);
813 SQL_ReadResult(hQuery, 1, flTime);
814
815 ClimbtimeToString(flTime, szTime, 16);
816
817 iLen += formatex
818 (
819 szMotd[iLen], iSize - iLen,
820 "<tr> \
821 <td>%d</td> \
822 <td>%s</td> \
823 <td>%s</td> \
824 </tr>",
825 i,
826 szName,
827 szTime
828 );
829
830 i++;
831 SQL_NextRow(hQuery);
832 }
833
834 formatex
835 (
836 szMotd[iLen], iSize - iLen,
837 "</table> \
838 </body> \
839 </html>"
840 );
841
842 show_motd(id, szMotd, "DR - Map Top");
843}
844stock SQL_PrepareString(const szQuery[], szOutPut[], iSize)
845{
846 copy(szOutPut, iSize, szQuery);
847 replace_all(szOutPut, iSize, "'", "\'");
848 replace_all(szOutPut, iSize, "`", "\`");
849 replace_all(szOutPut, iSize, "\\", "\\\\");
850}
851ClimbtimeToString(Float:flClimbTime, szOutPut[], iLen)
852{
853 new iMinutes = floatround(flClimbTime / 60.0, floatround_floor);
854 new iSeconds = floatround(flClimbTime - iMinutes * 60, floatround_floor);
855 new iMiliSeconds = floatround((flClimbTime - (iMinutes * 60 + iSeconds)) * 100, floatround_floor);
856
857 formatex(szOutPut, iLen, "%02i:%02i.%02i", iMinutes, iSeconds, iMiliSeconds);
858}
859public ClCmdTimer(id)
860{
861 if (~get_user_flags(id) & ADMIN_ACCESS)
862 {
863 #if defined COLORCHAT
864 ColorChat(id, NORMAL, "^4[%s]^1 You don't have enought access!", g_szPrefix);
865 #else
866 client_print(id, print_chat, "[%s] You don't have enought access!", g_szPrefix);
867 #endif
868
869 return(PLUGIN_HANDLED);
870 }
871 if (g_bTimerFound)
872 {
873 #if defined COLORCHAT
874 ColorChat(id, NORMAL, "^4[%s]^1 This map already have timers!", g_szPrefix);
875 #else
876 client_print(id, print_chat, "[%s] This map already have timers!", g_szPrefix);
877 #endif
878 return(PLUGIN_HANDLED);
879 }
880 if (!get_bit(g_bAlive, id))
881 {
882 #if defined COLORCHAT
883 ColorChat(id, NORMAL, "^4[%s]^1 You should be alive!", g_szPrefix);
884 #else
885 client_print(id, print_chat, "[%s] You should be alive!", g_szPrefix);
886 #endif
887 return(PLUGIN_HANDLED);
888 }
889
890 TimerMenu(id);
891
892 return(PLUGIN_HANDLED);
893}
894public TimerMenu(id)
895{
896 new iMenu = menu_create("\r[DeathRun]\y Timer Menu", "TimerMenu_Handler");
897
898 menu_additem(iMenu, "Create");
899 menu_additem(iMenu, "Rotate^n");
900
901 menu_additem(iMenu, "Save^n");
902
903 new szMenuItem[64];
904 formatex(szMenuItem, charsmax(szMenuItem), "Timer - (\y%s\w)", g_szTimerName[g_iPlayerTimer[id]]);
905 menu_additem(iMenu, szMenuItem);
906
907 menu_display(id, iMenu);
908}
909public TimerMenu_Handler(id, iMenu, iItem)
910{
911 if (iItem == MENU_EXIT)
912 {
913 menu_destroy(iMenu);
914 return(PLUGIN_HANDLED);
915 }
916
917 switch (iItem)
918 {
919 case 0: create_timer(id, g_iPlayerTimer[id]);
920 case 1:
921 {
922 if (is_valid_ent(g_iTimer[g_iPlayerTimer[id]]))
923 {
924 switch (g_iTimerAngles[g_iPlayerTimer[id]])
925 {
926 case 3: g_iTimerAngles[g_iPlayerTimer[id]] = 0;
927 case 0, 1, 2: g_iTimerAngles[g_iPlayerTimer[id]]++;
928 }
929
930 new Float:vAngles[3];
931 vAngles[1] = g_flTimerAngles[g_iTimerAngles[g_iPlayerTimer[id]]];
932
933 entity_set_vector(g_iTimer[g_iPlayerTimer[id]], EV_VEC_angles, vAngles);
934 }
935 }
936 case 2:
937 {
938 if (is_valid_ent(g_iTimer[g_iPlayerTimer[id]]))
939 {
940 if (g_iVault == INVALID_HANDLE)
941 return(PLUGIN_HANDLED);
942
943 new szData[128], iTimestamp;
944
945 if (nvault_lookup(g_iVault, g_szTimerName[g_iPlayerTimer[id]], szData, charsmax(szData), iTimestamp))
946 nvault_remove(g_iVault, g_szTimerName[g_iPlayerTimer[id]]);
947
948 formatex(szData, charsmax(szData), "^"%.1f^" ^"%.1f^" ^"%.1f^" ^"%d^"", g_vTimerOrigin[g_iPlayerTimer[id]][0], g_vTimerOrigin[g_iPlayerTimer[id]][1], g_vTimerOrigin[g_iPlayerTimer[id]][2], g_iTimerAngles[g_iPlayerTimer[id]]);
949
950 nvault_set(g_iVault, g_szTimerName[g_iPlayerTimer[id]], szData);
951
952 #if defined COLORCHAT
953 ColorChat(id, RED, "^4[%s]^1 Timer (^3%s^1) saved!", g_szPrefix, g_szTimerName[g_iPlayerTimer[id]]);
954 #else
955 client_print(id, print_chat, "[%s] Timer (%s) saved!", g_szPrefix, g_szTimerName[g_iPlayerTimer[id]]);
956 #endif
957 }
958 }
959 case 3:
960 {
961 switch (g_iPlayerTimer[id])
962 {
963 case START: g_iPlayerTimer[id] = STOP;
964 case STOP: g_iPlayerTimer[id] = START;
965 }
966 }
967 }
968
969 ClCmdTimer(id);
970 return(PLUGIN_HANDLED);
971}
972LoadTimers()
973{
974 if (g_iVault == INVALID_HANDLE)
975 return;
976
977 for (new i = 0; i < 2; i++)
978 {
979 new szData[128], iTimestamp;
980 if (nvault_lookup(g_iVault, g_szTimerName[i], szData, charsmax(szData), iTimestamp))
981 {
982 new szOrigin[3][17], szAngles[2];
983 parse(szData, szOrigin[0], charsmax(szOrigin[]), szOrigin[1], charsmax(szOrigin[]), szOrigin[2], charsmax(szOrigin[]), szAngles, charsmax(szAngles));
984
985 for (new x = 0; x < 3; x++)
986 g_vTimerOrigin[i][x] = str_to_float(szOrigin[x]);
987
988 g_iTimerAngles[i] = str_to_num(szAngles);
989
990 create_timer(0, i, g_vTimerOrigin[i]);
991 }
992 else
993 continue;
994 }
995}
996stock create_timer(id, iType, Float:vOrigin[3] = {0.0, 0.0, 0.0})
997{
998 if (!g_iTimer[iType])
999 {
1000 new iEntity = create_entity("func_button");
1001
1002 if (!is_valid_ent(iEntity))
1003 return;
1004
1005 new szClassName[32];
1006 formatex(szClassName, charsmax(szClassName), "Timer_%s", g_szTimerName[iType]);
1007
1008 entity_set_string(iEntity, EV_SZ_classname, szClassName);
1009 entity_set_int(iEntity, EV_INT_solid, SOLID_BBOX);
1010 entity_set_int(iEntity, EV_INT_movetype, MOVETYPE_NONE);
1011 entity_set_model(iEntity, g_szTimerModels[iType]);
1012 entity_set_size(iEntity, Float:{-16.0, -16.0, 0.0}, Float:{16.0, 16.0, 60.0});
1013
1014 g_iTimer[iType] = iEntity;
1015 }
1016 if (id)
1017 {
1018 new vOriginI[3];
1019 get_user_origin(id, vOriginI, 3);
1020
1021 new Float:vOriginF[3];
1022 IVecFVec(vOriginI, vOriginF);
1023
1024 entity_set_origin(g_iTimer[iType], vOriginF);
1025
1026 for (new i = 0; i < 3; i++)
1027 g_vTimerOrigin[iType][i] = vOriginF[i];
1028 }
1029 else
1030 entity_set_origin(g_iTimer[iType], vOrigin);
1031
1032 new Float:vAngles[3];
1033 vAngles[1] = g_flTimerAngles[g_iTimerAngles[iType]];
1034
1035 entity_set_vector(g_iTimer[iType], EV_VEC_angles, vAngles);
1036
1037 drop_to_floor(g_iTimer[iType]);
1038}
1039public plugin_end()
1040{
1041 if (g_bTimerFound)
1042 {
1043 TrieDestroy(g_tStarts);
1044 TrieDestroy(g_tStops);
1045 }
1046 else
1047 {
1048 if (g_iVault != INVALID_HANDLE)
1049 nvault_close(g_iVault);
1050 }
1051
1052 SQL_FreeHandle(g_hSqlTuple);
1053}