· 9 years ago · Dec 22, 2016, 11:40 AM
1/*
2 * shavit's Timer - Core
3 * by: shavit
4 *
5 * This file is part of shavit's Timer.
6 *
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, version 3.0, as published by the
9 * Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19*/
20
21#include <sourcemod>
22#include <sdkhooks>
23#include <sdktools>
24#include <geoip>
25#include <clientprefs>
26
27#undef REQUIRE_PLUGIN
28#include <adminmenu>
29#define USES_CHAT_COLORS
30#include <shavit>
31
32#pragma newdecls required
33#pragma semicolon 1
34#pragma dynamic 131072
35
36// #define DEBUG
37
38// game type (CS:S/CS:GO)
39ServerGame gSG_Type = Game_Unknown; // deperecated and here for backwards compatibility
40EngineVersion gEV_Type = Engine_Unknown;
41
42// database handle
43Database gH_SQL = null;
44bool gB_MySQL = false;
45
46// forwards
47Handle gH_Forwards_Start = null;
48Handle gH_Forwards_Stop = null;
49Handle gH_Forwards_Finish = null;
50Handle gH_Forwards_OnRestart = null;
51Handle gH_Forwards_OnEnd = null;
52Handle gH_Forwards_OnPause = null;
53Handle gH_Forwards_OnResume = null;
54Handle gH_Forwards_OnStyleChanged = null;
55Handle gH_Forwards_OnStyleConfigLoaded = null;
56Handle gH_Forwards_OnDatabaseLoaded = null;
57Handle gH_Forwards_OnChatConfigLoaded = null;
58
59// timer variables
60bool gB_TimerEnabled[MAXPLAYERS+1];
61float gF_StartTime[MAXPLAYERS+1];
62float gF_PauseStartTime[MAXPLAYERS+1];
63float gF_PauseTotalTime[MAXPLAYERS+1];
64bool gB_ClientPaused[MAXPLAYERS+1];
65int gI_Jumps[MAXPLAYERS+1];
66BhopStyle gBS_Style[MAXPLAYERS+1];
67bool gB_Auto[MAXPLAYERS+1];
68int gI_ButtonCache[MAXPLAYERS+1];
69int gI_Strafes[MAXPLAYERS+1];
70float gF_AngleCache[MAXPLAYERS+1];
71int gI_TotalMeasures[MAXPLAYERS+1];
72int gI_GoodGains[MAXPLAYERS+1];
73bool gB_DoubleSteps[MAXPLAYERS+1];
74float gF_StrafeWarning[MAXPLAYERS+1];
75
76float gF_HSW_Requirement = 0.0;
77StringMap gSM_StyleCommands = null;
78
79// cookies
80Handle gH_StyleCookie = null;
81Handle gH_AutoBhopCookie = null;
82
83// late load
84bool gB_Late = false;
85
86// modules
87bool gB_Zones = false;
88
89// cvars
90ConVar gCV_Autobhop = null;
91ConVar gCV_LeftRight = null;
92ConVar gCV_Restart = null;
93ConVar gCV_Pause = null;
94ConVar gCV_NoStaminaReset = null;
95ConVar gCV_AllowTimerWithoutZone = null;
96ConVar gCV_BlockPreJump = null;
97ConVar gCV_NoZAxisSpeed = null;
98
99// cached cvars
100bool gB_Autobhop = true;
101bool gB_LeftRight = true;
102bool gB_Restart = true;
103bool gB_Pause = true;
104bool gB_NoStaminaReset = true;
105bool gB_AllowTimerWithoutZone = false;
106bool gB_BlockPreJump = true;
107bool gB_NoZAxisSpeed = true;
108
109// table prefix
110char gS_MySQLPrefix[32];
111
112// server side
113ConVar sv_airaccelerate = null;
114ConVar sv_autobunnyhopping = null;
115
116// timer settings
117bool gB_Registered = false;
118int gI_Styles = 0;
119char gS_StyleStrings[STYLE_LIMIT][STYLESTRINGS_SIZE][128];
120any gA_StyleSettings[STYLE_LIMIT][STYLESETTINGS_SIZE];
121
122// chat settings
123char gS_ChatStrings[CHATSETTINGS_SIZE][128];
124
125public Plugin myinfo =
126{
127 name = "[shavit] Core",
128 author = "shavit",
129 description = "The core for shavit's bhop timer.",
130 version = SHAVIT_VERSION,
131 url = "https://github.com/shavitush/bhoptimer"
132}
133
134public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
135{
136 // get game type
137 CreateNative("Shavit_GetGameType", Native_GetGameType);
138
139 // get database handle
140 CreateNative("Shavit_GetDB", Native_GetDB);
141
142 // timer natives
143 CreateNative("Shavit_StartTimer", Native_StartTimer);
144 CreateNative("Shavit_StopTimer", Native_StopTimer);
145 CreateNative("Shavit_FinishMap", Native_FinishMap);
146 CreateNative("Shavit_GetTimer", Native_GetTimer);
147 CreateNative("Shavit_GetClientTime", Native_GetClientTime);
148 CreateNative("Shavit_GetClientJumps", Native_GetClientJumps);
149 CreateNative("Shavit_GetBhopStyle", Native_GetBhopStyle);
150 CreateNative("Shavit_GetTimerStatus", Native_GetTimerStatus);
151 CreateNative("Shavit_PauseTimer", Native_PauseTimer);
152 CreateNative("Shavit_ResumeTimer", Native_ResumeTimer);
153 CreateNative("Shavit_PrintToChat", Native_PrintToChat);
154 CreateNative("Shavit_RestartTimer", Native_RestartTimer);
155 CreateNative("Shavit_GetStrafeCount", Native_GetStrafeCount);
156 CreateNative("Shavit_GetSync", Native_GetSync);
157 CreateNative("Shavit_GetStyleCount", Native_GetStyleCount);
158 CreateNative("Shavit_GetStyleSettings", Native_GetStyleSettings);
159 CreateNative("Shavit_GetStyleStrings", Native_GetStyleStrings);
160 CreateNative("Shavit_GetChatStrings", Native_GetChatStrings);
161
162 // registers library, check "bool LibraryExists(const char[] name)" in order to use with other plugins
163 RegPluginLibrary("shavit");
164
165 gB_Late = late;
166
167 return APLRes_Success;
168}
169
170public void OnPluginStart()
171{
172 // forwards
173 gH_Forwards_Start = CreateGlobalForward("Shavit_OnStart", ET_Event, Param_Cell);
174 gH_Forwards_Stop = CreateGlobalForward("Shavit_OnStop", ET_Event, Param_Cell);
175 gH_Forwards_Finish = CreateGlobalForward("Shavit_OnFinish", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell, Param_Cell);
176 gH_Forwards_OnRestart = CreateGlobalForward("Shavit_OnRestart", ET_Event, Param_Cell);
177 gH_Forwards_OnEnd = CreateGlobalForward("Shavit_OnEnd", ET_Event, Param_Cell);
178 gH_Forwards_OnPause = CreateGlobalForward("Shavit_OnPause", ET_Event, Param_Cell);
179 gH_Forwards_OnResume = CreateGlobalForward("Shavit_OnResume", ET_Event, Param_Cell);
180 gH_Forwards_OnStyleChanged = CreateGlobalForward("Shavit_OnStyleChanged", ET_Event, Param_Cell, Param_Cell, Param_Cell);
181 gH_Forwards_OnStyleConfigLoaded = CreateGlobalForward("Shavit_OnStyleConfigLoaded", ET_Event, Param_Cell);
182 gH_Forwards_OnDatabaseLoaded = CreateGlobalForward("Shavit_OnDatabaseLoaded", ET_Event, Param_Cell);
183 gH_Forwards_OnChatConfigLoaded = CreateGlobalForward("Shavit_OnChatConfigLoaded", ET_Event);
184
185 LoadTranslations("shavit-core.phrases");
186
187 // game types
188 gEV_Type = GetEngineVersion();
189
190 if(gEV_Type == Engine_CSS)
191 {
192 gSG_Type = Game_CSS;
193 gF_HSW_Requirement = 399.00;
194 }
195
196 else if(gEV_Type == Engine_CSGO)
197 {
198 gSG_Type = Game_CSGO;
199 gF_HSW_Requirement = 449.00;
200
201 sv_autobunnyhopping = FindConVar("sv_autobunnyhopping");
202 sv_autobunnyhopping.BoolValue = false;
203 }
204
205 else
206 {
207 SetFailState("This plugin was meant to be used in CS:S and CS:GO *only*.");
208 }
209
210 // database connections
211 SQL_SetPrefix();
212 SQL_DBConnect();
213
214 // hooks
215 HookEvent("player_jump", Player_Jump);
216 HookEvent("player_death", Player_Death);
217 HookEvent("player_team", Player_Death);
218 HookEvent("player_spawn", Player_Death);
219
220 // commands START
221 // style
222 RegConsoleCmd("sm_style", Command_Style, "Choose your bhop style.");
223 RegConsoleCmd("sm_styles", Command_Style, "Choose your bhop style.");
224 RegConsoleCmd("sm_diff", Command_Style, "Choose your bhop style.");
225 RegConsoleCmd("sm_difficulty", Command_Style, "Choose your bhop style.");
226 gH_StyleCookie = RegClientCookie("shavit_style", "Style cookie", CookieAccess_Protected);
227
228 // timer start
229 RegConsoleCmd("sm_s", Command_StartTimer, "Start your timer.");
230 RegConsoleCmd("sm_start", Command_StartTimer, "Start your timer.");
231 RegConsoleCmd("sm_r", Command_StartTimer, "Start your timer.");
232 RegConsoleCmd("sm_restart", Command_StartTimer, "Start your timer.");
233
234 // teleport to end
235 RegConsoleCmd("sm_end", Command_TeleportEnd, "Teleport to endzone.");
236
237 // timer stop
238 RegConsoleCmd("sm_stop", Command_StopTimer, "Stop your timer.");
239
240 // timer pause / resume
241 RegConsoleCmd("sm_pause", Command_TogglePause, "Toggle pause.");
242 RegConsoleCmd("sm_unpause", Command_TogglePause, "Toggle pause.");
243 RegConsoleCmd("sm_resume", Command_TogglePause, "Toggle pause");
244
245 // autobhop toggle
246 RegConsoleCmd("sm_auto", Command_AutoBhop, "Toggle autobhop.");
247 RegConsoleCmd("sm_autobhop", Command_AutoBhop, "Toggle autobhop.");
248 gH_AutoBhopCookie = RegClientCookie("shavit_autobhop", "Autobhop cookie", CookieAccess_Protected);
249
250 // doublestep fixer
251 AddCommandListener(Command_DoubleStep, "+ds");
252 AddCommandListener(Command_DoubleStep, "-ds");
253
254 // style commands
255 gSM_StyleCommands = new StringMap();
256 // commands END
257
258 #if defined DEBUG
259 RegConsoleCmd("sm_finishtest", Command_FinishTest);
260 #endif
261
262 CreateConVar("shavit_version", SHAVIT_VERSION, "Plugin version.", FCVAR_NOTIFY|FCVAR_DONTRECORD);
263
264 gCV_Autobhop = CreateConVar("shavit_core_autobhop", "1", "Enable autobhop?\nWill be forced to not work if STYLE_AUTOBHOP is not defined for a style!", FCVAR_NOTIFY, true, 0.0, true, 1.0);
265 gCV_LeftRight = CreateConVar("shavit_core_blockleftright", "1", "Block +left/right?", 0, true, 0.0, true, 1.0);
266 gCV_Restart = CreateConVar("shavit_core_restart", "1", "Allow commands that restart the timer?", 0, true, 0.0, true, 1.0);
267 gCV_Pause = CreateConVar("shavit_core_pause", "1", "Allow pausing?", 0, true, 0.0, true, 1.0);
268 gCV_NoStaminaReset = CreateConVar("shavit_core_nostaminareset", "1", "Disables the built-in stamina reset.\nAlso known as 'easybhop'.\nWill be forced to not work if STYLE_EASYBHOP is not defined for a style!", 0, true, 0.0, true, 1.0);
269 gCV_AllowTimerWithoutZone = CreateConVar("shavit_core_timernozone", "0", "Allow the timer to start if there's no start zone?", 0, true, 0.0, true, 1.0);
270 gCV_BlockPreJump = CreateConVar("shavit_core_blockprejump", "1", "Prevents jumping in the start zone.", 0, true, 0.0, true, 1.0);
271 gCV_NoZAxisSpeed = CreateConVar("shavit_core_nozaxisspeed", "1", "Don't start timer if vertical speed exists (btimes style).", 0, true, 0.0, true, 1.0);
272
273 gCV_Autobhop.AddChangeHook(OnConVarChanged);
274 gCV_LeftRight.AddChangeHook(OnConVarChanged);
275 gCV_Restart.AddChangeHook(OnConVarChanged);
276 gCV_Pause.AddChangeHook(OnConVarChanged);
277 gCV_NoStaminaReset.AddChangeHook(OnConVarChanged);
278 gCV_AllowTimerWithoutZone.AddChangeHook(OnConVarChanged);
279 gCV_BlockPreJump.AddChangeHook(OnConVarChanged);
280 gCV_NoZAxisSpeed.AddChangeHook(OnConVarChanged);
281
282 AutoExecConfig();
283
284 sv_airaccelerate = FindConVar("sv_airaccelerate");
285 sv_airaccelerate.Flags &= ~FCVAR_NOTIFY;
286
287 // late
288 if(gB_Late)
289 {
290 OnAdminMenuReady(null);
291
292 for(int i = 1; i <= MaxClients; i++)
293 {
294 OnClientPutInServer(i);
295 }
296 }
297
298 gB_Zones = LibraryExists("shavit-zones");
299}
300
301public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
302{
303 gB_Autobhop = gCV_Autobhop.BoolValue;
304 gB_LeftRight = gCV_LeftRight.BoolValue;
305 gB_Restart = gCV_Restart.BoolValue;
306 gB_Pause = gCV_Pause.BoolValue;
307 gB_NoStaminaReset = gCV_NoStaminaReset.BoolValue;
308 gB_AllowTimerWithoutZone = gCV_AllowTimerWithoutZone.BoolValue;
309 gB_BlockPreJump = gCV_BlockPreJump.BoolValue;
310 gB_NoZAxisSpeed = gCV_NoZAxisSpeed.BoolValue;
311}
312
313public void OnLibraryAdded(const char[] name)
314{
315 if(StrEqual(name, "shavit-zones"))
316 {
317 gB_Zones = true;
318 }
319}
320
321public void OnLibraryRemoved(const char[] name)
322{
323 if(StrEqual(name, "shavit-zones"))
324 {
325 gB_Zones = false;
326 }
327}
328
329public void OnAdminMenuReady(Handle topmenu)
330{
331 Handle hTopMenu = INVALID_HANDLE;
332
333 if(LibraryExists("adminmenu") && ((hTopMenu = GetAdminTopMenu()) != INVALID_HANDLE))
334 {
335 AddToTopMenu(hTopMenu, "Timer Commands", TopMenuObject_Category, CategoryHandler, INVALID_TOPMENUOBJECT);
336 }
337}
338
339public void CategoryHandler(Handle topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength)
340{
341 if(action == TopMenuAction_DisplayTitle)
342 {
343 strcopy(buffer, maxlength, "Timer Commands:");
344 }
345
346 else if(action == TopMenuAction_DisplayOption)
347 {
348 strcopy(buffer, maxlength, "Timer Commands");
349 }
350}
351
352public void OnMapStart()
353{
354 // styles
355 if(!LoadStyles())
356 {
357 SetFailState("Could not load the styles configuration file. Make sure it exists (addons/sourcemod/configs/shavit-styles.cfg) and follows the proper syntax!");
358 }
359
360 else
361 {
362 Call_StartForward(gH_Forwards_OnStyleConfigLoaded);
363 Call_PushCell(gI_Styles);
364 Call_Finish();
365 }
366
367 // messages
368 if(!LoadMessages())
369 {
370 SetFailState("Could not load the chat messages configuration file. Make sure it exists (addons/sourcemod/configs/shavit-messages.cfg) and follows the proper syntax!");
371 }
372
373 else
374 {
375 Call_StartForward(gH_Forwards_OnChatConfigLoaded);
376 Call_Finish();
377 }
378
379 // cvar forcing
380 FindConVar("sv_enablebunnyhopping").BoolValue = true;
381}
382
383public Action Command_StartTimer(int client, int args)
384{
385 if(!IsValidClient(client))
386 {
387 return Plugin_Handled;
388 }
389
390 if(!gB_Restart)
391 {
392 if(args != -1)
393 {
394 char[] sCommand = new char[16];
395 GetCmdArg(0, sCommand, 16);
396
397 Shavit_PrintToChat(client, "%T", "CommandDisabled", client, gS_ChatStrings[sMessageVariable], sCommand, gS_ChatStrings[sMessageText]);
398 }
399
400 return Plugin_Handled;
401 }
402
403 if(gB_AllowTimerWithoutZone || (gB_Zones && Shavit_ZoneExists(Zone_Start)))
404 {
405 Call_StartForward(gH_Forwards_OnRestart);
406 Call_PushCell(client);
407 Call_Finish();
408
409 StartTimer(client);
410 }
411
412 else
413 {
414 Shavit_PrintToChat(client, "%T", "StartZoneUndefined", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
415 }
416
417 return Plugin_Handled;
418}
419
420public Action Command_TeleportEnd(int client, int args)
421{
422 if(!IsValidClient(client))
423 {
424 return Plugin_Handled;
425 }
426
427 if(gB_Zones && Shavit_ZoneExists(Zone_End))
428 {
429 Shavit_StopTimer(client);
430
431 Call_StartForward(gH_Forwards_OnEnd);
432 Call_PushCell(client);
433 Call_Finish();
434 }
435
436 else
437 {
438 Shavit_PrintToChat(client, "%T", "EndZoneUndefined", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
439 }
440
441 return Plugin_Handled;
442}
443
444public Action Command_StopTimer(int client, int args)
445{
446 if(!IsValidClient(client))
447 {
448 return Plugin_Handled;
449 }
450
451 Shavit_StopTimer(client);
452
453 return Plugin_Handled;
454}
455
456public Action Command_TogglePause(int client, int args)
457{
458 if(!IsValidClient(client))
459 {
460 return Plugin_Handled;
461 }
462
463 if(Shavit_InsideZone(client, Zone_Start))
464 {
465 Shavit_PrintToChat(client, "%T", "PauseStartZone", client, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable], gS_ChatStrings[sMessageText]);
466
467 return Plugin_Handled;
468 }
469
470 if(!gB_Pause)
471 {
472 char[] sCommand = new char[16];
473 GetCmdArg(0, sCommand, 16);
474
475 Shavit_PrintToChat(client, "%T", "CommandDisabled", client, gS_ChatStrings[sMessageVariable], sCommand, gS_ChatStrings[sMessageText]);
476
477 return Plugin_Handled;
478 }
479
480 if((GetEntityFlags(client) & FL_ONGROUND) == 0)
481 {
482 Shavit_PrintToChat(client, "%T", "PauseNotOnGround", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
483
484 return Plugin_Handled;
485 }
486
487 if(gB_ClientPaused[client])
488 {
489 ResumeTimer(client);
490 Shavit_PrintToChat(client, "%T", "MessageUnpause", client, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
491 }
492
493 else
494 {
495 PauseTimer(client);
496 Shavit_PrintToChat(client, "%T", "MessagePause", client, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
497 }
498
499 return Plugin_Handled;
500}
501
502#if defined DEBUG
503public Action Command_FinishTest(int client, int args)
504{
505 Shavit_FinishMap(client);
506
507 return Plugin_Handled;
508}
509#endif
510
511public Action Command_AutoBhop(int client, int args)
512{
513 if(!IsValidClient(client))
514 {
515 return Plugin_Handled;
516 }
517
518 gB_Auto[client] = !gB_Auto[client];
519
520 if(gB_Auto[client])
521 {
522 Shavit_PrintToChat(client, "%T", "AutobhopEnabled", client, gS_ChatStrings[sMessageVariable2], gS_ChatStrings[sMessageText]);
523 }
524
525 else
526 {
527 Shavit_PrintToChat(client, "%T", "AutobhopDisabled", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
528 }
529
530 char[] sAutoBhop = new char[4];
531 IntToString(view_as<int>(gB_Auto[client]), sAutoBhop, 4);
532
533 SetClientCookie(client, gH_AutoBhopCookie, sAutoBhop);
534
535 return Plugin_Handled;
536}
537
538public Action Command_DoubleStep(int client, const char[] command, int args)
539{
540 gB_DoubleSteps[client] = (command[0] == '+');
541
542 return Plugin_Handled;
543}
544
545public Action Command_Style(int client, int args)
546{
547 if(!IsValidClient(client))
548 {
549 return Plugin_Handled;
550 }
551
552 Menu m = new Menu(StyleMenu_Handler);
553 m.SetTitle("%T", "StyleMenuTitle", client);
554
555 for(int i = 0; i < gI_Styles; i++)
556 {
557 char[] sInfo = new char[8];
558 IntToString(i, sInfo, 8);
559
560 if(gA_StyleSettings[i][bUnranked])
561 {
562 char[] sDisplay = new char[64];
563 FormatEx(sDisplay, 64, "%T %s", "StyleUnranked", client, gS_StyleStrings[i][sStyleName]);
564 m.AddItem(sInfo, sDisplay);
565 }
566
567 else
568 {
569 m.AddItem(sInfo, gS_StyleStrings[i][sStyleName]);
570 }
571 }
572
573 // should NEVER happen
574 if(m.ItemCount == 0)
575 {
576 m.AddItem("-1", "Nothing");
577 }
578
579 m.ExitButton = true;
580 m.Display(client, 20);
581
582 return Plugin_Handled;
583}
584
585public int StyleMenu_Handler(Menu m, MenuAction action, int param1, int param2)
586{
587 if(action == MenuAction_Select)
588 {
589 char[] info = new char[16];
590 m.GetItem(param2, info, 16);
591
592 BhopStyle style = view_as<BhopStyle>(StringToInt(info));
593
594 ChangeClientStyle(param1, style);
595 }
596
597 else if(action == MenuAction_End)
598 {
599 delete m;
600 }
601
602 return 0;
603}
604
605void ChangeClientStyle(int client, BhopStyle style)
606{
607 if(!IsValidClient(client))
608 {
609 return;
610 }
611
612 Call_StartForward(gH_Forwards_OnStyleChanged);
613 Call_PushCell(client);
614 Call_PushCell(gBS_Style[client]);
615 Call_PushCell(style);
616 Call_Finish();
617
618 gBS_Style[client] = style;
619 UpdateAutoBhop(client);
620
621 Shavit_PrintToChat(client, "%T", "StyleSelection", client, gS_ChatStrings[sMessageStyle], gS_StyleStrings[style][sStyleName], gS_ChatStrings[sMessageText]);
622
623 if(gA_StyleSettings[style][bUnranked])
624 {
625 Shavit_PrintToChat(client, "%T", "UnrankedWarning", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
626 }
627
628 StopTimer(client);
629
630 if(gB_AllowTimerWithoutZone || (gB_Zones && Shavit_ZoneExists(Zone_Start)))
631 {
632 Call_StartForward(gH_Forwards_OnRestart);
633 Call_PushCell(client);
634 Call_Finish();
635 }
636
637 char[] sStyle = new char[4];
638 IntToString(view_as<int>(style), sStyle, 4);
639
640 SetClientCookie(client, gH_StyleCookie, sStyle);
641}
642
643public void Player_Jump(Event event, const char[] name, bool dontBroadcast)
644{
645 int client = GetClientOfUserId(event.GetInt("userid"));
646
647 if(gB_TimerEnabled[client])
648 {
649 gI_Jumps[client]++;
650 }
651
652 if(gB_NoStaminaReset && gA_StyleSettings[gBS_Style[client]][bEasybhop])
653 {
654 SetEntPropFloat(client, Prop_Send, "m_flStamina", 0.0);
655 }
656
657 if(view_as<float>(gA_StyleSettings[gBS_Style[client]][fGravityMultiplier]) != 1.0)
658 {
659 SetEntityGravity(client, view_as<float>(gA_StyleSettings[gBS_Style[client]][fGravityMultiplier]));
660 }
661
662 if(view_as<float>(gA_StyleSettings[gBS_Style[client]][fSpeedMultiplier]) != 1.0)
663 {
664 SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", view_as<float>(gA_StyleSettings[gBS_Style[client]][fSpeedMultiplier]));
665 }
666}
667
668public void Player_Death(Event event, const char[] name, bool dontBroadcast)
669{
670 int client = GetClientOfUserId(event.GetInt("userid"));
671
672 ResumeTimer(client);
673 StopTimer(client);
674}
675
676public int Native_GetGameType(Handle handler, int numParams)
677{
678 return view_as<int>(gSG_Type);
679}
680
681public int Native_GetDB(Handle handler, int numParams)
682{
683 SetNativeCellRef(1, gH_SQL);
684}
685
686public int Native_GetTimer(Handle handler, int numParams)
687{
688 // 1 - client
689 int client = GetNativeCell(1);
690
691 // 2 - time
692 float time = CalculateTime(client);
693 SetNativeCellRef(2, time);
694 SetNativeCellRef(3, gI_Jumps[client]);
695 SetNativeCellRef(4, gBS_Style[client]);
696 SetNativeCellRef(5, gB_TimerEnabled[client]);
697}
698
699public int Native_GetClientTime(Handle handler, int numParams)
700{
701 // 1 - client
702 int client = GetNativeCell(1);
703
704 // 2 - time
705 return view_as<int>(CalculateTime(client));
706}
707
708public int Native_GetClientJumps(Handle handler, int numParams)
709{
710 return gI_Jumps[GetNativeCell(1)];
711}
712
713public int Native_GetBhopStyle(Handle handler, int numParams)
714{
715 return view_as<int>(gBS_Style[GetNativeCell(1)]);
716}
717
718public int Native_GetTimerStatus(Handle handler, int numParams)
719{
720 int client = GetNativeCell(1);
721
722 if(!gB_TimerEnabled[client])
723 {
724 return view_as<int>(Timer_Stopped);
725 }
726
727 else if(gB_ClientPaused[client])
728 {
729 return view_as<int>(Timer_Paused);
730 }
731
732 return view_as<int>(Timer_Running);
733}
734
735public int Native_StartTimer(Handle handler, int numParams)
736{
737 StartTimer(GetNativeCell(1));
738}
739
740public int Native_StopTimer(Handle handler, int numParams)
741{
742 int client = GetNativeCell(1);
743
744 StopTimer(client);
745
746 Call_StartForward(gH_Forwards_Stop);
747 Call_PushCell(client);
748 Call_Finish();
749}
750
751public int Native_FinishMap(Handle handler, int numParams)
752{
753 int client = GetNativeCell(1);
754
755 Call_StartForward(gH_Forwards_Finish);
756 Call_PushCell(client);
757 Call_PushCell(view_as<int>(gBS_Style[client]));
758 Call_PushCell(CalculateTime(client));
759 Call_PushCell(gI_Jumps[client]);
760 Call_PushCell(gI_Strafes[client]);
761 Call_PushCell((gA_StyleSettings[gBS_Style[client]][bSync])? (gI_GoodGains[client] == 0)? 0.0:(gI_GoodGains[client] / float(gI_TotalMeasures[client]) * 100.0):-1.0);
762 Call_Finish();
763
764 StopTimer(client);
765}
766
767public int Native_PauseTimer(Handle handler, int numParams)
768{
769 PauseTimer(GetNativeCell(1));
770}
771
772public int Native_ResumeTimer(Handle handler, int numParams)
773{
774 ResumeTimer(GetNativeCell(1));
775}
776
777public int Native_PrintToChat(Handle handler, int numParams)
778{
779 int client = GetNativeCell(1);
780 static int written = 0; // useless?
781
782 char[] buffer = new char[300];
783 FormatNativeString(0, 2, 3, 300, written, buffer);
784 Format(buffer, 300, "%s %s%s", gS_ChatStrings[sMessagePrefix], gS_ChatStrings[sMessageText], buffer);
785
786 if(gEV_Type == Engine_CSS)
787 {
788 Handle hSayText2 = StartMessageOne("SayText2", client);
789
790 if(hSayText2 != null)
791 {
792 BfWriteByte(hSayText2, client);
793 BfWriteByte(hSayText2, true);
794 BfWriteString(hSayText2, buffer);
795 }
796
797 EndMessage();
798 }
799
800 else
801 {
802 PrintToChat(client, " %s", buffer);
803 }
804
805 return;
806}
807
808public int Native_RestartTimer(Handle handler, int numParams)
809{
810 int client = GetNativeCell(1);
811
812 Call_StartForward(gH_Forwards_OnRestart);
813 Call_PushCell(client);
814 Call_Finish();
815
816 StartTimer(client);
817
818 return;
819}
820
821public int Native_GetStrafeCount(Handle handler, int numParams)
822{
823 return gI_Strafes[GetNativeCell(1)];
824}
825
826public int Native_GetSync(Handle handler, int numParams)
827{
828 int client = GetNativeCell(1);
829
830 return view_as<int>((gA_StyleSettings[gBS_Style[client]][bSync])? (gI_GoodGains[client] == 0)? 0.0:(gI_GoodGains[client] / float(gI_TotalMeasures[client]) * 100.0):-1.0);
831}
832
833public int Native_GetStyleCount(Handle handler, int numParams)
834{
835 return (gI_Styles > 0)? gI_Styles:-1;
836}
837
838public int Native_GetStyleSettings(Handle handler, int numParams)
839{
840 return SetNativeArray(2, gA_StyleSettings[GetNativeCell(1)], STYLESETTINGS_SIZE);
841}
842
843public int Native_GetStyleStrings(Handle handler, int numParams)
844{
845 return SetNativeString(3, gS_StyleStrings[GetNativeCell(1)][GetNativeCell(2)], GetNativeCell(4));
846}
847
848public int Native_GetChatStrings(Handle handler, int numParams)
849{
850 return SetNativeString(2, gS_ChatStrings[GetNativeCell(1)], GetNativeCell(3));
851}
852
853void StartTimer(int client)
854{
855 if(!IsValidClient(client, true) || GetClientTeam(client) < 2 || IsFakeClient(client))
856 {
857 return;
858 }
859
860 float fSpeed[3];
861 GetEntPropVector(client, Prop_Data, "m_vecVelocity", fSpeed);
862
863 if(!gB_NoZAxisSpeed || gA_StyleSettings[gBS_Style[client]][bPrespeed] || fSpeed[2] == 0.0 || SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0)) <= 280.0)
864 {
865 gF_StartTime[client] = GetEngineTime();
866 gB_TimerEnabled[client] = true;
867 gI_Strafes[client] = 0;
868 gI_Jumps[client] = 0;
869 gI_TotalMeasures[client] = 0;
870 gI_GoodGains[client] = 0;
871
872 Call_StartForward(gH_Forwards_Start);
873 Call_PushCell(client);
874 Call_Finish();
875 }
876
877 gF_PauseTotalTime[client] = 0.0;
878 gB_ClientPaused[client] = false;
879
880 SetEntityGravity(client, gA_StyleSettings[gBS_Style[client]][fGravityMultiplier]);
881 SetEntPropFloat(client, Prop_Data, "m_flLaggedMovementValue", gA_StyleSettings[gBS_Style[client]][fSpeedMultiplier]);
882}
883
884void StopTimer(int client)
885{
886 if(!IsValidClient(client) || IsFakeClient(client))
887 {
888 return;
889 }
890
891 gB_TimerEnabled[client] = false;
892 gI_Jumps[client] = 0;
893 gF_StartTime[client] = 0.0;
894 gF_PauseTotalTime[client] = 0.0;
895 gB_ClientPaused[client] = false;
896 gI_Strafes[client] = 0;
897 gI_TotalMeasures[client] = 0;
898 gI_GoodGains[client] = 0;
899}
900
901void PauseTimer(int client)
902{
903 if(!IsValidClient(client) || IsFakeClient(client))
904 {
905 return;
906 }
907
908 gF_PauseStartTime[client] = GetEngineTime();
909 gB_ClientPaused[client] = true;
910
911 Call_StartForward(gH_Forwards_OnPause);
912 Call_PushCell(client);
913 Call_Finish();
914}
915
916void ResumeTimer(int client)
917{
918 if(!IsValidClient(client) || IsFakeClient(client))
919 {
920 return;
921 }
922
923 gF_PauseTotalTime[client] += (GetEngineTime() - gF_PauseStartTime[client]);
924 gB_ClientPaused[client] = false;
925
926 Call_StartForward(gH_Forwards_OnResume);
927 Call_PushCell(client);
928 Call_Finish();
929}
930
931float CalculateTime(int client)
932{
933 float time = 0.0;
934
935 if(!gB_ClientPaused[client])
936 {
937 time = (GetEngineTime() - gF_StartTime[client] - gF_PauseTotalTime[client]);
938 }
939
940 else
941 {
942 time = (gF_PauseStartTime[client] - gF_StartTime[client] - gF_PauseTotalTime[client]);
943 }
944
945 if(gA_StyleSettings[gBS_Style[client]][bHalftime])
946 {
947 time /= 2.0;
948 }
949
950 return time;
951}
952
953public void OnClientDisconnect(int client)
954{
955 StopTimer(client);
956}
957
958public void OnClientCookiesCached(int client)
959{
960 if(IsFakeClient(client))
961 {
962 return;
963 }
964
965 char[] sCookie = new char[4];
966 GetClientCookie(client, gH_AutoBhopCookie, sCookie, 4);
967 gB_Auto[client] = (strlen(sCookie) > 0)? view_as<bool>(StringToInt(sCookie)):true;
968
969 GetClientCookie(client, gH_StyleCookie, sCookie, 4);
970 gBS_Style[client] = view_as<BhopStyle>(StringToInt(sCookie));
971 UpdateAutoBhop(client);
972}
973
974public void OnClientPutInServer(int client)
975{
976 StopTimer(client);
977
978 if(IsFakeClient(client))
979 {
980 return;
981 }
982
983 gB_Auto[client] = true;
984 gB_DoubleSteps[client] = false;
985 gF_StrafeWarning[client] = 0.0;
986 gBS_Style[client] = view_as<BhopStyle>(0);
987 UpdateAutoBhop(client);
988
989 if(AreClientCookiesCached(client))
990 {
991 OnClientCookiesCached(client);
992 }
993
994 if(gH_SQL == null)
995 {
996 return;
997 }
998
999 SDKHook(client, SDKHook_PreThink, PreThink);
1000
1001 char[] sAuthID3 = new char[32];
1002
1003 if(!GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
1004 {
1005 KickClient(client, "%T", "VerificationFailed", client);
1006
1007 return;
1008 }
1009
1010 char[] sName = new char[MAX_NAME_LENGTH];
1011 GetClientName(client, sName, MAX_NAME_LENGTH);
1012
1013 int iLength = ((strlen(sName) * 2) + 1);
1014 char[] sEscapedName = new char[iLength]; // dynamic arrays! I love you, SourcePawn 1.7!
1015 gH_SQL.Escape(sName, sEscapedName, iLength);
1016
1017 char[] sIP = new char[64];
1018 GetClientIP(client, sIP, 64);
1019
1020 char[] sCountry = new char[128];
1021
1022 if(!GeoipCountry(sIP, sCountry, 128))
1023 {
1024 strcopy(sCountry, 128, "Local Area Network");
1025 }
1026 float points = 0.0;
1027 + if (LibraryExists("shavit-rankings"))
1028 + {
1029 + points = Shavit_GetPoints(client);
1030 +
1031 char[] sQuery = new char[512];
1032 FormatEx(sQuery, 512, "REPLACE INTO %susers (auth, name, country, ip, lastlogin, points) VALUES ('%s', '%s', '%s', '%s', %d , %f);", gS_MySQLPrefix, sAuthID3, sEscapedName, sCountry, sIP, GetTime(), points);
1033
1034
1035 gH_SQL.Query(SQL_InsertUser_Callback, sQuery, GetClientSerial(client));
1036}
1037
1038public void SQL_InsertUser_Callback(Database db, DBResultSet results, const char[] error, any data)
1039{
1040 if(results == null)
1041 {
1042 int client = GetClientFromSerial(data);
1043
1044 if(client == 0)
1045 {
1046 LogError("Timer error! Failed to insert a disconnected player's data to the table. Reason: %s", error);
1047 }
1048
1049 else
1050 {
1051 LogError("Timer error! Failed to insert \"%N\"'s data to the table. Reason: %s", client, error);
1052 }
1053
1054 return;
1055 }
1056}
1057
1058bool LoadStyles()
1059{
1060 char[] sPath = new char[PLATFORM_MAX_PATH];
1061 BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "configs/shavit-styles.cfg");
1062
1063 Dynamic dStylesConfig = Dynamic();
1064
1065 if(!dStylesConfig.ReadKeyValues(sPath))
1066 {
1067 dStylesConfig.Dispose();
1068
1069 return false;
1070 }
1071
1072 gI_Styles = dStylesConfig.MemberCount;
1073
1074 for(int i = 0; i < gI_Styles; i++)
1075 {
1076 Dynamic dStyle = dStylesConfig.GetDynamicByIndex(i);
1077 dStyle.GetString("name", gS_StyleStrings[i][sStyleName], 128);
1078 dStyle.GetString("shortname", gS_StyleStrings[i][sShortName], 128);
1079 dStyle.GetString("htmlcolor", gS_StyleStrings[i][sHTMLColor], 128);
1080 dStyle.GetString("command", gS_StyleStrings[i][sChangeCommand], 128);
1081
1082 gA_StyleSettings[i][bAutobhop] = dStyle.GetBool("autobhop", true);
1083 gA_StyleSettings[i][bEasybhop] = dStyle.GetBool("easybhop", true);
1084 gA_StyleSettings[i][bPrespeed] = dStyle.GetBool("prespeed", false);
1085 gA_StyleSettings[i][fVelocityLimit] = dStyle.GetFloat("velocity_limit", 0.0);
1086 gA_StyleSettings[i][iAiraccelerate] = dStyle.GetInt("airaccelerate", 1000);
1087 gA_StyleSettings[i][fRunspeed] = dStyle.GetFloat("runspeed", 260.00);
1088 gA_StyleSettings[i][fGravityMultiplier] = dStyle.GetFloat("gravity", 1.0);
1089 gA_StyleSettings[i][fSpeedMultiplier] = dStyle.GetFloat("speed", 1.0);
1090 gA_StyleSettings[i][bHalftime] = dStyle.GetBool("halftime", false);
1091 gA_StyleSettings[i][bBlockW] = dStyle.GetBool("block_w", false);
1092 gA_StyleSettings[i][bBlockA] = dStyle.GetBool("block_a", false);
1093 gA_StyleSettings[i][bBlockS] = dStyle.GetBool("block_s", false);
1094 gA_StyleSettings[i][bBlockD] = dStyle.GetBool("block_d", false);
1095 gA_StyleSettings[i][bBlockUse] = dStyle.GetBool("block_use", false);
1096 gA_StyleSettings[i][bForceHSW] = dStyle.GetBool("force_hsw", false);
1097 gA_StyleSettings[i][bBlockPLeft] = dStyle.GetBool("block_pleft", false);
1098 gA_StyleSettings[i][bBlockPRight] = dStyle.GetBool("block_pright", false);
1099 gA_StyleSettings[i][bBlockPStrafe] = dStyle.GetBool("block_pstrafe", false);
1100 gA_StyleSettings[i][bUnranked] = dStyle.GetBool("unranked", false);
1101 gA_StyleSettings[i][bNoReplay] = dStyle.GetBool("noreplay", false);
1102 gA_StyleSettings[i][bSync] = dStyle.GetBool("sync", true);
1103 gA_StyleSettings[i][bStrafeCountW] = dStyle.GetBool("strafe_count_w", false);
1104 gA_StyleSettings[i][bStrafeCountA] = dStyle.GetBool("strafe_count_a", true);
1105 gA_StyleSettings[i][bStrafeCountS] = dStyle.GetBool("strafe_count_s", false);
1106 gA_StyleSettings[i][bStrafeCountD] = dStyle.GetBool("strafe_count_d", true);
1107 gA_StyleSettings[i][fRankingMultiplier] = dStyle.GetFloat("rankingmultiplier", 1.00);
1108 gA_StyleSettings[i][iSpecial] = dStyle.GetInt("special", 0);
1109
1110 if(!gB_Registered && strlen(gS_StyleStrings[i][sChangeCommand]) > 0)
1111 {
1112 char[][] sStyleCommands = new char[32][32];
1113 int iCommands = ExplodeString(gS_StyleStrings[i][sChangeCommand], ";", sStyleCommands, 32, 32, false);
1114
1115 char[] sDescription = new char[128];
1116 FormatEx(sDescription, 128, "Change style to %s.", gS_StyleStrings[i][sStyleName]);
1117
1118 for(int x = 0; x < iCommands; x++)
1119 {
1120 TrimString(sStyleCommands[x]);
1121 StripQuotes(sStyleCommands[x]);
1122
1123 char[] sCommand = new char[32];
1124 FormatEx(sCommand, 32, "sm_%s", sStyleCommands[x]);
1125
1126 gSM_StyleCommands.SetValue(sCommand, i);
1127
1128 RegConsoleCmd(sCommand, Command_StyleChange, sDescription);
1129 }
1130 }
1131 }
1132
1133 gB_Registered = true;
1134
1135 dStylesConfig.Dispose(true);
1136
1137 return true;
1138}
1139
1140public Action Command_StyleChange(int client, int args)
1141{
1142 char[] sCommand = new char[128];
1143 GetCmdArg(0, sCommand, 128);
1144
1145 BhopStyle style = Style_Default;
1146
1147 if(gSM_StyleCommands.GetValue(sCommand, style))
1148 {
1149 ChangeClientStyle(client, style);
1150
1151 return Plugin_Handled;
1152 }
1153
1154 return Plugin_Continue;
1155}
1156
1157bool LoadMessages()
1158{
1159 char[] sPath = new char[PLATFORM_MAX_PATH];
1160 BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "configs/shavit-messages.cfg");
1161
1162 Dynamic dMessagesConfig = Dynamic();
1163
1164 if(!dMessagesConfig.ReadKeyValues(sPath))
1165 {
1166 dMessagesConfig.Dispose();
1167
1168 return false;
1169 }
1170
1171 Dynamic dMessage = dMessagesConfig.GetDynamic((gEV_Type == Engine_CSS)? "CS:S":"CS:GO");
1172 dMessage.GetString("prefix", gS_ChatStrings[sMessagePrefix], 128);
1173 dMessage.GetString("text", gS_ChatStrings[sMessageText], 128);
1174 dMessage.GetString("warning", gS_ChatStrings[sMessageWarning], 128);
1175 dMessage.GetString("variable", gS_ChatStrings[sMessageVariable], 128);
1176 dMessage.GetString("variable2", gS_ChatStrings[sMessageVariable2], 128);
1177 dMessage.GetString("style", gS_ChatStrings[sMessageStyle], 128);
1178
1179 dMessagesConfig.Dispose(true);
1180
1181 for(int i = 0; i < CHATSETTINGS_SIZE; i++)
1182 {
1183 for(int x = 0; x < sizeof(gS_GlobalColorNames); x++)
1184 {
1185 ReplaceString(gS_ChatStrings[i], 128, gS_GlobalColorNames[x], gS_GlobalColors[x]);
1186 }
1187
1188 for(int x = 0; x < sizeof(gS_CSGOColorNames); x++)
1189 {
1190 ReplaceString(gS_ChatStrings[i], 128, gS_CSGOColorNames[x], gS_CSGOColors[x]);
1191 }
1192
1193 ReplaceString(gS_ChatStrings[i], 128, "{RGB}", "\x07");
1194 ReplaceString(gS_ChatStrings[i], 128, "{RGBA}", "\x08");
1195 }
1196
1197 return true;
1198}
1199
1200void SQL_SetPrefix()
1201{
1202 char[] sFile = new char[PLATFORM_MAX_PATH];
1203 BuildPath(Path_SM, sFile, PLATFORM_MAX_PATH, "configs/shavit-prefix.txt");
1204
1205 File fFile = OpenFile(sFile, "r");
1206
1207 if(fFile == null)
1208 {
1209 SetFailState("Cannot open \"configs/shavit-prefix.txt\". Make sure this file exists and that the server has read permissions to it.");
1210 }
1211
1212 char[] sLine = new char[PLATFORM_MAX_PATH*2];
1213
1214 while(fFile.ReadLine(sLine, PLATFORM_MAX_PATH*2))
1215 {
1216 TrimString(sLine);
1217 strcopy(gS_MySQLPrefix, 32, sLine);
1218
1219 break;
1220 }
1221
1222 delete fFile;
1223}
1224
1225void SQL_DBConnect()
1226{
1227 if(gH_SQL != null)
1228 {
1229 delete gH_SQL;
1230 }
1231
1232 char[] sError = new char[255];
1233
1234 if(SQL_CheckConfig("shavit")) // can't be asynced as we have modules that require this database connection instantly
1235 {
1236 gH_SQL = SQL_Connect("shavit", true, sError, 255);
1237
1238 if(gH_SQL == null)
1239 {
1240 SetFailState("Timer startup failed. Reason: %s", sError);
1241 }
1242 }
1243
1244 else
1245 {
1246 gH_SQL = SQLite_UseDatabase("shavit", sError, 255);
1247 }
1248
1249 // support unicode names
1250 gH_SQL.SetCharset("utf8");
1251
1252 Call_StartForward(gH_Forwards_OnDatabaseLoaded);
1253 Call_PushCell(gH_SQL);
1254 Call_Finish();
1255
1256 char[] sDriver = new char[8];
1257 gH_SQL.Driver.GetIdentifier(sDriver, 8);
1258 gB_MySQL = StrEqual(sDriver, "mysql", false);
1259
1260 char[] sQuery = new char[512];
1261 FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%susers` (`auth` VARCHAR(32) NOT NULL, `name` VARCHAR(32), `country` VARCHAR(128), `ip` VARCHAR(64), `lastlogin` %s NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`));", gS_MySQLPrefix, gB_MySQL? "INT":"INTEGER");
1262
1263 // CREATE TABLE IF NOT EXISTS
1264 gH_SQL.Query(SQL_CreateTable_Callback, sQuery);
1265}
1266
1267public void SQL_CreateTable_Callback(Database db, DBResultSet results, const char[] error, any data)
1268{
1269 if(results == null)
1270 {
1271 LogError("Timer error! Users' data table creation failed. Reason: %s", error);
1272
1273 return;
1274 }
1275
1276 char[] sQuery = new char[64];
1277 FormatEx(sQuery, 64, "SELECT lastlogin FROM %susers LIMIT 1;", gS_MySQLPrefix);
1278 gH_SQL.Query(SQL_TableMigration1_Callback, sQuery, 0, DBPrio_High);
1279
1280 FormatEx(sQuery, 64, "SELECT points FROM %susers LIMIT 1;", gS_MySQLPrefix);
1281 gH_SQL.Query(SQL_TableMigration2_Callback, sQuery, 0, DBPrio_High);
1282}
1283
1284public void SQL_TableMigration1_Callback(Database db, DBResultSet results, const char[] error, any data)
1285{
1286 if(results == null)
1287 {
1288 char[] sQuery = new char[128];
1289 FormatEx(sQuery, 128, "ALTER TABLE `%susers` ADD %s;", gS_MySQLPrefix, gB_MySQL? "(`lastlogin` INT NOT NULL DEFAULT -1)":"COLUMN `lastlogin` INTEGER NOT NULL DEFAULT -1");
1290 gH_SQL.Query(SQL_AlterTable1_Callback, sQuery);
1291 }
1292}
1293
1294public void SQL_AlterTable1_Callback(Database db, DBResultSet results, const char[] error, any data)
1295{
1296 if(results == null)
1297 {
1298 LogError("Timer error! Table alteration 1 (core) failed. Reason: %s", error);
1299
1300 return;
1301 }
1302}
1303
1304public void SQL_TableMigration2_Callback(Database db, DBResultSet results, const char[] error, any data)
1305{
1306 if(results == null)
1307 {
1308 char[] sQuery = new char[128];
1309 FormatEx(sQuery, 128, "ALTER TABLE `%susers` ADD %s;", gS_MySQLPrefix, gB_MySQL? "(`points` FLOAT NOT NULL DEFAULT 0)":"COLUMN `points` FLOAT NOT NULL DEFAULT 0");
1310 gH_SQL.Query(SQL_AlterTable2_Callback, sQuery);
1311 }
1312}
1313
1314public void SQL_AlterTable2_Callback(Database db, DBResultSet results, const char[] error, any data)
1315{
1316 if(results == null)
1317 {
1318 LogError("Timer error! Table alteration 2 (core) failed. Reason: %s", error);
1319
1320 return;
1321 }
1322}
1323
1324public void PreThink(int client)
1325{
1326 if(IsPlayerAlive(client))
1327 {
1328 sv_airaccelerate.IntValue = gA_StyleSettings[gBS_Style[client]][iAiraccelerate];
1329 }
1330}
1331
1332public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3])
1333{
1334 if(!IsPlayerAlive(client) || IsFakeClient(client))
1335 {
1336 return Plugin_Continue;
1337 }
1338
1339 if(gB_ClientPaused[client])
1340 {
1341 buttons = 0;
1342 vel = view_as<float>({0.0, 0.0, 0.0});
1343
1344 return Plugin_Changed;
1345 }
1346
1347 int iGroundEntity = GetEntPropEnt(client, Prop_Send, "m_hGroundEntity");
1348 bool bInStart = Shavit_InsideZone(client, Zone_Start);
1349
1350 if(gB_TimerEnabled[client] && !gB_ClientPaused[client])
1351 {
1352 char[] sCheatDetected = new char[64];
1353
1354 // +left/right block
1355 if(gB_LeftRight && (!gB_Zones || !bInStart && ((gA_StyleSettings[gBS_Style[client]][bBlockPLeft] &&
1356 (buttons & IN_LEFT) > 0) || (gA_StyleSettings[gBS_Style[client]][bBlockPRight] && (buttons & IN_RIGHT) > 0))))
1357 {
1358 FormatEx(sCheatDetected, 64, "%T", "LeftRightCheat", client);
1359 StopTimer_Cheat(client, sCheatDetected);
1360 }
1361
1362 // +strafe block
1363 if(gA_StyleSettings[gBS_Style[client]][bBlockPStrafe] &&
1364 ((vel[0] > 0.0 && (buttons & IN_FORWARD) == 0) || (vel[0] < 0.0 && (buttons & IN_BACK) == 0) ||
1365 (vel[1] > 0.0 && (buttons & IN_MOVERIGHT) == 0) || (vel[1] < 0.0 && (buttons & IN_MOVELEFT) == 0)))
1366 {
1367 float fTime = GetEngineTime();
1368
1369 if(gF_StrafeWarning[client] < fTime)
1370 {
1371 FormatEx(sCheatDetected, 64, "%T", "Inconsistencies", client);
1372 StopTimer_Cheat(client, sCheatDetected);
1373 }
1374
1375 gF_StrafeWarning[client] = fTime + 0.20;
1376 }
1377 }
1378
1379 // key blocking
1380 if(!Shavit_InsideZone(client, Zone_Freestyle))
1381 {
1382 // block E
1383 if(gA_StyleSettings[gBS_Style[client]][bBlockUse] && (buttons & IN_USE) > 0)
1384 {
1385 buttons &= ~IN_USE;
1386 }
1387
1388 if(iGroundEntity == -1)
1389 {
1390 if(gA_StyleSettings[gBS_Style[client]][bBlockW] && ((buttons & IN_FORWARD) > 0 || vel[0] > 0.0))
1391 {
1392 vel[0] = 0.0;
1393 buttons &= ~IN_FORWARD;
1394 }
1395
1396 if(gA_StyleSettings[gBS_Style[client]][bBlockA] && ((buttons & IN_MOVELEFT) > 0 || vel[1] < 0.0))
1397 {
1398 vel[1] = 0.0;
1399 buttons &= ~IN_MOVELEFT;
1400 }
1401
1402 if(gA_StyleSettings[gBS_Style[client]][bBlockS] && ((buttons & IN_BACK) > 0 || vel[0] < 0.0))
1403 {
1404 vel[0] = 0.0;
1405 buttons &= ~IN_BACK;
1406 }
1407
1408 if(gA_StyleSettings[gBS_Style[client]][bBlockD] && ((buttons & IN_MOVERIGHT) > 0 || vel[1] > 0.0))
1409 {
1410 vel[1] = 0.0;
1411 buttons &= ~IN_MOVERIGHT;
1412 }
1413
1414 // HSW
1415 if(gA_StyleSettings[gBS_Style[client]][bForceHSW] && ((vel[0] < gF_HSW_Requirement && vel[0] > -gF_HSW_Requirement) ||
1416 !((vel[0] > 0 || (buttons & IN_FORWARD) > 0) && ((vel[1] < 0 || (buttons & IN_MOVELEFT) > 0) || (vel[1] > 0 || (buttons & IN_MOVERIGHT) > 0)))))
1417 {
1418 vel[1] = 0.0;
1419 buttons &= ~IN_MOVELEFT;
1420 buttons &= ~IN_MOVERIGHT;
1421 }
1422 }
1423 }
1424
1425 if(gA_StyleSettings[gBS_Style[client]][bStrafeCountW] && !gA_StyleSettings[gBS_Style[client]][bBlockW] &&
1426 (gI_ButtonCache[client] & IN_FORWARD) == 0 && (buttons & IN_FORWARD) > 0)
1427 {
1428 gI_Strafes[client]++;
1429 }
1430
1431 if(gA_StyleSettings[gBS_Style[client]][bStrafeCountA] && !gA_StyleSettings[gBS_Style[client]][bBlockA] && (gI_ButtonCache[client] & IN_MOVELEFT) == 0 &&
1432 (buttons & IN_MOVELEFT) > 0 && (gA_StyleSettings[gBS_Style[client]][bForceHSW] || ((buttons & IN_FORWARD) == 0 && (buttons & IN_BACK) == 0)))
1433 {
1434 gI_Strafes[client]++;
1435 }
1436
1437 if(gA_StyleSettings[gBS_Style[client]][bStrafeCountS] && !gA_StyleSettings[gBS_Style[client]][bBlockS] &&
1438 (gI_ButtonCache[client] & IN_BACK) == 0 && (buttons & IN_BACK) > 0)
1439 {
1440 gI_Strafes[client]++;
1441 }
1442
1443 if(gA_StyleSettings[gBS_Style[client]][bStrafeCountD] && !gA_StyleSettings[gBS_Style[client]][bBlockD] && (gI_ButtonCache[client] & IN_MOVERIGHT) == 0 &&
1444 (buttons & IN_MOVERIGHT) > 0 && (gA_StyleSettings[gBS_Style[client]][bForceHSW] || ((buttons & IN_FORWARD) == 0 && (buttons & IN_BACK) == 0)))
1445 {
1446 gI_Strafes[client]++;
1447 }
1448
1449 if(gA_StyleSettings[gBS_Style[client]][bAutobhop] && gB_Autobhop && gB_Auto[client])
1450 {
1451 bool bInWater = (GetEntProp(client, Prop_Send, "m_nWaterLevel") >= 2);
1452 bool bOnLadder = (GetEntityMoveType(client) == MOVETYPE_LADDER);
1453
1454 if((buttons & IN_JUMP) > 0 && iGroundEntity == -1 && !bOnLadder && !bInWater)
1455 {
1456 buttons &= ~IN_JUMP;
1457 }
1458
1459 else if(gB_DoubleSteps[client] && (iGroundEntity != -1 || bOnLadder || bInWater))
1460 {
1461 buttons |= IN_JUMP;
1462 }
1463 }
1464
1465 else if(gB_DoubleSteps[client])
1466 {
1467 buttons |= IN_JUMP;
1468 }
1469
1470 if(bInStart && gB_BlockPreJump && !gA_StyleSettings[gBS_Style[client]][bPrespeed] && (vel[2] > 0 || (buttons & IN_JUMP) > 0))
1471 {
1472 vel[2] = 0.0;
1473 buttons &= ~IN_JUMP;
1474 }
1475
1476 // velocity limit
1477 if(iGroundEntity != -1 && view_as<float>(gA_StyleSettings[gBS_Style[client]][fVelocityLimit] > 0.0) &&
1478 (!gB_Zones || !Shavit_InsideZone(client, Zone_NoVelLimit)))
1479 {
1480 float fSpeed[3];
1481 GetEntPropVector(client, Prop_Data, "m_vecVelocity", fSpeed);
1482
1483 float fSpeed_New = (SquareRoot(Pow(fSpeed[0], 2.0) + Pow(fSpeed[1], 2.0)));
1484
1485 if(fSpeed_New > 0.0)
1486 {
1487 float fScale = view_as<float>(gA_StyleSettings[gBS_Style[client]][fVelocityLimit]) / fSpeed_New;
1488
1489 if(fScale < 1.0)
1490 {
1491 ScaleVector(fSpeed, fScale);
1492 TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, fSpeed);
1493 }
1494 }
1495 }
1496
1497 float fAngle = (angles[1] - gF_AngleCache[client]);
1498
1499 while(fAngle > 180.0)
1500 {
1501 fAngle -= 360.0;
1502 }
1503
1504 while(fAngle < -180.0)
1505 {
1506 fAngle += 360.0;
1507 }
1508
1509 if(iGroundEntity == -1 && (GetEntityFlags(client) & FL_INWATER) == 0 && fAngle != 0.0)
1510 {
1511 float fAbsVelocity[3];
1512 GetEntPropVector(client, Prop_Data, "m_vecAbsVelocity", fAbsVelocity);
1513
1514 if(SquareRoot(Pow(fAbsVelocity[0], 2.0) + Pow(fAbsVelocity[1], 2.0)) > 0.0)
1515 {
1516 float fTempAngle = angles[1];
1517
1518 float fAngles[3];
1519 GetVectorAngles(fAbsVelocity, fAngles);
1520
1521 if(fTempAngle < 0.0)
1522 {
1523 fTempAngle += 360.0;
1524 }
1525
1526 float fDirectionAngle = (fTempAngle - fAngles[1]);
1527
1528 if(fDirectionAngle < 0.0)
1529 {
1530 fDirectionAngle = -fDirectionAngle;
1531 }
1532
1533 if(fDirectionAngle < 22.5 || fDirectionAngle > 337.5)
1534 {
1535 gI_TotalMeasures[client]++;
1536
1537 if((fAngle > 0.0 && vel[1] < 0.0) || (fAngle < 0.0 && vel[1] > 0.0))
1538 {
1539 gI_GoodGains[client]++;
1540 }
1541 }
1542
1543 else if((fDirectionAngle > 67.5 && fDirectionAngle < 112.5) || (fDirectionAngle > 247.5 && fDirectionAngle < 292.5))
1544 {
1545 gI_TotalMeasures[client]++;
1546
1547 if(vel[0] != 0.0)
1548 {
1549 gI_GoodGains[client]++;
1550 }
1551 }
1552 }
1553 }
1554
1555 gI_ButtonCache[client] = buttons;
1556 gF_AngleCache[client] = angles[1];
1557
1558 return Plugin_Continue;
1559}
1560
1561void StopTimer_Cheat(int client, const char[] message)
1562{
1563 Shavit_StopTimer(client);
1564 Shavit_PrintToChat(client, "%T", "CheatTimerStop", client, gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText], message);
1565}
1566
1567void UpdateAutoBhop(int client)
1568{
1569 if(sv_autobunnyhopping != null)
1570 {
1571 sv_autobunnyhopping.ReplicateToClient(client, (gA_StyleSettings[gBS_Style[client]][bAutobhop] && gB_Autobhop && gB_Auto[client])? "1":"0");
1572 }
1573}