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