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