· 6 years ago · Nov 09, 2019, 11:48 AM
1//#pragma newdecls required
2#pragma semicolon 1
3
4#include <sourcemod>
5#include <smlib>
6#include <emitsoundany>
7#include <colors_csgo>
8#include <geoip>
9#include <sdkhooks>
10
11#define FIRST 1
12#define UNIT_TYPE 2
13#define MAX 32
14#define DB_NAME "advanced_noscop"
15#define PREFIX ""
16
17ConVar cv_HudDistance = null;
18ConVar cv_Music = null;
19ConVar cv_Directory = null;
20ConVar cv_Weapons = null;
21ConVar cv_Volume = null;
22ConVar cv_Unit = null;
23ConVar cv_MinimumPlayer = null;
24ConVar cv_EnableRank = null;
25ConVar cv_PlayerTop = null;
26
27int gI_Music;
28int gI_MCount;
29int gI_TotalPlayer = 0;
30int gI_PlayerCount = 0;
31
32float gF_Distance[MAXPLAYERS+1];
33
34char gC_ClientAuth3[MAXPLAYERS+1][32];
35char gC_Sound[MAX][128];
36char gC_Chat[2][MAX];
37char gC_CurrentMap[64];
38char gC_Unit[UNIT_TYPE][MAX] =
39{
40 "meter",
41 "mile"
42};
43
44
45new const String:g_sCommands[2][9] = {
46 "spec",
47 "specinfo"
48};
49
50Database gH_SQL = null;
51
52//OLD SYNTAX//
53enum NoscopData
54{
55 String:Attacker[20],
56 String:Victim[20],
57 String:Weapon[32],
58 String:Map[64],
59 Float:Distance,
60 Rank,
61}
62
63Player[MAXPLAYERS+1][NoscopData];
64
65new String:g_sCountry[MAXPLAYERS+1][3];
66new Float:g_fLastRefresh[MAXPLAYERS+1];
67new bool:g_bSpecDisabled[MAXPLAYERS+1];
68
69public Plugin myinfo =
70{
71 name = "Advanced Noscop",
72 author = "Mish0UU",
73 description = "Advanced Noscop",
74 version = "1.1.0",
75 url = "www.balkanstar.fr"
76};
77
78public void OnPluginStart()
79{
80 HookEvent("player_death", Event_PlayerDeath);
81 HookEvent("round_start", Event_OnRoundStart);
82 HookEvent("player_spawn", Event_OnPlayerSpawn);
83
84 cv_HudDistance = CreateConVar("an_minimum_distance_hud", "40.0", "Minimum distance to show message in HUD", FCVAR_NOTIFY, true, 0.0, true, 160.0);
85 cv_Music = CreateConVar("an_music_enable", "0", "Enable music when HUD is displayed", FCVAR_NOTIFY, true, 0.0, true, 1.0);
86 cv_Directory = CreateConVar("an_music_path", " ", "Path of sounds directory example : sound/advanced_noscop/", FCVAR_NOTIFY);
87 cv_Volume = CreateConVar("an_music_volume", "0.5", "Music volume", FCVAR_NOTIFY, true, 0.0, true, 1.0);
88 cv_Weapons = CreateConVar("an_weapons_allowed", "3", "Allowed weapons: 1 = AWP Only | 2 = SSG08 Only | 3 = AWP + SSG08", FCVAR_NOTIFY, true, 1.0, true, 3.0);
89 cv_Unit = CreateConVar("an_weapons_unit", "1", "Unit of length used: 1 = Meter | 2 = Miles", FCVAR_NOTIFY, true, 1.0, true, 2.0);
90 cv_MinimumPlayer = CreateConVar("an_minimum_player", "3", "Minimum number of player to save noscop distance", FCVAR_NOTIFY);
91 cv_EnableRank = CreateConVar("an_enable_rank", "1", "Enable/Disable rank/top features", FCVAR_NOTIFY, false, 0.0, true, 1.0);
92 cv_PlayerTop = CreateConVar("an_show_player_top", "15", "Number of player to display on top", FCVAR_NOTIFY, true, 1.0, true, 100.0);
93
94 LoadTranslations("advanced_noscop.phrases");
95
96 RegConsoleCmd("sm_mytopnoscope", Cmd_MyNoscop);
97 RegConsoleCmd("sm_topnoscope", Cmd_TopNoscop);
98
99 AutoExecConfig(true);
100
101 for(int unit = 0; unit < UNIT_TYPE; unit++)
102 Format(gC_Chat[unit], 8, "%t", gC_Unit[unit]);
103
104 if(cv_EnableRank.IntValue)
105 SQL_DBConnect();
106
107 RegConsoleCmd("say", cmdSay);
108}
109
110
111public OnClientPostAdminCheck(id){
112 new String:sIp[64];
113 GetClientIP(id, sIp, 14);
114
115 if(!GeoipCode2(sIp, g_sCountry[id])){
116 FormatEx(g_sCountry[id], sizeof g_sCountry[], "??");
117 }
118}
119
120public onPlayerPreThink(id){
121 if((GetGameTime() - g_fLastRefresh[id]) >= 0.5){
122 formatSpecList(id);
123
124 g_fLastRefresh[id] = GetGameTime();
125 }
126}
127
128public OnClientDisconnect(id){
129 SDKUnhook(id, SDKHook_PreThinkPost, onPlayerPreThink);
130 g_bSpecDisabled[id]=false;
131 g_fLastRefresh[id] = GetGameTime();
132}
133
134
135stock formatSpecList(id){
136 if (g_bSpecDisabled[id] || IsPlayerAlive(id))
137 return;
138
139 new iSpecMode = GetEntProp(id, Prop_Send, "m_iObserverMode");
140 if(iSpecMode == 4 || iSpecMode == 5){
141 new iAliveTarget = GetEntPropEnt(id, Prop_Send, "m_hObserverTarget");
142
143 if(!(1 <= iAliveTarget <= MaxClients) || !IsClientConnected(iAliveTarget) || IsFakeClient(iAliveTarget)) return;
144
145 PrintHintText(id, "<font color='#00ccff'>Kills:</font> %d | <font color='#ff0000'>Deaths:</font> %d\n<font color='#996633'>Longest NoScope:</font> %.2fm\n<font color='#00cc00'>Country:</font> %s", GetClientFrags(iAliveTarget), GetClientDeaths(iAliveTarget), Player[iAliveTarget][Distance], g_sCountry[iAliveTarget]);
146
147 }
148}
149
150public Action:cmdSay(id, iArgs){
151 new String:sText[192], String:sPrefixes[2][19];
152 GetCmdArgString(sText, sizeof sText);
153 StripQuotes(sText);
154
155 for(new i = 0 ; i < 2 ; i++){
156 FormatEx(sPrefixes[0], sizeof sPrefixes[], "!%s", g_sCommands[i]);
157 FormatEx(sPrefixes[1], sizeof sPrefixes[], "/%s", g_sCommands[i]);
158 if(StrEqual(sText, sPrefixes[0]) || StrEqual(sText, sPrefixes[1])){
159 g_bSpecDisabled[id]=!g_bSpecDisabled[id];
160
161 PrintToChat(id, "Spectate info toggled %s", g_bSpecDisabled[id] ? "\x06ON" : "\x02OFF");
162 }
163 }
164}
165
166public void OnConfigsExecuted()
167{
168 if(!cv_EnableRank.BoolValue)
169 return;
170
171 if(gH_SQL == null)
172 SQL_DBConnect();
173}
174
175public void OnMapStart()
176{
177 GetCurrentMap(gC_CurrentMap, sizeof(gC_CurrentMap));
178 loadSounds();
179}
180
181public Action Cmd_MyNoscop(int client, int args)
182{
183 if(!cv_EnableRank.IntValue)
184 return;
185
186 if(Player[client][Distance] != 0.0)
187 {
188 CPrintToChatAll("%s%t", PREFIX, "an_chat_mynoscop", client, Player[client][Rank], gI_TotalPlayer, Player[client][Distance], gC_Unit[cv_Unit.IntValue-1], (Player[client][Distance] > 1.0 ? "s" : ""));
189 }
190 else
191 {
192 CPrintToChat(client, "%s%t", PREFIX, "an_chat_need_noscop");
193 }
194}
195
196public Action Cmd_TopNoscop(int client, int args)
197{
198 if(!cv_EnableRank.IntValue)
199 return;
200
201 char query[256];
202 FormatEx(query, sizeof(query), "SELECT name, distance FROM advanced_noscop WHERE map = '%s' AND distance > 0.0 ORDER BY distance DESC LIMIT 0,%d;", gC_CurrentMap, cv_PlayerTop.IntValue);
203 gH_SQL.Query(DisplayTop_Callback, query, client);
204}
205
206public void DisplayTop_Callback(Database db, DBResultSet result, char[] error, any id)
207{
208 if(result == null)
209 {
210 LogError("[Advanced_Noscop] Query Fail: %s", error);
211 return;
212 }
213
214 Menu menu = CreateMenu(MenuHandler_Top);
215
216 char sTitle[64];
217 FormatEx(sTitle, sizeof(sTitle), "Longest NoScope's on map: %s\n ", gC_CurrentMap);
218
219 SetMenuTitle(menu, sTitle);
220
221 int iCount = 0;
222
223 while(result.FetchRow())
224 {
225 iCount++;
226
227 char sName[MAX_NAME_LENGTH];
228 result.FetchString(0, sName, MAX_NAME_LENGTH);
229 float distance = result.FetchFloat(1);
230
231 char sDisplay[128];
232 FormatEx(sDisplay, sizeof(sDisplay), "#%d - %s (%.2f %s%s)", iCount, sName, distance, gC_Chat[cv_Unit.IntValue-1], distance > 1.0 ? "s":"");
233 menu.AddItem("0", sDisplay);
234 }
235 if(!iCount)
236 AddMenuItem(menu, "-1", "No record");
237
238 menu.ExitButton = true;
239 menu.Display(id, 30);
240}
241
242public int MenuHandler_Top(Menu menu, MenuAction action, int param1, int param2)
243{
244 if(action == MenuAction_End)
245 CloseHandle(menu);
246}
247
248public void Event_OnRoundStart(Handle event, const char[] name, bool dB)
249{
250 if(!cv_EnableRank.BoolValue)
251 return;
252
253 gI_PlayerCount = 0;
254 for(int i = 1; i <= GetMaxClients(); i++)
255 {
256 if(IsClientInGame(i) && GetClientTeam(i) > 1)
257 gI_PlayerCount++;
258 }
259 CacheTotalPlayer();
260}
261
262public void Event_OnPlayerSpawn(Handle event, const char[] name, bool dB)
263{
264 if(!cv_EnableRank.BoolValue)
265 return;
266
267 int client = GetClientOfUserId(GetEventInt(event, "userid"));
268
269 if(!IsValidClient(client))
270 return;
271
272 CacheRankPlayer(client);
273}
274
275public void OnClientPutInServer(int client)
276{
277 if(!IsValidClient(client) || IsFakeClient(client) || gH_SQL == null || !cv_EnableRank.BoolValue)
278 return;
279
280 GetClientAuthId(client, AuthId_Steam3, gC_ClientAuth3[client], sizeof(gC_ClientAuth3));
281
282 GetCurrentMap(Player[client][Map], 64);
283
284 Player[client][Distance] = 0.0;
285 Player[client][Rank] = -1;
286
287 char query[256];
288 FormatEx(query, sizeof(query), "SELECT distance FROM advanced_noscop WHERE auth = '%s' AND map = '%s';", gC_ClientAuth3[client], Player[client][Map]);
289
290 gH_SQL.Query(CheckPlayer_Callback, query, GetClientSerial(client));
291
292 SDKHook(client, SDKHook_PreThinkPost, onPlayerPreThink);
293 g_bSpecDisabled[client]=false;
294 g_fLastRefresh[client] = GetGameTime();
295}
296
297
298
299public void CheckPlayer_Callback(Database db, DBResultSet result, char[] error, any data)
300{
301 if(result == null)
302 {
303 LogError("[Advanced_Noscop] Query Fail: %s", error);
304 return;
305 }
306
307 int id = GetClientFromSerial(data);
308
309 if(!id)
310 return;
311
312 while(result.FetchRow())
313 {
314 Player[id][Distance] = result.FetchFloat(0);
315 updateName(id);
316 return;
317 }
318
319 char userName[MAX_NAME_LENGTH];
320 GetClientName(id, userName, sizeof(userName));
321
322 int len = strlen(userName) * 2 + 1;
323 char[] escapedName = new char[len];
324 gH_SQL.Escape(userName, escapedName, len);
325
326 len = strlen(gC_ClientAuth3[id]) * 2 + 1;
327 char[] escapedSteamId = new char[len];
328 gH_SQL.Escape(gC_ClientAuth3[id], escapedSteamId, len);
329
330 char query[512];
331 Format(query, sizeof(query), "INSERT INTO `advanced_noscop` (auth, name, distance, map) VALUES ('%s', '%s', '0', '%s') ON DUPLICATE KEY UPDATE name = '%s';", escapedSteamId, escapedName, gC_CurrentMap, escapedName);
332 gH_SQL.Query(Nothing_Callback, query, id);
333}
334
335public void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast)
336{
337 int victim = GetClientOfUserId(GetEventInt(event, "userid"));
338 int attacker = GetClientOfUserId(GetEventInt(event, "attacker"));
339
340 if(!IsValidClient(victim) || !IsValidClient(attacker))
341 return;
342
343 char weapons[32];
344 GetEventString(event, "weapon", weapons, sizeof(weapons));
345
346 if(cv_Weapons.IntValue == 1 && StrEqual(weapons, "ssg08"))
347 return;
348 if(cv_Weapons.IntValue == 2 && StrEqual(weapons, "awp"))
349 return;
350
351 if(!GetEntProp(attacker, Prop_Send, "m_bIsScoped") && (StrEqual(weapons, "awp") || StrEqual(weapons, "ssg08")))
352 {
353 GetClientName(attacker, Player[attacker][Attacker], 20);
354 GetClientName(victim, Player[attacker][Victim], 20);
355
356 float distance = Entity_GetDistance(victim, attacker);
357 if(cv_Unit.IntValue == 1)
358 {
359 distance = Math_UnitsToMeters(distance);
360 }
361 else
362 {
363 distance = Math_UnitsToMiles(distance);
364 }
365 gF_Distance[attacker] = distance;
366
367 if(cv_EnableRank.BoolValue)
368 {
369 if(distance > Player[attacker][Distance])
370 {
371 if(gI_PlayerCount >= cv_MinimumPlayer.IntValue)
372 {
373 DB_UpdateNoscop(attacker);
374 }
375 }
376 }
377 FormatEx(Player[attacker][Weapon], 32, "%s", weapons);
378 CreateTimer(0.1, Timer_Message, attacker);
379 }
380}
381
382public void DB_UpdateNoscop(int client)
383{
384 char query[512];
385 FormatEx(query, sizeof(query), "UPDATE `advanced_noscop` SET distance = %f WHERE auth = '%s' AND map = '%s'", gF_Distance[client], gC_ClientAuth3[client], Player[client][Map]);
386 gH_SQL.Query(UpdateKills_Callback, query, client);
387}
388
389public void UpdateKills_Callback(Database db, DBResultSet result, char[] error, any data)
390{
391 if(result == null)
392 {
393 LogError("[Advanced_Noscop] Query Fail: %s", error);
394 return;
395 }
396 Player[data][Distance] = gF_Distance[data];
397}
398
399public Action Timer_Message(Handle timer, any userid)
400{
401 if(IsClientInGame(userid))
402 SendMessageToAll(userid);
403}
404
405void SendMessageToAll(int id)
406{
407 if(gF_Distance[id] >= cv_HudDistance.FloatValue)
408 {
409 PrintHintTextToAll("%t", "an_hud_message", Player[id][Victim], Player[id][Attacker], gF_Distance[id], gC_Chat[cv_Unit.IntValue-1], (gF_Distance[id] > 1.0 ? "s":"")/*, (cv_MinimumPlayer.IntValue < gI_PlayerCount ? noSaved : "")*/);
410 if(cv_Music.BoolValue)
411 {
412 EmitSoundToAllAny(gC_Sound[gI_Music], SOUND_FROM_PLAYER, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, cv_Volume.FloatValue);
413 gI_Music++;
414
415 if(gI_Music > gI_MCount)
416 {
417 gI_Music = FIRST;
418 }
419 }
420 }
421 else
422 {
423 char noSaved[64];
424 FormatEx(noSaved, sizeof(noSaved), "%t", "an_noscop_no_saved");
425
426 CPrintToChatAll("%t", "an_chat_message", Player[id][Victim], Player[id][Attacker], gF_Distance[id], gC_Chat[cv_Unit.IntValue-1], (gF_Distance[id] > 1.0 ? "s":""), Player[id][Weapon], (gI_PlayerCount < cv_MinimumPlayer.IntValue ? noSaved : ""));
427 }
428}
429
430stock bool IsValidClient(int client)
431{
432 return (client >= 1 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client) && !IsClientSourceTV(client));
433}
434
435void loadSounds()
436{
437 gI_MCount = 0;
438
439 char directory[PLATFORM_MAX_PATH];
440 char path[PLATFORM_MAX_PATH];
441
442 cv_Directory.GetString(directory, sizeof(directory));
443
444 Format(path, sizeof(path), "sound/%s/", directory);
445 DirectoryListing pluginsDir = OpenDirectory(path);
446
447 if(pluginsDir != null)
448 {
449 char fileName[128];
450 char soundName[512];
451 while(pluginsDir.GetNext(fileName, sizeof(fileName)))
452 {
453 int fileExt = strlen(fileName) - 4;
454 if(StrContains(fileName, ".mp3", false) == fileExt)
455 {
456
457 Format(soundName, sizeof(soundName), "sound/%s/%s", directory, fileName);
458 AddFileToDownloadsTable(soundName);
459
460 gI_MCount++;
461
462 Format(gC_Sound[gI_MCount], 2048, "%s", soundName);
463 ReplaceString(gC_Sound[gI_MCount], 128, "sound/", "");
464
465 PrecacheSoundAny(gC_Sound[gI_MCount], true);
466
467 }
468 }
469 }
470 gI_Music = GetRandomInt(FIRST, gI_MCount);
471}
472
473void SQL_DBConnect()
474{
475 if(gH_SQL != null)
476 delete gH_SQL;
477
478 if(SQL_CheckConfig(DB_NAME))
479 {
480 Database.Connect(SQLConnect_Callback, DB_NAME);
481 }
482 else
483 {
484 LogError("[Advanced_Noscop] Startup failed. Error: %s", "\"advanced_noscop\" is not a specified entry in databases.cfg.");
485 }
486}
487
488public void SQLConnect_Callback(Database db, char[] error, any data)
489{
490 if(db == null)
491 {
492 LogError("[Advanced_Noscop] Can't connect to server. Error: %s", error);
493 return;
494 }
495 gH_SQL = db;
496 gH_SQL.Query(Nothing_Callback, "CREATE TABLE IF NOT EXISTS `advanced_noscop` (`auth` varchar(32) NOT NULL, `name` varchar(64) NOT NULL, `distance` float DEFAULT '0', `map` varchar(64) NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=utf8;", DBPrio_High);
497}
498
499public void Nothing_Callback(Database db, DBResultSet result, char[] error, any data)
500{
501 if(result == null)
502 LogError("[Advanced_Noscop] Error: %s", error);
503}
504
505void updateName(int client)
506{
507 char userName[MAX_NAME_LENGTH];
508 GetClientName(client, userName, sizeof(userName));
509
510 int len = strlen(userName) * 2 + 1;
511 char[] escapedName = new char[len];
512 gH_SQL.Escape(userName, escapedName, len);
513
514 len = strlen(gC_ClientAuth3[client]) * 2 + 1;
515 char[] escapedSteamId = new char[len];
516 gH_SQL.Escape(gC_ClientAuth3[client], escapedSteamId, len);
517
518 char query[128];
519 FormatEx(query, sizeof(query), "UPDATE `advanced_noscop` SET name = '%s' WHERE auth = '%s';", escapedName, escapedSteamId);
520 gH_SQL.Query(Nothing_Callback, query, client);
521
522}
523
524void CacheTotalPlayer()
525{
526 gI_TotalPlayer = 0;
527
528 char query[256];
529 FormatEx(query, sizeof(query), "SELECT count(distinct auth) FROM `advanced_noscop` WHERE map = '%s';", gC_CurrentMap);
530 gH_SQL.Query(CacheTotalPlayer_Callback, query, DBPrio_High);
531}
532
533public void CacheTotalPlayer_Callback(Database db, DBResultSet result, char[] error, any data)
534{
535 if(result == null)
536 {
537 LogError("[Advanced_Noscop] Query Fail: %s", error);
538 return;
539 }
540 while(result.FetchRow())
541 {
542 gI_TotalPlayer = result.FetchInt(0);
543 }
544}
545
546void CacheRankPlayer(int client)
547{
548 char query[256];
549 FormatEx(query, sizeof(query), "SELECT auth, distance FROM `advanced_noscop` WHERE distance >= %.2f AND map = '%s' ORDER BY distance DESC;", Player[client][Distance], gC_CurrentMap);
550 gH_SQL.Query(CacheRankPlayer_Callback, query, client);
551}
552
553public void CacheRankPlayer_Callback(Database db, DBResultSet result, char[] error, any client)
554{
555 if(result == null)
556 {
557 LogError("[Advanced_Noscop] Query Fail: %s", error);
558 return;
559 }
560 int count = 0;
561
562 while(result.FetchRow())
563 count++;
564
565 Player[client][Rank] = count;
566}