· 7 years ago · Sep 27, 2018, 07:32 PM
1#include <amxmodx>
2#include <amxmisc>
3#include <cstrike>
4#include <engine>
5#include <fakemeta>
6#include <hamsandwich>
7#include <geoip>
8#include <sqlx>
9#include <speedrun>
10
11new const PluginName [] = "Speedrun Mod [Timer & Stats]"
12new const PluginVersion [] = "1.3"
13new const PluginAuthor [] = "IceBeam / SQN, Mistrick, R3X"
14
15new const PREFIX[] = "^4[SR]";
16
17#define FL_WATERJUMP (1<<11)
18#define FL_ONGROUND (1<<9)
19
20#define MAX_STRAFES 600
21
22enum _:Categories
23{
24 Cat_100fps,
25 Cat_200fps,
26 Cat_250fps,
27 Cat_333fps,
28 Cat_500fps,
29 Cat_1000fps,
30 Cat_2000fps,
31 Cat_CS,
32 Cat_HCS,
33 Cat_ICS,
34 Cat_CSLG,
35 Cat_1kRun,
36 Cat_2kRun,
37 Cat_3kRun,
38 Cat_4kRun,
39 Cat_5kRun,
40 Cat_6kRun,
41 Cat_Gravity,
42 Cat_Legit,
43 Cat_100n,
44 Cat_200n,
45 Cat_250n,
46 Cat_333n,
47 Cat_500n,
48 Cat_ES,
49 Cat_SW,
50 Cat_DJUMP
51};
52
53new const szSounds[][] = {
54 "sound/newold_with_trocek/1.mp3",
55 "sound/newold_with_trocek/2.mp3",
56 "sound/newold_with_trocek/3.mp3",
57 "sound/newold_with_trocek/4.mp3",
58 "sound/newold_with_trocek/5.mp3",
59 "sound/newold_with_trocek/6.mp3",
60 "sound/newold_with_trocek/7.mp3",
61 "sound/newold_with_trocek/8.mp3",
62 "sound/newold_with_trocek/9.mp3",
63 "sound/newold_with_trocek/10.mp3",
64 "sound/newold_with_trocek/11.mp3",
65 "sound/newold_with_trocek/12.mp3",
66 "sound/newold_with_trocek/13.mp3",
67 "sound/newold_with_trocek/14.mp3",
68 "sound/newold_with_trocek/15.mp3",
69 "sound/newold_with_trocek/16.mp3",
70 "sound/newold_with_trocek/17.mp3",
71 "sound/newold_with_trocek/18.mp3",
72 "sound/newold_with_trocek/19.mp3",
73 "sound/newold_with_trocek/20.mp3",
74 "sound/newold_with_trocek/21.mp3",
75 "sound/newold_with_trocek/22.mp3",
76 "sound/newold_with_trocek/23.mp3",
77 "sound/newold_with_trocek/24.mp3",
78 "sound/newold_with_trocek/25.mp3",
79 "sound/newold_with_trocek/26.mp3",
80 "sound/newold_with_trocek/27.mp3",
81 "sound/newold_with_trocek/28.mp3",
82 "sound/newold_with_trocek/29.mp3",
83 "sound/newold_with_trocek/30.mp3",
84 "sound/newold_with_trocek/31.mp3",
85 "sound/newold_with_trocek/32.mp3",
86 "sound/newold_with_trocek/33.mp3",
87 "sound/newold_with_trocek/34.mp3",
88 "sound/newold_with_trocek/35.mp3",
89 "sound/newold_with_trocek/36.mp3",
90 "sound/newold_with_trocek/37.mp3",
91 "sound/newold_with_trocek/38.mp3",
92 "sound/newold_with_trocek/39.mp3",
93 "sound/newold_with_trocek/40.mp3",
94 "sound/newold_with_trocek/41.mp3",
95 "sound/newold_with_trocek/42.mp3",
96 "sound/newold_with_trocek/43.mp3",
97 "sound/newold_with_trocek/44.mp3",
98 "sound/newold_with_trocek/45.mp3",
99 "sound/newold_with_trocek/46.mp3",
100 "sound/newold_with_trocek/47.mp3",
101 "sound/newold_with_trocek/48.mp3",
102 "sound/newold_with_trocek/49.mp3"
103}
104
105new const DATABASE[] = "addons/amxmodx/data/speedrun_stats.db";
106
107new const g_szCategory[][] = { "100 FPS", "200 FPS", "250 FPS", "333 FPS", "500 FPS", "Simulated 1000 FPS", "Simulated 2000 FPS", "Crazy Speed", "Hard Crazy Speed", "Insane Crazy Speed", "CrazySpeed - LOW GRAVITY",
108 "1K RUN", "2K RUN", "3K RUN", "4K RUN", "5K RUN", "6K RUN", "Low Gravity", "Legit (No AutoBH)", "Strafe Booster - 100FPS", "Strafe Booster - 200FPS", "Strafe Booster - 250FPS", "Strafe Booster - 333FPS", "Strafe Booster - 500FPS", "Easy Crazy Speed", "Sideways", "Double Jump"};
109new Handle:g_hTuple, g_szQuery[512];
110new g_szMapName[32];
111new g_iMapIndex;
112new g_szMotd[1536];
113new g_iBestTime[33][Categories];
114new g_iBestTimeofMap[Categories];
115new g_iPlayerFinished;
116new g_iReturn;
117
118new m_iPlayerIndex[33];
119new m_iPlayerAuthorized[33];
120new m_iPlayerConnected[33];
121
122new Float:m_iStarted[33];
123new bool:m_iFinished[33];
124new m_iTimerStarted[33];
125new m_iJumpCount[33];
126new m_iStrafeCount[33];
127new m_CheckButton[33];
128
129new m_LastTime[33];
130new Float:m_LastInfo[33];
131
132new bool:g_bStrafingAw[33], bool:g_bStrafingSd[33], bool:g_bTurningLeft[33], bool:g_bTurningRight[33];
133new Float:g_fMaxSpeed[33], Float:g_fOldAngles[33], Float:g_fOldSpeed[33]
134new g_iGoodSync[33], g_iSyncFrames[33]
135new g_iStrafeFrames[33][MAX_STRAFES], g_iStrafeGoodSync[33][MAX_STRAFES];
136
137new FinishEntity = 0;
138new const EntityName[] = "sr_finish";
139new EntitySprite;
140new const EntitySprite2[] = "sprites/speedrun_paek/logo_sr.spr";
141
142public plugin_init()
143{
144 register_plugin(PluginName, PluginVersion, PluginAuthor)
145
146 new serverIP[] = "145.239.236.193:27125";
147
148 new szIp[ 33 ];
149 get_user_ip( 0, szIp, charsmax( szIp ) );
150
151 if( !equal( szIp , serverIP ) ){
152 server_print("Something went wrong!");
153 set_fail_state("Check all plugins.");
154 }
155
156 server_print("Loading speedrun..");
157
158 register_clcmd("setfinish", "Command_SetFinish", ADMIN_BAN);
159
160 register_think(EntityName, "CBasePlayer_Think");
161
162 register_clcmd("say /top15", "Command_Top15");
163 register_clcmd("say /top", "Command_Top15");
164 register_clcmd("say /wr", "Command_Top15");
165 register_clcmd("say !wr", "Command_Top15");
166 register_clcmd("say !top15", "Command_Top15");
167 register_clcmd("say !top", "Command_Top15");
168
169 register_clcmd("say /update", "Command_Update")
170 register_clcmd("say /nick", "Command_Update")
171 register_clcmd("say /updatenickname", "Command_Update")
172
173 RegisterHam(Ham_Spawn, "player", "CBasePlayer_Spawn");
174
175 register_forward(FM_PlayerPreThink, "CBasePlayer_PreThink");
176 register_forward(FM_PlayerPreThink, "CBasePlayer_StartTimer");
177 register_forward(FM_CmdStart, "CBasePlayer_JumpCount");
178
179 register_forward(FM_PlayerPostThink, "SRPlayer_Strafecount", 0);
180
181 g_iPlayerFinished = CreateMultiForward("SR_PlayerFinished", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL);
182
183 SQL_Init();
184}
185
186public plugin_precache()
187{
188 precache_model(EntitySprite2);
189 EntitySprite = precache_model("sprites/speedrun_paek/speedrun_logo_g.spr");
190
191 for(new i=0; i<sizeof(szSounds); i++)
192 precache_generic(szSounds[i]);
193}
194public Command_SetFinish(id, level, cid)
195{
196 if(!cmd_access(id, level, cid, 1 ))
197 return PLUGIN_HANDLED;
198
199 if(!FinishEntity)
200 {
201 client_print_color(id, print_team_red, "The finish entity is not set!");
202 if(get_user_flags(id) & ADMIN_CFG)
203 client_print_color(id, print_team_default, "%s^1[ADMIN]^3 You can set the finish entity sprite using 'setfinish' command.", PREFIX);
204 }
205
206 new Float:fOrigin[3];
207 pev(id, pev_origin, fOrigin);
208
209 Create_Finish(fOrigin);
210 Save_FinishOrigin()
211
212 client_print_color(id, print_team_default, "%s^1[ADMIN]^3 Finish entity sprite set!", PREFIX);
213
214 return PLUGIN_HANDLED;
215}
216Save_FinishOrigin()
217{
218 if(is_valid_ent(FinishEntity))
219 {
220 new Float:fOrigin[3]; pev(FinishEntity, pev_origin, fOrigin);
221 new iOrigin[3]; FVecIVec(fOrigin, iOrigin);
222
223 formatex(g_szQuery, charsmax(g_szQuery), "UPDATE `maps` SET finishX = '%d', finishY = '%d', finishZ = '%d' WHERE mid=%d",
224 iOrigin[0], iOrigin[1], iOrigin[2], g_iMapIndex);
225
226 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
227 }
228}
229SQL_Init() {
230 SQL_SetAffinity("sqlite");
231
232 if(!file_exists(DATABASE))
233 {
234 new file = fopen(DATABASE, "w");
235 if(!file)
236 {
237 new szMsg[128]; formatex(szMsg, charsmax(szMsg), "%s file not found and cant be created.", DATABASE);
238 set_fail_state(szMsg);
239 }
240 fclose(file);
241 }
242
243 g_hTuple = SQL_MakeDbTuple("", "", "", DATABASE, 0);
244
245 formatex(g_szQuery, charsmax(g_szQuery),
246 "CREATE TABLE IF NOT EXISTS `runners`( \
247 id INTEGER PRIMARY KEY,\
248 steamid TEXT NOT NULL, \
249 nickname TEXT NOT NULL, \
250 ip TEXT NOT NULL, \
251 nationality TEXT NULL)");
252
253 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
254
255 formatex(g_szQuery, charsmax(g_szQuery),
256 "CREATE TABLE IF NOT EXISTS `maps`( \
257 mid INTEGER PRIMARY KEY,\
258 mapname TEXT NOT NULL UNIQUE, \
259 finishX INTEGER NOT NULL DEFAULT 0, \
260 finishY INTEGER NOT NULL DEFAULT 0, \
261 finishZ INTEGER NOT NULL DEFAULT 0)");
262
263 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
264
265 formatex(g_szQuery, charsmax(g_szQuery),
266 "CREATE TABLE IF NOT EXISTS `results`( \
267 id INTEGER NOT NULL, \
268 mid INTEGER NOT NULL, \
269 category INTEGER NOT NULL, \
270 besttime INTEGER NOT NULL, \
271 recorddate DATETIME NULL, \
272 FOREIGN KEY(id) REFERENCES `runners`(id) ON DELETE CASCADE, \
273 FOREIGN KEY(mid) REFERENCES `maps`(mid) ON DELETE CASCADE, \
274 PRIMARY KEY(id, mid, category))");
275
276 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
277
278 set_task(1.0, "DelayedLoadMapInfo");
279}
280public DelayedLoadMapInfo()
281{
282 get_mapname(g_szMapName, charsmax(g_szMapName));
283 formatex(g_szQuery, charsmax(g_szQuery), "SELECT mid, finishX, finishY, finishZ FROM `maps` WHERE mapname='%s'", g_szMapName);
284 SQL_ThreadQuery(g_hTuple, "Query_LoadMapHandle", g_szQuery);
285}
286public Query_LoadMapHandle(failstate, Handle:query, error[], errnum, data[], size)
287{
288 if(failstate != TQUERY_SUCCESS)
289 {
290 log_amx("SQL error[LoadMapHandle]: %s", error); return;
291 }
292
293 if(SQL_MoreResults(query))
294 {
295 g_iMapIndex = SQL_ReadResult(query, 0);
296
297 CreateFinishI(SQL_ReadResult(query, 1), SQL_ReadResult(query, 2), SQL_ReadResult(query, 3));
298 }
299 else
300 {
301 formatex(g_szQuery, charsmax(g_szQuery), "INSERT INTO `maps`(mapname) VALUES ('%s')", g_szMapName);
302 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
303
304 formatex(g_szQuery, charsmax(g_szQuery), "SELECT mid, finishX, finishY, finishZ FROM `maps` WHERE mapname='%s'", g_szMapName);
305 SQL_ThreadQuery(g_hTuple, "Query_LoadMapHandle", g_szQuery);
306 }
307
308 if(g_iMapIndex)
309 {
310 for(new i = 1; i <= 32; i++)
311 {
312 if(m_iPlayerConnected[i]) ClientAuthorization(i);
313 }
314 for(new i; i < Categories; i++)
315 {
316 ShowTop15(0, i);
317 }
318 }
319}
320public Query_IngnoredHandle(failstate, Handle:query, error[], errnum, data[], size)
321{
322 if(failstate != TQUERY_SUCCESS)
323 {
324 log_amx("SQL error[IngnoredHandle]: %s", error); return;
325 }
326}
327CreateFinishI(x, y, z)
328{
329 if(!x && !y && !z) return;
330
331 new Float:fOrigin[3];
332 fOrigin[0] = float(x);
333 fOrigin[1] = float(y);
334 fOrigin[2] = float(z);
335
336 Create_Finish(fOrigin);
337}
338// not the best shit...
339public Create_Finish(const Float:fOrigin[3]) {
340
341 if(pev_valid(FinishEntity))
342 {
343 remove_entity(FinishEntity);
344 }
345
346 FinishEntity = 0;
347
348 new ent = create_entity("info_target");
349 set_pev(ent, pev_classname, EntityName);
350
351 engfunc( EngFunc_SetModel, ent, EntitySprite2);
352
353 set_pev(ent, pev_origin, fOrigin);
354
355 dllfunc(DLLFunc_Spawn, ent);
356
357 entity_set_size(ent, Float:{-50.0, -50.0, -25.0}, Float:{50.0, 50.0, 25.0});
358
359 set_pev(ent, pev_solid, SOLID_TRIGGER);
360 set_pev(ent, pev_movetype, MOVETYPE_NONE);
361
362 set_pev( ent, pev_rendermode, kRenderTransAdd);
363 set_pev( ent, pev_renderamt, 220.0);
364
365 FinishEntity = ent;
366
367 set_pev(ent, pev_nextthink, get_gametime() + 3);
368
369}
370
371public client_connect(id)
372{
373 m_iPlayerAuthorized[id] = false;
374 m_iFinished[id] = false;
375 m_iTimerStarted[id] = false;
376 m_iPlayerIndex[id] = 0;
377 m_LastTime[id] = 0;
378 m_CheckButton[id] = 0;
379 m_iJumpCount[id] = 0;
380 m_iStrafeCount[id] = 0;
381}
382public client_putinserver(id)
383{
384 if(!is_user_bot(id) && !is_user_hltv(id))
385 {
386 m_iPlayerConnected[id] = true;
387 ClientAuthorization(id);
388 }
389}
390public CBasePlayer_JumpCount(id, uc_handle)
391{
392 static button,flags
393 button = get_uc(uc_handle,UC_Buttons)
394 flags = pev(id, pev_flags)
395
396 if(button & IN_JUMP) {
397 if(flags & FL_ONGROUND) {
398 m_iJumpCount[id]++
399 }
400 }
401}
402public CBasePlayer_Spawn(id)
403{
404 if(!is_user_alive(id)) return;
405
406 m_iTimerStarted[id] = false;
407 m_iFinished[id] = false;
408 m_iStarted[id] = -1.0;
409 m_iJumpCount[id] = 0;
410 m_iStrafeCount[id] = 0;
411 m_CheckButton[id] = 0;
412
413 hide_timer(id);
414}
415
416public SRPlayer_Strafecount(id)
417{
418 if(!is_user_alive(id)) return FMRES_IGNORED;
419
420 static bool:bOnGround; bOnGround = bool:(pev(id, pev_flags) & FL_ONGROUND);
421
422 static Float:fAngles[3]; pev(id, pev_angles, fAngles);
423
424 g_bTurningRight[id] = false;
425 g_bTurningLeft[id] = false;
426
427 if(fAngles[1] < g_fOldAngles[id])
428 {
429 g_bTurningRight[id] = true;
430 }
431 else if(fAngles[1] > g_fOldAngles[id])
432 {
433 g_bTurningLeft[id] = true;
434 }
435 g_fOldAngles[id] = fAngles[1];
436
437 if(bOnGround) return FMRES_IGNORED;
438
439 static iButtons; iButtons = pev(id, pev_button);
440 static Float:fVelocity[3]; pev(id, pev_velocity, fVelocity);
441 static Float:fSpeed; fSpeed = floatsqroot(fVelocity[0] * fVelocity[0] + fVelocity[1] * fVelocity[1]);
442
443 if(g_bTurningLeft[id] || g_bTurningRight[id])
444 {
445 if(!g_bStrafingAw[id] && ((iButtons & IN_FORWARD)
446 || (iButtons & IN_MOVELEFT)) && !(iButtons & IN_MOVERIGHT) && !(iButtons & IN_BACK))
447 {
448 g_bStrafingAw[id] = true;
449 g_bStrafingSd[id] = false;
450
451 m_iStrafeCount[id]++;
452 }
453 else if(!g_bStrafingSd[id] && ((iButtons & IN_BACK)
454 || (iButtons & IN_MOVERIGHT)) && !(iButtons & IN_MOVELEFT) && !(iButtons & IN_FORWARD))
455 {
456 g_bStrafingAw[id] = false;
457 g_bStrafingSd[id] = true;
458
459 m_iStrafeCount[id]++;
460 }
461 }
462
463 if(g_fMaxSpeed[id] < fSpeed)
464 {
465 g_fMaxSpeed[id] = fSpeed;
466 }
467
468 if(g_fOldSpeed[id] < fSpeed)
469 {
470 g_iGoodSync[id]++;
471
472 if(m_iStrafeCount[id] && m_iStrafeCount[id] <= MAX_STRAFES)
473 {
474 g_iStrafeGoodSync[id][m_iStrafeCount[id] - 1]++;
475 }
476 }
477
478 g_iSyncFrames[id]++;
479
480 if(m_iStrafeCount[id] && m_iStrafeCount[id] <= MAX_STRAFES)
481 {
482 g_iStrafeFrames[id][m_iStrafeCount[id] - 1]++;
483 }
484
485 g_fOldSpeed[id] = fSpeed;
486
487 return FMRES_IGNORED;
488}
489public CBasePlayer_PreThink(id)
490{
491 if(!is_user_alive(id) || m_iStarted[id] <= 0.0)
492 return FMRES_IGNORED;
493
494 static Float:fNow;
495
496 if(!m_iFinished[id])
497 {
498 fNow = get_gametime();
499
500 if((fNow-m_LastInfo[id]) <= 0.5) return FMRES_IGNORED;
501
502 display_time(id, get_running_time(id));
503 }
504 return FMRES_IGNORED;
505}
506public CBasePlayer_StartTimer(id)
507{
508 if (entity_get_int(id, EV_INT_button) & 2) {
509 new flags = entity_get_int(id, EV_INT_flags)
510
511 if (flags & FL_WATERJUMP)
512 return PLUGIN_CONTINUE
513 if (entity_get_int(id, EV_INT_waterlevel) >= 2)
514 return PLUGIN_CONTINUE
515 if (!(flags & FL_ONGROUND))
516 return PLUGIN_CONTINUE
517
518 if(m_CheckButton[id] == 0 && !m_iTimerStarted[id])
519 {
520 PlayerStarted(id);
521 m_CheckButton[id] = 1;
522 }
523 }
524 new button = get_user_button(id)
525 if (button & IN_DUCK)
526 {
527 if(m_CheckButton[id] == 0 && !m_iTimerStarted[id])
528 {
529 PlayerStarted(id);
530 m_CheckButton[id] = 1;
531 }
532 }
533 return PLUGIN_CONTINUE
534}
535ClientAuthorization(id)
536{
537 if(!g_iMapIndex) return;
538
539 new szAuth[32]; get_user_authid(id, szAuth, charsmax(szAuth));
540
541 new data[1]; data[0] = id;
542 formatex(g_szQuery, charsmax(g_szQuery), "SELECT id, ip, nationality FROM `runners` WHERE steamid='%s'", szAuth);
543 SQL_ThreadQuery(g_hTuple, "Query_LoadRunnerInfoHandler", g_szQuery, data, sizeof(data));
544}
545public Query_LoadRunnerInfoHandler(failstate, Handle:query, error[], errnum, data[], size)
546{
547 if(failstate != TQUERY_SUCCESS)
548 {
549 log_amx("SQL error[LoadRunnerInfo]: %s",error); return;
550 }
551
552 new id = data[0];
553 if(!is_user_connected(id)) return;
554
555 new szCode[5];
556
557 if(SQL_MoreResults(query))
558 {
559 client_authorized_db(id, SQL_ReadResult(query, 0));
560
561 SQL_ReadResult(query, 2, szCode, 1);
562
563 if(szCode[0] == 0)
564 {
565 new szIP[32]; get_user_ip(id, szIP, charsmax(szIP), 1);
566
567 get_nationality(id, szIP, szCode);
568 formatex(g_szQuery, charsmax(g_szQuery), "UPDATE `runners` SET nationality='%s' WHERE id=%d", szCode, m_iPlayerIndex[id]);
569 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
570 }
571 }
572 else
573 {
574 new szAuth[32]; get_user_authid(id, szAuth, charsmax(szAuth));
575 new szIP[32]; get_user_ip(id, szIP, charsmax(szIP), 1);
576 new szName[64]; get_user_name(id, szName, charsmax(szName));
577 SQL_PrepareString(szName, szName, 63);
578
579 get_nationality(id, szIP, szCode);
580
581 formatex(g_szQuery, charsmax(g_szQuery), "INSERT INTO `runners` (steamid, nickname, ip, nationality) VALUES ('%s', '%s', '%s', '%s')", szAuth, szName, szIP, szCode);
582 SQL_ThreadQuery(g_hTuple, "Query_InsertRunnerHandle", g_szQuery, data, size);
583 }
584}
585public Query_InsertRunnerHandle(failstate, Handle:query, error[], errnum, data[], size)
586{
587 if(failstate != TQUERY_SUCCESS)
588 {
589 log_amx("SQL error[InsertRunner]: %s",error); return;
590 }
591
592 new id = data[0];
593 if(!is_user_connected(id)) return;
594
595 client_authorized_db(id , SQL_GetInsertId(query));
596}
597client_authorized_db(id, pid)
598{
599 m_iPlayerIndex[id] = pid;
600 m_iPlayerAuthorized[id] = true;
601
602 arrayset(g_iBestTime[id], 0, sizeof(g_iBestTime[]));
603
604 LoadRunnerData(id);
605}
606LoadRunnerData(id)
607{
608 if(!m_iPlayerAuthorized[id]) return;
609
610 new data[1]; data[0] = id;
611
612 formatex(g_szQuery, charsmax(g_szQuery), "SELECT * FROM `results` WHERE id=%d AND mid=%d", m_iPlayerIndex[id], g_iMapIndex);
613 SQL_ThreadQuery(g_hTuple, "Query_LoadDataHandle", g_szQuery, data, sizeof(data));
614}
615public Query_LoadDataHandle(failstate, Handle:query, error[], errnum, data[], size)
616{
617 if(failstate != TQUERY_SUCCESS)
618 {
619 log_amx("SQL Insert error: %s",error); return;
620 }
621
622 new id = data[0];
623 if(!is_user_connected(id)) return;
624
625 while(SQL_MoreResults(query))
626 {
627 new category = SQL_ReadResult(query, 2);
628 g_iBestTime[id][category] = SQL_ReadResult(query, 3);
629
630 SQL_NextRow(query);
631 }
632}
633
634public client_disconnected(id)
635{
636 m_iPlayerAuthorized[id] = false;
637 m_iPlayerConnected[id] = false;
638}
639
640
641public Command_Top15(id)
642{
643 if(is_flooding(id)) return PLUGIN_HANDLED;
644
645 ShowTop15(id, get_user_category(id));
646
647 return PLUGIN_CONTINUE;
648}
649
650public Command_Update(id)
651{
652 if(!m_iPlayerAuthorized[id] || is_flooding(id)) return PLUGIN_HANDLED;
653
654 new szName[32]; get_user_name(id, szName, charsmax(szName)); SQL_PrepareString(szName, szName, charsmax(szName));
655 formatex(g_szQuery, charsmax(g_szQuery), "UPDATE `runners` SET nickname = '%s' WHERE id=%d", szName, m_iPlayerIndex[id]);
656
657 client_print_color(id, print_team_default, "^4Nickname changed!");
658
659 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
660
661 return PLUGIN_CONTINUE;
662}
663
664PlayerStarted(id)
665{
666 m_iStarted[id] = get_gametime();
667 m_iTimerStarted[id] = true;
668 m_iJumpCount[id] = 1;
669 m_iStrafeCount[id] = 1;
670 client_print_color(id, print_team_default, "^4Time started!");
671}
672PlayerFinished(id)
673{
674 m_iFinished[id] = true;
675
676 new record = false;
677 new iTime = get_running_time(id);
678 new category = get_user_category(id);
679 new szTime[32]; get_formated_time(iTime, szTime, charsmax(szTime));
680 new szBestTime[32]; get_formated_time(iTime - g_iBestTimeofMap[category], szBestTime, charsmax(szBestTime));
681
682 if(g_iBestTimeofMap[category] != 0 && g_iBestTimeofMap[category]<iTime)
683 {
684 client_print_color(id, print_team_default, "%s^1 Category: ^3%s^1 | Run time: ^3%s^1 | Record: ^3+%s^1 | Jumps: ^3%d^1 | Strafes: ^3%i^1", PREFIX, g_szCategory[category], szTime, szBestTime, m_iJumpCount[id], m_iStrafeCount[id]);
685 }
686 if(g_iBestTime[id][category] == 0)
687 {
688 SaveRunnerData(id, category, iTime);
689 }
690 else if(g_iBestTime[id][category] > iTime)
691 {
692 // get_formated_time(g_iBestTime[id][category] - iTime, szTime, charsmax(szTime));
693 //client_print_color(id, print_team_default, "%s%s^3 Own record:^1 -%s", PREFIX, g_szCategory[category], szTime);
694 SaveRunnerData(id, category, iTime);
695 }
696 else if(g_iBestTime[id][category] < iTime)
697 {
698 get_formated_time(iTime - g_iBestTime[id][category], szTime, charsmax(szTime));
699 // client_print_color(id, print_team_default, "%s%s^3 Time to your best:^1 +%s", PREFIX, g_szCategory[category], szTime);
700 }
701 else
702 {
703 client_print_color(id, print_team_default, "%s%s^3 You did the same time! Congrats", PREFIX, g_szCategory[category]);
704 }
705
706 if(g_iBestTimeofMap[category] == 0 || g_iBestTimeofMap[category] > iTime)
707 {
708 g_iBestTimeofMap[category] = iTime;
709
710 new szName[32]; get_user_name(id, szName, charsmax(szName));
711 get_formated_time(iTime, szTime, charsmax(szTime));
712
713 client_print_color(0, print_team_default, "^3NEW MAP RECORD!!!!!")
714 client_print_color(0, print_team_default, "^3NEW MAP RECORD!!!!!")
715 client_print_color(0, print_team_default, "^3NEW MAP RECORD!!!!!")
716 client_print_color(0, print_team_default, "^3NEW MAP RECORD!!!!!")
717 client_print_color(0, print_team_default, "%s^4 %s^1 broke the map record! Category: ^4%s^1 | Time: ^4%s^1 | Jumps: ^4%d^1 | Strafes: ^4%i", PREFIX, szName, g_szCategory[category], szTime, m_iJumpCount[id], m_iStrafeCount[id]);
718
719 record = true;
720
721 client_cmd(0, "mp3 play %s", szSounds[random(sizeof(szSounds))]);
722 new Float:vOrigin[3]
723 pev(id, pev_origin, vOrigin)
724
725 //sprite_play_animation(vOrigin, 30.0)
726 sprites_play_animation2(id);
727 screen_player_effects(id);
728 }
729
730 ExecuteForward(g_iPlayerFinished, g_iReturn, id, iTime, record);
731
732 hide_timer(id);
733}
734public SaveRunnerData(id, category, iTime)
735{
736 if(!m_iPlayerAuthorized[id]) return;
737
738 g_iBestTime[id][category] = iTime;
739 new szRecordTime[32]; get_time("%Y-%m-%d %H:%M:%S", szRecordTime, charsmax(szRecordTime));
740
741 formatex(g_szQuery, charsmax(g_szQuery), "INSERT OR IGNORE INTO `results` VALUES (%d, %d, %d, %d, '%s'); \
742 UPDATE `results` SET besttime=%d, recorddate='%s' WHERE id=%d AND mid=%d AND category=%d",
743 m_iPlayerIndex[id], g_iMapIndex, category, iTime, szRecordTime,
744 iTime, szRecordTime, m_iPlayerIndex[id], g_iMapIndex, category);
745
746 SQL_ThreadQuery(g_hTuple, "Query_IngnoredHandle", g_szQuery);
747}
748
749ShowTop15(id, category)
750{
751 formatex(g_szQuery, charsmax(g_szQuery), "SELECT nickname, besttime FROM `results` JOIN `runners` ON `runners`.id=`results`.id WHERE mid=%d AND category=%d AND besttime ORDER BY besttime ASC LIMIT 15",
752 g_iMapIndex, category);
753
754 new data[2]; data[0] = id; data[1] = category;
755 SQL_ThreadQuery(g_hTuple, "Query_LoadTop15Handle", g_szQuery, data, sizeof(data));
756}
757public Query_LoadTop15Handle(failstate, Handle:query, error[], errnum, data[], size)
758{
759 if(failstate != TQUERY_SUCCESS)
760 {
761 log_amx("SQL error[LoadTop15]: %s",error); return;
762 }
763
764 new id = data[0];
765 if(!is_user_connected(id) && id != 0) return;
766
767 new category = data[1];
768
769 new iLen = 0, iMax = charsmax(g_szMotd);
770 iLen = formatex(g_szMotd[iLen], iMax-iLen, "<meta charset=utf-8>");
771 iLen += formatex(g_szMotd[iLen], iMax-iLen, "<style>{font:normal 10px} table, th, td{border: 1px solid black;border-collapse:collapse;text-align:center;}");
772 iLen += formatex(g_szMotd[iLen], iMax-iLen, "</style><html><table width=100%%><thead><tr><th width=5%%>%s</th> <th width=10%%>%s</th><th width=10%%>%s</th><th width=10%%></th><th width=10%%>%s</th><th width=10%%>%s</th></tr></thead><tbody>", "#", "Player", "Time", "Jumps(in curand)", "Strafe(in curand)")
773
774
775 new i = 1;
776 new iTime, szName[32], szTime[32];
777 while(SQL_MoreResults(query))
778 {
779 SQL_ReadResult(query, 0, szName, 31);
780 iTime = SQL_ReadResult(query, 1);
781 get_formated_time(iTime, szTime, 31);
782
783 iLen += formatex(g_szMotd[iLen], iMax-iLen, "<tr><td>%d</td><td>%s</td>", i, szName);
784 if(i == 1)
785 {
786 g_iBestTimeofMap[category] = iTime;
787 iLen += formatex(g_szMotd[iLen], iMax-iLen, "<td>%s</td><td></td>", szTime);
788 if(id == 0) return;
789 }
790 else
791 {
792 iLen += formatex(g_szMotd[iLen], iMax-iLen, "<td>%s</td>", szTime);
793
794 get_formated_time(iTime-g_iBestTimeofMap[category] , szTime, 31);
795 iLen += formatex(g_szMotd[iLen], iMax-iLen, "<td>+%s</td>", szTime);
796 }
797 iLen += formatex(g_szMotd[iLen], iMax-iLen, "</tr>");
798
799 i++;
800 SQL_NextRow(query);
801 }
802 iLen += formatex(g_szMotd[iLen], iMax-iLen, "</pre>");
803 show_motd(id, g_szMotd, "Speedrun Top");
804}
805
806/*
807sprite_play_animation(const Float:vOrigin[3], Float:Add)
808{
809 engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, vOrigin, 0)
810 write_byte(TE_SPRITE)
811 engfunc(EngFunc_WriteCoord, vOrigin[0])
812 engfunc(EngFunc_WriteCoord, vOrigin[1])
813 engfunc(EngFunc_WriteCoord, vOrigin[2] + Add)
814 write_short(EntitySprite)
815 write_byte(25)
816 write_byte(250)
817 message_end()
818}
819*/
820sprites_play_animation2(id) {
821 new Float:vOrigin[3]
822
823 set_pev(id, pev_iuser2, 0)
824 pev(id, pev_origin, vOrigin)
825
826 message_begin (MSG_BROADCAST,SVC_TEMPENTITY)
827 write_byte( TE_SPRITETRAIL )
828 write_coord( floatround(vOrigin[ 0 ]) )
829 write_coord( floatround(vOrigin[ 1 ]) )
830 write_coord( floatround(vOrigin[ 2 ]) )
831 write_coord( floatround(vOrigin[ 0 ]) )
832 write_coord( floatround(vOrigin[ 1 ]) )
833 write_coord( floatround(vOrigin[ 2 ]) +20)
834 write_short(EntitySprite)
835 write_byte(20)
836 write_byte(random_num(2,3))
837 write_byte(2)
838 write_byte(random_num(25,30))
839 write_byte(15)
840 message_end()
841}
842screen_player_effects(id)
843{
844 message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("ScreenFade"), _, id);
845 write_short((1<<12) * 1)
846 write_short(1<<12)
847 write_short(0)
848 write_byte(random(255))
849 write_byte(random(255))
850 write_byte(random(255))
851 write_byte(155)
852 message_end()
853
854 message_begin(MSG_ONE,get_user_msgid("ScreenShake"),{0,0,0},id);
855 write_short(7<<14);
856 write_short(1<<13);
857 write_short(1<<14);
858 message_end();
859}
860
861// [BOX SYSTEM]
862public box_start_touch(box, id, const szClass[])
863{
864 if(!is_user_alive(id))
865 return PLUGIN_CONTINUE;
866
867 if(equal(szClass, "finish") && !m_iFinished[id])
868 {
869 PlayerFinished(id);
870 }
871 return PLUGIN_CONTINUE;
872}
873public box_stop_touch(box, id, const szClass[]) {
874 if(!is_user_alive(id))
875 return PLUGIN_CONTINUE;
876
877 if(m_iPlayerAuthorized[id] && !m_iTimerStarted[id])
878 {
879 PlayerStarted(id);
880 }
881 return PLUGIN_CONTINUE;
882}
883
884display_time(id, iTime)
885{
886 show_status(id, "Time: %d:%02d,%03ds", iTime / 60000, (iTime / 1000) % 60, iTime % 1000);
887}
888hide_timer(id)
889{
890 show_status(id, "");
891}
892get_running_time(id)
893{
894 return floatround((get_gametime() - m_iStarted[id]) * 1000, floatround_ceil);
895}
896get_formated_time(iTime, szTime[], size)
897{
898 formatex(szTime, size, "%d:%02d.%03ds", iTime / 60000, (iTime / 1000) % 60, iTime % 1000);
899}
900show_status(id, const szMsg[], any:...)
901{
902 static szStatus[128]; vformat(szStatus, charsmax(szStatus), szMsg, 3);
903 static StatusText; if(!StatusText) StatusText = get_user_msgid("StatusText");
904
905 message_begin(MSG_ONE_UNRELIABLE, StatusText, _, id);
906 write_byte(0);
907 write_string(szStatus);
908 message_end();
909}
910get_nationality(id, const szIP[], szCode[5])
911{
912 new szTemp[3];
913 if(geoip_code2_ex(szIP, szTemp))
914 {
915 copy(szCode, 4, szTemp);
916 }
917 else
918 {
919 get_user_info(id, "lang", szCode, 2);
920 SQL_PrepareString(szCode, szCode, 4);
921 }
922}
923bool:is_flooding(id)
924{
925 static Float:fAntiFlood[33];
926 new bool:fl = false;
927 new Float:fNow = get_gametime();
928
929 if((fNow-fAntiFlood[id]) < 1.0) fl = true;
930
931 fAntiFlood[id] = fNow;
932 return fl;
933}
934stock SQL_PrepareString(const szQuery[], szOutPut[], size)
935{
936 copy(szOutPut, size, szQuery);
937 replace_all(szOutPut, size, "'", "\'");
938 replace_all(szOutPut,size, "`", "\`");
939 replace_all(szOutPut,size, "\\", "\\\\");
940}