From 94d1dfe43a1a7def63b3404b96a3af70e8227b27 Mon Sep 17 00:00:00 2001 From: gsd Date: Sun, 22 Sep 2024 20:04:53 +0300 Subject: [PATCH] migrate 2 posgress --- FSB_BanSystem/fsb.sp | 17 +- FSB_BanSystem/modules/bans.sp | 67 +- FSB_BanSystem/modules/chat_cleaner.sp | 42 + FSB_BanSystem/modules/killfeed.sp | 2 +- FSB_BanSystem/modules/messages.sp | 32 +- FSB_BanSystem/modules/mutes.sp | 2 +- FSB_BanSystem/plugins/bans.smx | Bin 0 -> 6394 bytes HookGrabRope/hookgrabrope.smx | Bin 0 -> 30948 bytes HookGrabRope/hookgrabrope.sp | 2171 +++++++++++++++++++++++++ RtdUltimate/rtd_ultimate.smx | Bin 0 -> 19631 bytes RtdUltimate/rtd_ultimate.sp | 605 +++++++ VipAlarm/vip.sp | 207 +++ bad_nicknames.sp | 95 ++ plugins/fsb.smx | Bin 15321 -> 15338 bytes plugins/hookgrabrope.smx | Bin 0 -> 29969 bytes plugins/rtd_ultimate.smx | Bin 0 -> 13651 bytes plugins/vip.smx | Bin 0 -> 6159 bytes sql_userconnections.sp | 64 +- 18 files changed, 3162 insertions(+), 142 deletions(-) create mode 100644 FSB_BanSystem/modules/chat_cleaner.sp create mode 100644 FSB_BanSystem/plugins/bans.smx create mode 100644 HookGrabRope/hookgrabrope.smx create mode 100644 HookGrabRope/hookgrabrope.sp create mode 100644 RtdUltimate/rtd_ultimate.smx create mode 100644 RtdUltimate/rtd_ultimate.sp create mode 100644 VipAlarm/vip.sp create mode 100644 bad_nicknames.sp create mode 100644 plugins/hookgrabrope.smx create mode 100644 plugins/rtd_ultimate.smx create mode 100644 plugins/vip.smx diff --git a/FSB_BanSystem/fsb.sp b/FSB_BanSystem/fsb.sp index d6764a3..b7856ef 100644 --- a/FSB_BanSystem/fsb.sp +++ b/FSB_BanSystem/fsb.sp @@ -4,6 +4,7 @@ #define _message_module #define _mute_module #define _killfeed_module +#define _chat_cleaner_module //#define _steam_backend @@ -23,6 +24,10 @@ #include "modules/killfeed.sp" #endif +#if defined _chat_cleaner_module +#include "modules/chat_cleaner.sp" +#endif + #define PLUGIN_VERSION "3.1" public Plugin:myinfo = { @@ -48,9 +53,8 @@ public OnPluginStart() { MuteSetup(); #endif - #if defined _ban_module - HookEvent("player_connect", EventConnect, EventHookMode_Pre); - HookEvent("player_disconnect", EventDisconnect, EventHookMode_Pre); + #if defined _chat_cleaner_module + //setupChatEvents(); #endif #if defined _message_module @@ -89,12 +93,11 @@ public OnMapStart() { public OnPluginEnd() { #if defined _mute_module - MuteDeSetup() + MuteDeSetup(); #endif - #if defined _ban_module - UnhookEvent("player_connect", EventConnect); - UnhookEvent("player_disconnect", EventDisconnect); + #if defined _chat_cleaner_module + //unSetupChatEvents(); #endif } diff --git a/FSB_BanSystem/modules/bans.sp b/FSB_BanSystem/modules/bans.sp index 6221394..4501a0b 100644 --- a/FSB_BanSystem/modules/bans.sp +++ b/FSB_BanSystem/modules/bans.sp @@ -7,8 +7,8 @@ //MYSQL QUERYS char g_SQL_QUERY_UNBAN[512] = "UPDATE %s SET active = '0', unbanned_by_id = '%s', unbanned_timestamp = CURRENT_TIMESTAMP WHERE id = %i"; char g_SQL_QUERY_DETECT_NEW_BAN[512] = "INSERT INTO %s (player_name, steam_id, account_id, ban_length, ban_reason, banned_by, banned_by_id, ip, timestamp, active) VALUES ('%s','%s','%d','%d','%s','SERVER','STEAM_0:0:63666481','%s',CURRENT_TIMESTAMP, '1')"; -char g_SQL_QUERY_SEARCH_BAN[512] = "SELECT ban_length*60, ban_reason, UNIX_TIMESTAMP(timestamp), steam_id, ip, player_name, id, active FROM %s WHERE active = '1' and steam_id = '%s' OR active = '1' and ip = '%s' ORDER BY `id` DESC"; -char g_SQL_QUERY_SEARCH_BAN_WITHOUT_IP[512] = "SELECT ban_length*60, ban_reason, UNIX_TIMESTAMP(timestamp), steam_id, ip, player_name, id, active FROM %s WHERE active = '1' and steam_id = '%s' ORDER BY `id` DESC"; +char g_SQL_QUERY_SEARCH_BAN[512] = "SELECT ban_length*60, ban_reason, extract(epoch from timestamp), steam_id, ip, player_name, id, active FROM %s WHERE active = '1' and steam_id like '%s' OR active = '1' and ip like '%s' ORDER BY id DESC"; +char g_SQL_QUERY_SEARCH_BAN_WITHOUT_IP[512] = "SELECT ban_length*60, ban_reason, extract(epoch from timestamp), steam_id, ip, player_name, id, active FROM %s WHERE active = '1' and steam_id like '%s' ORDER BY id DESC"; char g_SQL_QUERY_NEW_BAN[512] = "INSERT INTO %s (player_name, steam_id, account_id, ban_length, ban_reason, banned_by, banned_by_id, ip, timestamp) VALUES ('%s','%s','%d','%d','%s','%s','%s','%s',CURRENT_TIMESTAMP)"; //RESPONDES @@ -23,29 +23,6 @@ char g_BansTableName[32] = "bans_tablename"; Handle g_hBansDatabase = INVALID_HANDLE; bool g_ipCheckNewAccount = false; -//EVENTS -//player_connect -public Action:EventConnect(Handle:event, const String:name[], bool:dontBroadcast) -{ - SetEventBroadcast(event, true); - char player_name[64]; - GetEventString(event, "name", player_name, 64); - PrintToConsoleAll("%s connect to server", player_name); - return Plugin_Continue; -} - -//player_disconnect -public Action:EventDisconnect(Handle:event, const String:name[], bool:dontBroadcast) -{ - SetEventBroadcast(event, true); - char player_name[64]; - char reason[64]; - GetEventString(event, "name", player_name, 64); - GetEventString(event, "reason", reason, 64); - PrintToConsoleAll("%s leave from server with reason: %s", player_name, reason); - return Plugin_Continue; -} - //FUNCTIONS stock void BanCheckPlayer(int client){ @@ -53,6 +30,7 @@ stock void BanCheckPlayer(int client){ GetClientIP(client, client_ip, sizeof(client_ip)); GetClientAuthId(client, AuthId_Steam2, client_auth, sizeof(client_auth)); Format(Query, sizeof(Query), g_SQL_QUERY_SEARCH_BAN, g_BansTableName, client_auth, client_ip); + //LogMessage(Query); SQL_TQuery(g_hBansDatabase, Callback_BanCheck, Query, GetClientUserId(client)); return; } @@ -65,45 +43,6 @@ public DB_Processing(Handle:owner, Handle:hndl, const String:error[], any:data) return; } -stock bool BansTable_VerifyTable(const char[] database_name, const char[] table_name){ - char error[255], query[2048]; - new db = SQL_Connect(database_name, true, error, sizeof(error)); - if (db == INVALID_HANDLE) { - LogError("%s Cannot connect to Database: %s", g_BansChatPrefix, database_name); - return false; - } - - Format(query, sizeof(query), "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", - "CREATE TABLE IF NOT EXISTS `", - g_BansTableName, - "` (", - " `id` int(11) NOT NULL,", - " `steam_id` varchar(32) NOT NULL,", - " `account_id` bigint(20) NOT NULL,", - " `player_name` varchar(65) NOT NULL,", - " `ban_length` int(1) NOT NULL DEFAULT 0,", - " `ban_reason` varchar(100) NOT NULL,", - " `banned_by` varchar(100) NOT NULL,", - " `banned_by_id` varchar(32) NOT NULL,", - " `ip` varchar(15) NOT NULL,", - " `timestamp` timestamp NOT NULL DEFAULT current_timestamp(),", - " `active` tinyint(1) NOT NULL DEFAULT 1,", - " `unbanned_by_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,", - " `unbanned_timestamp` timestamp NULL DEFAULT NULL", - " PRIMARY KEY (`id`)", - " ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;"); - - bool success = SQL_FastQuery(db, query); - if(!success) { - SQL_GetError(db, error, sizeof(error)); - LogError("%s [ERROR] Unable to verify mysql_bans table:%s", g_BansChatPrefix, query); - LogError("%s [ERROR] %s", g_BansChatPrefix, error); - } - - CloseHandle(db); - return true; - } - //MYSQL CALLBACKS public Callback_BanCheck(Handle:owner, Handle:hndl, const String:error[], any:data) { int client; diff --git a/FSB_BanSystem/modules/chat_cleaner.sp b/FSB_BanSystem/modules/chat_cleaner.sp new file mode 100644 index 0000000..a740b70 --- /dev/null +++ b/FSB_BanSystem/modules/chat_cleaner.sp @@ -0,0 +1,42 @@ +#include + +//EVENTS +//player_connect +public Action:EventConnect(Handle:event, const String:name[], bool:dontBroadcast) +{ + SetEventBroadcast(event, true); + char player_name[64]; + GetEventString(event, "name", player_name, 64); + PrintToConsoleAll("%s connect to server", player_name); + return Plugin_Continue; +} + +//player_disconnect +public Action:EventDisconnect(Handle:event, const String:name[], bool:dontBroadcast) +{ + SetEventBroadcast(event, true); + char player_name[64]; + char reason[64]; + GetEventString(event, "name", player_name, 64); + GetEventString(event, "reason", reason, 64); + PrintToConsoleAll("%s leave from server with reason: %s", player_name, reason); + return Plugin_Continue; +} + +public Action:EventCallMedic(Handle:event, const String:name[], bool:dontBroadcast) +{ + SetEventBroadcast(event, true); + return Plugin_Continue; +} + +stock setupChatEvents() { + HookEvent("player_connect", EventConnect, EventHookMode_Pre); + HookEvent("player_disconnect", EventDisconnect, EventHookMode_Pre); + HookEvent("player_calledformedic", EventCallMedic, EventHookMode_Pre); +} + +stock unSetupChatEvents() { + UnhookEvent("player_connect", EventConnect); + UnhookEvent("player_disconnect", EventDisconnect); + UnhookEvent("player_calledformedic", EventCallMedic); +} \ No newline at end of file diff --git a/FSB_BanSystem/modules/killfeed.sp b/FSB_BanSystem/modules/killfeed.sp index 0973ada..b1fc25b 100644 --- a/FSB_BanSystem/modules/killfeed.sp +++ b/FSB_BanSystem/modules/killfeed.sp @@ -3,7 +3,7 @@ char g_KillfeedChatPrefix[16] = "[FSB.Message]"; char g_KillfeedTableName[32] = "user_killfeed"; -char g_SQL_QUERY_ADDKILL[512] = "INSERT INTO `%s` (`attacker_id`, `victim_id`, `assister_id`, `utime`, `weapon_name`, `weapon_id`, `weapon_classname`, `weapon_index`, `custom_kill`, `crit_type`, `server_id`) VALUES ('%d', '%d', '%d', '%d', '%s', '%d', '%s', '%d', '%d', '%d', '%s')"; +char g_SQL_QUERY_ADDKILL[512] = "INSERT INTO %s (attacker_id, victim_id, assister_id, utime, weapon_name, weapon_id, weapon_classname, weapon_index, custom_kill, crit_type, server_id) VALUES ('%d', '%d', '%d', '%d', '%s', '%d', '%s', '%d', '%d', '%d', '%s')"; Handle g_hKillfeedDatabase = INVALID_HANDLE; char g_kf_server_id[32] = ""; diff --git a/FSB_BanSystem/modules/messages.sp b/FSB_BanSystem/modules/messages.sp index ded2b15..0be63ef 100644 --- a/FSB_BanSystem/modules/messages.sp +++ b/FSB_BanSystem/modules/messages.sp @@ -3,7 +3,7 @@ char g_MessageChatPrefix[16] = "[FSB.Message]"; char g_MessageTableName[32] = "user_messages"; -char g_SQL_QUERY_ADDMESSAGE[512] = "INSERT INTO `%s` (`account_id`, `utime`, `message`, `server_id`) VALUES ('%d', '%d', '%s', '%s')"; +char g_SQL_QUERY_ADDMESSAGE[512] = "INSERT INTO %s (account_id, utime, message, server_id) VALUES ('%d', '%d', '%s', '%s')"; Handle g_hMessageDatabase = INVALID_HANDLE; char g_messages_server_id[32] = ""; @@ -18,36 +18,6 @@ stock MessageSetup(){ RegConsoleCmd("say_team", SayHook); } - -stock bool MessageTable_VerifyTable(const char[] database_name, const char[] table_name){ - char error[255], query[2048]; - new db = SQL_Connect(database_name, true, error, sizeof(error)); - if (db == INVALID_HANDLE) { - LogError("%s Cannot connect to Database: %s", g_MessageChatPrefix, database_name); - return false; - } - - Format(query, sizeof(query), "%s%s%s%s%s%s%s%s", - "CREATE TABLE IF NOT EXISTS `", - g_MessageTableName, - "`id` int(11) NOT NULL," - "`account_id` int(11) NOT NULL," - "`utime` bigint(20) NOT NULL," - "`message` varchar(512) NOT NULL," - "`server_id` varchar(32) NOT NULL" - ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;"); - - bool success = SQL_FastQuery(db, query); - if(!success) { - SQL_GetError(db, error, sizeof(error)); - LogError("%s [ERROR] Unable to verify %s table:%s", g_MessageChatPrefix, g_MessageTableName, query); - LogError("%s [ERROR] %s", g_MessageChatPrefix, error); - } - - CloseHandle(db); - return true; - } - stock void AddMessage(int account_id, const String:message[]) { char Query[512]; char EscMessage[256]; diff --git a/FSB_BanSystem/modules/mutes.sp b/FSB_BanSystem/modules/mutes.sp index 61a9914..bfaade2 100644 --- a/FSB_BanSystem/modules/mutes.sp +++ b/FSB_BanSystem/modules/mutes.sp @@ -25,7 +25,7 @@ enum struct player_settings { player_settings g_MutePlayers[MAXPLAYERS]; //MYSQL QUERYS -char g_SQL_QUERY_SEARCH_MUTE[512] = "SELECT *, UNIX_TIMESTAMP(timestamp) FROM %s WHERE active = '1' AND steam_id = '%s' ORDER BY `id` DESC"; +char g_SQL_QUERY_SEARCH_MUTE[512] = "SELECT *, extract(epoch from timestamp) FROM %s WHERE active = '1' AND steam_id like '%s' ORDER BY id DESC"; char g_SQL_QUERY_MUTE[512] = "INSERT INTO %s (steam_id, player_name, mute_length, mute_reason, mute_by, mute_by_id, timestamp) VALUES ('%s','%s','%i','%s','%s','%s',CURRENT_TIMESTAMP)"; char g_SQL_QUERY_UNMUTE[512] = "UPDATE %s SET active = '0', unmute_by_id = '%s', unmute_timestamp = CURRENT_TIMESTAMP WHERE id = %i"; diff --git a/FSB_BanSystem/plugins/bans.smx b/FSB_BanSystem/plugins/bans.smx new file mode 100644 index 0000000000000000000000000000000000000000..22f9969c117db4f602fae95598a73c2cd2c50d6f GIT binary patch literal 6394 zcmY+AcQ~9|w8keABx(>u@4ZDgjNTG$qIaT<&VT6?X%zO^+p9vkA_xbf#c2&AJA0#RLnK%o8`z~^5NWCei; z09IlLfi9>)AQFHfGC&MC5Q0Jh<^`M?P%*$y0OtX83k(9i1{#F{&Qk<|Mga$oL2gPQ z& z4jy(0#Q%j(t}qYa0%1pcXJIE-kH3@tqKB*3f9UGv1pnXUf7AY{aQ1-P+j;y~4tMy= zfpfc75xz#IHk~4hv9Cz(vR>#7xfAD(=}z8xtOfq~lI3Os=_A=3CG&cuj+4zxb8c}v zC%o>uLH>r16Y`aHAr)o($42TUnvfN9qlH3~DuMSd`rcLUb9I&#*0ilV!a^Ru&Vx?Q zzqg9#XxA-Xb{Wd?h%ALD;;v4^aVH_2z{!G~w_$u;PVDD0i++qvDXFjgfT@tRcT4_q zNNg1D+cKf#X+8Z#F@a(c8soN4On>o`ptBI2&KGOy`qVI*P~w!E^m`ThTryBEnq_P` z?w{({1d8QojLSaI7)8)ojIMFpucJ)vkoZ)NzDXaNK|t=lZ%5hzjb@oz#<=er(qB{( zpvIO>B?8r5z1uW^O9OKWaMR0R(r~3{mhpdUV5H&7(VbOjb#w1Fi|A?B{bc$!%V^-L zF#3yl0>uh+>OWTjWj4`Jm;E7nt5>vrwC?-V^pFCywA;QEDf86wB|W4Zed4+w{r`Hn zNW=C1_H5HH;3l!!(KX+eJ?Yz^(W!3xH|a0vNW-n7QRB-SlBe_Z3yP|%agu>b(M@jq zni7Eq(ZGLdN}P(4hHFHlCYNa?PmM|UYQ`$h=|igs;FHT?^pG+%(99!o+RT1RmDlS` z=xcqqjOC|H2hjl{$l^P`knswYuX^HFzV(Cc2OAfZmOZ6>m&D3sDgkIi4wp6e3k@Ohs$ntvY~lJs0N1`@cKBOrGSFQR1%XVm2m2 zBQoei#8N+%9mo_Z9p5QIIyWau#Uzro~Dd&Czvoo;D_PkZw;C>W|>Kd5F>H zB_W83p5=6NRV!T?8>IkstA3vk_mIEzbo4G`@p01T*|HxLlhToRZ1+$>-zIZ$v;HM4 z;E&On@cNbM)8;ETbF$U-nF%egK8)w;)i;K^l$5fUd}~)S_6jYGiQY0#7gu$^1ziMp zjQWMiO5NS?=0*OLdDnQiBOgxO(!n@?8(|Am{QP=*?ze82NlVZR#&$bBX4Li>?Ta5w z!zVWf+xwdLL|99?nM}w0%2oKcyz@J;2%5vUqc_>w#4!XLGZD8X>EGFX&Fug z_4B|bfIlDgQxdeE)Nlr#qT9K>x^Ip?ba(o7CRtx_NiK`=U_fmoQ~Zpd)Z|OWL{eg; zKiht;mKJ`zh50re$8_=@_Wn1_7|dO9I5fN}_L|t4CUCn`+?KqqW2riS;pze}NPlBX zcW$Zk!zq2|rbUNs&HC@vQ1aFG^dq9BqgBW;^l7LGKlfpB@bW;X5+)!l{nHn#f(^wF z*yvxKiI?ZTr&YP!ouilKE1GSpe7~1se&Gm{%P>N3Y#{A{-r*2WMRDPM`%TKXa8256 zX0yW6oNcYj?Mii6hC`-l%_2l0>}c-y$|Q@F-lwM{ht>~^Y^Ozx`!!gc&55Qj?JsHv zW)NS>O$TaQMm3dFs9_VSjFv0OahG}ZteuxJ_?Rb(MDxEykomjMv-KL0r-UDn>WRCI z)^9{`Hpy-GbF+yCng2X7-t5K_3c`8e+bLt6 zJm0~&wSKYf(bWpyUasMS2>0~lFzu=SkO_3$L^u6>Z|=c-lDX&!vH@-D=xL_E9D;1P zal}6x?nTon+d;U>{91ArrMsTQc=@UAJn7KJ=J`pF;l9n)&HWSw^f~Mxj7p9RnoOD; z8LQOQ5;FZ=0Pkd}zU5c`x5#hqcRC}w+9OFLB`=IqFMo+E#-Or%d-0M*J$n$bJ`qWo z^B(F52fFt>nw-Rfj=S{Qj)J{0E{T1X6C51lMr|DFBj$Vp(PA8%i&LCt669VOP9GD5 zEYf#!6+HB)i9}OeufqF2_<==xxc!L+UN#nbhUVm!dOY_;ijYX42rE zFfJY)WJ)rsE&7S&C#`FCmd9zE4SLdm%_%86^^xeI=#&jJ zch6{F@#)!pcZp7UFk{et@<+_Qb0ZrVI&%EOSXatDmk^&;bLK7r(@i&ajqVo1AoLbNvEeh1$$#QP$F&v&aquggv`SG>A4ggd!%_PIU7W?RBYu< z^y*kAA&LHPJm>VpiTy47MJ6FW{%=}MC$Mi0){Yhwcz2JLU7N_YTEk{+UY-|xoF^<< zR9KKWVQY8EkDo6b5FMgRsxpycV5(cF_13D8Y1o9R2XG^`$zPC41-iX?US(3JUx+}Bd%@7YtO#Yppb{T=A(vOT4WhaNH-;N%0=epUThy;UM zEpxvpBVbcIcVb6e1hZ#6bI4yeM9u{x1SRk4mQ)5hK7qW9ziFLg{KLw=d+=u=N0IOQ z66t$H{;?cCj;ql5Pba6m5FwTi?n&$h3s9{TVXjA@A2_(~oYRtLnB_-U z8fwBn^i|eZC0_R|M)Xs<&quLwenFR3Q6#oXS6bG4Ew(glGc@;e*1wl_XK*(SE1upA z4~}9&XMHG~Y@NbC_~y1d0(%Jan{ttr@*s1X;K&y;Ek&$n=pfT)dUj}QXs~7l6Pm(htx2$XtEic4UzSSjqT_%n@yw-iQ%A$*7S#;J6 ze$fCcHFWZlNtdiQacatJ4s&{K&~KF6$CP&wv)R)gys2YVEQW^RLE!X7Ex(*H?PyUG9N*FhlH#=w^eWJfF2= zK5fsta!c2j5FUYv}lqN;!n*0M>GqTrIu%hs>H_Kr&l6 zqq=ImU1;EW<{(Vn8Lp{W%){u0TVS7@=bhjfN>bx3PMQ%Z;h;G1o>i0OqBmKJxZWZN zZXw;HPvVZrjaRQXNzEMOzFV8%AzV*?P47CKF%aqE;r#rk*3bv)dA>Q`v?9&#YpMw| zqiLRxqjX}u5ZqZtV!mbbDH5`x?^kZRr4UIys`rFbo1gO;&X{of8%#2K6_814a`7sA zC0?DdTBJW)r0}4|Z0XsQPuazZU=u1PBFgx=s5Ly!IZ3+sR>rN2%yLNNKa*z^u(uP6 zEH2t%YYTH`o*MFhC$2yGl+^2bpthrwIA5P${wAYpq0+@2@jQRi;WsaQ$n2wzDbZZ| zg|z;#?g7t1+_Y1eiZ}=T1(JZ`Wm(W;xJJ*w3KPJo{kE(K117NsMvC&$$xaZG$H}QS0I(gN!+dW#`=C z6?$n>{B6*@mQivf>+OQQby*7q@s}4#3mFeI_J4eT;-XnB{z-mf;cHIZ(XCt+A z&6O0$CD3u@se?$_NCWH#?(9|F{Y4rkZ{7YjYk8`A>S2H;jwaamg#-cKB9pFM)Z2Uo zqP&9meD60uIl_uJYl|~?>uEQ4-rX(HaPXJ9q=R)hjSKP`OBT)UpM_FtC_JW{u@!5r zq~p3_nxOCS>fL^(4_}cZ?KA!g(-!xy!VdRGzBbl)H`XldOJ?7d9NekY*J3&o8!1^Y zxb=8qA73jJ)|#fe_zhM>CbIs@t=4b^#-)JL_nMKZI2&w++~+-FTit-~)neg4th?jy z?(6=3ph*$W`XK~Q|JFo2XWBKTCN*FYNkzn8m6^x!_t?IC)_b+j&(86T4q`?6)>CQtEelA@;n+biy-sGXSw;L?+R{kFZ zjW0(2Kxx!ww6zWn$+LcL5E30=sMnC*Q7H=KXYh10QXC0-V|)G2?M^gL0Li`Zi#BZy zf@e#GG!;{AkIDtSwibQ(sE<|=1}6p;OM3Flh(S+(Lvn8-PpPa&);PWl|ARZIox>!E zNkn%m8rR%@PC2ydo;}QtOk+)cB2hvZ{7XSLUB^m6TT2^Gln^G~r5MjYmG5`hY47 z&}BeB^tXE&3LBvmUPuMFyGL1#YIq?W2x)^fvD0jd<9~Tf(=vy#2*@jk7hc~vOSqz4 zxj8zOD)8PW6=9jA+hG?*)Y zOvVbSohPisfsZMxID_v)^s@|GKzoMZ6m>|A7>Ou_%NRjL;VG7tL01zoqE1woo znkSc?Af*!irs+NKgpxqgqMw|F?9AI9A6WnI6QHmITFo5$MkRSe+412da=QXSCwaD` zVR>oYb04NeP-4?m?SyhE7e3C06C%*oWnYeboz&CyIqyM{fLxp7p`${#th!nhX<{UV$fYEF5$A ztxgu!T+s9?SWBl?HL>&iHLBmY#%*@?I9f;#eX8%y+>wTu{%Pq#tpACeG)OJ{ZWUDF zdkxuyLGLEpcTh1s!=OYWz)l?cZC}AkzG>J)wOY@Wh0x{{Tkb@h@bsk01>f+HTeEOJ zhwK-g=z{DDe3hM*3_5cKzgo+F-LGPN2o=}Z1Z6N1P)sc+jifh(WwrfmZ&H8M({*;ZK7&LoXoAXasZNYpN zzf`+anpO?11vkKRtRhAQGqzJZHL4YvBz-QyMjX>9grv`6`6uIQxiWa>c5+azm2(R` zV_SRMr@4dCMtC}Vb!ffC$G+LhbW|vNo2W6w-g@)FdP~&fRU~_DFA2W*t3~XPOc)PN zrP9!Up$oRu=P9^6$tAd!>=VlX5>CQO6*b}~mRtaH?7s|Q}dNTjKy-M7ah%A$r5rd0GxDOj|8xuz5q9CSNZ3$$EFkKap}fL3^$B46sMLSgF?l#vC^uOPk8pnv%%1N&ty6rAj-?$ZedH5vlOF;_iv+E?CuV)K2C|W zZJWbJ5ptn06oK(9?A8jYe9$amln8IZ&<4xjPdVP$9#$Z}@pSX+E|z*d{o5`!3a^DJ zO!vlO%6DGSu2g3k49|3d8};@) zh_>CEJkoQBbH<3hDVc$RPrr{cVKc9d2Q!R2bN)o2lAt!riO-4pT!hF@_WN#_R$QVf2ua2C|n1tC$7}-d| zq&YnQ=rog)DYB4}36ik=1UcDvl8zJ!T zCt=%VaxzvDcO+2|2@8-om_+3y>`&s~NW{NFvP0r=Btnz$2NKU9k>n~l*%s-XA?kz~!T-y*Kb*;7np3o}Tvq(ft=W13m3rt^cR{zpDR^0A0MC|EJ#*>;|+3 z+WbEx5YY2~BrB(nAkhCkXk!m_BAFAkwzL(rv3L4s-G88yy~}^0y^D?Oe>(rW_P-jo zPOg?8o&KxtYV{BHo!&;!`?J12QEW-b<#a~f$yELHi0a;rTgaN4TMy&Jv}W$TVwsME z-BK-UbiCWR{A%}=Udf$G)gO;u7QK1)zV=0YHbXIG>781;v7(nG5V+M{q`TF>`%&2oMkhdF3n09Kxji?XafbEyAqvyJDqzs>*D>2@P5!Yyi5m!Y)8Cw zhkmnPG@hvup>LZSgzX zVjt_G1M6Zk>!O70KXZ0GziolO$fqyN(``7q`f9;brY(g7c{<8$@qBqGY>5d(rZ!DhQWVdhm zU^oROXR>D57FS8p%5;oNchpLEIJD=S#+`Z`BZ-+LJvMf*M9wgyT zub~KaZh3}Pc07MS0;6n%a9RBrrSZ!minf)NDo|SOuW3qGQ@_G*uY`avTY@vd zS>}Cvm@6#7KK9Zq{8T;OP@B4@i!a~gjbQBX7V8kLCdf#E2kfRX>psjr`EGj z%eAuen{1xbGgG+K(gC#|g_j)Y6=T%UPjs0Lv=oyfF71sQ=* z>t8lX#w;UJ;vtY2c)d}hk53F?*I-wEeSeN>Mf~(~Z`!dO{Q2@K`{(E9HydvHvfjUX z!D38vM*nxxB$?8;6eln`<*LyCUht;0f|5*^R>DQ36U&o}hC8h~UAAf`Xlt2j#o@;U z{6f*(t>!u^Ph%G$jCzCUvN)GQ1`e{{@{EzNVvLcD^rC6i?FLo>@_Ri7-`U-_ms3v; zP){}sw>|uLvc0C-5+HK^zHmwK^UOoM9FFy;ZP2c@Ny2y)ZN&b8$zQnUrq*VBNVVmD z`;oqV!H%8OueFh7<5}myXjc_P8thw@=Fg4cAMOrKKK*slH18W#eH-By6Tt$Wi+B8Z>$b^gHgkLue~e;tG`7kVq3GPv#KvTJ5Hs^Gy@=IlRrgf)8e z8`%t+^w_$-qJS0%?}*cM@h67Z?qRJGT;Jo(=1(=;1ugU$#p^mLr-F$h-T~Ec??dzF zz->Qy^IzSC+Cl1Rh8Y>g`SNOG_AGatGcsk;d|LMDob>XY1vka)^zv;Qok6;-U=M$V zUzlBkO<&wVhYY)Vb`mch9-Y1XOyB5j(O(ee13TRb z=%--l^EGF?j0qL41E%*2-a1UoJFv=q-9q6SVa~5>H=uXc`Mve+9@EnclkeE#V_Uup z|4zk;$@kBiO(=(Bnl5tQYbtD~vrXXkc)th|m;6ky!AyMk4LvIl5v8Asa|t6%{hqd_ za#n9LTzf3%#yUKhPlS&VzsCd}q-ojT%$UUM#_REzNG$unB*7=MTWqF*K9D6~KgOjL zsmOkk_abSLbOaa>KWlSdoM8kY2nSLy~#?Z;@WIx%~P_XOOC-j#_;?r+L`EcKI+u zCN8hT#^oin736La)fo^VxZ7Xb;F{4Mkf+`h80y)n-bBH;vAqnjdnvG^Ssn0IiIw5g zZ=p4qansE>f35h7VrzMPW3y_nEo`y;tsPvq%lt{k$4!hpDkk4VmU0lWlsP3qIoRSp zf)Sw{3_vY*zvv41*oiG3X&AA@Sm#2T7qLM1XaM?V2`(U%uUdkzYyLxuo8_%_9w1&X zIK*gl$(x{1W~P|9j8IrP&3cS8FE!)P-k%HZJN)?=XHXu^4aS*{3A>wk5ax2thPC$R z>iN*NkHM~?(;1|pyPM69Q^&xZ$xcKbP+hU~STs(ozOYFv3;Z)R{676)C<9b0*{uPx|g70;nT3 z298{)%Tt3V;FR|O6pZi?27oBzG`P=lZ?r=Tt;^*K;85b3A@%?yBZ2{a6f(~B?r_s>oG%-Z$$de6D>@Gt7v&G%uinzi;+1db~N z-*^}V%J#*q)W2R3&OD}{{44t_<^4(2Q@QUQ(R>$H5^^>6z4)G@x1LRl<;4}NKgFM&_~|*1d!6VVZ|k2mJNd3^YLu29@ygNh zUbIV`dFU-m7X5u{ULr>bFFjew>nYb>sMOfQ)h$SJMPXlntIjCzv8ym#exq$YyLSS7 zrhAaRC}d_i=xX!*jPD+MU?r$?bznSoG<#?3 zV2DMp)M>Ce^=$ihXh(>O{e#os5@4V2>%9cQ>Q$3p*>fd^zBRlTB)7ibJ8?GfrQy2> zk~rfdMU(wE(Wm-dy`(9=SY0=I{HdG_!=(*N;5hI8magx%!C8RBnZvtf$%4Q4bgZHH;81>Fa)#pTKv9POL|o4M zIxvNSoyc(ciMI8__cJgbY{?-7FatM$^a0|CLI7JHIYf49_sVi|+G13MKzw7Y72_uKyVK9oOh%|BSY zb@$#0n1P+)dn+;oJ8|zs{Ha{iy-P-xKzZK%nXBZAs(}8=Q^To8V`X9x1l|v8rFhTD7~PNx43! zo?ZH`=#wWNJ*%GNqVM!p3TKzwI(G2PNXusc*rc1V5!I~OEiECrQDp|}cTW;T1DoU$ zHf$O+6L2E4nh6_lLDZl}Qdt|Y=~cqUcXL?EnuvK=zh|BxD!x(EXhFn0uiw)^5M|J; zX|yC_UfS>JC5RGl&|LFLD(eL{W%heI3!+||!L~e;T&nv$%>_};?nz}cz@}0`)M0~W z{UERjkg!qLtXbamP5z;t7KYAxtjGY3fMFk1LY0i|@{e7O zO-a5`PptmV3@Z{*5Gd-dN{EqBS^u$ncT@J0Qd4xX#4oxHh5YGX(z(Q%robM~+3F&= zR4%cAPe}Y|L!o#mSUML1s8#V$C8VAX4sgz*inMZ-nuMNid?C%t>HDnIL|=F$PQsc0 z;OGL0Cc2IEci3=}A4au2o~i^kFTqaES^gsUWUi?r($!FcXeQKvGYGGJR%|6!uD@+V z$LB42j$;!}8Yv_7W+bdbNrXE;BE9ak5Mb&%Y3n6NWq{Y)-TI(5S z@R*nSXBe#rU2CFu+}pYmQCqpu2daFXKJJxobK#KMG;ubhPwqij?2ElxSKW1g!U=rg;?7;Crm&RKlKv^%pMt1I z<{4E{TIN{Cn!IG8Aj*D)r6(_&k+3sLo#<;i^}zdHCLvagTZa)cVh2iOyAN9U(H;4s z6SReX9jf&c#!7~Fb5z(+=67Sk@fL;q1F1PR7L`?ukI^--(}vFEM^3*ZwFc5)zos7*Juu}o$wFQ{?MF=Hck5` z(PzF@7D>{{VRl@aDR3$Enq|`gvFy|@#6lta&ST)HW(gVHor)bgpPe?(H?mHxTrF%- zn2)G>O!}O6K@$q*+IZffz%R|y5UIXtc68~beraL5dAa3unj}^~`i(YYZbrvRF{gZ| zL1W5C80tTqcIqNEy0eX#F_#rh8y&jl(_IgmnUy#{RGQH@gy+eywzgk@*H-7bwyp~n^3-S zIzC9ZW}akLHKzm!oxfV~`_F><<dv=&WQt;WQO%|!4x=1|5VpFB#?0V~ZXa^{n0--kODe$hADgRcEWHR zpjR6SS(wXr%+qWhJW86jJtK2(;WTXYQxTO&0i_Fx6yXWAADlY?;LuLf0m8A6D5~Q* zgKI*Y&ydc{5o9;gl{gA z@J;H8oQ%+&fEjT=lJIvxr(=ZGU#j?7KU(v8bT^1iu=UdCDfUuU6MKoPX12{W;r?gG zmdWo0DDQP0^t{~NQl<-$Xo{tPi7wCo?edj=x?aP~pKC(r=X6Yyc2)W*CO5UwYY)0+ zyfDx0<2>y7W`<+>9`>kux1OZdxKls?&{8SmlSbFkLe;X z+q!ztcp>VbuY-=X9eh$Tm9GX(QCxS+6Dt4g)i=f7fQec^+H&3#(LIz%seF|Tv@9p> zTUl*?4qd_vzvcNu5yPHM4<0I#y_YUVaMm%;sR#z702T2c?>oIhMvmq$0&j8e_^o~;K7C#}I&iw2BZ+HE4@ zY?4UdY&@4kv0V7>dd-M|{2-SoirKv$xO+J#9#b*>`}e`_Vuz!LIJynocPe@*efXKPPJ(Y^OwhL?7yQ#T?ca1gnc!CLkdVKZ~T8F+7qj`M79TK5w9 z3zuoReHrHVZT~;!DWpBQ+MMyt6>p_88SxQ`S@ptIGPjSV`35NLr!S*T3JI^fTXDKw ztvcH9?E+h8Z^aFlVcNrzL30jo7k+d0bj^qi$L~g49}aqr*|v|};1L!sFM8kB$c1W*O97XRH93OYlu6RgUN@FNqR4SSapzxuZeIPjC}r1&3f+pmiCs zC7$WAXUQ+Tu#8I)D3_G|U5R)}LO^dqeV1ps?kb$n+2`~(qerAz2Km$n7s_Mf^yBg( z5iZ@SGIM#ZPK1u6ZI2(oY@Zo>%6mLmHyH=XpoQM|x(rjH^yr%|wDs6Z#N(kQYnvlf z$krj09Xg0Z70O~Pud!iA)h`~+k?PB=p1}S*nhC-29ZliA7s8%+$oZPye=?1|U?x5N z@KXqUEcbJIEW2vAUv1^|^LW3J9dndERqy6!E}cB6dB$j2Xu3L-C1N}uR!oEE`Bc^z z5Fsqyf6E^U<`A_yYce!xuPN8wW=`hs?l9utqPw3i*(Hl|X3erSMp$KGzMvD6dzA`O)dsMknP>w&jMy;^#CZ&r@%}GGr+O z&NUb8J<5~vt^CR~!1UPiflk)9XXbtH2L~mHdQsxI(G#!63tL+!cDrg3de5h7ft&16 zR(q^f3(|6Q>CA#)LwV;xym5@&xD*KL5y?1{Q>_8oMHw4G7<;4%ws#0_Y<@B)@@D75 z9h-TspNZ#hyi77y1<$Qf$5vR>UI2KmIt(~<6~swrO~WU8SUG>(jT*2y>07u5zsB^xX+LswqT&($Ok9)jp+Lz$(6XlP!DkZXv45 zZ+Pk?46TDGCXD;ZExDA(=*Xbvgi)d&cYr6(xW)rytwZ;pHKb9-X22{{WGmZgcaPrh z+PgD!Hy~^~+Ct{V-jmI;wWs<7?P1-sY4g1k@lE1;UZznndd&(rP}P{P9FC=!I}=Qd zV6R9{NV?8uc32oTu4lF3*6f|MQDq+W^n?&qZT@aYiBcggT}IP~L%(6|kP`wzQ;=&*|+mO(JCFRc9+N4!@%N~H-*z3W{C`b z{}d1E$AG4dq4BFFyHFi*YtscdlM&R8p&!z0o*xdTnJEdSzv| zCwwEJd2bzF$D~uTEe>B##aXZ55|KmQ&eojy3ac5qIKTy6i`_FQAQ?aUAjnDPRbyCm9cQi82fDw8)TIfbc-`q&THa@ikW4cX^+1af7do9x4BM&t>57Y-U-*7D_yV?YKD3}J-3f$wj zS7*WWV?UQ0_gmz>DxVIqO^bmQ{zjYu5%-ESRNIeNbX#G9Z;U;KdmtCv$#X z>0TtS&u5j%kqe%Qx`X2V>ZLqi;uqEx0sTW_`@BXUv*Be}05mfL%c1c2Ja@RMU^6-| zBdh04`Xg-je&_tm`>1;}+gQWDC9!Bg#84V(3TG{?@S_W2F4ErQy-kc0L zQuR5lZiMD{DyC>-jUuH-DJ*pSwR>z|Ow;P`=vW}4;(5H%4~_2tN1cmXZbQ04<83i# z0<6;65?oH)6?^NQy794 z{8Cy|pX!~!PBYf)>K3IZq_ZM8dKo+;{ASK069+_wp5kctr#Fz4Z*UfXS{QghIhM*) zF}s6VOoJi$+-ihXe6&Q@E^2xi^noV1TT9G`S1fvFMD97I7Imb$s88GUE->U*Lw$2S zCI_E+UUfHG;BIu?=VKhdi|;mjkV;fo_xy`&fEY4qi+6V>i}u{??)jqYlTALZS>N@w zq;T@O3A}TU8uq7<;u-@vRc4KdY=2VjVB@`BR!5$pAdvNTz zl!X%?9VTi=1YZ0rDfXYyJUy`0iq?^2KfPviVzkbr6Rl%AVe7Kal)Q5JA|i0(Up)(_ zU(n#dmH*5c7PzE7PbOLKQfloGxWq<|x+bz`xX2x7XdMvv5Bh65MB4@fs$RCwBVO#g zEt=T4;BlQ>`qlCg?!&$ZD#2msBa&>y4`5hYHn3le$DjL}J9ZX(q{53d;g7J<=w?HB zQCDyAbjQ|T!je}7L;0rrX3B%R4!@{dT;bp;=e}DGO7(NB z4l~02R-ScTtp%sTn>687fpG=IL3mSFuVXlPfROX=5Rf#a1*bcIs!K=#dqwNHI*acW zow;Z4O5&$wv;p$m00=bopJ{%iX(?d|1fH-a?11Bp6!Cd@nAupqEsQVVbBAR@#?<(;&Vv{$xv~|;g`X-zbJ+U z!XewMH8E*9>fS@VQ_{KCYhPp1mejn5xTmBOt=IHp(zr+h*OYXG_1fc@G%MBa)R%l9 zvO+j2e?Ka{Pu7PIH&O_{OA=E0WF7f%nT2pY*nU)EpR5HR&TS)*M`MMJKi&tXKlk|^ zIA3jr?Mb{(l>Qv&J1~zbFe0NbQ9fSSm(OZbzpH119nW0?RlLIj<#;>s@n3pg+RlFN z<#g8M^SL4?Gwsdqa;vSKamOz9)Xvr@Y!Ilwyc7-MxZmx!`}3Y%q2oUN<7)0p)d9oe zw=EizrB5Wg3|+Rb40zvehNjp-U{S4@5wV%gfr_ci91&WvK}aC!h6o1Ehz@Zd83X=Z zKb}#pg-l(@IyUF0L=bN4vCz?&)-N~;&e)Xpp8`^p*;;IhQk(_*;tJ!`v=rN~UGBx% zmdHFP)-0^4e?L(QRV{Nl4ZJ*c#XW@}mEE_fIkvu9a6d)>@T!ZqILEpW?*3Y5Cnl%$J2(X1YW=DY3nj z9$7Kk=GfE3&S|RC{9pFWtBp$H9HcTT!TBZVplWYMC%JvOx~FF7#jK>0oZ}^J6N7}6 z%OPfI52@oLpSTrRnOnR%`-3Zo6+d?9N}Z;p4x!^0OR(D`y0N`mb&U+5`97=}CocYM zL*QKKhj?{*x@w~+K3SEyW=Z^~*UB4-Lva=W;cVw<^!|_z4)D;>Q6hq{ysqHUNA%2t z+lU9ghjmnHhs4P=PI+=H9mvx~HO??~8Kd6%I4>UsqB!YAN{?ZJRY6f}Ba2cJ z>d7|GLH)7tn?tOnRYa*eLjUPXfroAs`O2Kk${b91w|0ifH@jP)ce^nsYP3doD{wur ziQ~-!Ai%sjA%zEBruBin3)#4OX1t=bGgGYTHS|Vw&Swugnx{^*ZaVfh1HaLH^X8uP z{TPoQwlNgN;Qn>MllQ}a_<_gol0u#G0*5L`3cZ_#3u58e$59M6TG4w3_ROFKhjb6E z1sr?9`{$!eP5stv!k5yL5COEZN#w@BFuD|03%V>_n$q8A7qXc1P-@X;)J_8X zpPlwJphwo`mV^UZ@D2SwU7#2ael2fl%ICPfbp9EX=B0l__!D!a1=kYkQhD!Rmoe>a zmJ{&S1nT?tr)j-&#W}XO{N~ZN?Yf{@J**Z5X#7(cNk&8Q zHOqt*(e(n*6R_aQTm!m*aE7)#1RTD%WG?N3Zl0Pp*KA&VGnt;;S{U~`__HR)Xyq?+ zBq_G8JgoS6xFFmCc!~1dF;9#-xz&uALX|=X9Qk(A74uJYixJKQKe^Gyclo|KTBmZA z5>xWMOAZ6j=k27UtG4Yg(XM=uEB3+N*}Va;2ZRTQqNMi^8C)jp-2~C%lOc1H^ctM_ z_9|NdP6|63Eep@#NWiVv-hIoB2RZo&exHTxJz&Chj-FqMKXWylyHVfdn}ONbXWrBC zAVeghk}__074J`q@p4DM0UVq!$9Zg%_CtFgBA^dJ?A`;E;QF&hq!u+WOkI;YlBg90 z&ER}6YxfnyJ&@L3VZ^l(&-|Alxuq*hfE>1Po$%VFHcy@DHKu*Dz`MPmJ*{Qk6!0cm zV6HT6wQw*11o(bxSt7mU`8Rp{AVTLTH;ul(`c=RMPfGe_uW;i=_0JR~#wvGJFhSKe za9ja5Ps`p<81t;D<}+Hw@q6R??#^BW>7lR}-sc_4e?_+RgF-nSsq(w5OI_ZVI8zCF zWKbDI(-7|v#Pkn`H$J9*W z$6D^gAgtJz;~?1xVZ-#!Kn0ugr7rI2&E_!hSwjBUN!lJL_Qq0c<-Yy#p=fEWK>g`? zuY*%uwcxLMxL0pv*5a9^xjbXRyctw#Yl|8c#v6fBHbF`9OGba+51 z{bnuzw)XWvUUo>%Jz$vRfB&KK-t%=*jN}(-}mFFO>?_Lw(&D(P|U^*EKtzAg=b~o^bp85i?%X14p`GN0xY$XM+wxN zUg$fYUWna3%-hc>5ScEmmuNxp5HWPx^)0v`{cE#o5+cC!6#TT}Gee75&8loze{#Bi z(oRd7jxt9{AXIWjq!*|U_SSO}R+uw( zLA@sD=un2=BI$?Ft0B)oy@= z4AWzg!s)S<+t&tcE7%*K&H>s4=YC`?gj?>%LK~Z1v&It|h>Q-}37H_FJUs_~O_TTfx%tWfr1TkMrzwE0uTnZT08E=tVyIKbARogeUX&O>Vmm%MB z^x*ywpr!r2u4)zcnAl}c59(Nu?Y(`Hmit#Ex)@YToAN7(JLOkc5l=nDy5VFZdwN=K z{?CLBZ0uwF_c=bj)5=XRtC@o3#%&AAo0vnPRnOIn;5~P&;!Vp_bWeC-dg;5U%y18V zUV@9^?hYUUUK)w2&#K~ocX?#Bd#Q%nfW-a=$zekxAd#nK4UY`5D&^AB_`O%Iaq&-N zg`hp1ehF|fg&A*3!08eYOB|@!1m-@^i8|EZSeqOfR{PvCE6UY!vo>C~R9sH1%fDsRCRU4(*cznC zzSNw8B1pw2%+?F#*Ht*QdM?|Jz?>(h<(P^!PaC%#bY4w)bUihVQkwEW>eq!mkepn( zObkD>O*z1XAuUc%wDEGkoW%?wLiL$BQIdqA@JPw()#zt88$De9?3$*H<3%Q9#^n;Q zy+@H&Y>1`cF97E zuvsBxUV*kif0;F9gXAud$NKans4Ax;_DH(W6B^p*o@mNZd{Mf}v|k32Y;E&&Knykr z8oFLXgYQguH%YG{`4p)Hj&4_0sf@K=nysnLi%%flfRD@+g}3lDO-o5!lDh`ZbukFZ zqRaB=+TqVzrCYt~fUy88yvyH?(rD46NcpmD77b{~HkXuZ#U-WAm)(PiQN;p0={HjP z7~%)C)@mc#R1;t6?T7&7wIBs=tw?(#c$y4dN=|rI!IxLIq)Q$ofQ(O1{z!-!nnpy9 ziGl_pq&ra_HoQVdkl@B-fTP9=+>GB`3gG9`LdbtLqa7+MFKW|>Z5aY%W6r9VjnBDt z;E@OWkfZ~19@QS z5SItd={}7mwo8E8bXx(><6IoQ!zsp8?47mkFdBGvoQFX(;d7qN3s~K|NO*;D0$;^z{kXYAhNx& z(wK`bM)p_buX(At8s{Zg>6DK=LBu>ES%diD&5&D$8{nOd_{LnxTqJ*WzR^Yu;P<;= zK!QBNA>lyAz%TQIO8F4UHz_~nx`SjhWPiE-25<`L2vRHOjRHhHLue-)oGz}fOd)3$ zV*o=U@#*MafM^ZBTK9uKrwwNxHCH26grKQkvl)^lGAAEA05LE@;254-QI{`f0QUlA z^!C>H1HCwi9w`LVUu*MUItaF)Bp9|*B=fz@>3AJ#p}YF5wKUdSUi<-;`kyBst*U0q-J^bUp7Myiy|thh?Q(1+ z9z4zUemh+}%e!^KVs7*fqUG`Z{lX2y*V8Gck{y4-O}PetYE}OIGeP_NQ%s=lx35+U zGZc}F?*!m-V{?l)9k?HSl!uGVas4N!yldd>E>G8dkvHP&e=X{ z*;DZ}WSI-E0Tm-wRt&UwSQwAI-1;I9VlAUCiSFn#y65-=FOKltLn{j}mG@4BH*!l~jPf33!UO9FKFGwcAl{`e+jRdi0G^`>Uv&kG%b( z6_18T9UU!q4DT^eJ}K$(j?mU@$wA*^jt1y0%l*nvEKw=v-7f>^0Tt41G|LjlrtKV;%55h}sDpuXOQQM6S`-`Ct;cVrna2`=2 zzl>RZaZ60*eXpaz!$(yQ&#D-`TI1|zg{m`&*B}cC;`ziUkWQV6>q=X%!EGEX( zGhOzkUvYBt(fgki`?xj}oRqDZE;6;_QNEDO>!F?yMpon zv9G^3+o%@$X)*HdCht`gqG@`y;4mg$Z}aalysQ~(iQhWSHF`jr%Zp`CmZiDBxTEjv zvkJvH5GTWI{8^@Z0oeszd-{To{YrC;7P*x-g7+mTQz)EpvPQFh2?XRf!zIVi)xA2; zuUvCp{uzO>T5yikLHEIru8!A7HfQG@Z#*TGxg3_>q=f(cA(@@8zrnrA%Nl9A z?D*uRd#sQ7(`<|nf0xOeYHay9ivw+s?6tg47J0bUZei2gc$#3$J1Bp0j*Xt_!?_H( zw8P(dJ1xY?l!A*`mHb*b7wLo~pPdD6&^tSIaxK{M2d^Mj$SpLy3X%pt9}uoR5O#8o zUN=(qbuYH~>giV>a`t(?$`G2V_mw~3_mA7w#;p*w<{vk|dg0VF6s}q}7A2#pzBwkJ z|KtYKvMS%Y2!7`LdsQ{mLI*3@npYl#S37kkAKlH}!BZ7oDP{3|Rm|s7_&cYRiGRD5 z=M_{pQ;#V^$rpS-op0{R0X|$Q3nEcNoTv>|4liEFb_)mmVuh0}ul3thy^WQgQG=S%erqvcz;XRpVcwSKD399G-9Vj3z7gx4Jr zMbF@cmAv|6_y624xC$-}D*n0^v^6}geXhMIWK`xgy?+^0wLH(+6VxAy|HI%m$5wW= zjHV3PF5f9$%2-BTcB728>~7i3GL|x`GA0))j9`O2`!1ALI+*1X%U6~!vNV!3l2;@* zZwsAEyMf(K+yD(%hEVPCZSlVi{us26{}FE!|6Tjr>yOuOulB>X!#_KpX0Fv!mC=`R zxRAL#4DPo>uu4C*%67_pN_xH;^LFEUM+Ce+-x!b1Czb!!>`jej+!CZw+Jc%ev}$;Yo0zs! zg`46fX3SR6PxBMA0;+_jg@`#6RXQ?HiFry@t}>5^`8ie5GTg+%rK`9Py`88Z8>b zakx?ZvaDykKlG^IXKipF0Z#F^oqL8&AoTmJDDBIiB>Jli1^0)hTr;9EqBgo=M1dw_ z`nvUX<_emkp3Q{`184|rpm0-iQ<;A=AB9KA-dq`$c|!GXT1bgmHugi_G-?yS;r7H0 z=oarbZX#!N=U^duetKSJp=rKp!EfGg!P|OIQ)}#|8Hbr7h79u%a|`pa;bX(?2HnjS zwRzeEss#GAVE#}1A^e~DNn4^gq&V0yu|t&cH^=`z*=_-D=WY~kL2gR1zGaV&+auc| zkv~LP&KCCP_ZQ%9*W5b)>xNsc8?Bp`o3mS*o4MPpo4gysO?KY<_s(b1h70|F?Up_* zS#1hvgIt5Zl#tnPdpYQ>vxUBSzJ;O%hlL08|0|HToi8&KXeu9ttM+ZW1V+D_kyv6~ar)AID+N=6v&DKG{l8@~Q zGTuxZ_*F9H-76|VbCcF=ub(Y+;airfMu;w;Nb!}Hqb^v-)@lv^$|+0bah?KZb*9I; zwC3ooN^xso0OX+?G*e+@Gur$n2>cVU%Aax-U;OyaCRY}%S(eWV>Y8n-PLPs!jImn3gK49sP_356Uu?46$ z8v#}V71tH8KI1Xs3;$(;nPYcooontuv(g+l#@Gdb_$zqlX*cS9mA25K6hB{;yP6ls z|EZhUm}S2n^5Esl&|1n!N^ z$D09W;`IOvfd(hU0IdsMEu|zge?Och<<%TFHh|nUyu7xZNqL~@MdrB1OXZ{oETr3p z`cd@e&UKb2W#WO3SO@`D;i2_vAM4NU~n3V^1LLO1Rui zwP?Z<*00N*##w;9Z8y$>m)aGtohx2sE37gxbfbRUQ~|q!96`BLOvmqt)40wGc>PaDFX`*}TWW|A^m0jU$~qUnt0a*HzGk6zrWBy4PL+inS0o3>@T*HONzPGaAGJBIZ3 zf}e?IrD-F*lKIne>GQfK)GX(LEyKDz8{qr(+Q^OQ!q`bYw_tIv#-bj!hQ$8oFhR>A zFPT<5j;!^oFRcX3b8WTOze>X(-D9seNl(#lI7@~oyxSF$*z+D!8700mQU_^)wd=J- z`UkIWJWlg&@`}k8^*p^>5UZSGy8akZsE1Nply*a^owgz4wUOOFthOFECVbgYP)W;O z`-qWI%U6VHBN@Ke=S2F2<)}zs_Y#&sZtzG--0{j>=OQ@}kc$o)xnY#D%cjR6jgf^3 zzT15!F}qa|uFL=fIpyM0U&!a8bn@BXrCX&PU5$$TXYEjBi0L|~x!gOH(yNO+_A7Og z`wT`J7_JbIt-mT}IPHmc`i&iibmv;^05Z6K|0&RUuP>h85P*v}eYAmM-mxUAwhEK~ zbZeF_Pqi{FXdS)Tn&>QA_RX>XPyC{|jLZZ$rbn`-wkkNEGcAmeha}fyt zT_;J5bkz+U6cyLtaPxb~VaebQ<{*CKWt|9cpLJnu8a z&D$;neEi!V1hK~O)3@vw__zs`1={}=4T4ZAN**(xH#|NGGcfJ(0pi{TbdP8xfC?bI z(fsfB7ZW9%v>lHT#f@GYhwSAWOGWiHG(w2#{zujQ54fsl{C7@M?D;pXKZof=;@HvP z?;0r+a=pWYWt+X6J6BhG8`D{lFmatO$oCXK4^`REV2?7M&>H)}SYeoC*M8Uiz`~0` zi6e#l%`4|@tkNFeC7pO^WN)-{TY`H`+3Z~H>H6sx_hjB+a-r_^nI@bH5TZdKfbj*l z8*DJ*-V>FS_(ylIL+Ai_jBp6!QO4S)T`TK_XV{NCY;}En7rMsqd&LuD}!JrG7 zbTj73OcCGAg#d{%_#nb%}fyvmF$2T zx0CEngTYkz}5)-X_5 zF=MH5qw!pGk>B1T^@c@th59gxjo%Pc6v`x20;u$lV#MEMUnwpwGAsias9hrC!xMx` zjOA4JhF8E3kTRUy^{=WT>8D;FcUns`=J&^ai`{1nN6n~5&nRf2hWdZmexs;{DRngp z-fQ49O&#A^dZ6>+dSXf_(~amFVkK``O>( z-$do7Wg7saOQY;-GF>^zN4LxL;5|7zR4##9B`R_any5hG*Qsd%bNcSw>hkCZfl4Te zD_p~2;=wA4S@s!=r@y!4r`J9=-jth;hJ6?9igq8gY*fK7f0?6Y51{=RSg4Xhn|dg% z)l6>Oq*B6>dh%M!^d{z}-uNLvv-~0PSnu>cX0pwEG&mL8*dPEi$jZQRM zjMP+rnmNjHYKz&Do6c)9f5N`w_knjm;AX`oSj&_aL*UzFG7dj;;VeVe&{L$akJYSw z{z)aa^ZJ8VJq$rp0=d5Q?85~j`3N+BJr14mi6JGELz`;&2P}=*rczQweZF=Xd6ybBR?KN^k}uT(g$;2s)#LYFB3rS#6=uedqPp{yYrvF0U0s7dCn zfYw#0;hMBRa2%Vj-yVKOnAud}P)Lwizu5sWg?z3bIXV;3YEF^Z@YPO{w?xP|qrm{l zpSISm@eptt|Izqj(q@NMK`6mpQAmGC6eD?aVHgxG_|;;y#k`HfJ-U3ua#&!Kb2r{V z#(c5~M|mk~UmQggTu9GHbprB(u46mSt6?{12;>SBZ4_;{c4j`iuAQ4CAKia0W&ZGR zj>-Dm1EOsB*o>m5(@3SXL5gEO}A5&Q~o0F|6JQ< zP?JPeMkPTmY4e@*-^)ynW6lo@fA6+k|NHub_+QhSR;m_i0rHEV-p6fFikqKoGimUj z60U$g;T!77-GraJCQtTf-k+pNy@9zZa8=DiE83bj*b^&wpY;ZMMI7ak1WEh7|iW0%EE z@e7d+(>lLDqB!`KRO@<#te2DOyM^fmiFW5;2=%Vse-t5Zioq-)L@JEEFF<`^q8)K< z_amul%U=MHo-YueVH6j*7p5Q-X1C3FF^?K%=Kb9`Nu^!)Li!itRZPM>itW7eqXs%7$L>VPYZ!J6}i(J|0ZWK_4vmisjOGCG3B?^U<#9RlP_luBM@`cX9gs z!JFjp<(K#Sg{g}y45~e*_VfNgiHonr`3)WZ&>3U0#?e$VT!*KPR(~8>L7zUDRw(Rp zy$u-i^-@AyFi6i!`YycM<{At+^{`*QF7&RZ$2E^b0d9^eiuXUjPks> zm$h2#L9%W~1>)mBwig&)1;=&1Iv4#YU^X-yQ<*6>{)7=w1Z9W}Hri~oDtJ_*%bw0D z^ersG?ghIE=a*6H4R9}pi7kyATMUo?#HoV94jt9Q4l4>f;5LGlfzJ#rDVNj*1Uupr6BgA6 zZaRc9OC%(s4ZGrBJga0kR4)mQztbINs;7?`h|jdp<9kV;!uJ{d4-PlD667BLP_V<` ziclws3gX);8t;s$JobKK_>87-JUcYrVYFSnwnJW3YmZ*1AGSJi$XQw{KeF!VL_M}; zpIC=xdYkyz85L6LzUQ}cI~~l8m-Z7)}FQZ4yj$c)U3Ta z)LtzjwwggpYsRLEASwuc`F*~ByxjB7J?G_|d(XY+z4OjH2^4N`+Ei!{$aI=7iBtT} z!4BKwf}(=vKO2nZ=5!?e+Fh2F#Z7R9|!+4;%#q=-53b1}7Oq2*JJmAHCF*Dqc)b8WX|Y_$`u(&DqftJ4-{u5N4R%`Q$) zPmR!glxY@?5j8TmVtn~@?2i@)mREX8s_1r|whG(`MdS8Rqoo(3p*#KI94>;8_0STS zW_tBTP`#7?xvndYzlJH`aTPbCJtE( z)aAZj!~ zJ@jjd{rOx7I9ycsQ|z;qmhVD}97xaDFD(aF&mS4e24$>9S#OlX#Ze^Z~EjY(S zY2_K)h}P`6GR@Q}*Cb03U2?{?FMF95o34I#U8bfTx--Tp(SO#W@9fPop^B@Ioz^j$ zkv0*3nPoo&Y0oR({iAMG95=^$uPoUzW@eNjVL4oNe0dfN2_j`ty6e&?3(XI|FCsRkK6Nj~s1uk# zYC14bm~>cvVLb=<_-YQ%<>@u^e>j=uQ{3e{ z0DLkr==;Oa)DSwrQ)49o`D`riM>r}z%jMPnzLGMh2oM=eMpl|B{GLDa-YA9 z7(*KcJ9g=g|F!e_^EWelZV^$IG5~+o@pBF~>AR#EU@ISb^iN%hv{Km=A9y~Euu^M( zriQ@Irj}ryNw4rL?>vhI0X0(lS*C=BxpI_M--Du`SZROJuXIXweNz@)@avuWMmCbq zhh?|SMu07y{Z?Z9e6r62nM?lb8QljD%jfz9KYun@HSKH_7LEzds}-^PW??dOH^|O3 zDzICZd@p)EKRsVFmCXOgJ4)q2!5?gWEE*h?9=Q9kUx2kl4{A`r6h%1?6HioV3A>oV zd|4nz?Kf#A^KD8|x}=9KI9i!vE8i>fpAi?7(14*eBf}lqt8P)|$HmvAO_KEh3QjhP zKlzkaFX1GzWDE;;KNIuX$NC`RPrpAOe=k5jytvxBFeUW>6_9ek(Dk8;6y+AEtvS|+ zS}+gM^+Q=37LG@T9wQ2fC_w*?%)mN$BBx1H{nU;9jH}%0%rjFWT?p{MU8soC%m%=|LD=TT2svjEh$X>i` zfXP@*W}jySlHX}=cai3Q1D(REK2)WA;`e7NDP0_8)%R3G|I0vkeMEHYC&A_nEh-x1 z>10Y7$En}zaxQLQDCa%&T_&OGVTw8Ce$6B~pM<5F&r+vl%1oV3j$Kn}B`WDkDJmm; z<&$(;w9HS-Ex>!*4G&%qGVtAwo~|5B{QmgMw`WBy?wz7KPlws+Uk>y+=zW9TKSchr z3ng3oO~uaNU#0_XO1N1=ooro}gKapOTqs*cl^di!nK#r|AwE?hIQ9dS3`@oyC($vC zXR+n6W;|qOrv8zT#i`!Ht1u{<5SX`g8zXn=6yFDnRB~{caG!tlGyZf)Sy`zO<~bD_ z$mCZmYQD0_kvhgG!A2<+*gBc!qaPgTFNpl>Z6D^xs+9YC{7Z^PGR%2zX#cJ^vFR>* z5BXX^u~jjDf|+TgixF*;PASFgUfN^aEeQ{bTMI^Pa!0*ZD{%+qs%#o+p=C_0P_F*F z`ScUdAlwmrt1*z=y7l)@6wJbZ1~PWF4So^EUg8jobgr*Mr4hh@X3*5n^LZdFZ`SmA z4BSu~A-0-LO9;TEazBoE9d+hMBV5w`DL-|@b4J?O(^JROGtkMx$4TC#eUa*xub&FO zcsGx}C{@i^$09KBMWAdKHfMd%-KLgbNvVz6r0HmMd_wj^u(#4o>!wlCliAED6HlKP z@=8jX%_CAHQcWXGBm5y-29py#OAcw!r<_lJ|29a^d#S3wakrd}M>3duceh9(^wZdy zun+r%IC5N{O=t&wB>-vVK^Mf6saooy-0oot2EY?$7{ zeGX##bleQl z9uIAtcW^@8HArq1fAD#(@mftTI;(2iaoM7%@4i2z0dC`0k#0EWW$^_jtFA^w?k3pV{wJ zv9KUxD4#ctBF$(aGoY?Uv^kN3@p-}i_tA+?Ig3YJoC5O#N)PKY+>NV>B=@Y!t&UM_ znW)-K<*zQc9A41~-S_fKyN(pK2og0{Q4&+)3*D?XaoE`PP3iD0XDH@R}SKSnYO!9;70DJ&Ml5ZMI6mp*9N;-sf8H%#)i?PCg1b48lukh z)t+txV;?7<-~IjPk zQpfg(EXd6VTE&nGF18d3CRG9IH5aNN+1{J%I3MXZO3+n5V|p0NP>5^2AoV7Wt|&<# z`j*sB`rB8E)tk&XKk57e;)#{_gQ!=mYIDhG~4!YIt3Jvy@UB>D3mn^eWA5s|; zgA5sAEOSe6OrWcaE_X+$A=_PbwUqBJ+IrDSEXz|asXF@X(?n^5))hB2t_iy3N^#H} z(h%uTdmQ()c$$s})nN{4sI;Pe@FSK#M;vjHT-5(u7XQ)2xYq0Tsjzf;{ES)UIMG~J zVA1l(iVK%kT=+y6%+5l+&#^(_LpsW6OP3R1KLfrqF32 z*NW87{9;$3Cm41^HjWZjqU_LS6WSsXYCzg|4D~c;`k>#2i3l~&ReK0y?#iiWuNXI{ zucfhsOP3U)CUxb((Hk;RNgh@wf`)SU*Vyq3z>vU+a~Bm zYqM}kT5?m<|E{8{%OrgxEr~DZqq^hzL2q4S>riXjCL>@FBQ@=v;n9yra8fgIH>x58 zsG0SnS92;gxE-@L&r_t`9SYM|)GFcj2&x%mhR1;H>Xoy8v~DX`pH$^4cQGJN>>X)( zR%!R$@Gj|?4VgHv4AP9Q#%q&@eR|o6tD&x(`plQ{eAGN96x`n2s^l;BysU6sDHSbB>eK2O2K-Valf;5eV>E(!VxT zLeDE#`BJ2ruir|eD<1Rptz^f&m!5FIIZu~lhB)EQrt33ZnXWseF$DQt(fV4((+)U) zSByTP3>GJ~T3*~Lu`AI7d*ise?6?wwfW)q}BhFE)j?>~SV_0Yz+p=! zx5AygT6;nk-5$$fduOQc$#1VO|H#(cL(|05%Qg5@HiAv>QEy_SAH&l^VtUxXdX-a) zAeCP4)N{hB(N*b_X()gDSoig#2_*>%~`kNzeW7W0@LtXpZj1Xb>BKk(wPwUHCl zV)`wiLcL$*NM_$LDizbS^q0!ke+YQs8f=omm3%lHPZ}KLK*p_X9Vgzukj|BSbTCd! z8p0|S^LQD^+$(m&3lY-tz>DaWqUT6Ue zv?xL+9EX=$@5?FZ^)p<3@U(sQ4y@n|$hl7883j;Dc|+ z8#IKR@up{3WZ-}$Clro=fD0Y7YAHwaYlKhHl~bGUP6W;N?Sg`rkgsL@0;wISR zjk~dJYC+Jc*Xrd#NZjGi4~O1A(%zq#PtEu_PR&KPY-(tFY!-Qhz>q`b9-CQ z^xMv|8BeDd4PGq%y>c{U)4QTJWK+E|G<3(RmLzIbc2_0>E4sfV8ZIkbZ}gx*E`P!J zT0Ys}n<74{#cuH53P2~HY|wVFKNthDbRfc)^2r7|FE?_!sS$@t4U_@?kfi3|7Qv6> z;B~L;w9blsEyW5+kO*Ghr9M?0K0)0k8A?b?y0f91FMHuNCl1ty{M$8?ZK73zQ_JsE(X+G~~u4S$(P+ zjb@2@XsU*EtU27ZlNi(B3{qny_T_Fdt4=!G@<6sdDk^!jtbcwh@Z=n%+Plq$6CDw} zXyF$;L!KR<0}*M*)ZuEylvpU?)_@c*P%MTX!m$ylO>EPKrcp|EA!SE)&DOdQiT0d- zm^mRt|9q&l6hN&Q1r0U-I=(>;_HZNT1UwXgc!w>~T`}tNZ$-}qwFa+n5UU!h5G`F& zow9jDitW+-xJ9C3`>)HK%aM3>(Z&_xjmsca>~W4+tzXQtyS(ns`1m&26)GSVMQJfX z7g~DBRtgS$&y7VQ6*R#v=bGTL5y)huDlJGzXXJR?xYOnjO}4D|6t>Dq#E%R zQte2ADD}}qROG*e<&zs6Tj}Jv(B^fxPp+;E#yaca#Gbdr^ts*RnS+zqi4~ym_FB~m zVTs>r&jm%=VCrMyVMIb9J0OfxYN_*^qd_Yh8HiLV6i>Q&N&ML8kfiK=EF{5Khme;2 zm*hHYvr|1w>M&&umC=WE7KD1;*;mHvOid{47#BNtSPRU5CB-q1s9{L{Tv6VSR3rqX zbiq~v7gObs2MU-su;y8z4Vz*UY>vWCu@~Bp%u-#2qBHUImT>uUhhFFCU!v^M0hgp- z6OhDhnH#$w;DuegqeWRj&ha_Pizi;z!bR)c$byfPqI8pfc+MV~$&{95$v4Q9F{-U{@YUeQ`V;|Ryps@$g(QS7KISa?tVL3$dLjln zW$v_0R=W^`tfw-YB>3pgFxYiA98yRu4|hCC78|L(vz`j*WYe4drBbP50wxd{-%*kc~>sMrw2uC$M)#?y+Od`g8}&xjE)4&FIYJf zXhW2CJ!+h?Umm?fEJ5?3Lq8cvv&b_DsC2YrtM4#K20Dq}S&#aH^uxUuzH=1``?_;8 zI&%MJ<(cTkO_A@^&Dp!8>l^Q{JBNOZiPwnWjGaR_2mx@*_|2(UWN4$fFLo(tJ9)^vPh`8@P&s*qWrUu zHiu{oA?$K`Top*S`SN>Td451aSA5q*Y4`VrYE$(55S1UEs zHl9(aJh2qS>UmV6xL>~0O#A!kPN+lulbwvI2c^25qcI#GZ`InI!-YN`!exX(-qb@f z$d(!qnmwzaKxW@48yXB*xN>U11ul%Qy|e?@XPg1AYT_-VJ%D?wj6NTpor?Hoh+@VG z94Z8KKiec(eeCI@Sf5*a046&Xq6ITBQhcxUf$)I})n6Nx#ZRth4IELd1gz04(3^e_ z5UjQbz%kDDeOW6U>aY~1skIcP>39W16#5c{rxOm)D0op*!L-yB{Fo-{&_Sh!*6&Fn za>xvd+_bw7zc8%7uQi{#@%qScb>oQ^`=~ps>D6S3 zw3dK;@qaYwUU#34{6uSLV^-}rY4m7mG(1~`f&nhMmuhQI+OM#9i;wpDH9U3U5ODoq76GR$aBf+F0d?D@KCJ!00shfUb)g0Q!7U)dlin=P;Fogb zedJpw3D~|X7sys+cYcHx0sWa_G2ij&QCCwGNwht0 z(I5Mw8&yog0XT5HTC2SDOYXKF%kv_E!H>?84B1DP?{1;@qO6^+0M>R0_*IQH+C;Fp zpfraWj8_C3EDF;+U|SO2`s22IPd45K2rD=b{+#Q!K!X?EJM%ydje#(i$&m%}4nBtq z{hf9Hhz6$!D9$|~j-F$hEd1T1Ag0=VQgp}mc<(ky+VkM{3h6&UWDgEB#fTpS;CW{N zk@poyuH(+b9*td{5=ZKWM1ZgodvrL^ATaF-%?cMnW<&Xw%2*&URh%6oM%aU_1>2C_ zO;+&oEH|{;@J%7AJ2|rY7n?mlMt&U{$KllBpX9|@sScLw*b<)@-I9qqT%@0u93;C*bg`Ik*LUxw-@dFMy{#wTd#Xw^FTfJp>#8VNv@S z+Xl0T6T1Bx)v?Ix_TQA=piy$X07d{~pEblz$awKY8=;9XuG!n=s4!tL#teO(_D1Vz z7c{c~Nu)-uOctKHiEq!1ULg%HItRh>_o){90!d+UrycYc=>;Q1YNMgQ1!?TqiD9X} zIB6``9u!Bi1;O!7lfYvAiy7lvQ;E7q!j*w4L&v~w4TVs~(A4u=u$*IZJjW;ro^F!^ zM}PdAmnK4Fkyo}(5Xe!cOcdF38FiC(N~~<4Ky>|Pp9U|p2gb2h-Q2=5fOAN$i}v*` zm~EgK<1q+kGK*l1xn5{%f~V?kDpE_7-P%$>M%FJD-vOas0B`z^iLLEn#nGy3Tk=RM z8)om@^~Av}sGIll&8_tE?+Vt5ssTYn)xb-5H4scZd5cDcpQc@8nOdcP+%IaI=#2OT z4n&^7K~WHIsiJKO#JZC*k`n$LnFLosK8y;BYKppq=N!S%o5*scP~M?&&ylJPT|GcP z{+!f`dhtrIK>?+K4u>V3XW?Ev#k=k>*sx+qr%9G?jV(nha=x@t*aNmFp8`5bm~JhP zTo8%!N1!RTK*6kXycbl1j>vD530@i&@XzOuPe^v?Y;Ku?7HK+@Hi5GBu&BML_$U~R zo|v>fWXf6M!0v05;bPWKlikyD4YUffrfZn~q{$@QPmzME$x01mg(ODnWN-V~(O0mb zE%d`PCDbY0*MVDs*(H(FlxQe?8I!q6Y zP-;NVphpJx4;w-sf)0VT`pN9zCi{8 zIY~6U3risuD0bEBPV*-xG8!2%t#gVYZ!dutY zkOBvGQYYfi|JEht+K36RopcOv05ICxdVv&NWTTX4FvUpDvzd~=C#52;2A&Zc6DHOS z+32NSN8}bIMMxB){Cdua8Z~T*f&jq8VpSPPxl&y{sC?2HK#atb6hTfX7SHTWYf3c6 z9t8tTu+kQUw*czawycqNtAG=vsl-X}ftA+?Th%DPugpxCS2inc{cVeM=y03sHVFja z1+Z>&%NBWicBpND&rS=u2M<|+s}g4uJ^T(0<~|2P($z40$Dr(t8$hS^TebT4czDt< z)KuddIk0i_GC6t}+Mb1nze8RjEpRE!ruRcvqG8-BXkSlrQp+Cy75bG5KLl81$RGJ` z5ku4dW;aU4Jrez@inafef0L*^Za1oB4B{;^12`m_2)#dZ;Gk&3esc5Xm-ZKMu-qol zbkbifii)@(O0^1DYp(=k&7;|=4#(4mX6{Dq!LN``XmQLqvNsx4kQE)hwh$^-AG=HQ z#&Dq#7IS7=1#E4&hM!5Y*BAOyQb{ePJ?0w`s*m1{I(uvdXU#hpveQyOG%g9sqX|}% ziv=QLccTh^ry|=Vm(qU;Pk_UtcB5Xpd!ZNdXmFhM*ylU;RX|T$1RUHH5p`&%08e|8 z8cD(8&X2Yi7Q-wdNzv=!9E7zFK-1R@6~8h3;|nA0GE_yL9Vy&G6z^01-Si{F6Ya6$ zG-hYGk}2T<$o(-nj38PS9WQ8tOe1o>W>ZYvry_(G)Cl2)PGU791rk-Q(C(-r=Sx74 zPm>CoUqB3L{C46d8c`ii9Mr^y+%_{t8aFJ)OQ?$+q;*~ZG*NfC6_SO($gPN?w`#VadiYPMZ~ z$Pq(eq>#J16Lt9t(F;AQ2a9|@M8Ubf(!#RL?~jz=mA4CcJVDo_!5cx%LptA9%AuvI zS*H9xN&Twm$0O{R$a71)hD~X|d7=e;DAy}d>vmHrg)j-n_6a2(ybud*ap^eL#X^y0 zH%ZsTzcAf)QvIGbqTXPPf2|{q-k)EbOc@wV6wEi1QqoQ22}HmP1c@iPUfQU7ZxtV@ zQn_C?{knxC!-U(MTGQ$xZsM;=+L?DYSrTsO-GpcW&QpP;!Ghj{5?FrA6QWKkQ$Q!% z4#*1d_ZA~z({~1TMKZ`LIwBR29BAb&)?n)Te_lKM1ZQ$em_i*iZGAHSnx+dZO!7iJ zG7?h2IFsuvI7(gPa7B~@NK2!zD9O8tf)R54a{N+;)%wlTzeQ>mOHo-GUf;aFCS_!c zFFplWQZ9yA)-dE9dF?o(MQwn4n=5vi8*gvaZzQde)WX|tF7(;-zldvymq!DMTY()> zXMi>$r6yOettr_iWn|l1QH+N>C`~sk>im`}!5gaf%7`F!n-oABQ$;oiNtOA`-{JB9 zTn@P-(3fVSHe&T)9AK6o6OFXxl=G_{K6W7(5;CpP5?M&_lTuk}H+5f5z|)`Zt>Y9B zNCcktg(=DT*WuSfCBog2_db^p+llIrB!3vy(|j`^AnlZ_KrfSp7XQwZ;+UITAz!-B z!!$pk9ruml9>eAfq1&GJ%q)r(RM;!kZRPEVi7#rob+CWR+lyfnU(XPS5yjA#U14Rc zhYHIozf;1NJE}{EO4PQF0!}<3lied7+w!XZazn8P@Pp{-xmW7HJ0QUb)Qf)$OC8qU zSEZNjFqO_r-W!^T#LJrMpgQm6(2%oxX{_^uA@VaFKucXh;ukog@RIUEM~-jd^me8n z(M1>sKNgJov%K8({UoMUt4;HUY6+||b{>TokD$I{ZC)JeFdDp2&)fJ$cOiP_*b;Q; z_a3oah(;W4FGckPFmBDGT8yvmF}5cnP0X2Z6D*kqq{6 zovg^C(qw%_8g{ZmrQr?@Q~;_6)eznFc@u|PeU9Zn^1S1(f(_qc+#z9uJb->>MUSGQxvs4nEU0VtE2D)a7FA7^_SUhTkh!irRFcP&3IEer>uKqa7(f)HiMYG{0` zdK-%4g7zkot=7#2gtc|~+LM%KM~@97&~yI{>I_RGHi!+G40WXm1q2Q>W~s}PUVao zOFIX;FqxplieDBa?sdMoW?W|9Tq!MN^J1*^auLB6TdM7Z{e@hJ9Z>Fou+)x!A#`a#s3pPraeV#Z~kM_RdNBQQ7RS% zqR5kNV~i@;{h#E)*xS`mG>Vl5-86?)(=>`-{sU%c6r;C&NDf$=qbJrv)XkpR0I|1= zK>o7(B`L~jLR}qMfvC}74wOQ3^fV+$4(mIwQHKs0J2`kTud#ikTyo+HdWk%VvbwLd zqge#PzM3CDJ9w%L-jQjJmL+s2xqz;uCxM|N`z6V{e_M#oL|kOBIxdu0zFKa7g=XN0 z9r@;G@8Y#kO%rv9mPupejz@F!@$s`h zyBU#-zQMIACX>H|VkSV$;dar&Dx-c6TzT)|8 zxcgvGd*Nsb6#3xq`tdK&73OlPE=koi`Ezo_GMnXN-q%qPVwAO|2aJQugD19n1E0{o zf{420wsxr)(uBH$NB9oNP25-X$%wtZ@E=TWda*u!w?m2eh9e>IEUzT8f)df847xZd zI($9psbb%5nQ&M+iFSd6lZ2$E4gDg%xFxxKwu`>tLqx9IQE6%=YcN6W!F>Hp(TNhR zQ6$7WqeD1!&YI;^wbv&~iCZ%-F`M?n%n@f!-_RX$LW6?hp1BP~!aC~3DlfiW*bA$x zTf+wVra*_1knn@8cC^J%@EUk6Km3kmZGZgr14#I0yAC#^;PAEAA~7U<)pR%(;c2OK z(fV@#wHWJX%Bi4z7D)Kdd`pa>#l~wdmLwh&Xx|(XK4C@%S9LD-=^09v@W%>vER#SR zc|~#leqJc&WC>d=T}KZ|aebvIE^109M%7x5FdhRc+EB3rt_y!3@Kk)#5eoZz&B}a3 zi;66wWyjdiT7=Q7B#klY5GCj4n0&ayaK^VFmDm;TV_!lZ?NVUB8UN^_M?E_>{b_5u z47Wp}u!Aibd0cDyPuADfuo$Z64&O-?7-Bn{O(!+BdNdhLXonaU_=WBc*KIR4TE+^Q2RgnE#Hd zl+3elv|`4TX8$x>OJ$r*({a4!!@bP6$I4K~ls|?0*T*%pQ)%TWVw0+3FBsOEp68uA z2|9886c%2NRW+8uj2CZKRXa7a_fTJJ-3tic>7f-i8c zA>qv;6T_@%?K8{ooTGKaAI*o&g?*uI>9GPEj_+b?U|gGG!Vb*|os4bir98(6KQsrc z_3Pip)|7DZN((!LP@nH2HD`aMm$5K5mc(`Pw4|>F91o6Z>U8R3)>;;^7`B5R zM<>PB{N?i66mbZ-{n6Nt%dIq_J3dx8=B^P9qa=|o?0Z`}@1qUp07^6C`{Clk4h;-G zL=EW-FZ$hjG@UroFYYlmR=v6Nydk|oY|;-{LwbN!|5>jlN6(O*a?=kTANz7h`OdN3vLB#z%Ql|s1tf@(<-7slv*AJW3{-D?A8^l@JZTaqM zuGt3y$d}c|#s9+Fo<5uov6PtuY&Tbzw7=*>tS~t1zI=KI_ ziml{6?)uO?$;0+(R^}oAFwz5Ueq?+?15~&mr|E~>@wn1Lu^SrSrXgA6uocnSMb7m| z#pP(}S;w=D+RhmbpHb~`8-|&0YQZ6*6 zqoyjLjdd(tX{KVM!5IH!Jrc z;H3MISnc)-qO{`PA4^p2SKB=^dVG1_%r^E0VSEdh&)%QUlfCTTw8b*;X_)U<$X{%W z)Fh4eTvqq~z5aOqqmlnL-}8r%xjvPh^FK?iqOsZeo++60R%M*mqNy4cXvGM32R&#H zIQE&RJ=2xAcFI0&fxiCvX`0Gk)r6afi;W+|#cE$RE{PuSX~J z=zH~9X!E7)^>oK5wjZ3Xy7rvK=id|ch--xZ^cvdS@hGMFF{yseDZ)BdQSeYMTY|L8 zQ0ce2m1Lu4p^%jQr_Q_Ih_iIh?;+VGs5zjUu0pRoJKcr&Or816 zZ1ca>#E>cH^zUA(J2&+mZFXc2(rh2^gRR~eag+tz%>D%G_8-ek3>JAN|gPtKGP zuV(vej47WMgNlciR-I#23y2_xBG`|4kS0|T0}&a1``PJU|7s7_nU1Bdh)tso#{D^e zuz1Ie=*Qlc~HJLpTIJDRZmD`oiJO_~;Gv|;tiU<{p+WniLdPOnm&wljtM=2lP;*MyZ z|K)!FdV}9%Q<|^OC${%uL~v2ZdaF8JSPf+yx20|{#QY$f>ZT9+^#M?^qOyk0{7dAb za_E7CnZ}GsDK+Dta_3C=@7NN3?UQjEn^zxq?>A-NKwhm)jafFOZJqG~pFSLanBUUu zUFTUJlG&vs$!l5Q5fkpXtf;8&dH<`8we#u**$m0(9EO$3;L`6M+%-~`Ik&ZJ>*087 znP$j&)kDkpB)3C)Td9iJ8SJOuy}T|EBiq?+qneFR&^Xl@`!mm|KWpmwZ8EF^8cOM! zG+7+<4+GZ=&Wn2O*N8YC?T1mMksFc~h`cA5$);M*%;!p!Gl=7nt~o`-t0%wzn|(tu zqE6EtKQ)d=AZual$3$1c>}O?X8jj36T|VgP{qZF8x08rSjU}1HxCe}jDcAfJ@nTJ7 ztcRi3W?I4NY0)9NVvq$i4U5}5M zu;h+0IBlH`JnP9jX8~q@?Hvnu9TR?^C&&C>hmifZXvXjl9r?!E5h7!+xomA(L4z=P^b!mC;q)vKB`TSz@ z&Jno@3Q{W`Hj*Z}d19#{1yUy=|Lf?@-BOV9k`~Vs8XHUNuR-OVbNwd?{vcOdQOer! zKMvz0g=(pjhW~L86jPL1vH9Pn(wM)T6hy(_6{yGLo!90PDM_t({?`*Jw>3I3Cdc}p zCaiX$`(xpS|7o&(yUE9SOX>eLIq{&+4BB28M2@s3imxwy!VCU44(#-4&RZ}4<5q#5WNn8nBS(tT#JlGPnzzooCXgdtqP=6C gvQ8S4V{ZRXMG#xUHPp$ +#include +#include + +#pragma semicolon 1 + +#define PLUGIN_VERSION "1.1.4" + +public Plugin:myinfo = +{ + name = "Hook Grab Rope", + author = "Sheepdude, SumGuy14", + description = "Allows admins (or all players) to hook on to walls, grab other players, or swing on a rope", + version = PLUGIN_VERSION, + url = "http://www.clan-psycho.com" +}; + +// General handles +new Handle:h_cvarAnnounce; +new Handle:h_cvarSoundAmplify; +new Handle:h_cvarOverrideMode; +new Handle:h_cvarRopeOldMode; +new Handle:h_cvarUpButton; +new Handle:h_cvarDownButton; + +// Hook handles +new Handle:h_cvarHookEnable; +new Handle:h_cvarHookAdminOnly; +new Handle:h_cvarHookFreeze; +new Handle:h_cvarHookSlide; +new Handle:h_cvarHookSpeed; +new Handle:h_cvarHookInitWidth; +new Handle:h_cvarHookEndWidth; +new Handle:h_cvarHookAmplitude; +new Handle:h_cvarHookBeamColor; +new Handle:h_cvarHookRed; +new Handle:h_cvarHookGreen; +new Handle:h_cvarHookBlue; +new Handle:h_cvarHookAlpha; +new Handle:h_cvarHookSound; + +// Grab handles +new Handle:h_cvarGrabEnable; +new Handle:h_cvarGrabAdminOnly; +new Handle:h_cvarGrabFreeze; +new Handle:h_cvarGrabSlide; +new Handle:h_cvarGrabSpeed; +new Handle:h_cvarGrabInitWidth; +new Handle:h_cvarGrabEndWidth; +new Handle:h_cvarGrabAmplitude; +new Handle:h_cvarGrabBeamColor; +new Handle:h_cvarGrabRed; +new Handle:h_cvarGrabGreen; +new Handle:h_cvarGrabBlue; +new Handle:h_cvarGrabAlpha; +new Handle:h_cvarGrabSound; + +// Rope handles +new Handle:h_cvarRopeEnable; +new Handle:h_cvarRopeAdminOnly; +new Handle:h_cvarRopeFreeze; +new Handle:h_cvarRopeSlide; +new Handle:h_cvarRopeSpeed; +new Handle:h_cvarRopeInitWidth; +new Handle:h_cvarRopeEndWidth; +new Handle:h_cvarRopeAmplitude; +new Handle:h_cvarRopeBeamColor; +new Handle:h_cvarRopeRed; +new Handle:h_cvarRopeGreen; +new Handle:h_cvarRopeBlue; +new Handle:h_cvarRopeAlpha; +new Handle:h_cvarRopeSound; + +// Forward handles +new Handle:FwdClientHook; +new Handle:FwdClientGrabSearch; +new Handle:FwdClientGrab; +new Handle:FwdClientRope; + +// HGR variables +new g_cvarSoundAmplify; +new bool:g_cvarAnnounce; +new bool:g_cvarOverrideMode; +new bool:g_cvarRopeOldMode; +new bool:g_cvarFreeze[3]; +new bool:g_cvarSlide[3]; +new bool:g_cvarEnable[3]; +new bool:g_cvarAdminOnly[3]; +new Float:g_cvarSpeed[3]; +new Float:g_cvarInitWidth[3]; +new Float:g_cvarEndWidth[3]; +new Float:g_cvarAmplitude[3]; +new g_cvarBeamColor[3]; +new g_cvarBeamRed[3]; +new g_cvarBeamGreen[3]; +new g_cvarBeamBlue[3]; +new g_cvarBeamAlpha[3]; +new String:g_cvarSound[3][64]; + +// Client status arrays +new bool:g_Status[MAXPLAYERS+1][3]; // Is client using hook, grab, or rope +new bool:g_AllowedClients[MAXPLAYERS+1][3]; // Does client have hook, grab, or rope access +new bool:g_Grabbed[MAXPLAYERS+1]; // Is client being grabbed +new bool:g_Backward[MAXPLAYERS+1]; // Is client hooking backward or forward +new bool:g_Attracting[MAXPLAYERS+1][2]; // Is client pushing or pulling grab target +new bool:g_Climbing[MAXPLAYERS+1][2]; // Is client ascending or descending rope +new bool:g_TRIgnore[MAXPLAYERS+1]; // Used to ignore traceray collisions with originating player +new Float:g_Gravity[MAXPLAYERS+1]; // Used to reset client gravity to previous value +new Float:g_MaxSpeed[MAXPLAYERS+1]; // Used to reset grab target speed after being slowed + +// HGR Arrays +new g_Targetindex[MAXPLAYERS+1][4]; +new Float:g_Location[MAXPLAYERS+1][4][3]; +new Float:g_Distance[MAXPLAYERS+1][4]; + +// Button bitstrings +new g_cvarUpButton; +new g_cvarDownButton; + +// Freezetime variables +new bool:g_HookedFreeze; +new bool:g_HookedRoundStart; +new bool:g_Frozen[3]; + +// Offset variables +new OriginOffset; +new GetVelocityOffset_x; +new GetVelocityOffset_y; +new GetVelocityOffset_z; + +// Precache variables +new precache_laser; + +enum HGRAction +{ + Hook = 0, /** User is using hook */ + Grab = 1, /** User is using grab */ + Rope = 2, /** User is using rope */ +}; + +enum HGRAccess +{ + Give = 0, /** Gives access to user */ + Take = 1, /** Takes access from user */ +}; + +public OnPluginStart() +{ + // Load Translation Files + LoadTranslations("common.phrases"); + LoadTranslations("hookgrabrope.phrases"); + + PrintToServer("----------------| [HGR] %t |---------------", "Loading"); + + // Create global forwards + FwdClientHook = CreateGlobalForward("HGR_OnClientHook", ET_Hook, Param_Cell); + FwdClientGrabSearch = CreateGlobalForward("HGR_OnClientGrabSearch", ET_Hook, Param_Cell); + FwdClientGrab = CreateGlobalForward("HGR_OnClientGrab", ET_Hook, Param_Cell); + FwdClientRope = CreateGlobalForward("HGR_OnClientRope", ET_Hook, Param_Cell); + + // Hook events + HookEventEx("player_spawn", PlayerSpawnEvent); + g_HookedFreeze = HookEventEx("round_freeze_end", RoundFreezeEndEvent); + g_HookedRoundStart = HookEventEx("round_start", RoundStartEvent); + + // Register client commands + RegConsoleCmd("+hook", HookCmd); + RegConsoleCmd("-hook", UnHookCmd); + RegConsoleCmd("hook_toggle", HookToggle); + + RegConsoleCmd("+grab", GrabCmd); + RegConsoleCmd("-grab", DropCmd); + RegConsoleCmd("grab_toggle", GrabToggle); + + RegConsoleCmd("+rope", RopeCmd); + RegConsoleCmd("-rope", DetachCmd); + RegConsoleCmd("rope_toggle", RopeToggle); + + RegConsoleCmd("+push", PushCmd); + RegConsoleCmd("-push", UnPushCmd); + RegConsoleCmd("push_toggle", HookToggle); + + // Register admin cmds + RegAdminCmd("sm_hgr_givehook", GiveHook, ADMFLAG_GENERIC); + RegAdminCmd("sm_hgr_takehook", TakeHook, ADMFLAG_GENERIC); + + RegAdminCmd("sm_hgr_givegrab", GiveGrab, ADMFLAG_GENERIC); + RegAdminCmd("sm_hgr_takegrab", TakeGrab, ADMFLAG_GENERIC); + + RegAdminCmd("sm_hgr_giverope", GiveRope, ADMFLAG_GENERIC); + RegAdminCmd("sm_hgr_takerope", TakeRope, ADMFLAG_GENERIC); + + // Find offsets + OriginOffset = FindSendPropOffs("CBaseEntity", "m_vecOrigin"); + if(OriginOffset == -1) + SetFailState("[HGR] Error: Failed to find the origin offset, aborting"); + + GetVelocityOffset_x = FindSendPropOffs("CBasePlayer", "m_vecVelocity[0]"); + if(GetVelocityOffset_x == -1) + SetFailState("[HGR] Error: Failed to find the velocity_x offset, aborting"); + + GetVelocityOffset_y = FindSendPropOffs("CBasePlayer", "m_vecVelocity[1]"); + if(GetVelocityOffset_y == -1) + SetFailState("[HGR] Error: Failed to find the velocity_y offset, aborting"); + + GetVelocityOffset_z = FindSendPropOffs("CBasePlayer", "m_vecVelocity[2]"); + if(GetVelocityOffset_z == -1) + SetFailState("[HGR] Error: Failed to find the velocity_z offset, aborting"); + + // Public convar + CreateConVar("sm_hgr_version", PLUGIN_VERSION, "[HGR] Plugin version", FCVAR_DONTRECORD|FCVAR_NOTIFY|FCVAR_PLUGIN|FCVAR_REPLICATED|FCVAR_SPONLY); + + // General convars + h_cvarAnnounce = CreateConVar("sm_hgr_announce", "1", "Enable plugin announcements, 1 - enable, 0 - disable", 0, true, 0.0, true, 1.0); + h_cvarSoundAmplify = CreateConVar("sm_hgr_sound_amplify", "3", "Control the sound effect volume, 0 - No Sound, 1 - Quiet, 5 - Loud", 0, true, 0.0, true, 5.0); + h_cvarOverrideMode = CreateConVar("sm_hgr_overridemode", "0", "If enabled, only players who have manually been given access can use plugin", 0, true, 0.0, true, 1.0); + h_cvarRopeOldMode = CreateConVar("sm_hgr_rope_oldmode", "0", "Use the old rope type, 1 - Use old type, 0 - Don't use old type", 0, true, 0.0, true, 1.0); + h_cvarUpButton = CreateConVar("sm_hgr_upbutton", "IN_JUMP", "Button to use for ascending rope, hooking forward, and pushing grab target"); + h_cvarDownButton = CreateConVar("sm_hgr_downbutton", "IN_DUCK", "Button to use for descending rope, hooking backward, and pulling grab target"); + + // Hook convars + h_cvarHookEnable = CreateConVar("sm_hgr_hook_enable", "1", "This will enable the hook feature of this plugin", FCVAR_NOTIFY, true, 0.0, true, 1.0); + h_cvarHookAdminOnly = CreateConVar("sm_hgr_hook_adminonly", "1", "If 1, only admins can use hook", 0, true, 0.0, true, 1.0); + h_cvarHookFreeze = CreateConVar("sm_hgr_hook_freeze_enable", "0", "Allow players to hook during freezetime, 1 - Allow, 0 - Disallow", 0, true, 0.0, true, 1.0); + h_cvarHookSlide = CreateConVar("sm_hgr_hook_slide_enable", "1", "Allow players to reverse the direction of the hook, 1 - Allow, 0 - Disallow", 0, true, 0.0, true, 1.0); + h_cvarHookSpeed = CreateConVar("sm_hgr_hook_speed", "5.0", "The speed of the player using hook", 0, true, 0.0, true, 100.0); + h_cvarHookInitWidth = CreateConVar("sm_hgr_hook_initwidth", "5.0", "The initial width of the hook beam", 0, true, 0.0, true, 100.0); + h_cvarHookEndWidth = CreateConVar("sm_hgr_hook_endwidth", "5.0", "The end width of the hook beam", 0, true, 0.0, true, 100.0); + h_cvarHookAmplitude = CreateConVar("sm_hgr_hook_amplitude", "0.0", "The amplitude of the hook beam", 0, true, 0.0, true, 100.0); + h_cvarHookBeamColor = CreateConVar("sm_hgr_hook_color", "2", "The color of the hook, 0 = White, 1 = Team color, 2 = custom, 3 = Reverse team color", 0, true, 0.0, true, 3.0); + h_cvarHookRed = CreateConVar("sm_hgr_hook_red", "255", "The red component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarHookGreen = CreateConVar("sm_hgr_hook_green", "0", "The green component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarHookBlue = CreateConVar("sm_hgr_hook_blue", "0", "The blue component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarHookAlpha = CreateConVar("sm_hgr_hook_alpha", "255", "The alpha component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarHookSound = CreateConVar("sm_hgr_hook_sound", "hgr/hookhit.mp3", "Location of hook sound effect relative to /sound/music/"); + + // Grab convars + h_cvarGrabEnable = CreateConVar("sm_hgr_grab_enable", "1", "This will enable the grab feature of this plugin", FCVAR_NOTIFY, true, 0.0, true, 1.0); + h_cvarGrabAdminOnly = CreateConVar("sm_hgr_grab_adminonly", "1", "If 1, only admins can use grab", 0, true, 0.0, true, 1.0); + h_cvarGrabFreeze = CreateConVar("sm_hgr_grab_freeze_enable", "0", "Allow players to grab during freezetime, 1 - Allow, 0 - Disallow", 0, true, 0.0, true, 1.0); + h_cvarGrabSlide = CreateConVar("sm_hgr_grab_slide_enable", "1", "Allow players to push or pull grab target, 1 - Allow, 0 - Disallow", 0, true, 0.0, true, 1.0); + h_cvarGrabSpeed = CreateConVar("sm_hgr_grab_speed", "5.0", "The speed of the grabbers target", 0, true, 0.0, true, 100.0); + h_cvarGrabInitWidth = CreateConVar("sm_hgr_grab_initwidth", "1.0", "The initial width of the grab beam", 0, true, 0.0, true, 100.0); + h_cvarGrabEndWidth = CreateConVar("sm_hgr_grab_endwidth", "10.0", "The end width of the grab beam", 0, true, 0.0, true, 100.0); + h_cvarGrabAmplitude = CreateConVar("sm_hgr_grab_amplitude", "0.0", "The amplitude of the grab beam", 0, true, 0.0, true, 100.0); + h_cvarGrabBeamColor = CreateConVar("sm_hgr_grab_color", "2", "The color of the grab beam, 0 = White, 1 = Team color, 2 = custom, 3 = Reverse team color", 0, true, 0.0, true, 3.0); + h_cvarGrabRed = CreateConVar("sm_hgr_grab_red", "0", "The red component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarGrabGreen = CreateConVar("sm_hgr_grab_green", "0", "The green component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarGrabBlue = CreateConVar("sm_hgr_grab_blue", "255", "The blue component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarGrabAlpha = CreateConVar("sm_hgr_grab_alpha", "255", "The alpha component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarGrabSound = CreateConVar("sm_hgr_grab_sound", "hgr/hookhit.mp3", "Location of grab sound effect relative to /sound/music/"); + + // Rope convars + h_cvarRopeEnable = CreateConVar("sm_hgr_rope_enable", "1", "This will enable the rope feature of this plugin", FCVAR_NOTIFY, true, 0.0, true, 1.0); + h_cvarRopeAdminOnly = CreateConVar("sm_hgr_rope_adminonly", "1", "If 1, only admins can use rope", 0, true, 0.0, true, 1.0); + h_cvarRopeFreeze = CreateConVar("sm_hgr_rope_freeze_enable", "0", "Allow players to rope during freezetime, 1 - Allow, 0 - Disallow", 0, true, 0.0, true, 1.0); + h_cvarRopeSlide = CreateConVar("sm_hgr_rope_slide_enable", "1", "Allow players to slide up or down rope, 1 - Allow, 0 - Disallow", 0, true, 0.0, true, 1.0); + h_cvarRopeSpeed = CreateConVar("sm_hgr_rope_speed", "5.0", "The speed of the player using rope", 0, true, 0.0, true, 100.0); + h_cvarRopeInitWidth = CreateConVar("sm_hgr_rope_initwidth", "3.0", "The initial width of the rope beam", 0, true, 0.0, true, 100.0); + h_cvarRopeEndWidth = CreateConVar("sm_hgr_rope_endwidth", "3.0", "The end width of the rope beam", 0, true, 0.0, true, 100.0); + h_cvarRopeAmplitude = CreateConVar("sm_hgr_rope_amplitude", "0.0", "The amplitude of the rope beam", 0, true, 0.0, true, 100.0); + h_cvarRopeBeamColor = CreateConVar("sm_hgr_rope_color", "2", "The color of the rope, 0 = White, 1 = Team color, 2 = custom, 3 = Reverse team color", 0, true, 0.0, true, 3.0); + h_cvarRopeRed = CreateConVar("sm_hgr_rope_red", "0", "The red component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarRopeGreen = CreateConVar("sm_hgr_rope_green", "255", "The green component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarRopeBlue = CreateConVar("sm_hgr_rope_blue", "0", "The blue component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarRopeAlpha = CreateConVar("sm_hgr_rope_alpha", "255", "The alpha component of the beam (Only if you are using a custom color)", 0, true, 0.0, true, 255.0); + h_cvarRopeSound = CreateConVar("sm_hgr_rope_sound", "hgr/hookhit.mp3", "Location of rope sound effect relative to /sound/music/"); + + // General convar changes + HookConVarChange(h_cvarAnnounce, ConvarChanged); + HookConVarChange(h_cvarSoundAmplify, ConvarChanged); + HookConVarChange(h_cvarOverrideMode, ConvarChanged); + HookConVarChange(h_cvarRopeOldMode, ConvarChanged); + HookConVarChange(h_cvarUpButton, ConvarChanged); + HookConVarChange(h_cvarDownButton, ConvarChanged); + + // Hook convar changes + HookConVarChange(h_cvarHookEnable, ConvarChanged); + HookConVarChange(h_cvarHookAdminOnly, ConvarChanged); + HookConVarChange(h_cvarHookFreeze, ConvarChanged); + HookConVarChange(h_cvarHookSlide, ConvarChanged); + HookConVarChange(h_cvarHookSpeed, ConvarChanged); + HookConVarChange(h_cvarHookInitWidth, ConvarChanged); + HookConVarChange(h_cvarHookEndWidth, ConvarChanged); + HookConVarChange(h_cvarHookAmplitude, ConvarChanged); + HookConVarChange(h_cvarHookBeamColor, ConvarChanged); + HookConVarChange(h_cvarHookRed, ConvarChanged); + HookConVarChange(h_cvarHookGreen, ConvarChanged); + HookConVarChange(h_cvarHookBlue, ConvarChanged); + HookConVarChange(h_cvarHookAlpha, ConvarChanged); + HookConVarChange(h_cvarHookSound, ConvarChanged); + + // Grab convar changes + HookConVarChange(h_cvarGrabEnable, ConvarChanged); + HookConVarChange(h_cvarGrabAdminOnly, ConvarChanged); + HookConVarChange(h_cvarGrabFreeze, ConvarChanged); + HookConVarChange(h_cvarGrabSlide, ConvarChanged); + HookConVarChange(h_cvarGrabSpeed, ConvarChanged); + HookConVarChange(h_cvarGrabInitWidth, ConvarChanged); + HookConVarChange(h_cvarGrabEndWidth, ConvarChanged); + HookConVarChange(h_cvarGrabAmplitude, ConvarChanged); + HookConVarChange(h_cvarGrabBeamColor, ConvarChanged); + HookConVarChange(h_cvarGrabRed, ConvarChanged); + HookConVarChange(h_cvarGrabGreen, ConvarChanged); + HookConVarChange(h_cvarGrabBlue, ConvarChanged); + HookConVarChange(h_cvarGrabAlpha, ConvarChanged); + HookConVarChange(h_cvarGrabSound, ConvarChanged); + + // Rope convar changes + HookConVarChange(h_cvarRopeEnable, ConvarChanged); + HookConVarChange(h_cvarRopeAdminOnly, ConvarChanged); + HookConVarChange(h_cvarRopeFreeze, ConvarChanged); + HookConVarChange(h_cvarRopeSlide, ConvarChanged); + HookConVarChange(h_cvarRopeSpeed, ConvarChanged); + HookConVarChange(h_cvarRopeInitWidth, ConvarChanged); + HookConVarChange(h_cvarRopeEndWidth, ConvarChanged); + HookConVarChange(h_cvarRopeAmplitude, ConvarChanged); + HookConVarChange(h_cvarRopeBeamColor, ConvarChanged); + HookConVarChange(h_cvarRopeRed, ConvarChanged); + HookConVarChange(h_cvarRopeGreen, ConvarChanged); + HookConVarChange(h_cvarRopeBlue, ConvarChanged); + HookConVarChange(h_cvarRopeAlpha, ConvarChanged); + HookConVarChange(h_cvarRopeSound, ConvarChanged); + + // Auto-generate configuration file + AutoExecConfig(true, "hookgrabrope"); + + PrintToServer("----------------| [HGR] %t |---------------", "Loaded"); +} + +public APLRes:AskPluginLoad2(Handle:myself, bool:late, String:error[], err_max) +{ + decl String:file[PLATFORM_MAX_PATH]; + BuildPath(Path_SM, file, sizeof(file), "plugins/hookgrabrope.smx"); + if(!FileExists(file)) + { + SetFailState("ERROR: Cannot find required plugin hookgrabrope.smx"); + return APLRes_Failure; + } + RegPluginLibrary("hookgrabrope"); + + // Access natives + CreateNative("HGR_Access", __Access); + CreateNative("HGR_ClientAccess", __ClientAccess); + + // Status bools + CreateNative("HGR_IsHooking", __IsHooking); + CreateNative("HGR_IsGrabbing", __IsGrabbing); + CreateNative("HGR_IsBeingGrabbed", __IsBeingGrabbed); + CreateNative("HGR_IsRoping", __IsRoping); + CreateNative("HGR_IsPushing", __IsPushing); + CreateNative("HGR_IsAttracting", __IsAttracting); + CreateNative("HGR_IsRepelling", __IsRepelling); + CreateNative("HGR_IsAscending", __IsAscending); + CreateNative("HGR_IsDescending", __IsDescending); + + // Information natives + CreateNative("HGR_GetHookLocation", __GetHookLocation); + CreateNative("HGR_GetGrabLocation", __GetGrabLocation); + CreateNative("HGR_GetRopeLocation", __GetRopeLocation); + CreateNative("HGR_GetPushLocation", __GetPushLocation); + CreateNative("HGR_GetHookDistance", __GetHookDistance); + CreateNative("HGR_GetGrabDistance", __GetGrabDistance); + CreateNative("HGR_GetRopeDistance", __GetRopeDistance); + CreateNative("HGR_GetPushDistance", __GetPushDistance); + CreateNative("HGR_GetHookTarget", __GetHookTarget); + CreateNative("HGR_GetGrabTarget", __GetGrabTarget); + CreateNative("HGR_GetRopeTarget", __GetRopeTarget); + CreateNative("HGR_GetPushTarget", __GetPushTarget); + + // Action overrides + CreateNative("HGR_ForceHook", __ForceHook); + CreateNative("HGR_ForceGrab", __ForceGrab); + CreateNative("HGR_ForceRope", __ForceRope); + CreateNative("HGR_ForcePush", __ForcePush); + CreateNative("HGR_StopHook", __StopHook); + CreateNative("HGR_StopGrab", __StopGrab); + CreateNative("HGR_StopRope", __StopRope); + + return APLRes_Success; +} + +/********** + *Forwards* +***********/ + +public OnConfigsExecuted() +{ + UpdateAllConvars(); + // Precache models + precache_laser = PrecacheModel("materials/sprites/laserbeam.vmt"); + + // Precache sounds + if(g_cvarSoundAmplify > 0) // Don't download sounds if sound is disabled + { + for(new HGRAction:i = Hook; i <= Rope; i++) + { + Format(g_cvarSound[i], sizeof(g_cvarSound[]), "music/%s", g_cvarSound[i]); + decl String:path[64]; + Format(path, sizeof(path), "sound/%s", g_cvarSound[i]); + AddFileToDownloadsTable(path); + PrecacheSound(g_cvarSound[i], true); + } + } +} + +public bool:OnClientConnect(client, String:rejectmsg[], maxlen) +{ + // Initialize variables for special plugin access when clients connect + // PrintToServer("Connect %d", client); + ResetAccess(client); + return true; +} + +public OnClientDisconnect(client) +{ + // Disable special plugin access for client when they disconnect + ResetAccess(client); +} + +/********* + *Natives* +**********/ + +public __Access(Handle:plugin, numParams) +{ + decl String:client[64]; + GetNativeString(1, client, sizeof(client)); + new HGRAccess:access = GetNativeCell(2); + new HGRAction:action = GetNativeCell(3); + return Access(client, access, action); +} + +public __ClientAccess(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + new HGRAccess:access = GetNativeCell(2); + new HGRAction:action = GetNativeCell(3); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + return ClientAccess(client, access, action) == 1; +} + +public __IsHooking(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + return g_Status[client][Hook]; +} + +public __IsGrabbing(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + return g_Status[client][Grab]; +} + +public __IsBeingGrabbed(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + return g_Grabbed[client]; +} + +public __IsRoping(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + return g_Status[client][Rope]; +} + +public __IsPushing(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Hook]) + return g_Backward[client]; + return false; +} + +public __IsAttracting(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Grab]) + return g_Attracting[client][1]; + return false; +} + +public __IsRepelling(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Grab]) + return g_Attracting[client][0]; + return false; +} + +public __IsAscending(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Rope]) + return g_Climbing[client][0]; + return false; +} + +public __IsDescending(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Rope]) + return g_Climbing[client][1]; + return false; +} + +public __GetHookLocation(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Hook]) + { + SetNativeArray(2, g_Location[client][0], 3); + return true; + } + return false; +} + +public __GetGrabLocation(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Grab]) + { + new Float:buffer[3]; + GetEntityOrigin(g_Targetindex[client][Grab], buffer); + SetNativeArray(2, buffer, 3); + return true; + } + else + return false; +} + +public __GetRopeLocation(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Rope]) + { + SetNativeArray(2, g_Location[client][2], 3); + return true; + } + else + return false; +} + +public __GetPushLocation(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Hook]) + { + SetNativeArray(2, g_Location[client][3], 3); + return true; + } + else + return false; +} + +public __GetHookDistance(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Hook]) + return _:g_Distance[client][0]; + else + return -1; +} + +public __GetGrabDistance(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Grab]) + return _:g_Distance[client][1]; + else + return -1; +} + +public __GetRopeDistance(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Rope]) + return _:g_Distance[client][2]; + else + return -1; +} + +public __GetPushDistance(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Hook]) + return _:g_Distance[client][3]; + else + return -1; +} + +public __GetHookTarget(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Hook]) + return g_Targetindex[client][Hook]; + else + return -1; +} + +public __GetGrabTarget(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Grab]) + return g_Targetindex[client][Grab]; + else + return -1; +} + +public __GetRopeTarget(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Rope]) + return g_Targetindex[client][Rope]; + else + return -1; +} + +public __GetPushTarget(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Hook]) + return g_Targetindex[client][3]; + else + return -1; +} + +public __ForceHook(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(!g_Status[client][Hook] && !g_Status[client][Grab] && !g_Status[client][Rope] && !g_Grabbed[client]) + { + HookCmd(client, 0); + return true; + } + return false; +} + +public __ForceGrab(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(!g_Status[client][Hook] && !g_Status[client][Grab] && !g_Status[client][Rope] && !g_Grabbed[client]) + { + GrabCmd(client, 0); + return true; + } + return false; +} + +public __ForceRope(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(!g_Status[client][Hook] && !g_Status[client][Grab] && !g_Status[client][Rope] && !g_Grabbed[client]) + { + RopeCmd(client, 0); + return true; + } + return false; +} + +public __ForcePush(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(!g_Status[client][Hook] && !g_Status[client][Grab] && !g_Status[client][Rope] && !g_Grabbed[client]) + { + PushCmd(client, 0); + return true; + } + return false; +} + +public __StopHook(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Hook]) + { + UnHookCmd(client, 0); + return true; + } + return false; +} + +public __StopGrab(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Grab]) + { + DropCmd(client, 0); + return true; + } + return false; +} + +public __StopRope(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Rope]) + { + DetachCmd(client, 0); + return true; + } + return false; +} + +public __StopPush(Handle:plugin, numParams) +{ + new client = GetNativeCell(1); + if(client < 1 || client > MaxClients) + return ThrowNativeError(SP_ERROR_NATIVE, "Invalid client index [%d]", client); + else if(!IsClientInGame(client)) + return ThrowNativeError(SP_ERROR_NATIVE, "Client is not currently ingame [%d]", client); + if(g_Status[client][Hook] && g_Backward[client]) + { + DetachCmd(client, 0); + return true; + } + return false; +} + +/******** + *Events* +*********/ + +public OnGameFrame() +{ + for (new i = 1; i <= MaxClients; i++) + { + if (IsClientInGame(i) && IsPlayerAlive(i)) + { + new cl_buttons = GetClientButtons(i); + if(g_Status[i][Hook] && g_cvarSlide[Hook]) + { + if(cl_buttons & g_cvarUpButton && g_Backward[i]) + { + SetEntityMoveType(i, MOVETYPE_WALK); + g_Backward[i] = false; // Hook in forward direction if client is jumping + } + else if(cl_buttons & g_cvarDownButton && !g_Backward[i]) + { + SetEntityMoveType(i, MOVETYPE_WALK); + g_Backward[i] = true; // Hook in reverse direction if client is crouching + } + } + else if(g_Status[i][Grab] && g_cvarSlide[Grab]) + { + if(cl_buttons & g_cvarUpButton) + { + if(!g_Attracting[i][0]) + { + g_Attracting[i][0] = true; // Repel grab target away from client while jumping + g_Attracting[i][1] = false; + } + } + else + { + if(g_Attracting[i][0]) + g_Attracting[i][0] = false; // Tell plugin client is no longer repelling grab target while no longer jumping + if(cl_buttons & g_cvarDownButton) + { + if(!g_Attracting[i][1]) + g_Attracting[i][1] = true; // Attract grab target toward client while crouching + } + else if(g_Attracting[i][1]) + g_Attracting[i][1] = false; // Tell plugin client is no longer attracting grab target while no longer crouching + } + } + else if(g_Status[i][Rope] && g_cvarSlide[Rope]) + { + if(cl_buttons & g_cvarUpButton) + { + if(!g_Climbing[i][0]) + { + g_Climbing[i][0] = true; // Ascend rope while jumping + g_Climbing[i][1] = false; + } + } + else + { + if(g_Climbing[i][0]) + g_Climbing[i][0] = false; // Tell plugin client is no longer ascending rope while not jumping + if(cl_buttons & g_cvarDownButton) + { + if(!g_Climbing[i][1]) + g_Climbing[i][1] = true; // Descend rope while crouching + } + else if(g_Climbing[i][1]) + g_Climbing[i][1] = false; // Tell plugin client is no longer descending rope while not crouching + } + } + } + } +} + +public PlayerSpawnEvent(Handle:event, const String:name[], bool:dontBroadcast) +{ + new client = GetClientOfUserId(GetEventInt(event,"userid")); + if(IsFakeClient(client)) + return; + + // Tell plugin that the client isn't using any of its features + g_Status[client][Hook] = false; + g_Status[client][Grab] = false; + g_Status[client][Rope] = false; + g_Grabbed[client] = false; + g_Backward[client] = false; + g_Attracting[client][0] = false; + g_Attracting[client][1] = false; + g_Climbing[client][0] = false; + g_Climbing[client][1] = false; + g_Targetindex[client][0] = -1; + g_Targetindex[client][1] = -1; + g_Targetindex[client][2] = -1; + g_Targetindex[client][3] = -1; + if(g_cvarAnnounce) + { + decl String:buffer[128]; + Format(buffer, sizeof(buffer), "\x01\x0B\x04[HGR]\x01 %t\x04 ", "Enabled"); + if(HasAccess(client, Hook)) + Format(buffer, sizeof(buffer), "%s[+Hook] ", buffer); + if(HasAccess(client, Grab)) + Format(buffer, sizeof(buffer), "%s[+Grab] ", buffer); + if(HasAccess(client, Rope)) + Format(buffer, sizeof(buffer), "%s[+Rope]", buffer); + PrintToChat(client, buffer); + } +} + +public RoundStartEvent(Handle:event, const String:name[], bool:dontBroadcast) +{ + // Tell plugin whether players can use hook grab rope during freezetime + if(g_HookedFreeze) + { + for(new HGRAction:i = Hook; i <= Rope; i++) + g_Frozen[i] = g_cvarFreeze[i]; + } + else + { + for(new HGRAction:k = Hook; k <= Rope; k++) + g_Frozen[k] = true; + } +} + +public RoundFreezeEndEvent(Handle:event, const String:name[], bool:dontBroadcast) +{ + // Freezetime has ended + for(new HGRAction:i = Hook; i <= Rope; i++) + g_Frozen[i] = true; +} + +/****************** + *Console Commands* +*******************/ + +public Action:HookCmd(client, args) +{ + g_Backward[client] = false; + Action_Hook(client); + return Plugin_Handled; +} + +public Action:UnHookCmd(client, args) +{ + if(IsPlayerAlive(client)) + Action_UnHook(client); + return Plugin_Handled; +} + +public Action:HookToggle(client, args) +{ + if(g_Status[client][Hook]) + g_Status[client][Hook] = false; + else + { + g_Backward[client] = false; + Action_Hook(client); + } + return Plugin_Handled; +} + +public Action:GrabCmd(client, args) +{ + Action_Grab(client); + return Plugin_Handled; +} + +public Action:DropCmd(client, args) +{ + if(IsPlayerAlive(client)) + Action_Drop(client); + return Plugin_Handled; +} + +public Action:GrabToggle(client, args) +{ + if(g_Status[client][Grab]) + g_Status[client][Grab] = false; + else + Action_Grab(client); + return Plugin_Handled; +} + +public Action:RopeCmd(client, args) +{ + Action_Rope(client); + return Plugin_Handled; +} + +public Action:DetachCmd(client, args) +{ + if(IsPlayerAlive(client)) + Action_Detach(client); + return Plugin_Handled; +} + +public Action:RopeToggle(client, args) +{ + if(g_Status[client][Rope]) + g_Status[client][Rope] = false; + else + Action_Rope(client); + return Plugin_Handled; +} + +public Action:PushCmd(client, args) +{ + if(!CheckCommandAccess(client,"",ADMFLAG_BAN)) { + PrintCenterText(client, "поешь говна"); + return Plugin_Stop; + } + + g_Backward[client] = true; + Action_Hook(client); + return Plugin_Handled; +} + +public Action:UnPushCmd(client, args) +{ + if(IsPlayerAlive(client)) + { + g_Backward[client] = false; + Action_UnHook(client); + } + return Plugin_Handled; +} + +public Action:PushToggle(client, args) +{ + if(!CheckCommandAccess(client,"",ADMFLAG_BAN)) { + PrintCenterText(client, "ты долбаеб?"); + return Plugin_Stop; + } + + if(g_Status[client][Hook]) + { + g_Backward[client] = false; + g_Status[client][Hook] = false; + } + else + { + g_Backward[client] = true; + Action_Hook(client); + } + return Plugin_Handled; +} + +/**************** + *Admin Commands* +*****************/ + +public Action:GiveHook(client, args) +{ + if(args > 0) + { + decl String:target[64]; + GetCmdArg(1, target, sizeof(target)); + if(Access(target, Give, Hook) == 0) + { + new targetindex = FindTarget(client, target); + if(targetindex > 0) + { + ClientAccess(targetindex, Give, Hook); + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %N", client, "Admin Give", "hook", targetindex); + } + } + else + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %s", client, "Admin Give", "hook", target); + } + else + ReplyToCommand(client,"\x01\x0B\x04[HGR] Usage:\x01 sm_hgr_givehook <@all/@t/@ct/partial name>"); + return Plugin_Handled; +} + +public Action:TakeHook(client, args) +{ + if(args > 0) + { + decl String:target[64]; + GetCmdArg(1, target, sizeof(target)); + if(Access(target, Take, Hook) == 0) + { + new targetindex = FindTarget(client, target); + if(targetindex > 0) + { + ClientAccess(targetindex, Take, Hook); + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %N", client, "Admin Take", "hook", targetindex); + } + } + else + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %s", client, "Admin Take", "hook", target); + } + else + ReplyToCommand(client,"\x01\x0B\x04[HGR] Usage:\x01 sm_hgr_givehook <@all/@t/@ct/partial name>"); + return Plugin_Handled; +} + +public Action:GiveGrab(client, args) +{ + if(args > 0) + { + decl String:target[64]; + GetCmdArg(1, target, sizeof(target)); + if(Access(target, Give, Grab) == 0) + { + new targetindex = FindTarget(client, target); + if(targetindex > 0) + { + ClientAccess(targetindex, Give, Grab); + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %N", client, "Admin Give", "grab", targetindex); + } + } + else + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %s", client, "Admin Give", "grab", target); + } + else + ReplyToCommand(client,"\x01\x0B\x04[HGR] Usage:\x01 sm_hgr_givehook <@all/@t/@ct/partial name>"); + return Plugin_Handled; +} + +public Action:TakeGrab(client, args) +{ + if(args > 0) + { + decl String:target[64]; + GetCmdArg(1, target, sizeof(target)); + if(Access(target, Take, Grab) == 0) + { + new targetindex = FindTarget(client, target); + if(targetindex > 0) + { + ClientAccess(targetindex, Take, Grab); + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %N", client, "Admin Take", "grab", targetindex); + } + } + else + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %s", client, "Admin Take", "grab", target); + } + else + ReplyToCommand(client,"\x01\x0B\x04[HGR] Usage:\x01 sm_hgr_givehook <@all/@t/@ct/partial name>"); + return Plugin_Handled; +} + +public Action:GiveRope(client, args) +{ + if(args > 0) + { + decl String:target[64]; + GetCmdArg(1, target, sizeof(target)); + if(Access(target, Give, Rope) == 0) + { + new targetindex = FindTarget(client, target); + if(targetindex > 0) + { + ClientAccess(targetindex, Give, Rope); + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %N", client, "Admin Give", "rope", targetindex); + } + } + else + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %s", client, "Admin Give", "rope", target); + } + else + ReplyToCommand(client,"\x01\x0B\x04[HGR] Usage:\x01 sm_hgr_givehook <@all/@t/@ct/partial name>"); + return Plugin_Handled; +} + +public Action:TakeRope(client, args) +{ + if(args > 0) + { + decl String:target[64]; + GetCmdArg(1, target, sizeof(target)); + if(Access(target, Take, Rope) == 0) + { + new targetindex = FindTarget(client, target); + if(targetindex > 0) + { + ClientAccess(targetindex, Take, Rope); + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %N", client, "Admin Take", "rope", targetindex); + } + } + else + ShowActivity2(client, "\x01\x0B\x04[HGR]\x01 ", "%N %t %s", client, "Admin Take", "rope", target); + } + else + ReplyToCommand(client,"\x01\x0B\x04[HGR] Usage:\x01 sm_hgr_givehook <@all/@t/@ct/partial name>"); + return Plugin_Handled; +} + +/******** + *Access* +*********/ + +public Access(const String:target[], HGRAccess:access, HGRAction:action) +{ + new clients[MAXPLAYERS]; + new count = FindMatchingPlayers(target, clients); + if(count == 0) + return 0; + for(new x = 0; x < count; x++) + ClientAccess(clients[x], access, action); + return count; +} + +public ClientAccess(client, HGRAccess:access, HGRAction:action) +{ + if(IsFakeClient(client)) + return 0; + decl String:actionName[64]; + if(action == Hook) + actionName = "Hook"; + else if(action == Grab) + actionName = "Grab"; + else if(action == Rope) + actionName = "Rope"; + if(access == Give) + { + g_AllowedClients[client][action] = true; + if(IsClientInGame(client)) + PrintToChat(client, "\x01\x0B\x04[HGR]\x01 %t", "Given Access", actionName); + } + else + { + g_AllowedClients[client][action] = false; + if(IsClientInGame(client)) + PrintToChat(client, "\x01\x0B\x04[HGR]\x01 %t", "Taken Access", actionName); + } + return 1; +} + +public bool:HasAccess(client, HGRAction:action) +{ + // Hook, Grab, or Rope is disabled + if(!g_cvarEnable[action]) + return false; + // If Override Mode is active, client only has access if it has been given to him + if(g_cvarOverrideMode) + return g_AllowedClients[client][action]; + // Check for admin flags if selected HGR action is admin only + if(g_cvarAdminOnly[action]) + { + decl String:actionName[24]; + if(action == Hook) + actionName = "+hook"; + else if(action == Grab) + actionName = "+grab"; + else if(action == Rope) + actionName = "+rope"; + if(CheckCommandAccess(client, actionName, ADMFLAG_GENERIC, true)) + return true; + // If user does not have proper admin access, check if admin + // has specially allowed the client to use HGR anyway + else + return g_AllowedClients[client][action]; + } + return true; +} + +/********* + *Convars* +**********/ + +public ConvarChanged(Handle:cvar, const String:oldVal[], const String:newVal[]) +{ + // General convars + if(cvar == h_cvarAnnounce) + g_cvarAnnounce = GetConVarBool(h_cvarAnnounce); + else if(cvar == h_cvarSoundAmplify) + g_cvarSoundAmplify = GetConVarInt(h_cvarSoundAmplify); + else if(cvar == h_cvarOverrideMode) + g_cvarOverrideMode = GetConVarBool(h_cvarOverrideMode); + else if(cvar == h_cvarRopeOldMode) + g_cvarRopeOldMode = GetConVarBool(h_cvarRopeOldMode); + else if(cvar == h_cvarUpButton) + g_cvarUpButton = GetButtonBitString(newVal, 1 << 1); + else if(cvar == h_cvarDownButton) + g_cvarDownButton = GetButtonBitString(newVal, 1 << 2); + + // Hook convars + else if(cvar == h_cvarHookEnable) + g_cvarEnable[Hook] = GetConVarBool(h_cvarHookEnable); + else if(cvar == h_cvarHookAdminOnly) + g_cvarAdminOnly[Hook] = GetConVarBool(h_cvarHookAdminOnly); + else if(cvar == h_cvarHookFreeze) + g_cvarFreeze[Hook] = GetConVarBool(h_cvarHookFreeze); + else if(cvar == h_cvarHookSlide) + g_cvarSlide[Hook] = GetConVarBool(h_cvarHookSlide); + else if(cvar == h_cvarHookSpeed) + g_cvarSpeed[0] = GetConVarFloat(h_cvarHookSpeed); + else if(cvar == h_cvarHookInitWidth) + g_cvarInitWidth[0] = GetConVarFloat(h_cvarHookInitWidth); + else if(cvar == h_cvarHookEndWidth) + g_cvarEndWidth[0] = GetConVarFloat(h_cvarHookEndWidth); + else if(cvar == h_cvarHookAmplitude) + g_cvarAmplitude[0] = GetConVarFloat(h_cvarHookAmplitude); + else if(cvar == h_cvarHookBeamColor) + g_cvarBeamColor[Hook] = GetConVarInt(h_cvarHookBeamColor); + else if(cvar == h_cvarHookRed) + g_cvarBeamRed[Hook] = GetConVarInt(h_cvarHookRed); + else if(cvar == h_cvarHookGreen) + g_cvarBeamGreen[Hook] = GetConVarInt(h_cvarHookGreen); + else if(cvar == h_cvarHookBlue) + g_cvarBeamBlue[Hook] = GetConVarInt(h_cvarHookBlue); + else if(cvar == h_cvarHookAlpha) + g_cvarBeamAlpha[Hook] = GetConVarInt(h_cvarHookAlpha); + else if(cvar == h_cvarHookSound) + GetConVarString(h_cvarHookSound, g_cvarSound[Hook], sizeof(g_cvarSound[])); + + // Grab convars + else if(cvar == h_cvarGrabEnable) + g_cvarEnable[Grab] = GetConVarBool(h_cvarGrabEnable); + else if(cvar == h_cvarGrabAdminOnly) + g_cvarAdminOnly[Grab] = GetConVarBool(h_cvarGrabAdminOnly); + else if(cvar == h_cvarGrabFreeze) + g_cvarFreeze[Grab] = GetConVarBool(h_cvarGrabFreeze); + else if(cvar == h_cvarGrabSlide) + g_cvarSlide[Grab] = GetConVarBool(h_cvarGrabSlide); + else if(cvar == h_cvarGrabSpeed) + g_cvarSpeed[1] = GetConVarFloat(h_cvarGrabSpeed); + else if(cvar == h_cvarGrabInitWidth) + g_cvarInitWidth[1] = GetConVarFloat(h_cvarGrabInitWidth); + else if(cvar == h_cvarGrabEndWidth) + g_cvarEndWidth[1] = GetConVarFloat(h_cvarGrabEndWidth); + else if(cvar == h_cvarGrabAmplitude) + g_cvarAmplitude[1] = GetConVarFloat(h_cvarGrabAmplitude); + else if(cvar == h_cvarGrabBeamColor) + g_cvarBeamColor[Grab] = GetConVarInt(h_cvarGrabBeamColor); + else if(cvar == h_cvarGrabRed) + g_cvarBeamRed[Grab] = GetConVarInt(h_cvarGrabRed); + else if(cvar == h_cvarGrabGreen) + g_cvarBeamGreen[Grab] = GetConVarInt(h_cvarGrabGreen); + else if(cvar == h_cvarGrabBlue) + g_cvarBeamBlue[Grab] = GetConVarInt(h_cvarGrabBlue); + else if(cvar == h_cvarGrabAlpha) + g_cvarBeamAlpha[Grab] = GetConVarInt(h_cvarGrabAlpha); + else if(cvar == h_cvarGrabSound) + GetConVarString(h_cvarGrabSound, g_cvarSound[Grab], sizeof(g_cvarSound[])); + + // Rope convars + else if(cvar == h_cvarRopeEnable) + g_cvarEnable[Rope] = GetConVarBool(h_cvarRopeEnable); + else if(cvar == h_cvarRopeAdminOnly) + g_cvarAdminOnly[Rope] = GetConVarBool(h_cvarRopeAdminOnly); + else if(cvar == h_cvarRopeFreeze) + g_cvarFreeze[Rope] = GetConVarBool(h_cvarRopeFreeze); + else if(cvar == h_cvarRopeSlide) + g_cvarSlide[Rope] = GetConVarBool(h_cvarRopeSlide); + else if(cvar == h_cvarRopeSpeed) + g_cvarSpeed[2] = GetConVarFloat(h_cvarRopeSpeed); + else if(cvar == h_cvarRopeInitWidth) + g_cvarInitWidth[2] = GetConVarFloat(h_cvarRopeInitWidth); + else if(cvar == h_cvarRopeEndWidth) + g_cvarEndWidth[2] = GetConVarFloat(h_cvarRopeEndWidth); + else if(cvar == h_cvarRopeAmplitude) + g_cvarAmplitude[2] = GetConVarFloat(h_cvarRopeAmplitude); + else if(cvar == h_cvarRopeBeamColor) + g_cvarBeamColor[Rope] = GetConVarInt(h_cvarRopeBeamColor); + else if(cvar == h_cvarRopeRed) + g_cvarBeamRed[Rope] = GetConVarInt(h_cvarRopeRed); + else if(cvar == h_cvarRopeGreen) + g_cvarBeamGreen[Rope] = GetConVarInt(h_cvarRopeGreen); + else if(cvar == h_cvarRopeBlue) + g_cvarBeamBlue[Rope] = GetConVarInt(h_cvarRopeBlue); + else if(cvar == h_cvarRopeAlpha) + g_cvarBeamAlpha[Rope] = GetConVarInt(h_cvarRopeAlpha); + else if(cvar == h_cvarRopeSound) + GetConVarString(h_cvarRopeSound, g_cvarSound[Rope], sizeof(g_cvarSound[])); +} + +public UpdateAllConvars() +{ + // General convars + g_cvarAnnounce = GetConVarBool(h_cvarAnnounce); + g_cvarSoundAmplify = GetConVarInt(h_cvarSoundAmplify); + g_cvarOverrideMode = GetConVarBool(h_cvarOverrideMode); + g_cvarRopeOldMode = GetConVarBool(h_cvarRopeOldMode); + decl String:UpButton[24]; + GetConVarString(h_cvarUpButton, UpButton, sizeof(UpButton)); + g_cvarUpButton = GetButtonBitString(UpButton, 1 << 1); + decl String:DownButton[24]; + GetConVarString(h_cvarDownButton, DownButton, sizeof(DownButton)); + g_cvarDownButton = GetButtonBitString(DownButton, 1 << 2); + + // Hook convars + g_cvarEnable[Hook] = GetConVarBool(h_cvarHookEnable); + g_cvarAdminOnly[Hook] = GetConVarBool(h_cvarHookAdminOnly); + g_cvarFreeze[Hook] = GetConVarBool(h_cvarHookFreeze); + g_cvarSlide[Hook] = GetConVarBool(h_cvarHookSlide); + g_cvarSpeed[0] = GetConVarFloat(h_cvarHookSpeed); + g_cvarInitWidth[0] = GetConVarFloat(h_cvarHookInitWidth); + g_cvarEndWidth[0] = GetConVarFloat(h_cvarHookEndWidth); + g_cvarAmplitude[0] = GetConVarFloat(h_cvarHookAmplitude); + g_cvarBeamColor[Hook] = GetConVarInt(h_cvarHookBeamColor); + g_cvarBeamRed[Hook] = GetConVarInt(h_cvarHookRed); + g_cvarBeamGreen[Hook] = GetConVarInt(h_cvarHookGreen); + g_cvarBeamBlue[Hook] = GetConVarInt(h_cvarHookBlue); + g_cvarBeamAlpha[Hook] = GetConVarInt(h_cvarHookAlpha); + GetConVarString(h_cvarHookSound, g_cvarSound[Hook], sizeof(g_cvarSound[])); + + // Grab convars + g_cvarEnable[Grab] = GetConVarBool(h_cvarGrabEnable); + g_cvarAdminOnly[Grab] = GetConVarBool(h_cvarGrabAdminOnly); + g_cvarFreeze[Grab] = GetConVarBool(h_cvarGrabFreeze); + g_cvarSlide[Grab] = GetConVarBool(h_cvarGrabSlide); + g_cvarSpeed[1] = GetConVarFloat(h_cvarGrabSpeed); + g_cvarInitWidth[1] = GetConVarFloat(h_cvarGrabInitWidth); + g_cvarEndWidth[1] = GetConVarFloat(h_cvarGrabEndWidth); + g_cvarAmplitude[1] = GetConVarFloat(h_cvarGrabAmplitude); + g_cvarBeamColor[Grab] = GetConVarInt(h_cvarGrabBeamColor); + g_cvarBeamRed[Grab] = GetConVarInt(h_cvarGrabRed); + g_cvarBeamGreen[Grab] = GetConVarInt(h_cvarGrabGreen); + g_cvarBeamBlue[Grab] = GetConVarInt(h_cvarGrabBlue); + g_cvarBeamAlpha[Grab] = GetConVarInt(h_cvarGrabAlpha); + GetConVarString(h_cvarGrabSound, g_cvarSound[Grab], sizeof(g_cvarSound[])); + + // Rope convars + g_cvarEnable[Rope] = GetConVarBool(h_cvarRopeEnable); + g_cvarAdminOnly[Rope] = GetConVarBool(h_cvarRopeAdminOnly); + g_cvarFreeze[Rope] = GetConVarBool(h_cvarRopeFreeze); + g_cvarSlide[Rope] = GetConVarBool(h_cvarRopeSlide); + g_cvarSpeed[2] = GetConVarFloat(h_cvarRopeSpeed); + g_cvarInitWidth[2] = GetConVarFloat(h_cvarRopeInitWidth); + g_cvarEndWidth[2] = GetConVarFloat(h_cvarRopeEndWidth); + g_cvarAmplitude[2] = GetConVarFloat(h_cvarRopeAmplitude); + g_cvarBeamColor[Rope] = GetConVarInt(h_cvarRopeBeamColor); + g_cvarBeamRed[Rope] = GetConVarInt(h_cvarRopeRed); + g_cvarBeamGreen[Rope] = GetConVarInt(h_cvarRopeGreen); + g_cvarBeamBlue[Rope] = GetConVarInt(h_cvarRopeBlue); + g_cvarBeamAlpha[Rope] = GetConVarInt(h_cvarRopeAlpha); + GetConVarString(h_cvarRopeSound, g_cvarSound[Rope], sizeof(g_cvarSound[])); + + // Freezetime variables + for(new HGRAction:i = Hook; i <= Rope; i++) + { + if(!g_HookedRoundStart || !g_HookedFreeze) + g_Frozen[i] = true; + else + g_Frozen[i] = g_cvarFreeze[i]; + } +} + +public GetBeamColor(client, HGRAction:action, color[4]) +{ + // Custom beam color + if(g_cvarBeamColor[action] == 2) + { + color[0] = g_cvarBeamRed[action]; + color[1] = g_cvarBeamGreen[action]; + color[2] = g_cvarBeamBlue[action]; + color[3] = g_cvarBeamAlpha[action]; + } + // Teamcolor beam color + else if(g_cvarBeamColor[action] == 1) + { + if(GetClientTeam(client) == 2) + { + color[0]=255;color[1]=0;color[2]=0;color[3]=255; + } + else if(GetClientTeam(client) == 3) + { + color[0]=0;color[1]=0;color[2]=255;color[3]=255; + } + } + // Reverse teamcolor beam color + else if(g_cvarBeamColor[action] == 3) + { + if(GetClientTeam(client) == 3) + { + color[0]=255;color[1]=0;color[2]=0;color[3]=255; + } + else if(GetClientTeam(client) == 2) + { + color[0]=0;color[1]=0;color[2]=255;color[3]=255; + } + } + // White beam color + else + { + color[0]=255;color[1]=255;color[2]=255;color[3]=255; + } +} + +/****** + *Hook* +*******/ + +public Action_Hook(client) +{ + if(g_cvarEnable[Hook] && g_Frozen[Hook]) + { + if( client > 0 && + client <= MaxClients && + IsPlayerAlive(client) && + !g_Status[client][Hook] && + !g_Status[client][Rope] && + !g_Grabbed[client]) + { + if(HasAccess(client, Hook)) + { + // Init variables + new Float:clientloc[3], Float:clientang[3]; + GetClientEyePosition(client, clientloc); + GetClientEyeAngles(client, clientang); + + // Hook traceray + TR_TraceRayFilter(clientloc, clientang, MASK_SOLID, RayType_Infinite, TraceRayTryToHit); // Create a ray that tells where the player is looking + TR_GetEndPosition(g_Location[client][0]); // Get the end xyz coordinate of where a player is looking + g_Targetindex[client][Hook] = TR_GetEntityIndex(); // Set hook end target + g_Distance[client][0] = GetVectorDistance(clientloc, g_Location[client][0]); // Get hook distance + + // Push traceray + decl Float:temp[3]; + GetAngleVectors(clientang, temp, NULL_VECTOR, NULL_VECTOR); + NegateVector(temp); + GetVectorAngles(temp, clientang); + TR_TraceRayFilter(clientloc, clientang, MASK_SOLID, RayType_Infinite, TraceRayTryToHit); // Create a ray in opposite direction where player is looking + TR_GetEndPosition(g_Location[client][3]); // Get the end xyz coordinate opposite of where a player is looking + g_Targetindex[client][3] = TR_GetEntityIndex(); // Set push end target + g_Distance[client][3] = GetVectorDistance(clientloc, g_Location[client][3]); // Get push distance + + // Change client status + g_Gravity[client] = GetEntityGravity(client); + g_Status[client][Hook] = true; // Tell plugin the player has landed hook + + // Call hook forward + new ret; + Call_StartForward(FwdClientHook); + Call_PushCell(client); + Call_Finish(ret); + if(ret) + { + Action_UnHook(client); + return; + } + + // Finish hooking + SetEntityGravity(client, 0.0); // Set gravity to 0 so client floats in a straight line + EmitSoundFromOrigin(g_cvarSound[Hook], g_Location[client][0]); // Emit sound from where the hook landed + Hook_Push(client); + CreateTimer(0.1, Hooking, client, TIMER_REPEAT); // Create hooking loop + } + else + PrintToChat(client,"\x01\x0B\x04[HGR]\x01 %t\x04 hook", "No Permission"); + } + else if(client > 0 && client <= MaxClients && IsPlayerAlive(client)) + PrintToChat(client,"\x01\x0B\x04[HGR]\x01 %t", "Error"); + } + else + PrintToChat(client,"\x01\x0B\x04[HGR] Hook\x01 %t", "Disabled"); +} + +public Hook_Push(client) +{ + // Init variables + new Float:clientloc[3], Float:velocity[3]; + GetClientEyePosition(client, clientloc); // Get the xyz coordinate of the player + + // Calculate velocity vector + if(!g_Backward[client]) + SubtractVectors(g_Location[client][0], clientloc, velocity); + else + SubtractVectors(g_Location[client][3], clientloc, velocity); + NormalizeVector(velocity, velocity); + ScaleVector(velocity, g_cvarSpeed[0] * 140.0); + + // Create beam effect + new color[4]; + clientloc[2] -= 18.0; + GetBeamColor(client, Hook, color); + BeamEffect(clientloc, g_Location[client][0], 0.2, g_cvarInitWidth[0], g_cvarEndWidth[0], color, g_cvarAmplitude[0], 0); + + // Move player + TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, velocity); // Push the client + + // If client has reached the end of the hook + g_Distance[client][0] = GetVectorDistance(clientloc, g_Location[client][0]); + if(g_Distance[client][0] < 40.0 && !g_Backward[client]) + { + SetEntityMoveType(client, MOVETYPE_NONE); // Freeze client + SetEntityGravity(client, g_Gravity[client]); // Set gravity to normal + } + + // If client has reached the end of the push + new Float:pdistance = GetVectorDistance(clientloc, g_Location[client][3]); + if(pdistance < 40.0 && g_Backward[client]) + { + SetEntityMoveType(client, MOVETYPE_NONE); // Freeze client + SetEntityGravity(client, g_Gravity[client]); // Set gravity to normal + } +} + +public Action:Hooking(Handle:timer, any:client) +{ + if( IsClientInGame(client) && + IsPlayerAlive(client) && + g_Status[client][Hook] && + !g_Grabbed[client]) + { + Hook_Push(client); + return Plugin_Continue; + } + else + { + Action_UnHook(client); + return Plugin_Stop; // Stop the timer + } +} + +public Action_UnHook(client) +{ + if( IsClientInGame(client) && + IsPlayerAlive(client) && + g_Status[client][Hook] ) + { + g_Status[client][Hook] = false; // Tell plugin the client is not hooking + g_Targetindex[client][Hook] = -1; // Tell plugin that the hook is not attached to an entity + SetEntityGravity(client, g_Gravity[client]); // Set gravity to normal + SetEntityMoveType(client, MOVETYPE_WALK); // Unfreeze client + } +} + +/****** + *Grab* +*******/ + +public Action_Grab(client) +{ + if(g_cvarEnable[Grab] && g_Frozen[Grab]) + { + if( client > 0 && + client <= MaxClients && + IsPlayerAlive(client) && + !g_Status[client][Grab] && + !g_Grabbed[client]) + { + if(HasAccess(client, Grab)) + { + g_Status[client][Grab] = true; // Tell plugin the seeker is grabbing a player + + // Call grab search forward + new ret; + Call_StartForward(FwdClientGrabSearch); + Call_PushCell(client); + Call_Finish(ret); + if(ret) + { + g_Status[client][Grab] = false; + return; + } + + // Start grab search timer + CreateTimer(0.1, GrabSearch, client, TIMER_REPEAT); // Start a timer that searches for a client to grab + } + else + PrintToChat(client,"\x01\x0B\x04[HGR]\x01 %t\x04 grab.", "No Permission"); + } + else if(client > 0 && client <= MaxClients && IsPlayerAlive(client)) + PrintToChat(client, "\x01\x0B\x04[HGR]\x01 %t", "Error"); + } + else + PrintToChat(client, "\x01\x0B\x04[HGR] Grab\x01 %t", "Disabled"); +} + +public Action:GrabSearch(Handle:timer, any:client) +{ + PrintCenterText(client, "%t", "Searching"); // Tell client the plugin is searching for a target + if( client > 0 && + IsClientInGame(client) && + IsPlayerAlive(client) && + g_Status[client][Grab] && + !g_Grabbed[client]) + { + // Init variables + new Float:clientloc[3], Float:clientang[3]; + GetClientEyePosition(client, clientloc); + GetClientEyeAngles(client, clientang); + + // Grab search traceray + TR_TraceRayFilter(clientloc, clientang, MASK_ALL, RayType_Infinite, TraceRayGrabEnt); // Create a ray that tells where the player is looking + g_Targetindex[client][Grab] = TR_GetEntityIndex(); // Set the seekers targetindex to the person he picked up + + // Found a player or object + if(g_Targetindex[client][Grab] > 0 && IsValidEntity(g_Targetindex[client][Grab])) + { + // Init variables + new Float:targetloc[3]; + GetEntityOrigin(g_Targetindex[client][Grab], targetloc); // Find the target's xyz coordinate + g_Distance[client][1] = GetVectorDistance(targetloc, clientloc); // Tell plugin the distance between the two to maintain + if( g_Targetindex[client][Grab] > 0 && + g_Targetindex[client][Grab] <= MaxClients && + IsClientInGame(g_Targetindex[client][Grab])) + { + g_MaxSpeed[client] = GetEntPropFloat(client, Prop_Send, "m_flMaxspeed"); + g_Grabbed[g_Targetindex[client][Grab]] = true; // If target is a player, tell plugin player is being grabbed + SetEntPropFloat(g_Targetindex[client][Grab], Prop_Send, "m_flMaxspeed", 0.01); // Slow grab target + } + + // Call grab forward + new ret; + Call_StartForward(FwdClientGrab); + Call_PushCell(client); + Call_Finish(ret); + if(ret) + { + Action_Drop(client); + return Plugin_Stop; + } + + // Finish grabbing + EmitSoundFromOrigin(g_cvarSound[Grab], targetloc); // Emit sound from the entity being grabbed + CreateTimer(0.05, Grabbing, client, TIMER_REPEAT); // Start a repeating timer that will reposition the target in the grabber's crosshairs + return Plugin_Stop; // Stop the search timer + } + } + else + { + Action_Drop(client); + return Plugin_Stop; // Stop the timer + } + return Plugin_Continue; +} + +public Action:Grabbing(Handle:timer, any:client) +{ + PrintCenterText(client, "%t", "Found"); + if( IsClientInGame(client) && + IsPlayerAlive(client) && + g_Status[client][Grab] && + !g_Grabbed[client] && + IsValidEntity(g_Targetindex[client][Grab])) + { + if( g_Targetindex[client][Grab] > MaxClients || + g_Targetindex[client][Grab] > 0 && + g_Targetindex[client][Grab] <= MaxClients && + IsClientInGame(g_Targetindex[client][Grab]) && + IsPlayerAlive(g_Targetindex[client][Grab])) + { + // Init variables + new Float:clientloc[3], Float:clientang[3], Float:targetloc[3], Float:velocity[3]; + GetClientEyePosition(client, clientloc); + GetClientEyeAngles(client, clientang); + GetEntityOrigin(g_Targetindex[client][Grab], targetloc); + + // Grab traceray + g_TRIgnore[client] = true; + TR_TraceRayFilter(clientloc, clientang, MASK_ALL, RayType_Infinite, TraceRayTryToHit); // Find where the player is aiming + TR_GetEndPosition(velocity); // Get the end position of the trace ray + g_TRIgnore[client] = false; + + // Calculate velocity vector + SubtractVectors(velocity, clientloc, velocity); + NormalizeVector(velocity, velocity); + if(g_Attracting[client][0]) + g_Distance[client][1] += g_cvarSpeed[1] * 10.0; + else if(g_Attracting[client][1]) + { + g_Distance[client][1] -= g_cvarSpeed[1] * 10.0; + if(g_Distance[client][1] <= 30.0) + g_Distance[client][1] = 30.0; + } + ScaleVector(velocity, g_Distance[client][1]); + AddVectors(velocity, clientloc, velocity); + SubtractVectors(velocity, targetloc, velocity); + ScaleVector(velocity, g_cvarSpeed[1] * 3 / 5); + + // Move grab target + TeleportEntity(g_Targetindex[client][Grab], NULL_VECTOR, NULL_VECTOR, velocity); + + // Make a beam from grabber to grabbed + new color[4]; + if(g_Targetindex[client][Grab] <= MaxClients) + targetloc[2] += 45; + clientloc[2] -= 5; + GetBeamColor(client, Grab, color); + BeamEffect(clientloc, targetloc, 0.2, g_cvarInitWidth[1], g_cvarEndWidth[1], color, g_cvarAmplitude[1], 0); + } + else + { + Action_Drop(client); + return Plugin_Stop; // Stop the timer + } + } + else + { + Action_Drop(client); + return Plugin_Stop; // Stop the timer + } + return Plugin_Continue; +} + +public Action_Drop(client) +{ + if( IsClientInGame(client) && + IsPlayerAlive(client) && + g_Status[client][Grab] ) + { + g_Status[client][Grab] = false; // Tell plugin the grabber has dropped his target + if(g_Targetindex[client][Grab] > 0) + { + PrintCenterText(client, "%t", "Dropped"); + if( g_Targetindex[client][Grab] > 0 && + g_Targetindex[client][Grab] <= MaxClients && + IsClientInGame(g_Targetindex[client][Grab])) + { + g_Grabbed[g_Targetindex[client][Grab]] = false; // Tell plugin the target is no longer being grabbed + SetEntPropFloat(g_Targetindex[client][Grab], Prop_Send, "m_flMaxspeed", g_MaxSpeed[client]); // Set speed back to normal + } + g_Targetindex[client][Grab] = -1; + } + else + PrintCenterText(client, "%t", "Not Found"); + } +} + +/****** + *Rope* +*******/ + +public Action_Rope(client) +{ + if(g_cvarEnable[Rope] && g_Frozen[Rope]) + { + if( client > 0 && + client <= MaxClients && + IsPlayerAlive(client) && + !g_Status[client][Rope] && + !g_Status[client][Hook] && + !g_Grabbed[client]) + { + if(HasAccess(client,Rope)) + { + // Init variables + new Float:clientloc[3], Float:clientang[3]; + GetClientEyePosition(client, clientloc); // Get the position of the player's eyes + GetClientEyeAngles(client, clientang); // Get the angle the player is looking + + // Rope traceray + TR_TraceRayFilter(clientloc, clientang, MASK_ALL, RayType_Infinite, TraceRayTryToHit); // Create a ray that tells where the player is looking + TR_GetEndPosition(g_Location[client][2]); // Get the end xyz coordinate of where a player is looking + g_Targetindex[client][Rope] = TR_GetEntityIndex(); + + // Change client status + g_Status[client][Rope] = true; // Tell plugin the player is roping + g_Distance[client][2] = GetVectorDistance(clientloc, g_Location[client][2]); + + // Call rope forward + new ret; + Call_StartForward(FwdClientRope); + Call_PushCell(client); + Call_Finish(ret); + if(ret) + { + Action_Detach(client); + return; + } + + // Finish roping + EmitSoundFromOrigin(g_cvarSound[Rope], g_Location[client][2]); // Emit sound from the end of the rope + CreateTimer(0.1, Roping, client, TIMER_REPEAT); // Create roping loop + } + else + PrintToChat(client,"\x01\x0B\x04[HGR]\x01 %t\x04 rope.", "No Permission"); + } + else if(client > 0 && client <= MaxClients && IsPlayerAlive(client)) + PrintToChat(client,"\x01\x0B\x04[HGR]\x01 %t", "Error"); + } + else + PrintToChat(client,"\x01\x0B\x04[HGR] Rope\x01 %t", "Disabled"); +} + +public Action:Roping(Handle:timer,any:client) +{ + if( IsClientInGame(client) && + g_Status[client][Rope] && + IsPlayerAlive(client) && + !g_Grabbed[client]) + { + // Init variables + new Float:clientloc[3], Float:velocity[3], Float:direction[3], Float:ascension[3], Float:climb = 3.0; + GetClientEyePosition(client, clientloc); + SubtractVectors(g_Location[client][2], clientloc, direction); + if(g_Climbing[client][0]) + { + climb *= g_cvarSpeed[2]; + g_Distance[client][2] -= climb; + if(g_Distance[client][2] <= 10.0) + g_Distance[client][2] = 10.0; + } + else if(g_Climbing[client][1]) + { + climb *= -g_cvarSpeed[2]; + g_Distance[client][2] -= climb; + } + else + climb = 0.0; + + // Don't move player if rope is slack + if(g_cvarRopeOldMode || GetVectorLength(direction) - 5 >= g_Distance[client][2]) + { + // Calculate velocity vector + GetVelocity(client, velocity); + NormalizeVector(direction, direction); + ascension[0] = direction[0] * climb; + ascension[1] = direction[1] * climb; + ascension[2] = direction[2] * climb; + ScaleVector(direction, g_cvarSpeed[2] * 60.0); + velocity[0] += direction[0] + ascension[0]; + velocity[1] += direction[1] + ascension[1]; + if(ascension[2] > 0.0) + velocity[2] += direction[2] + ascension[2]; // Move client up if they are climbing the rope + if(g_Location[client][2][2] - clientloc[2] >= g_Distance[client][2] && velocity[2] < 0.0) + velocity[2] *= -1; // Reverse vertical component of velocity if rope is taut + TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, velocity); + } + + // Create beam effect + new color[4]; + clientloc[2] -= 10; + GetBeamColor(client, Rope, color); + BeamEffect(clientloc, g_Location[client][2], 0.2, g_cvarInitWidth[2], g_cvarEndWidth[2], color, g_cvarAmplitude[2], 0); + } + else + { + Action_Detach(client); + return Plugin_Stop; // Stop the timer + } + return Plugin_Continue; +} + +public Action_Detach(client) +{ + if( IsClientInGame(client) && + IsPlayerAlive(client) && + g_Status[client][Rope] ) + { + g_Status[client][Rope] = false; // Tell plugin the client is not hooking + g_Targetindex[client][Rope] = -1; + } +} + +/*************** + *Trace Filters* +****************/ + +public bool:TraceRayTryToHit(entity, mask) +{ + // Check if the beam hit a player and tell it to keep tracing if it did + if(entity > 0 && entity <= MaxClients) + return false; + return true; +} + +public bool:TraceRayGrabEnt(entity, mask) +{ + // Check if the beam hit an entity other than the grabber, and stop if it does + if(entity > 0) + { + if(entity > MaxClients) + return true; + if(entity <= MaxClients && !g_Status[entity][Grab] && !g_Grabbed[entity] && !g_TRIgnore[entity]) + return true; + } + return false; +} + +/********* + *Helpers* +**********/ + +public EmitSoundFromOrigin(const String:sound[], const Float:orig[3]) +{ + //Disabled this shit + return; + // Amplify sound + //for(new i = 0; i < g_cvarSoundAmplify; i++) + // EmitSoundToAll(sound, SOUND_FROM_WORLD, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, SNDVOL_NORMAL, SNDPITCH_NORMAL, -1, orig, NULL_VECTOR, true, 0.0); +} + +public GetEntityOrigin(entity, Float:output[3]) +{ + GetEntDataVector(entity, OriginOffset, output); +} + +public GetVelocity(client, Float:output[3]) +{ + output[0] = GetEntDataFloat(client, GetVelocityOffset_x); + output[1] = GetEntDataFloat(client, GetVelocityOffset_y); + output[2] = GetEntDataFloat(client, GetVelocityOffset_z); +} + +public ResetAccess(client) +{ + g_AllowedClients[client][0] = false; + g_AllowedClients[client][1] = false; + g_AllowedClients[client][2] = false; +} + +public FindMatchingPlayers(const String:matchstr[], clients[]) +{ + new k = 0; + if(StrEqual(matchstr, "@all", false)) + { + for(new x = 1; x <= MaxClients; x++) + { + if(IsClientInGame(x)) + { + clients[k] = x; + k++; + } + } + } + else if(StrEqual(matchstr, "@t", false)) + { + for(new x = 1; x <= MaxClients; x++) + { + if(IsClientInGame(x) && GetClientTeam(x) == 2) + { + clients[k] = x; + k++; + } + } + } + else if(StrEqual(matchstr, "@ct", false)) + { + for(new x = 1; x <= MaxClients; x++) + { + if(IsClientInGame(x) && GetClientTeam(x) == 3) + { + clients[k] = x; + k++; + } + } + } + return k; +} + +public GetButtonBitString(const String:matchstr[], def) +{ + if(StrEqual(matchstr, "IN_ATTACK")) + return 1 << 0; + else if(StrEqual(matchstr, "IN_JUMP")) + return 1 << 1; + else if(StrEqual(matchstr, "IN_DUCK")) + return 1 << 2; + else if(StrEqual(matchstr, "IN_FORWARD")) + return 1 << 3; + else if(StrEqual(matchstr, "IN_BACK")) + return 1 << 4; + else if(StrEqual(matchstr, "IN_USE")) + return 1 << 5; + else if(StrEqual(matchstr, "IN_CANCEL")) + return 1 << 6; + else if(StrEqual(matchstr, "IN_LEFT")) + return 1 << 7; + else if(StrEqual(matchstr, "IN_RIGHT")) + return 1 << 8; + else if(StrEqual(matchstr, "IN_MOVELEFT")) + return 1 << 9; + else if(StrEqual(matchstr, "IN_MOVERIGHT")) + return 1 << 10; + else if(StrEqual(matchstr, "IN_ATTACK2")) + return 1 << 11; + else if(StrEqual(matchstr, "IN_RUN")) + return 1 << 12; + else if(StrEqual(matchstr, "IN_RELOAD")) + return 1 << 13; + else if(StrEqual(matchstr, "IN_ALT1")) + return 1 << 14; + else if(StrEqual(matchstr, "IN_ALT2")) + return 1 << 15; + else if(StrEqual(matchstr, "IN_SCORE")) + return 1 << 16; + else if(StrEqual(matchstr, "IN_SPEED")) + return 1 << 17; + else if(StrEqual(matchstr, "IN_WALK")) + return 1 << 18; + else if(StrEqual(matchstr, "IN_ZOOM")) + return 1 << 19; + else if(StrEqual(matchstr, "IN_WEAPON1")) + return 1 << 20; + else if(StrEqual(matchstr, "IN_WEAPON2")) + return 1 << 21; + else if(StrEqual(matchstr, "IN_BULLRUSH")) + return 1 << 22; + else if(StrEqual(matchstr, "IN_GRENADE1")) + return 1 << 23; + else if(StrEqual(matchstr, "IN_GRENADE2")) + return 1 << 24; + return def; +} + +/********* + *Effects* +**********/ + +public BeamEffect(Float:startvec[3], Float:endvec[3], Float:life, Float:width, Float:endwidth, const color[4], Float:amplitude,speed) +{ + TE_SetupBeamPoints(startvec, endvec, precache_laser, 0, 0, 66, life, width, endwidth, 0, amplitude, color, speed); + TE_SendToAll(); +} + +/****** + *FIX* +******/ +public OnClientPostAdminCheck(int client) { + if (!IsFakeClient(client)) { + PrintToServer("Get access"); + ClientAccess(client, Give, Hook); + if (CheckCommandAccess(client, "+hook", ADMFLAG_GENERIC)) + { + PrintToServer("Access to hook...."); + ClientAccess(client, Give, Hook); + } + if (CheckCommandAccess(client, "+grab", ADMFLAG_GENERIC)) + { + PrintToServer("Access to grab...."); + ClientAccess(client, Give, Grab); + } + if (CheckCommandAccess(client, "+rope", ADMFLAG_GENERIC)) + { + PrintToServer("Access to rope...."); + ClientAccess(client, Give, Rope); + } + } +} \ No newline at end of file diff --git a/RtdUltimate/rtd_ultimate.smx b/RtdUltimate/rtd_ultimate.smx new file mode 100644 index 0000000000000000000000000000000000000000..1cc2d677c4d8fda9397e6b02c8807da436ee692a GIT binary patch literal 19631 zcmcG#g;yI<*Z)h9ra+O>0>w&kiaQi9TA)awI20)E?h>rHYti6R+=~WEad#^OcL;8Q zJ|jg#L#2(T3k9GNqHN=T{3!lU{2mk+ zuLIDMG0@P)Q7p6#Kx4*7TX5wao#^L1t-Ok$7^}pa@;(`JP6E|xQ^Z$Z9 z%DA|>S^rPp|B}7Ao0X&4|8f6s*Z&?dcW}4=KYllFCv!7%i~rA_tGV0%*)z2>adrKF z4_a88+o8g7n0>e8u&}oK&$$0VJ8OskMQaBO$NzEu@7VwCVQJ_1-Nf#HyE~fxhrO0h zItl!~_O%L%XN5)(y|en-7!fTc8%q-!I8`8p{>CQo`G!$(7=v$8rJYCmDjt0lKZ|DN z*Sca7V${~z$l0`5!rt8K=Dv=Tn^4yr@pG^CW&by2R^S@B0ZK z=l1qKd#acBQuJ~ZYMJYu%j+tTQ-hP}8KZM~;tpqhggFF_4JVt}$BJCQbfSJ%BtwYJIUC9dfJa*4K1}du~N-GK~ zD}73<6)LNCN-IPBMhD<>0C3p^xa42;<^$^GU{oyyHO~h%PX#rP z1v=azx_AnOJL^U zhzhGqUaV)HvU}c~@MI>Hl`WN37NwOwm6ZskRSte*Cw^lKr4^9MN}kHp-EvXD_=@0G5p35{KjuUy^mf0 zNqd;eY7W2A9KZ1=hJ6l(eFKJlI7Zb-&`lb~Nd!jKI$OBdz<<@)kksG&PfTIT|73#F z0VTp);4;mB73eVr>JJBLok~`Cf|ggnks$iwJ<(();Bum0Z3e zKHuXs`L(h@7hjlfm%C&S*Iw@Lhz+hxD2xc{id;|)Gf#WfHyyD3fWOFn2#8rVo=Y2| z*XW(OoZK4VHA*dgR6!) zwYW60LgyLtmt}sudcx71pr1DUp(WxYvHd{H5|A2J+WH~%V|%1s;tSE)YS%_?v22D3 z!WF&2AuezzQjG%W{AZK1HnvJ3IbhYef~|8rA4mSF7@K*%Kc2i{_M-=^xMR=S_pfn9 zEZ@tFUCWHqo^FikIw3q6bs%+FfKEB5hqZfQ? zVqX$uRS9zstF(_Q_e5DGuFa9&T5B(HG9NXXnzZu!Mw-0JNjT>>x0>#B*iRQW3mfk~ zvF9p)EN9&L1bgS+WE}C$czw&i8HzM(k2$Q^O8<4%VBZ!O}h}Ve6M=Q_96|NcP{@(2mTXA zUT{z&syuL`wn*6uK}>6Xri-}aRKk4Kz}jsvN`0&E8E^+fP( zPx5|?=jzLqOl0|y77Xd%CM3rXVGZXNH7(>fDS$(Mvh3M4_3zm{?3{(C`8~YuBvEb8 z1e4($`b{$~ESF52BM5kFqKnBc2A?d@{MoeJiA5IqfMI595RO?h%W{^&LCd9zHqokH z*WyhidZ)&l?_;2Yvn%gZf$@YZ_lLacy${XTueyF(lfE}J$m=&KC77}sTkJC^G4L&9 z^A^iL@oi)OjJ3R%df2{LVx*G&3GB)%E`*C@sy|y9=;FdfGE*SS(8sDr{UQNd3`ln$@8ULd6nY%&O;`#S)PgWpkl$M(YcC!(C&8sNOQr~yAYn%@|o4~ z9&NZG{nh+%Bwj70E3|;yu=+vV)D3$6F1xF`LSFyK=cL&GR&teuHzl^o)XgW?u6Z$T zDviC_)~$`*!>W-%{~@5g`CU7^*1mCcs!?WZhqCVQ%z%HXz-jw4q0^EV%UkqFU@D%} zB%5Ov%bs^uj&?#HV$Gc>E9AjBcG|kJCZ^%Ks-nA~g{5pSUjX)g{bHajz_6Eb1$$ZF z<5%a(F~!&pBV_KBimCDz|20IhR|AYs#~tf7v)Hx8VP{XBY|`PXDY2r9wQAZz=3%qt zn!$2JKE^aZb z-3PvT3!|U+W4Dq;@V0)7T3enDkPG<;Fx6mt`6AQ%Gu*hkzSt+#VBdWSKA$1$apL== zzx=RL0~^pCo?ZZVR$`DNdjM(tUxzxyz^z6ZqTsLo-0l-4BN^a%xhx5PYTAeM5%@47 zKX}wN)&8V(Y2FmxtlcGjBoAs>>dDcA0GHn$y4Hke|9u?DW`lmnd~tZ>g5;VPp=){)a5QLh z7!(=O5iL6gnNVP~{{ssJ@DX#8XLf~+dH)_3kQWA-!zqK@UZju6n{jx# zS2-@?6;tIMAL*lG&Tl5-8jl{xv7nJs-;u$YYL>?zmJwwntZwro=_7E>ccNa}@C^3B ztV!a7WPl-OwfmRbESQdajVrIms;bUS0WJdB_JCV{M?(6jZFv2irE3)n8Il8Ow9_Sh z)CZTV_Ib9ilP)hW9R-8j_Dko5-83LxbIX^8XUNTP5sh;?jys7?-n1xc*B&F^cm~MT zg~^j|By!v-MHzkS8)#bx>$!DLKlQ38-)jF}2k9*II^0puud)AL zr@oN1Wa;{gg=DSiNQx2!(}Je4Bn$;qbBcej8{MA>s-NRk@4`%uj{C5Xp{ckU=k^W{ zkRCmWc7rp|bX~Y=de%b|0+lG_@*JxBuz-auY^QFzs>!-<&le_^I1C1@bzslyypZ5W zNRd9m0}Ad9IqpD=0=f?qSjhBfw)?EZVB}wdO0Ondgc`HiQdj99WKgH&ESmlvtE~LOBRA!!r{P3@Chkcfdm?!!HphozdqLDA{^|WC`Duu-$)+? zbANLaPq4bxA;GnNx9F((KHI|?3GnCvU4>qs_QQff+Jl+M@1&2(T>;F*oSr=pyQQqO zr{iFxxO23*L_4`e1=5}4PO!s17Rf{U2!lK|Hz83{!^-9mKXC)5+UM&bhG!7NM_yYt zgEL6^iBZ<-ECi|tS}{EHbkn(PshEsKdQDCvQSv-=U7yykU?C?0EMk%Q8rvutk&&;` zkW)v&NNR}r7;^n3$76gI2`CX4p>1@j|1g7vgiCl&{$~VZW;U|I1Pfh=a!rXv(Bh$(;`3D4_SBnaR@g zYr#c;*&nN~5vV|j#q_G*xCl*Xw#^cl;|^-y#Y!x38jKveZSu9;YpXT7)rE1&wXP!{ z?_6??m_Ms zwzDHq1B1d!^!JQ7?k2LVbHMb5X9FT^@P=M2)>_Hvf* zZ}CYV7e=8roe=jP=-ixnA8M$=dyp^6+-HceJ)zc?X*hoXP$dzGT9UU-w}Jzx>kg_% zC&!)Vs^CaHB--FE-t#f~8qtk~3^Sa6O8z42uqI&*n?_wqzIL{uCYY0E6nB&eD zU!~zx^>xnjQwEuAsYk#U)YU`&1Y;ht6%6tJ?T)l*#YGHg{j)ofK&99@QBQ5kaR<3q z8Ufj|x?Cb=$dRaIVb-3&h4u_k6++oz9+{=8x0n93E@-_J5YiI>K|ZoU=JKKXqcfXI z9G@TyR-7;!chBVm-;x#*^V1`@)rH4SO^dn{iqJZIwPia~mrC9hs4XnM(JNgG!GA~r z4_8sI=Im{0P#>_`A?dX3lkZw-!GG9g^$J3LuGsDjG1p%-6%15d6vc(e=a{3Nnsn2wF1K4v5cQPvbSP@*cJQc`<)=|}iTX~?)ZZ(_v zw~D@ayxPyse6AUS`?oLR@he9&QQp$N1@rgG)30WI7|C8iJP~1uyHA6E+@4Y%#7Ixt ze|@_))Fh6MT`W9^Jj3#bT$YcXtzIoP!!TRehR@hH(S~{8M!&3P(^sP(Ze)=H-=8qD zYb^6GJqa(K2B$`kI!>f2PG6E;foHKmjhn8G%_?8-a{?q7PvCcb8KBG3&G-Xo>(3`> zt57FfQqUS56Vjd;{-!tpdbxSkNx$M(bdx8cCtR)B!>xxL`6{;C67T>^UED*OU9-;x z!01;fZ(2m#?b0~h)5elh&2K!DPTDP7o^V z!U)eNqx7$G$GnFI_YnAmw&fN-#85Gy|3S;^$^O8?fLv`U{}m4&uT^Q-p)j3so(TX>HH;>hDN`unaU=ql@ z7f0#-Ur&Sb2#u0SAKEU^b{xh{WL!?D=O|B%=FJn9U;$RD* z)lGg|$NGS1&c32(Xl!9ug0xd)udGtv9~w-75T7q(AAKY|Yib{KClgx1?Ghyc%R9Ex zX%D^z^NyT*lW4uWq~ zk?!r+W&$GD4T6gj(6R}biZz1fiBSz??+1q^E`b`PknEVgV(n?5#%r@f*sjGMv@{tO z{q1ponda#zv27s++dT30s~=3jBneTXPmd zY^S=IvPY2&Am%KjuUf+rK16=>dzk1;ovG?KmF(a$kArk(P0&fA5(YvN3AUHoYu#XqsE7 zpyzvX@}^?W(C^vGm+Cn~=gehi@TN#@lF2RA;cdK@MJs_D`L>PYKi%r@iq%QyqxO~a z%R0W~{mzbQ9&A&G-vXYkOjXWNiG-Y3%^aQzg`DWr%ypi>Xf|!ox^3oNjHA+9Z67xl z@vwD=eF!<(pFccBnZ=qp|8>5mE%8*?Aj@1DNt49iSx1TH+LI=cKYs4q0YC}5VbD>b z=$~dMC*t%OsEgE!m<#8FUHh0%_GIeT|2wS zsMhM_7^)?3v_Rnlzj?kIsOq5Noh zW)^=&e94Ka#ay*wnR>Z3E_2Qf%%OeTCzNg zU1I$UkXzMIcC}kshk7U}H_U13t(ezOcT2OCJ(VYpnYIbMN3qi-fi;azpr%bb@cPS` ziGT>xBKO%P=2L(S2-=!;X&ZMv7s zZ2>Ttb^OEll0G?><6Ar4LQKv!^}aEG=JsA2|`s*__1yIjn0E!J#>o|l!x>j zR&_ryZ$I*35lBMz#1D*<4dyoS^#-`JnDS5Z-hO`6kN1D{G$?|49dALlXjlA?L2FcL zpSQ#lM5vWi&%5M6U4@f7wUfms#S`Wm@^;Cu+a@6*apqn6yJr94!iUcCT+z!R5(GDZ_oGx$SL9@s&|G+Z~<9N#=S*!8ph?R>g&-rTzJM2nu z=@|5C?vdg|so@`P=NBE2k_u!6tc3)Ysv&{?NQbftfva383ZEH&cu*tF3iOm0*#%4e zl?_aN%C1PIfmH3E80mUHF(2tjjF8X9*T>m_7BV-dC%iwmQ#|FnTk3)Y>u)-{K%_ns zXUUiDo#}@0)JILHU*E#!?ym2EdXLhqkgm1MF_GWPIc6-X3#uY-MOqyS&)EkxZxyL$ zZbBfxXLw6}27GSQ#oKOi_(2Cp(g&{AH$9J8+a3`AynuThO@f2P&s|*yEtU`M&IBJG zb!vf;Bf6j<4?GV1=rtMQhJtZ zyHhRZA4s;3=ad{6Fs=SPfZMgdJ>CxwXg-><*1alo4D@O2{qdFxekETj@1CP`+t|<{ zUc6bNa_qCr(thu?+m&|X8oOHANl@<92J^0>@Xo%8>7%~fJ~vGsFq{auy0A(gE1bZ$ zgRK2-g279I4v|5K8|7xP+bYW(cX-Jb#>|NrlP*T^|sLRZzS=o|`ywswM~# zrz+s9)Y5SLG;PnG)R#P$c*F(tX`RbNetR^5LX@EQ!Tc&)P1ii%^ar+@+zsm3pE^Uk z5ZC;c;ED66f1Vb$5Y5`1AII=bAvIVm3geRfw9axcU{I=9Ez99}+wqbzfV)hcP*qw3nZn`(v>b0x>ss zDJt}&ouxNuAU(#Kjl~Rv*z=)83UuH9zE@RpYnlSGvrv!@NGlZbkmHqZo+$LjX!8R% zE&M*Z^5woJnb@=vwd&t%ZZ0}&_%jul>-dr9Z4{sGK}Mn(^O8exseI<2urvsZB9{Jv ztQGcu@9JC6`NeYf>==7|5o;3qV#>!@g-F$DFdG;;E#CT_bs)s=Yb|u@Asp8Z zj?>`H{PvbWo?Hb_fm~(G!3REiKIt^ib={NIu-fu3l)N`-w&=(@ZR@MvkPA!IkSk8h zVrENH3YV3&a&wgn+r7#LADQX~--niEvmqax(xLXa8FTT@&q}9C>IE9pW`iE{)$bmU zKk*RnaX4jTMQx?|xwf&8$MtJwXN^1aF_6XT-wPQEgiI$u@8w?j3_c&nAu~ytBF}Fl zd86QfJ}}2T{5#2-Oj|j@xjJ{tX4}j_v!<`yrYQef-ThteFO2iAR1u|z33}>tL0-S` z|7y4wZT`ZaFR(T=c>TPEd{<|bnm*gi-u5Mc7^m+tW_|%XX2*oDQEHpXfHt;d3}>!q;lx2f5Iflu9?hLI{$UqD;8O420bSp{EQ%;D(V*m zHm6A}QAXSqzLa)$QIJ#P1ogz|A98iN)Tm%;Grs@!y>Uo@GL*)9+pgLB;N#k%m0NK} zOU9MQk^Yqbch&7d?H&z{em2B@z%ZG~HxzQ}h zdIMr9v0n`{EJK1aw*QfJb1GG?NG9(KUO&#fbPyMLNEa3@p1KL9F@2Q{|2$uK5jHD& zg&qc@9k!$;Iz@yaCT;h#Whs|XbWcT6`ARM+b&9Iz3|e0{SpNitrAqyIUbQ0mn}Hl# zT~CXB<4}$7GdYI6zI4}d)V$Yke`P+!=nfh}z9bgjUC!JXiYn}o%`Y)3k^+Q@wO>22 zqgwLN!>V33U#~YPVBm30zlp2n-ZXeu{3`!Uac7}V-&CPohkP?X4HL)Oia@657;BSt z>_**SKv1^#BOOt?ed>W%o|tSjh0ni;vb*8k?%{-}7D+|Ap}-h<1)7Q&9x4JEE3Oat zPh{I(lvVUU6GDc5hrZ;hSm%q4wQ*yqA}=k*x&3RIq^y-U@oNfI4tDld zDxv6s8?_(iUzc_XU`ZwZjj|F|yj73+#ENaK;mVizl}OQ5^8UJ&Yp*98!_|r2PVf&Q z#uR0sLg+@8SLuSe<-p80th32C=E9sz52E)(#vL+KI53RCs1on6+b?lAp zmEbEeh18K28Q)%U9}$=mL>dRKm{ZP#Tie^k4142-XJ#tvraLqIrnJmYKL0AODX;Ez z+89OQlg*Ou%%8zijTy0(hUToN?8ah`oscV_eo$mmmXT~d*XUFxn>zJfXGfl%&zxGA zL6L6qJEn9Mds`Z}vjNAzSgLV}Y1O%o&WNqMOtA**$6`~n>kNC7Y=)<7i-S@!M{F#* z<;HhZ3Ic!gv&=;k?c(KkGOZ&8_%MlRKE$)14DG66jHuAp3OmWCU=cgNkAAts{hcJA z3h$+6*w4@&FJr8}xn;}2ddnM8lEBy2^&B(5BwjBp@Dx|AsR@%<5#)(+|BaQDcCBnm zTnp)s@v8W@H>(%_>1l&r5Nwv*8xiuLTQ?pz>YQ zq$1Vbbe>4Tjf?C@VkCccys7Qqf4a6dgYmh0isp+aB(-uoSj*2z6R8{p{y!D!_? zH}?(SuPT)|q8)sr$Pt+odtbj%M%i{G5nzO z$WPi>->(q7J@@1$pDVmxN54-9HP1=7-=$E?qQ8vLZVvnNaW?s9P!75agE{G)%^f}V z{(k7M7NU7sS~4Azl8*!na?*)KHn^iT^R+CH@#hrW% zXyS4i{wDS;Mo;v21;h~o!=F3np}{ZJXx7LXWhR`C7k)?`Qw4Rx4GzYz*5ONQhIzpxDAmuN#GAEdeq{X$oj5yqdpChc3Lx1XV z$n=@f43|Ft;!{P~M=TWsQHiKqz}-Nm5Eho;a9=#5iE?;daK?BAB7cyeGOW2W``
!w|xvX;&Vj=FJ10FkWN%r+;HZ8fbSj(BOec3El0Dq1|SG5-aWc-h|OB| zhm`DAGmAMX-NC;}>QmXD`>VlRCfCDBVOArd{gTo=e9lBx-VoC7^trU6N@r}nuc8@~ zuJZ?N=#pakSB^01bcALJKZO+}UfpEi5&epjQSuiht2DCz`-%s4m1bp2e-JP5kepA_ zOC5FhN=}-O=<^*0LPu!Q;qTMAmC&)O0EJctuZ8y5)kNkuO~DmaylkB`mUNuRX2zTm zL#n82$T5!Z(zUVnWkRBE+2hha!fY0r$+cqLA`>C*ksL& zUjxH&&TR}bTkkTeYt!44tl}6-hKnk{cO`NqsZY24D zN6B$xq`?c@J#SPQF!C-21w-;b5L%4#qP_$!<^m)xe(#0E0XZ)_%yB0|5X(51#Tm2L`y;Q_I5>eZUuQeTf7 zznVR`81&C}*9P>q&;RJAD*4h6obu;<%clAY%=Ri+Bh5MTyTsppU$Gp*p#|Tr7Do&j z)XnwNAKea%w-HbdJ*FDhJS?01J=+6&`H#@WTc?TJh^<)v_+kD(*I?1Dsw%mTRp^`N zKVsM4*iwFjdE<>C1k$MZ-{M`~c05z5q_Y8ojDW&&BZu(8^JmYY3P;)0(bp>rf&Qh` zhI;X{f<9dG_QxhuQVdq%~_fCdu zq5=te;PQvk;xAE-a##zEa%VbAWI7wkec-bvs|WhzmTvg?L!}K)jso}@YGC>kmuLPY z`N^s{vDly5>ERricpRxm9k#MUleHJ8xlFh2pQ@rw&P>P4t`@kzLvIUz=H#u)U;Kt` z5Rr8+cxr@P^ES~?1_L~|%1@2R1WNnnc=sl*!h;u+9WoRuWLC0#-qLL_>OKiHrBZPI zNY{E5JKj=kSD`6M))ZMJE-uOXa>7%6Gx$StuiVk)N?^?p_bL6f=Z++7n>}1^>%Tu3 z%)-_;^RzT+=p5~a5%lX8$9nD90=V4t zsu9iYp}*g9EzMuQpA(LsW6k(R;!}@1Cvi7E3)ouXU{>gp^(p zy%=8FpRg|@a9WU};lMinb7z336YIACI1TI3AXtR|B&*X>@|FzU^E|sSfl?9bq^E)WTA-wxVOKPzH4K?K|9U60D#bblb%@y zt_FfIkI^4P2}}V(Qv;AfJ*=Oe;@iCg<~8&Ya#hbL3B0I{IhPS{*15N#I1wAfH4k3@ zJOQVAacyYrTyc=13qkC2?e0@jvg-EdPob3d_o0NO7!Dn8E-`;2J@-l1r##h|j8{Iz zyj;&m$~^^k%7-qZz3E@~OWh~MIj1!yJXk=>0<@!HJuw;Q z5c7Kb=aN`-V&k4X7q)TFBpQD92$+DLzhEcaq!k7Kq`!I=YKI_ z?xlG4xtEs|^}yOMELQ2dOf}l~zYdK}v}AjyywK0R1_@o!?KNGtK1Hb2D424RlGX~_9I}w%`>N?m+0=x2Wv4lnmNx%f zH0wv*yL)aDa|?Q*n!4(xvLNSQ`Ib##y{-jQ5n;dj5w8tR-;g<9ZmLj{xPSBe@-7Cy zP@vP_^#xs|+-#Dvy$LCE^2#5bQC>6f#$P%8Exdk%<7VtHMvjdPM-&Cl(z07}$x|hp zk?X^|R&M5h6d8APTzHmr!hYWK6qo0gnzt?2SLg-5{}(eWmrEwn{?a*`tD)|t3T@Mb zlx(m&4ZGp1PenG0(j1?44zT2StT9{paF-|zHCAmjo6%N2^Hka8Iz~@ieS2w6xf4g% zv_7Bd6VUlXMmqW$otd3Mxv}J7m&J$4>~HyL+KpNfH;dx1A}i{3XpuSxwWDu!N%Bm@ zrUPVsPO1~_(_uX+XF1TbkWtWCc+1-zq4q@zFa3!`tFoxlZ*%)S18z)Mo0U7Ox4GWe z&MqSM{7<$->NB)Nw23hbOj4fYv^2gfQZE#T8I43*EB|Iw@<%lnHGVf9o=awDq6hQc zSp5sd9-@?S)~N3EP#p5Z2>XZ;IT36o`r4YvpD^-aUQI3KbEXiMv@q04hIs5(^VQd( zqWY-!#0=ZMkmHm=>c$ZLD&|xO7%YnKZhQ`uVP=T>6oc=k} zKPv8IPW{U#eMI-*=ve4M`z1c&vw0rjv#=93{0LO3kL5_^gNSMm4K~ zYCp-6ze~Z5`GjsUXA`np7=y^aU{O?3`jv@s-e!fDqF}Ip9=0pAQeeN2ANoIVR zH++0>C`tcD0CVLCd+H57pUL4XWl`>(;^dN)+3&~6n$NI3sNDWsIq8^5{`ecE^+Lmd zPi~8AvPT4)s_4C4P4v71uWA=Q5t*7ZT|%JG`}Yuhb^Zp16az^NebSvinuqV?v#0N> zKE2nga{0I*_lovSRJ4`o?Cao912Nr-bSl5NmpH!Xn@Kn5P~o-Ef)-J~b=|Ts5})S{ zCq8fd%k_pKd4$VFvp%`3o~%DVn(s*47`?9W zEGyPw71W}~P%g;l&y{3g4-z;g4nDaR&OAvvGMgf7O<}fn9yV}UeO)=Rw8(7EUjOl+ z+~OW~^)5wTtn(sm7)`@wFjXU76Sus|3=kwvgjd8Y%cD-MINK76)egAE8Hwatdd9+0 z{PK$%sfd6~bAS(*j=2v-!ZO*g{!1EMTZ`hB-f~Q9<@ZWb2z}giI@v7Ffg(r1MQUvc zzL(>tVUXoCK=vtE$5=UZi}p<{J?qw#B%zYv`xlW}q+cjXv#pqCjdA$tQmobmOC(og z0>+~>Ecaw>daDvl?4rtlmyE}n*$f2#1BTKpeBqt1kEo73d#Axs+^Qbe_{n?W&qarF ztR2H_wE<9G?^S-GERNXgFCOnr&# zIo0R;{Jw3v#-j0g6D2G9G<5}NjddKjUkfhGE$ByP=oN$!B~(9St6##N4#qXTYF1lt zlSwEP)5qs-?%W>R*pHI@&G9yZUWYhRwn4{rDJ84CHib`T`O_@_K%uQp$a^ij5f>bj zJThnNe`>u2bshzSKPFBxs9qoVLiGOHfM-(iF2;D!hvtPM(6AG^89WhJ!t}$r)rLXU z6JavLpBUK0;xdS9y4%#xhx_}^)uzkr!mo=rqj)rCT&L3Bh~D0-Z&@KP%0{szw|JUa zD3#yXG<+0caQS$Iqe+XFX2?SrMIWI!Y?k;>&9*?<;B|i@-xuO$95zXHfl*;5!osCS zp>A>Bq{>)%(_lnmXLVT6NVEn*Nr6=$eC>}@t5t6S+AK9j;};gb`j>%8k`^J}EqP+W zVglqn>S0uIt0mZfXo=C;JA~bzNkz7?u(cDT?yA+BHfkn{Z+6Vi&#AK{r-_c*7Ab^; z=INJ3%G3&=LMa zgi==j#q<(oI5cZ3;(o14&&2iPo7zivsdvxuz(2e3wUqdTXr>4WK32$PGKSLPZOrF! z2c;Ne6P4z(lryMm7-E0eE-mK~X8QU}Ym-lNiSoH%m~?EZ?IF2NQcrNsuG{t073`?^ zz%P@W2@h-pqwOH9Wwp;g4Tk;@J90M@Z{B9)~G)RrBL*6789p2Q|ko z^X?Rj79j8$619DmJraxn!M?lKF~1 z9$hY85it=nsHibT`S-$A=tJ3s9c{sHubmIG6h(w1w?Wx^729q8F&tMrBR*l<_g}%l zojq-mGv@T2?=jnFDfx_KL&Y>1G%Vrx)s!V;q(0h=^8Da^O(}Po=0R;a_T6b$Q%!MQ zr2uREhY3RpB34wY>Ajk2f!xE|-Xq(uHFvq#*e+joBe8h>eh?-OXMeo^m*KVJ#1d_s zdrW{$$TEJ5CpBhZYQABtknxkVkNtFHBW8B4LnmP8`Dfms>0i@v*(Sw%jDeijsk^(R z&uLKKon%WfTK&$X!a2n0YbJJtsCZsTJ>a_&N{8cJ<-!5(@1(=Ir4tb4!awt+GhTi& z${lbP&Tf5u;C+}EhHuT>DMz(9X@XY_)&>f?J(oHVJ46e|cijKFuYLF~9N&3=5$W%q zCmsGld)oK*BPFzKzYyr0jqh3g@j=UdQaW6;KEQolI$TU6AwZhyaWbEPN(Z4#g*LT8 zU})Sf4Bm2k!$WaUQ-MJv{6a78igT`qkV++Q<@>QNWoa)Bd5w*`noPKioAmc+VXlJS zf;qQO1^97R_@}S^oMeEX+^pPM)-mXXKNU#RDb}a~72UjK4$6de4*gPR2r4ib|9pAC za-WnjS9_p1?2g2b-7n~lpY3@?#ZyJ zyOVw@#>m5`rbhqLe(-LehMM}B*ya{WbgM$?d{jWL*@La#e9+Z7U@Cx`nkdn3`s0+N zzn_i_(B941?ax5CTxe-XVF#tSXaQmdp#Bk`n$|F-7pM?g+Drd|K)TiN3)X@0K^vvG zL1u0*@H4OLT|&7)I6-FG_L<4d1*N!C0fwlso6Yb>2-CEJ+g-}w21Xg&<&H3_AB7Y+3}@eXT`@IfN-jb_z~@2RvbYo^ASC9$ns9YB*6dcu z{=}>QK-zqD6@29u!oF&vBw?-u;hCMM)^7{Y@$ngGJ+OB5pKje>NPOcONeH32C(BXM zkNqn!IEcZFbm8AE^nxeS_&MA}4-tSze7}^ORk`YtE=mI`uzOaA2CBaZ9kjT$?i%oF zIi-=cGyU-8B5n}sO8O(_%`t-AXu~4cF=Bok`?U+C*oR0M;U@nf5?-eTk6o^Epc)sM zx}9_2t4r|At@_cil`RqMnaLTmzPbUU(`i858Jw=Rq|OEaRqNJ?HDmXDz4im34w?R< zP$qkpyNIr256Wfpvq!qzLN7#%an-f-v|6C=z8=#$5@3LTry6Jr0Ac=K8X!-K+dyVi z4i&|{PCM8aO^6h6is)NPLRj4J6HDybvj z&`{$M^E8W5X2tVDU8vXhH zyS8A!PXZx~Gq&!Xz!1O!dM@5?vNKAQR|vD#l4}J2Nnthr%F?s$b@)^&UiU`e3>q#V z9T10RCz9p)S2=JGaEi%RP(cy62fv%R_$DcWop$<3Qes^;Py@hOl56tn;(%J~J963-%b;r|<(>-!9jJ>WyZ4^lc{QdD{a0O74$IlhI@aJQb z^ey@~EFmIXm`%4!_xEnSZrj;$UG(3%)%s`-7;MF?ELeWmKM;SpPR<4ZOaPLP1SuG4 z=qk@D0omw_FTB_dP4aUHosQIU2kfQ25jW@oY5lmhxx08i^e=RtzsbKrTa$gl=*a5N zIBRqO92^B>1VRe~09_xqUUXh!kXv>mm7mDRFTZhT@A(cn<-(dbL??U!;JgO_xWF6e zmwA^Lkz4#2I5G8zCa&s&euv)ls;we-o0v=T0gzBl$q9Us7=Ug^bN|dh_6S3`I(44( zogu}V6Ni4dF962ikN$M`Vu)!SzZ<{1X37hI;5?*WSD`jiCa6NIvBu)AU#3u>VHM1Pa~Q=i z?s%GBIf)!>L@%Ph^{XR9O8VS<@5-F>=GN~X06{0qHci`-Gyx8q+bA?@;Y2yua^>%;RemD;!*CY{1JMDrCxN;=@v zuFz}iHLLl;rb6BL)3;+jSCdxrV660d1REsfdUsh#*Qgo=J0&RaFdTlkSS+rj4hhiV znpKfF8Y(x{QRN`(^>OKaGoLKdf7T`}8g{+4KH}wH)fscWH9n#var3SJq3*$DKKh7r z@4D{5P8lS<{@M=V+LjFPkzxt}WfES8MvA|+M_C}sm2gNsLE?Lm zYM0iB=8w8D<+^V}Y0P1KplLTWfChX?#Rc9Ew0!wwvvy<}X!+{Nrpv|iwbS#d=%tHz z06v58I#&S(K9ewsHq8`3o{;Lypa3IR-i@t|7G+i4x^W}$y=bQD-pCXAqx+JGFr8^a z3IoCKgh>vV3oyP(xphy;06S9lbvgnHFyd&0*Ue?XgY(wbWGh_U-Oi}&=%)ZR?;hxn z2~gdV_5-zFQk~fpq)W%6Mj|i3NF(gbuAxm+>6dovj+6ni(Fw297pV475>YwvOaV$! zot7yPyl2ERkTkK9oWO-wRA(A8HG#({`>X(C?b8)b7rL$w)rv*k(c;W9wvK{ZH%oyL z0Y%{cLIbe*l@rMnz>)Exw3aafUnpxo5X>mN&MpJSp^|g!{vZR)R&wk1mVpF`wY^!d zLhYi;#gc&})>!qUk)kqqIRzkn^~89CX&R^$iGN3i8c^=a+Rn8fO#*e|N+iCH>ea#V z$9^;n8KA*Ox9(>J+Vz%X7<>`}GR@uXff^H4Q+ouyyfOO} z0EWtc4>chKQ#j6jKi84UHnEgN_RG9Qg@pS*tH|yFF_;*56dlz&6ro9)9 zP$gqd0l@Ua>nO?l{*y*2%Jl-}Vi0~Ts|w@~R5lY_9d=Yt3cO9|#PH%gfa%{WUajfh z`&{;m6dHn-0&r|p>&_esTFxI=t6 zAf1SM-Tv$8_ZzKtk_IXdLMN;pd5ecD8(d?$B`l@8;oE$MN3Dj}KmL7u!ZJ{}Ppda< zb$<_;6YWSjX>J0Wh@1$m?+wOD7T+dNIa93I9|0C#Qm==YE&OVUlSiX2c=9FNj<|7^ ze28&ewWN{%3liB5-fwB>obwP_(bsph^sS&ctN1#8V&_Rb+tAt6oO@Cwc5P>gmEMrk zWcp!6I~)y6hkW0CqbbyVGYja}9t_a!xtYx+wo@hMtEJ*E3_2;p!?Tlc7p%>3s|Y#Q)9V{@>Uih_&3Ln3;gwv&eFuE6S~-AM_|_Cg!sR| z2zO^*_(Gk^rh$i=!Fl0qsLfthFz8vFeQ67`m{-n^1o! zGg@g%ds;kOJsvpi$a-3&^K78j50Z7FIY^$UlW0G6J%%{IDdDAsrzS|ZOR;0{+uz|& zGi$z!5>!h)i2Wq|8~H4eMdS>zoSfVD$V>5N zk;_v{NW)gZjY#`{fH1lt_;JAf{|WR73-;`PcCX_%(&5iTpON4C0Q4Ezmw?k~JOHPY z{|q>j?A{0X&GlOf`mxAwCO-|Zn*1}s+2o%AewyrREdE=lAAmK~Unqe&)L+24)E~fk zn*T-pI z0l!M}`elCCx9!V(GO+i{?C+1?#D0Cng<1sE0_nR|80_!ukwk- zp0DzIj01rGhv?W0{)yxo@JH0{&HU+567Zj?9Kioe>kv+QH@#;9e3Rq=@FyhCfd4|} zKEdxg^RTJxBR>%Er_>+7pOaq&_^(vYQ+#4l0r(555AZ*zUr+I;N^O9@qVb>;JeqgF zU(M|1Z3i{lCpy+3)M#%6{MB zt?cI=*~{r#j z$bQw~7ulaGdWrq1;+NQes(6Y0rtnMbH*I-|{iTC1v7a>UW%iGjz0Cg5@|W2k>Uf#` zpzSZSAJq9W`#t{c?Dy1dXTRt0cJ_CQUSWTy_!ahVYF=UgrsEa%Yxcat{>;`_*^i-< zj1P1Ap1OQeJMr+TCs&=gQpGM>ZH#NM+>$Y>E!T>stu2-HjphyC%|M2UM|=cr1yPaRb#VRecHH1wee-uFY5Qz zf{;~XVpmb?;Bz;LJ{ZtbvCKbug38k~9Bk9{iDM>n# zK3J5mb4=u8SMpblQdj6X>61tP=26Q@*9@eV)RFYjqkI)&u?OWBka9ifNcv1tzO>Pi z^i8DneAAFLbua43-0=tLD@o~#Svkj!rB5W~Ha5|xm*Ud7+< z%2j0|j-+pHrDdQa=>uW89O;-+BAd90(k3FJ znUj24xzJ3cs4D#}In2^~P9Z0C$<--M0*ifYYDw-;%QN>P?N-uq9cf-oB4pc%6DNF+ z0eKW&-$pv}%snJJ3Hbz&JsR>jA)h05g(UV~LcRcGvxcNe$bC_}6J7-g2(!aqYfYs+}}SI#QOoMaxMQ^?ryld+6X8h~tIongLbxQy_bWtF0HR zShD{@yU3Ojn}U4nHe1>p=}6i58;~;y#MUBiJnh`MGquZaU20p;ou?rS)z1dxF4d4? zQt6LM7wwxQcAxTT*w%Ka;o8zhHl#A;g8@pUwpSL09bbQflLq<(YPAEdF9)3HNC$})eb-4jeJQ@=d8pQiX7^Mp z(uIs^3P}@JOvv|v^rw*H4;Gu6p=dL^pu}EE$PbZo@MiWy30Y3aJZ!bSkMp%r>URYp zhXQ$2At~onLS77Hk3x#`f?^sq{*yrNG?BR@4|bWdv@C@@#N$~u*t)x#rfqcOc(d^v zUSL0tkg`WLVBhmRUtjGqd$btH-3po3qixSIGOb5jp0jeMdeotiX*~*>NHo6Vgc|wk z6msOjRFBNtw`o1nk)>vj#y`!Td0IOQx9|nrv~~_w$h3AIQP+CY+Sy|w^>*$`A+>gz zw}R8!sUu52Q0-jz3VW8aorJs>?4_?*wtcGcBeyd$t?`8lnb!DY>JD;R&TSMZ+(f~@a4LMl)l8d(?)*ei;PTf{EJpjtMTf>bb8}WWLo1>NWJmf ztTL^}YsggN_dLt*QqmS|=d&zNX^r3d3?tJTzxf#}XR7gQ6*8^y%T1)-_!%jr)_C)B zcv|CiWXfVOuZ`1N2AT68wY%h`){dLDV#jCrsHe+RmBhYH-7-(<o4&r>>C8oDOZ z+$qweEHsvTGp}^&)NWn62Gbr*6u2&ef19%c@R8 zQr~6mOKr%bWFE8tS+fy~_A&0_F+#2(e@jCi?^Q#$>rqC^b`tVl!tgYZ#X8a)`Mv7CeOfooOZaKsG?8iDG?8iD)RA&4|0a-2Hu0<9l+X1BHR;Q| d0i;I$pXn2UFImWxD4O2^q|K&|{C{l+2A*$Ywh;gT literal 0 HcmV?d00001 diff --git a/RtdUltimate/rtd_ultimate.sp b/RtdUltimate/rtd_ultimate.sp new file mode 100644 index 0000000..976bbae --- /dev/null +++ b/RtdUltimate/rtd_ultimate.sp @@ -0,0 +1,605 @@ +#include +#include +#include +#include +#include + +#pragma semicolon 1 + +#define UID(%0) GetClientUserId(%0) +#define CID(%0) GetClientOfUserId(%0) +#define PLUGIN_VERSION "1.0" + +#define HUD_X -1.0; +#define HUD_Y 0.4; +#define HUD_HOLD 1.0; + +new Handle:g_cmd_timeout; +new Handle:g_cmd_timeout_vip; + +new Handle:g_EffectTimer[MAXPLAYERS+2] = {INVALID_HANDLE, ...}; + +char g_SQL_RANDOM[256]; +//char g_SQL_EFFECT[256]; + +int g_ClientStartTime[MAXPLAYERS+2] = {0, ...}; +int g_ClientEndTime[MAXPLAYERS+2] = {0, ...}; +int g_ClientLastUse[MAXPLAYERS+2] = {0, ...}; +int g_ClientLastActivate[MAXPLAYERS+2] = {0, ...}; + +char g_ClientActivateCmd[MAXPLAYERS+2][256]; +char g_ClientDeactivateCmd[MAXPLAYERS+2][256]; + +bool g_ClientDeactivateIfDead[MAXPLAYERS+2] = {false, ...}; +char g_ClientEffectName[MAXPLAYERS+2][256]; +bool g_ClientSettedEffect[MAXPLAYERS+2] = {false, ...}; +bool g_ClientUpdatedEffect[MAXPLAYERS+2] = {false, ...}; +bool g_ClientShowHud[MAXPLAYERS+2] = {false, ...}; + +new Handle:g_Database = INVALID_HANDLE; +new Handle:g_hCounterHud = INVALID_HANDLE; + +public Plugin:myinfo = +{ + name = "RTD ULTIMATE", + author = "gsd", + description = "SQL RTD VERSION WITH WEIGHT RANDOM AND SERVER COMMAND EXECUTE", + version = PLUGIN_VERSION, + url = "http://vk.com/facti13" +} + +public OnPluginStart(){ + SQL_Start(); + HookEvent("post_inventory_application", Event_Spawn); + CreateConVar("sm_rtd_version", PLUGIN_VERSION, "RTD ULTIMATE VERSION", FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY|FCVAR_DONTRECORD); + + g_cmd_timeout = CreateConVar("sm_rtd_timeout", "120", "Amount of time in seconds a player roll the ULTIMATE DICE FACTI 13", FCVAR_NOTIFY, true, 0.0); + g_cmd_timeout_vip = CreateConVar("sm_rtd_timeout_vip", "180", "Amount of time in seconds a vip player roll the ULTIMATE DICE FACTI 13", FCVAR_NOTIFY, true, 0.0); + + RegAdminCmd("sm_rtd", User_roll, ADMFLAG_RESERVATION, "Roll the ULTIMATE DICE"); + RegAdminCmd("sm_rtd_use", Admin_roll, ADMFLAG_ROOT, "Roll the ULTIMATE DICE to user"); + + RegAdminCmd("sm_rtd_addcond", Command_AddCondition, ADMFLAG_GENERIC, "Add a condition to the target(s), Usage: sm_rtd_addcond \"target\" \"condition number\" \"duration\""); + RegAdminCmd("sm_rtd_removecond", Command_RemoveCondition, ADMFLAG_GENERIC, "Add a condition to the target(s), Usage: sm_rtd_removecond \"target\" \"condition number\""); + RegAdminCmd("sm_rtd_kill", Command_Kill, ADMFLAG_GENERIC, "Kill target', Usage: sm_rtd_kill \"target\" \"condition number\""); + RegAdminCmd("sm_rtd_reset", Command_Reset, ADMFLAG_GENERIC, "Reset RTD timeout on target', Usage: sm_rtd_reset \"target\""); + RegAdminCmd("sm_rtd_playsound", Command_PlaySound, ADMFLAG_GENERIC, "Play sound on target', Usage: sm_rtd_playsound \"target\""); + g_hCounterHud = CreateHudSynchronizer(); +} + +public OnPluginEnd(){ + for (new i = 0; i < MAXPLAYERS + 2; i ++){ + if(g_EffectTimer[i] != INVALID_HANDLE){ + TriggerTimer(g_EffectTimer[i]); + } else { + DeactivateEffect(i); + } + } +} + +//SQL INIT FUNCTIONS +stock SQL_Start(){ + Format(g_SQL_RANDOM, sizeof(g_SQL_RANDOM), "SELECT name, activate, deactivate, time, de_ondead, alarm_all, -LOG(random()) / chance as priority FROM rtd_ultimate ORDER BY priority LIMIT 1"); + //Format(g_SQL_EFFECT, sizeof(g_SQL_EFFECT), "SELECT name, activate, deactivate, time, de_ondead FROM rtd_ultimate WHERE id LIKE %i LIMIT 1"); + SQL_TConnect(SQL_SetDatabase, "rtd_ultimate"); +} + +public SQL_SetDatabase(Handle:owner, Handle:hndl, const String:error[], any:data) { + if (hndl == INVALID_HANDLE) { + LogError("Database Connection Error: %s", error); + } else { + g_Database = hndl; + } +} + +//CLIENT CONNECTION/SPAWN +public void OnClientAuthorized(client){ + DeactivateEffect(client); + g_ClientLastUse[client] = GetTime(); + g_EffectTimer[client] = INVALID_HANDLE; +} + +public void OnClientDisconnect(client){ + if(g_EffectTimer[client] != INVALID_HANDLE){ + KillTimer(g_EffectTimer[client]); + } + g_EffectTimer[client] = INVALID_HANDLE; + DeactivateEffect(client); +} + +public Event_Spawn(Event event, const char[] name, bool dontBroadcast){ + new client = CID(GetEventInt(event, "userid")); + //LogMessage("Client effect setted: %b Client currenly updating: %b", g_ClientSettedEffect[cid], g_ClientUpdatedEffect[cid]); + if (g_ClientSettedEffect[client] && !g_ClientUpdatedEffect[client]) { + /* + if (g_ClientDeactivateIfDead[client]){ + LogMessage("Deactivate effect on %i client", cid); + DeactivateEffect(cid); + } else { + LogMessage("Refresh effect on %i client", cid); + RefreshEffect(cid); + } + */ + //LogMessage("Refresh effect on %i client", cid); + + float time = float(g_ClientEndTime[client] - GetTime()); + if (time <= 2.0){ + DeactivateEffect(client); + } else { + RefreshEffect(client); + } + } + return Plugin_Continue; +} + +public void OnGameFrame(){ + for(int i = 1; i < MaxClients; i++){ + if(IsClientInGame(i) && g_ClientShowHud[i]){ + if (g_ClientEndTime[i] - GetTime() >= 0){ + SetHudTextParams(-1.0, 0.45, 1, 255, 255, 255, 255); + ShowSyncHudText(i, g_hCounterHud,"%i", g_ClientEndTime[i] - GetTime()); + } + } + } +} + +//STOCK's FUNCTiONs +stock SecToHuman(int i_time, char[] s_time, int str_size){ + int s, m; + m = i_time / 60; + s = i_time % 60; + char minutes[64]; + char seconds[64]; + ////////////////////////////////////////////////////////////// + if (m > 10 && m < 20){ + Format(minutes, sizeof(minutes), "%i минут", m); + } else { + if (m % 10 > 1 && m % 10 < 5){ + Format(minutes, sizeof(minutes), "%i минуты", m); + } else { + if (m % 10 == 1){ + Format(minutes, sizeof(minutes), "%i минута", m); + } else { + Format(minutes, sizeof(minutes), "%i минут", m); + } + } + } + ////////////////////////////////////////////////////////////// + if (s > 10 && s < 20){ + Format(seconds, sizeof(seconds), "%i секунд", s); + } else { + if (s % 10 > 1 && s % 10 < 5){ + Format(seconds, sizeof(seconds), "%i секунды", s); + } else { + if (s % 10 == 1){ + Format(seconds, sizeof(seconds), "%i секунда", s); + } else { + Format(seconds, sizeof(seconds), "%i секунд", s); + } + } + } + ////////////////////////////////////////////////////////////// + if (m > 0){ + Format(s_time, str_size, "%s %s", minutes, seconds); + } else { + Format(s_time, str_size, "%s", seconds); + } +} + +stock ActivateEffect(int client, const char[] name, const char[] act_cmd, const char[] deact_cmd, int time, bool reset_on_dead){ + if (g_ClientSettedEffect[client]){ + DeactivateEffect(client); + } + + strcopy(g_ClientActivateCmd[client], 256, act_cmd); + strcopy(g_ClientDeactivateCmd[client], 256, deact_cmd); + ReplaceCmdString(client); + + strcopy(g_ClientEffectName[client],256, name); + g_ClientStartTime[client] = GetTime(); + if (time < 0){ + g_ClientEndTime[client] = GetTime(); + } else { + g_ClientEndTime[client] = GetTime() + time; + } + g_ClientDeactivateIfDead[client] = reset_on_dead; + g_ClientSettedEffect[client] = true; + RefreshEffect(client); +} + +stock ReplaceCmdString(int client){ + char s_uid[32]; + Format(s_uid, sizeof(s_uid), "#%i", UID(client)); + ReplaceString(g_ClientActivateCmd[client], 256, "%i", s_uid); + ReplaceString(g_ClientDeactivateCmd[client], 256, "%i", s_uid); + ///////////////////////////////////////////////////////////////////////////////////////////// + if (StrContains(g_ClientActivateCmd[client], "%team%") != -1){ + switch (TF2_GetClientTeam(client)) { + case TFTeam_Red: ReplaceString(g_ClientActivateCmd[client], 256, "%team%", "@red"); + case TFTeam_Blue: ReplaceString(g_ClientActivateCmd[client], 256, "%team%", "@blue"); + default: ReplaceString(g_ClientActivateCmd[client], 256, "%team%", ""); + } + } + if (StrContains(g_ClientActivateCmd[client], "%class") != -1){ + switch (TF2_GetPlayerClass(client)){ + case TFClass_Scout: ReplaceString(g_ClientActivateCmd[client], 256, "%class%", "scout"); + case TFClass_Soldier: ReplaceString(g_ClientActivateCmd[client], 256, "%class%", "soldier"); + case TFClass_Pyro: ReplaceString(g_ClientActivateCmd[client], 256, "%class%", "pyro"); + case TFClass_DemoMan: ReplaceString(g_ClientActivateCmd[client], 256, "%class%", "demoman"); + case TFClass_Heavy: ReplaceString(g_ClientActivateCmd[client], 256, "%class%", "heavy"); + case TFClass_Engineer: ReplaceString(g_ClientActivateCmd[client], 256, "%class%", "engineer"); + case TFClass_Medic: ReplaceString(g_ClientActivateCmd[client], 256, "%class%", "medic"); + case TFClass_Sniper: ReplaceString(g_ClientActivateCmd[client], 256, "%class%", "sniper"); + case TFClass_Spy: ReplaceString(g_ClientActivateCmd[client], 256, "%class%", "spy"); + default: ReplaceString(g_ClientActivateCmd[client], 256, "%class%", ""); + } + } + ///////////////////////////////////////////////////////////////////////////////////////////// + if (StrContains(g_ClientDeactivateCmd[client], "%team%") != -1){ + switch (TF2_GetClientTeam(client)) { + case TFTeam_Red: ReplaceString(g_ClientDeactivateCmd[client], 256, "%team%", "@red"); + case TFTeam_Blue: ReplaceString(g_ClientDeactivateCmd[client], 256, "%team%", "@blue"); + default: ReplaceString(g_ClientDeactivateCmd[client], 256, "%team%", ""); + } + } + if (StrContains(g_ClientDeactivateCmd[client], "%class%") != -1){ + switch (TF2_GetPlayerClass(client)){ + case TFClass_Scout: ReplaceString(g_ClientDeactivateCmd[client], 256, "%class%", "scout"); + case TFClass_Soldier: ReplaceString(g_ClientDeactivateCmd[client], 256, "%class%", "soldier"); + case TFClass_Pyro: ReplaceString(g_ClientDeactivateCmd[client], 256, "%class%", "pyro"); + case TFClass_DemoMan: ReplaceString(g_ClientDeactivateCmd[client], 256, "%class%", "demoman"); + case TFClass_Heavy: ReplaceString(g_ClientDeactivateCmd[client], 256, "%class%", "heavy"); + case TFClass_Engineer: ReplaceString(g_ClientDeactivateCmd[client], 256, "%class%", "engineer"); + case TFClass_Medic: ReplaceString(g_ClientDeactivateCmd[client], 256, "%class%", "medic"); + case TFClass_Sniper: ReplaceString(g_ClientDeactivateCmd[client], 256, "%class%", "sniper"); + case TFClass_Spy: ReplaceString(g_ClientDeactivateCmd[client], 256, "%class%", "spy"); + default: ReplaceString(g_ClientDeactivateCmd[client], 256, "%class%", ""); + } + } +} + +stock RefreshEffect(int client){ + //LogMessage("Effect setted: %b, De_ondead:%b, Start: %i, End: %i",g_ClientSettedEffect[client], g_ClientDeactivateIfDead[client], g_ClientStartTime[client], g_ClientEndTime[client]); + if (g_ClientUpdatedEffect[client]){ + //LogMessage("Effect currently try update..."); + return; + } else { + g_ClientUpdatedEffect[client] = true; + } + if (!IsClientInGame(client) || !IsPlayerAlive(client)) + { + g_ClientUpdatedEffect[client] = false; + return; + } + + if (GetTime() - g_ClientLastActivate[client] >= 0.5){ + if(g_EffectTimer[client] != INVALID_HANDLE){ + if (g_ClientDeactivateIfDead[client]) { + TriggerTimer(g_EffectTimer[client]); + g_ClientUpdatedEffect[client] = false; + return; + } + } + ExecuteActivateCmd(client); + }/* else { + LogMessage("Ignore refresh effect on %i client", client); + }*/ + + if (g_ClientStartTime[client] != g_ClientEndTime[client]){ + float time = float(g_ClientEndTime[client] - GetTime()); + if (time <= 2){ + DeactivateEffect(client); + return; + } + } + g_ClientUpdatedEffect[client] = false; + return; +} + +stock ExecuteActivateCmd(int client){ + g_ClientShowHud[client] = true; + g_ClientLastActivate[client] = GetTime(); + if (g_ClientStartTime[client] == g_ClientEndTime[client]){ + ServerCommand(g_ClientActivateCmd[client]); + PrintCenterText(client, "Наложен эффект: %s", g_ClientEffectName[client]); + LogMessage("(%L) Наложен эффект: %s", client, g_ClientEffectName[client]); + g_ClientUpdatedEffect[client] = false; + return; + } else { + float time = float(g_ClientEndTime[client] - GetTime()); + if(time > 0){ + ServerCommand(g_ClientActivateCmd[client]); + if (g_EffectTimer[client] == INVALID_HANDLE){ + g_EffectTimer[client] = CreateTimer(time, DeactivateTimer, client, TIMER_FLAG_NO_MAPCHANGE); + } + PrintCenterText(client, "Наложен эффект:%s, длительностью %i секунд", g_ClientEffectName[client], RoundFloat(time)); + LogMessage("(%L) Наложен эффект:%s, длительностью %i секунд", client, g_ClientEffectName[client], RoundFloat(time)); + } else { + DeactivateEffect(client); + } + g_ClientUpdatedEffect[client] = false; + return; + } +} + +stock DeactivateEffect(int client){ + if(g_EffectTimer[client] != INVALID_HANDLE) TriggerTimer(g_EffectTimer[client]); + g_ClientShowHud[client] = false; + g_ClientUpdatedEffect[client] = false; + g_ClientSettedEffect[client] = false; + strcopy(g_ClientActivateCmd[client], 256,""); + strcopy(g_ClientDeactivateCmd[client], 256, ""); + strcopy(g_ClientEffectName[client], 256, ""); + g_ClientStartTime[client] = 0; + g_ClientEndTime[client] = 0; + g_ClientDeactivateIfDead[client] = false; +} + +// TIMERs + +public Action:DeactivateTimer(Handle:timer, any:client){ + g_ClientUpdatedEffect[client] = true; + ServerCommand(g_ClientDeactivateCmd[client]); + PrintCenterText(client, "Эффект: %s, был снят", g_ClientEffectName[client]); + LogMessage("(%L) Эффект: %s, был снят", client, g_ClientEffectName[client]); + DeactivateEffect(client); + g_EffectTimer[client] = INVALID_HANDLE; + return Plugin_Stop; +} + +// SQL FUNCTIONs +public SQL_SetEffect(Handle:owner, Handle:hndl, const String:error[], any:data) { + int client; + if ((client = CID(data)) == 0) { + return; + } + + if(g_EffectTimer[client] != INVALID_HANDLE){ + TriggerTimer(g_EffectTimer[client]); + } else { + DeactivateEffect(client); + } + + if (hndl == INVALID_HANDLE) { + LogError("Query failed! %s", error); + g_ClientLastUse[client] = 0; + PrintToChat(client, "Невозможно выдать рандомный эффект из-за ошибки базы данных!"); + return; + } else { + g_ClientLastUse[client] = GetTime(); + } + + if (SQL_FetchRow(hndl)) { + char effect_name[256]; + SQL_FetchString(hndl, 0, effect_name, sizeof(effect_name)); + char activate_cmd[256]; + SQL_FetchString(hndl, 1, activate_cmd, sizeof(activate_cmd)); + char deactivate_cmd[256]; + SQL_FetchString(hndl, 2, deactivate_cmd, sizeof(deactivate_cmd)); + int time = SQL_FetchInt(hndl, 3); + bool de_ondead = SQL_FetchInt(hndl, 4); + bool alarm_all = SQL_FetchInt(hndl, 5); + + if (alarm_all) { + PrintCenterTextAll("Игрок: %N, применил для всех эффект: %s", client, effect_name); + LogMessage("Игрок: %L, применил для всех эффект: %s", client, effect_name); + } + + ActivateEffect(client, effect_name, activate_cmd, deactivate_cmd, time, de_ondead); + if (time == 0) { + DeactivateEffect(client); + } + } else { + PrintToChat(client, "Применяемый эффект не найден в базе..."); + } + return; +} + +// COMMAND FUNTION's +public Action:User_roll(client, args){ + if (g_ClientSettedEffect[client]){ + PrintToChat(client, "У тебя уже присутствует эффект: %s", g_ClientEffectName[client]); + return Plugin_Handled; + } + + int timeout = GetTime() - g_ClientLastUse[client]; + int cmd_timeout; + if (CheckCommandAccess(client, "sm_rtd_vip", ADMFLAG_RESERVATION, false)){ + cmd_timeout = GetConVarInt(g_cmd_timeout_vip); + } else { + cmd_timeout = GetConVarInt(g_cmd_timeout); + cmd_timeout = cmd_timeout + cmd_timeout * GetClientCount(true) / 5; + } + + //if (GetClientCount(true)/5 > 0){ + // cmd_timeout = cmd_timeout + cmd_timeout * GetClientCount(true) / 5; + //} + + if (timeout < cmd_timeout){ + char s_timeout[64]; + SecToHuman(cmd_timeout - timeout, s_timeout, sizeof(s_timeout)); + PrintToChat(client, "Ты еще не можешь ролить рандомный эффект, подожди еще %s", s_timeout); + return Plugin_Handled; + } + + PrintToChat(client, "{black}Крутим колесо фартуны......"); + SQL_TQuery(g_Database, SQL_SetEffect, g_SQL_RANDOM, UID(client)); + return Plugin_Handled; +} + +public Action:Admin_roll(client, args){ + if (args > 2 || args == 0) { + ReplyToCommand(client, "Usage: sm_rtd_player "); + return Plugin_Handled; + } + + new String:buffer[64];GetCmdArg(1, buffer, sizeof(buffer)); + new String:target_name[MAX_NAME_LENGTH]; + new target_list[MAXPLAYERS]; new target_count; new bool:tn_is_ml; + if ((target_count = ProcessTargetString( + buffer, + client, + target_list, + MAXPLAYERS, + COMMAND_FILTER_CONNECTED, + target_name, + sizeof(target_name), + tn_is_ml)) <= 0) + { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + + if(target_count > 0){ + new count = 0; + for (new i = 0; i < target_count; i ++){ + if (args == 1){ + SQL_TQuery(g_Database, SQL_SetEffect, g_SQL_RANDOM, UID(target_list[i])); + count++; + } else { + char SQL[256]; + char strBuffer[16]; + GetCmdArg(2, strBuffer, sizeof(strBuffer)); + int effect_id = StringToInt(strBuffer); + Format(SQL, sizeof(SQL), "SELECT name, activate, deactivate, time, de_ondead, alarm_all FROM rtd_ultimate WHERE id LIKE %i LIMIT 1", effect_id); + SQL_TQuery(g_Database, SQL_SetEffect, SQL, UID(target_list[i])); + count++; + } + } + ReplyToCommand(client, "Было заролено %i раз", count); + return Plugin_Handled; + } else { + ReplyToCommand(client, "Не было найдено целей для использования команды..."); + return Plugin_Handled; + } +} + +public Action:Command_Kill(client, args){ + if(args != 1){ + ReplyToCommand(client, "[SM] Usage: sm_rtd_kill \"target\""); + return Plugin_Handled; + } + + new String:strBuffer[MAX_NAME_LENGTH], String:target_name[MAX_TARGET_LENGTH], target_list[MAXPLAYERS], target_count, bool:tn_is_ml; + GetCmdArg(1, strBuffer, sizeof(strBuffer)); + if ((target_count = ProcessTargetString(strBuffer, client, target_list, MAXPLAYERS, COMMAND_FILTER_ALIVE, target_name, sizeof(target_name), tn_is_ml)) <= 0) + { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + + for(new i = 0; i < target_count; i++) + { + FakeClientCommand(target_list[i], "explode"); + //SDKHooks_TakeDamage(target_list[i], target_list[i], target_list[i], 99999999.0); + } + return Plugin_Handled; +} + +public Action:Command_Reset(client, args){ + if(args != 1){ + ReplyToCommand(client, "[SM] Usage: sm_rtd_reset \"target\""); + return Plugin_Handled; + } + + new String:strBuffer[MAX_NAME_LENGTH], String:target_name[MAX_TARGET_LENGTH], target_list[MAXPLAYERS], target_count, bool:tn_is_ml; + GetCmdArg(1, strBuffer, sizeof(strBuffer)); + if ((target_count = ProcessTargetString(strBuffer, client, target_list, MAXPLAYERS, COMMAND_FILTER_ALIVE, target_name, sizeof(target_name), tn_is_ml)) <= 0) + { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + + int count = 0; + for(new i = 0; i < target_count; i++) + { + g_ClientLastUse[target_list[i]] = 0; + count++; + } + ReplyToCommand(client, "RTD таймер был сброшен у %i игроков", count); + return Plugin_Handled; +} + +public Action:Command_AddCondition(client, args){ + + if(args != 3) + { + ReplyToCommand(client, "[SM] Usage: sm_rtd_addcond \"target\" \"condition number\" \"duration\""); + return Plugin_Handled; + } + + new String:strBuffer[MAX_NAME_LENGTH], String:target_name[MAX_TARGET_LENGTH], target_list[MAXPLAYERS], target_count, bool:tn_is_ml; + GetCmdArg(1, strBuffer, sizeof(strBuffer)); + if ((target_count = ProcessTargetString(strBuffer, client, target_list, MAXPLAYERS, COMMAND_FILTER_ALIVE, target_name, sizeof(target_name), tn_is_ml)) <= 0) + { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + + new iCondition, Float:flDuration; + + GetCmdArg(2, strBuffer, sizeof(strBuffer)); + iCondition = StringToInt(strBuffer); + + GetCmdArg(3, strBuffer, sizeof(strBuffer)); + flDuration = StringToFloat(strBuffer); + + for(new i = 0; i < target_count; i++) + { + TF2_AddCondition(target_list[i], TFCond:iCondition, flDuration); + } + return Plugin_Handled; +} + +public Action:Command_RemoveCondition(client, args){ + + if(args != 2) + { + ReplyToCommand(client, "[SM] Usage: sm_rtd_removecond \"target\" \"condition number\""); + return Plugin_Handled; + } + + new String:strBuffer[MAX_NAME_LENGTH], String:target_name[MAX_TARGET_LENGTH], target_list[MAXPLAYERS], target_count, bool:tn_is_ml; + GetCmdArg(1, strBuffer, sizeof(strBuffer)); + if ((target_count = ProcessTargetString(strBuffer, client, target_list, MAXPLAYERS, COMMAND_FILTER_ALIVE, target_name, sizeof(target_name), tn_is_ml)) <= 0) + { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + + new iCondition; + + GetCmdArg(2, strBuffer, sizeof(strBuffer)); + iCondition = StringToInt(strBuffer); + + for(new i = 0; i < target_count; i++) + { + TF2_RemoveCondition(target_list[i], TFCond:iCondition); + } + return Plugin_Handled; +} + +public Action:Command_PlaySound(client, args){ + if(args != 2) + { + ReplyToCommand(client, "[SM] Usage: sm_rtd_playsound \"target\" \"filepath\""); + return Plugin_Handled; + } + + new String:strBuffer[MAX_NAME_LENGTH], String:target_name[MAX_TARGET_LENGTH], target_list[MAXPLAYERS], target_count, bool:tn_is_ml; + GetCmdArg(1, strBuffer, sizeof(strBuffer)); + if ((target_count = ProcessTargetString(strBuffer, client, target_list, MAXPLAYERS, COMMAND_FILTER_ALIVE, target_name, sizeof(target_name), tn_is_ml)) <= 0) + { + ReplyToTargetError(client, target_count); + return Plugin_Handled; + } + + char SoundPath[256]; + GetCmdArg(2, SoundPath, sizeof(SoundPath)); + + for(new i = 0; i < target_count; i++) + { + EmitSoundToClient(target_list[i], SoundPath); + } + return Plugin_Handled; +} \ No newline at end of file diff --git a/VipAlarm/vip.sp b/VipAlarm/vip.sp new file mode 100644 index 0000000..2151277 --- /dev/null +++ b/VipAlarm/vip.sp @@ -0,0 +1,207 @@ +#include +//#include +#pragma newdecls required + +Handle hDatabase = INVALID_HANDLE; + +enum struct PlayerStatus { + int time_remain; + int status; +} + +PlayerStatus VipTimeLeft[MAXPLAYERS+1]; + +//SELECT `status`,UNIX_TIMESTAMP(`reg_date`), amount FROM `sm_admins` WHERE 1 + +/*CONNECTS*/ +/*public bool OnClientConnect(int client, char[] rejectmsg, int maxlen) +{ + PrintToServer("Get %d client permitions", client); + GetClientPermitions(client); +}*/ +/* +public void OnClientAuthorized(int client) +{ + GetClientPermitions(client); +} +*/ +public void OnClientPostAdminCheck(int client) { + GetClientPermitions(client); +} + +public void OnClientDisconnect(int client) +{ + VipTimeLeft[client].time_remain = 0; + VipTimeLeft[client].status = 0; +} +/*CONNECTS*/ + +public Plugin myinfo = +{ + name = "Facti13 VIP", + author = "gsd", + description = "Get user's SteamID", + version = "1.1", + url = "https://vk.com/facti13" +} + +public bool DrawTime(int client, char[] time_string, int size_string){ + if (VipTimeLeft[client].time_remain > 0) { + int day = VipTimeLeft[client].time_remain / (24 * 3600); + if (day == 0){ + int n = VipTimeLeft[client].time_remain % (24 * 3600); + int hour = n / 3600; + Format(time_string, size_string, "%d часов", hour); + } else { + Format(time_string, size_string, "%d дней", day); + } + } else { + Format(time_string, size_string, "бесконечны"); + } +} + + +/*SQL FUNCTIONS*/ +public void GotDatabase(Handle owner, Handle hndl, const char[] error, any data) { + if (hndl == INVALID_HANDLE) { + LogError("Database Connection Error: %s", error); + } else { + hDatabase = hndl; + /*//////////////////////////////////////// + for(int i = 1; i < MAXPLAYERS; i++){ + if(IsClientInGame(i)){ + GetClientPermitions(i); + } + }*/ + } +} + +int GetClientPermitions(int client){ + char Query[512]; + char SteamID[32]; + GetClientAuthId(client, AuthId_Steam2, SteamID, sizeof(SteamID)); + Format(Query, sizeof(Query), "SELECT status, extract(epoch from reg_date), amount FROM sm_admins WHERE identity LIKE '%s'", SteamID); + //LogMessage(Query); + SQL_TQuery(hDatabase, GetClientPermitionsCallback, Query, GetClientUserId(client)); + return 0; +} + +stock void GetClientPermitionsCallback(Handle owner, Handle hndl, char [] error, any data) { + int client; + + if((client = GetClientOfUserId(data)) == 0) + { + return; + } + //////////////////////////////////////////// + if(hndl == INVALID_HANDLE) + { + LogError("Query failure: %s", error); + return; + } + //////////////////////////////////////////// + if (SQL_FetchRow(hndl)) { + char status[16]; + SQL_FetchString(hndl, 0, status, sizeof(status)); + if(StrEqual(status, "VIP")) VipTimeLeft[client].status = 1; + if(StrEqual(status, "MOD")) VipTimeLeft[client].status = 2; + if(StrEqual(status, "admin")) VipTimeLeft[client].status = 3; + /* + } else { + VipTimeLeft[client].status = 3; + } + */ + ////////////////////////////////////////////////// + int TimeRemainig = SQL_FetchInt(hndl, 1) + SQL_FetchInt(hndl, 2) - GetTime(); + if (TimeRemainig >= 0 && !SQL_FetchInt(hndl, 2) == 0){ + VipTimeLeft[client].time_remain = TimeRemainig; + } else { + VipTimeLeft[client].time_remain = 0; + } + } + return; +} + +stock void ConnectDB(){ + SQL_TConnect(GotDatabase, "admins"); +} + +/*SQL FUNCTIONS*/ + + +public void OnPluginStart(){ + RegConsoleCmd("sm_vip", Command_newVIP); + ConnectDB(); + for(int i = 1; i < MAXPLAYERS; i++){ + VipTimeLeft[i].time_remain = 0; + VipTimeLeft[i].status = 0; + } +} + +/*USER COMMANDS*/ +public Action Command_MySID(int client, int args) +{ + //char steamid[64]; + + //if(GetClientAuthId(client, AuthId_Steam2, steamid, 64)) + //CPrintToChat(client, "\n{yellow}Твой SteamID: {magenta}%s\n{orangered}Проверь до конца ли ты его скопировал!\n{yellow}Купить ВИП можно по ссылке: https://vk.cc/bWaAMG\n",steamid); + //else + //CPrintToChat(client, "{fullred}Невозможно получить твой SteamID"); + PrintToChat(client, "Как купить вип узнай на нашем сайте, еблан"); + + return Plugin_Handled; +} + +public int Select_Panel(Handle panel, MenuAction action, int client, int option) { + switch (action){ + case MenuAction_End:delete panel; + } +} + +public Action Command_newVIP(int client, int args) +{ + char steamid[64]; + GetClientAuthId(client, AuthId_Steam2, steamid, 64); + + Menu VipMenu = CreateMenu(BuyCB); + char PlayerInformation[256]; + StrCat(PlayerInformation, sizeof(PlayerInformation), "Информация о тебе:\n"); + + ///////////////////////////////////// + StrCat(PlayerInformation, sizeof(PlayerInformation), "Твой SteamID:\n"); + StrCat(PlayerInformation, sizeof(PlayerInformation), steamid); + StrCat(PlayerInformation, sizeof(PlayerInformation), "\n"); + ///////////////////////////////////// + StrCat(PlayerInformation, sizeof(PlayerInformation), "Текущий статус:\n"); + switch (VipTimeLeft[client].status){ + case 0:StrCat(PlayerInformation, sizeof(PlayerInformation), "Обычный игрок"); + case 1:StrCat(PlayerInformation, sizeof(PlayerInformation), "VIP игрок"); + case 2:StrCat(PlayerInformation, sizeof(PlayerInformation), "Модератор"); + case 3:StrCat(PlayerInformation, sizeof(PlayerInformation), "Администратор"); + case 4:StrCat(PlayerInformation, sizeof(PlayerInformation), "Неизвестно"); + } + StrCat(PlayerInformation, sizeof(PlayerInformation), "\n"); + ///////////////////////////////////// + if (VipTimeLeft[client].status > 0){ + StrCat(PlayerInformation, sizeof(PlayerInformation), "Кончаются через:\n"); + char time[32]; + DrawTime(client, time, sizeof(time)); + StrCat(PlayerInformation, sizeof(PlayerInformation), time); + } else { + StrCat(PlayerInformation, sizeof(PlayerInformation), "Купить VIP:\n"); + StrCat(PlayerInformation, sizeof(PlayerInformation), "!buyvip"); + } + StrCat(PlayerInformation, sizeof(PlayerInformation), "\n"); + SetMenuTitle(VipMenu, PlayerInformation); + AddMenuItem(VipMenu, "buy", "Купить сразу"); + DisplayMenu(VipMenu, client, 0); + SetMenuExitButton(VipMenu, true); + return Plugin_Handled; +} + +public int BuyCB(Handle menuhandle, MenuAction action, int client, int pos){ + switch(action){ + case MenuAction_Select:{FakeClientCommand(client, "sm_buyvip");} + case MenuAction_End:{delete menuhandle;} + } +} diff --git a/bad_nicknames.sp b/bad_nicknames.sp new file mode 100644 index 0000000..cd611de --- /dev/null +++ b/bad_nicknames.sp @@ -0,0 +1,95 @@ +#include +#include +#define PLUGIN_VERSION "1.1" + +public Plugin:myinfo = { + name = "[ANY] Bad Nicknames", + author = "gsd", + description = "Kick users have substring from DataBase", + version = PLUGIN_VERSION, + url = "https://kremlin.ru" +}; + +//void KickClient(int client, const char[] format, any... ...) +//bool GetClientName(int client, char[] name, int maxlen) + +new Handle:hDatabase = INVALID_HANDLE; +new Handle:gReason = INVALID_HANDLE; + +char g_IgnoreOverride[32] = "sm_bdn_override"; + +public OnPluginStart() { + //VerifyTable(); + StartSQL(); + CreateConVar("sm_bdn_version", PLUGIN_VERSION, "Bad Nicknames Version", FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); + gReason = CreateConVar("sm_bdn_reason", "Change you nickname before connect to server...\nYou nickname is trash. Have not funny meme or trade sites.", "Kick reason"); +} + +StartSQL() { + SQL_TConnect(GotDatabase, "bad_nicknames"); +} + +public GotDatabase(Handle:owner, Handle:hndl, const String:error[], any:data) { + if (hndl == INVALID_HANDLE) { + LogError("Database Connection Error: %s", error); + } else { + hDatabase = hndl; + } +} + +public T_Check(Handle:owner, Handle:hndl, const String:error[], any:data) { + if (hndl == INVALID_HANDLE) { + LogError("Query failed! %s", error); + } + return; +} + +public OnClientPostAdminCheck(client) { + //User Connect to Server + if(IsFakeClient(client)) { + return; + } + //Vars + char player_name[64]; + char query[1024]; + + //Get Vars + GetClientName(client, player_name, sizeof(player_name)); + + //Get SQL Vars + char dbs_player_name[64]; + SQL_EscapeString(hDatabase, player_name, dbs_player_name, 64) + + //Format SQL + //SELECT `comment` FROM `bad_nicknames` WHERE LOCATE(`substr`, 'pelmen trade'); + Format(query, sizeof(query), "SELECT comment FROM bad_nicknames WHERE position(substr in '%s')>0", dbs_player_name); + + //Function + SQL_TQuery(hDatabase, T_CheckPlayer, query, GetClientUserId(client)); +} + +public T_CheckPlayer(Handle:owner, Handle:hndl, const String:error[], any:data) { + + new client; + if ((client = GetClientOfUserId(data)) == 0) { + return; + } + + char player_name[64]; + GetClientName(client, player_name, sizeof(player_name)); + + char reason[256]; + GetConVarString(gReason, reason, sizeof(reason)); + + if (SQL_GetRowCount(hndl) > 0) { + //KickClient(client, reason); + if(CheckCommandAccess(client, g_IgnoreOverride, ADMFLAG_ROOT)){ + return; + } else { + SetClientName(client, "facti13 player"); + } + LogMessage("%s kicked from server. Nickname invalid, have trade link or other string.", player_name); + return; + } + return; +} \ No newline at end of file diff --git a/plugins/fsb.smx b/plugins/fsb.smx index 4a4ef0752aeb040a4a588a91997bdf792efc172c..3ccc0b5d351d000cdbc0916ccdb47890fe0101ca 100644 GIT binary patch literal 15338 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 literal 15321 zcmZ9S1yEa2*RHWbi&Lynq~xN8V{)9?Sk zxp!`6*1XT&>)k8s3~NloF(8o^e_H--Xb8(z!}_xfPf3vRd}4i zSp(j~0i2~<5D;vT5fEHk{)ld*90aQNSOcW-BlZx)vS&&bWf{eMU1 z_NH!b|2JuAV`2Z_a{sB|?&@LwU+@2&F#ca3+cz^SHcK1(fBpSKdmG39qK%`a)BjBV zx5xiDtn8i4Ozr<`cQXISUdt!`SbiD{9(x&axLmJsbxiEVL`)Eoe#J_>zOcD|^>%+O zz9w%V4t3&(hAgSK<+ofaRu$)-H!AYddNZ1O>2-`tGrwqQsop49e{S|lar~6*xWsZY z%I08`a>~S*5lh{d{UW;8=?Tv8j_*Eo3^W3%YC}6;+KuJqj)+Jm400X;l z0hs)8PY{~C(;tJgB&CVE51^gb83Q`}_g7D7I5Yin6#S(fp!h)PUY10wP`bc^TBOIE zE$_C7??4ey{KEspD5;Lza=Ln}qiFN9)wp|629^Omt(QGf(X^2gxHr}DTh&Y%H=6FZ^vHAhl z^L3`);hoQ_3-;&CCey7Bw#{*${nSB+lrjozpNk9ssF*Vh$_Lm|uI%>4$|H;Z7M3;W zen(d#|J9AKg0-YUR>%;K5lmdYpU zQO0QTS{QzI@X%^(3B}Hnw4X@-PxOA2}Wu9 zGU};w32i^bIcOPc`_fB6bgx9>^-b0`o7`t*cS*zls&{3wtF^o4VKKNl%OZ2@kKx{h z7!CzLtO+#GY?&?uZhQFqwNkb4kYCPlXZAt4YeU{HY(q6Rqxd4qC?y8NL6Mf?@b-0K zPFYqArr;1aNW{-T<=27@|J69&@`T8ZYq7#}>x?S9%C_?cRYJkEO_s$^|b;uW|zh}w&~V3 zA(sq=Wcv}s1>!~t&a(|&=A${>HY1lqYs92yf)7ZengUT4Zy_xsP|J+mIdtoK}@0R!}Ii;VU1di~4aD~cH2t%f6b|S|<27k8uAz-&9xTR5*w)iD6 z!l-|VPwC!YwUA<)f7NaD=9TMHnFunuU7;aWJD=hj%@YY}lus)jjzu`8`spKq&p?mq zsIl<&^eFHP_gmr)Z%#~sxS9VPD{$@pEdOw}*(y>chb{ZyZ*h|0)*Jnl+xP1S zUI%RqRyMAd^0OWjwI4-wwOd`Byq>NHJEsqd&ooq90zk=zEwWw72BVNq#)Nty8Tn~D zZlLLq0#F61tSlgU)jgRe#d7H;Z&y%NU^eFd_2R~x{)0)_tx{CcMd>wLOylb-SflXmm7VzJ9&B5% za`k|3oq3boJTnG{4B8ttC^Pc1F1QKNu<7`)L&;XTN?^k(AE#m&?tWdTwFAZc zf9(PAvWx#5d2A9V%Hd>iOX+c|i!=|09REG?)MXqDF-SS~U%Y9*SWf@G`72bP*k9R> zviuldJ;h%syiS!e@0gkL&#`Ry%}~r|u!wLw+vPAaCmZ3$IR!Vy;Z#989>+=#`nDGGqjkOC9{_wDsPwiRvieH z6KJC}j!J#j7v$nR%Xp?vqh?Pyoq)pv%@t{Oi&vKn6kJteO{w?2`30uY%qxv|rQgO4 zDyxj=?By5smhBkMWc}>}Lp^Gr468z~O%Ho2JkLM-WH$}jR&h^q_x+9159AN&xPb!j zuAu;5niZLG=UBxzOjavO`e440kQBvizBsC6#WCJicfYD;W!l)&N=nNS15eS`nSn{c zP%#|YmWgzg6GCjeo{YjX)ns38@n3US?d`+DKq>_^n^h8eprm#{kY0c%E$|>7+)4mb zPH{iAhOMc@<&c~vGXwSC-p)!fU!r~2cMl~q8_Z7^U9mr_jSnbl*sheh^(jr8Bv;6v zr-{PUCiRYR&?lSWxJmJ+xEN~L3MFC~%fP2_nFZ$^dn?^vzy?(GSL|X;eC1Q>T0Oqa z-Xg4-n;6-?pXo+!kJ(;&wbn%oV(Pqq35t6V&rV6ZEkRSsC|_wR94i!aFqF&zmvw#w zEndy4qMyjW->HR++v`tWuenw6M{7-9k8}h~eB4p`__PVB6tj9xiH%{F{n(t=ybQcl zy6jjK1@VdOUu`i!yAsr2-F6&@EUs)EJ*cp;D4)u`=2jCIYIb)Q@u3+YP3U41*x35& z29Bz;VpnzydLQ4l1VY_g@n5tOfR>>&h>3kIZ$8i?&-y4IeWkL4IZE+SDVh8JemZ|q zm{JSutyJ&wr)zolvPDDZ+WLMrf6<26?tb3N!tYA-&oeZ&sE^9v=JG|@BduzVt`{X) zaPJ3w;7`i>%MfEI^3%Tfz*tsWPk!Rw*OmO~Lgt+@3TpMDWBfGNFJR!uCy$)#g?60G zrs2%sTb(Y|>>Kff3I_cqDs%T6cazqpW-b5fg}3QYYXIRQ^rcCO&HvC!=He z(1m|ijcx0lJs>m7rGW16E;;vbZ`jsezPd~G2m6V(&n!6#QML}THg~xW6^3@c_w_>^ zptveCFkdTT(7w+3QTejk%6};qDV+aznxgTURBZ}YHf46X4=~sZ!1gDf+nRIVYst?3 z85;9B`?Lvg>KGzptjbQ_D!S%kt0)ITK7HoRH1K|>>s;jSUbo?BW2@_YOFsH@Dm~62 z^^7P6+?nF@GJoTX(;Rqo-#L9|?iMPSar#ldvN*>xiALG3c*<5^PL%!WNR17e#-grj zn57366GzWDJyH|jyYa~DKL5U0;7^r*3_a~yuD;P+3-DmzUz*&f7-LpnyiHPeSs!+p z4JApahmal}H!oP935>sA*Gk*1)ATvPp|o*o8JUIE$<5ES_YcONDxMzQua`xntGMbc z({i%`wf6b|%ycU~w z756?Zo3*?28uQn8Y&$Ug(BT-;cLhuDthfj`6t!G}c0y6Cz|9`|o&k=es9=@Tg(7ml z6Q6ctoYAf_|EtWWHY@+b0MWbK{dpgy_s6w2O-8;MThH$=rbBX%CVlq0VD>hFe`7{` zZQc%L`ihh;>CDJ<$q=~(gw6{)6jY-FOFVmay{jGeJK{up*I_gu+cRD9Z(uT;s87b# z0u_~Ooylf~Qk3;LEDA+5=WG>r5VcWv*1zU$UqG43Nl zf#c9ue<>EYP7Jki)+Jgn^jb1u`P)>T_Uvt!#;lW)(6y+A_20PNhxbegH#X;kX(DH^=UX|yp)Y4+rI6Gx z_L+6U%nx@MKcn!0>c>jCJtcL0-lAYOf0p`Dqd-l&4b73WI|9=6hbi?FH~J)Qxr7C7Ta%?7VY4IdTtoT_u+h zJoQP;H&1n4by;e@aV40iP1&COIO;OA-5KLX(;@Av0+BVVg+A0cE@NX#ujt0OUPpe3 zreGY33;ieu=Ggh|)iAbXy5;WG-^!ts8QU*NzaWq7ox#JJD8zYmpW2Y*xDu%J%?Tu1 ze0-ufeHPFs{}d!5AR8AQzmfvl;jzHFqmMhw1b+ZVV2v!s5iIr?Frco5Ze}I;J`4y=2N*t~xl4@3HJDb$L=d%l}hZ+o`$Bd*uG- zB)=!^+8=_m<`x*ee;BuYS;vi7o6>An(;UM}l=>10NQrD6RgkQ+bhl9_fFhq;ciySeaXJm)@A-$Z@*RclmP!-X}B z!+|?~z0z85>u={oo6Pb6V^_WDytH+gx}4GysKJ9X(O28A7+F=7bC4|09fvhejJjLIkR&-Tc_G^*7x9aZT$6l3q=np4RGguG1Cr`jd#u+b6HrZ;| ztF&6q$i}rOOLIf%y}#KMVNvaeMl5irrE6yIj(>6=At3=F5dl$R#YZDkf@C&UCWE#L zXA+O_KQnVkA96wfr>&%f?a^r- zv5_u@sa}Wl%{hv*?WdCQ$lSuo(Qg#6$02Iu`0-?^OH1zKkkxNWao@IkKUeu$r8y9} znJ8E^=}rRZl9ntb(ULVR859pswg=KD`L4G*ziD|uN_z%H-U{fyXCBilL%P}m?3N`< z)QC>QTm@>_YI2<=19F>vt!mnZ$!ynJfsNcK?nVZo_*sUVUet?o(lJa;e7u@-%?(X| z|7!9!C(iMr8kJPpmZ6t;T?s`&17Cy!d2c2(m01Dl_sOUnl18euE#hQ$C)nSEuaFB2 zQQJ!nuEIE%sc`=CHU`+yu67Df_bk*pb5NXUEsV1)7luzQB~aFQ(HW=On{L4BmMb+U z03rjLm+ar3`dA51U}f|M4H`*vjYL&!28MMV1qB5y4e~!}YYhWTB&UA{pEVy@2To`< zY7(;QWw0?Zy7L{)-={l#f7;c>YW=c@!&4jNk!q93v$Xj43);FFz$7B|&nv|AKAo`N zes6eq=t2*UYjd=;cwdb+qb&w=jv*yTrIG1_P@yN8F)bpK+GhFFKo@g2Z%OYO;b&^Fx=g=5eoq$d zxjd~;alSa6;4($wy`3t`+pngyqL>&;gluoIXG~g{iB9630i9W4(FmbB$&CCCdC(XcwcQ{Ad~lanOF&|I!r*2grR7? zaV9tylI|&Q=Ms6N#!abd2;>a1#4nMjKcN-UH!~?5a%2)*K7Am5kycn>{3ic7GX4QRP)Bu?XFK)P+Rr>LzNHNtW2(vHJJR0)edXv#30yS6{iNJo-IP z@w)O4uhDw0fUGdF;uKYV12g?!pwA%QJw2ZBRofN?bzT3RhlC>NOy*d&rJ$v;ArG4# zKC6fMWW!&qU0v6_t!R$EL%%?yo9Z3@$Mp8KqUG>*B(SklpwnaSL#ekcIgfF+^(P@u zPg=d{@e9-K!FD~*0nf4@C*+&AqKwX-I=dA6z{Uc|siu_l!NC)dxaEHHx%ws$cF2JA zWPI?V_0n7&@OWs7)P=tfoC@rE(bvYg4TK)%J)hkM4y7)T?29kFko(*zn^hyc6860z z^tmKlEu8|l-p7?wYJrUMzJS~A@zDJzy@qT0M0hdzrRo#Bc;52qRd%?&+@7+ThS+_=lwA}3ORZ^VOP`g*vzLi*okP*?WxZx@ejOVZC->C8I!F?if zn0KxWjEsh^_>n`kXB@khi=CS$stx*#)yu4C@fo+TWxk{BV+TVwyE^%^e}6CiS+=5M z^@q0>Xq71Xp_QN3Sh%kPtWB}Sz@6|#Aa(y;n4J0rtyfJ#D(D+afhpJ9sx%TMAon-( z%D8>U2qz^Lg7tyOAm?#`jrVPQts&=8Un(P#(bA#nY=(eK9d{?P)|2Sa$YgBNbSa)L z_mdbPL646EHBr0QMZJ)J2)y9Ao(;<7F9fyyPRW8jr;IsSq9I(QDUJf{DOl8}1S}bAk;S^MKv1IU) zIB4Z8mN0pC)R8)QR-E;D4;s~#F$s=pi<>+HE0LMMdq^)4fq)9!Jre?pdpX3E100%6 z{bC*m%`Ul1ItoKLO<4-L`#6?|fnpJ(G66!OFL+|NiknYq1ma^Hy9t4|KTYjvUKZ*5 z1XP}reEL56jB}_|P<6&VHfjhunRNOGnXb~mEV}lkaz$@}iku;PYImw}fj=L`X9 zXv9Bcb#Ek#21@xquID&1u^(~D9^475)UI@pvSCqGN1WD9h!GW((KS%w^gZPH_i9dp zZ^CNK$W!L3jxBg-r1FEdtRr(PN~<(PO!kz2B#Rnq;hHjR$N)8WHK!*TOn@Bzd|>({ zR}I$FUs+zA(NG75Rp(TfS=(51>FM`9ysbP8{ync1FXi%^kx!?$rilN(&tnDeBx)e)i*w*AZh3;l z?x#^Hybj)V*qCWo0}=tjboD2~dKLoPFs-D7{ znHbr$My~j#qG<8yaL~F*bi>f3HC+4ISQ#~I-?wEX2u8m0`mPftVDQtfoTfI=~~ZORV8R0i?!7_MqmO0_f*e9t%0-MozNMUugH zi9WzLP|A$tY>~q92>ISh*I|4j82!GWvElNIb+^b$+nxn)JiinMi%yg6T;0#zPZfuS z>n8m*Y|A#sPS~D9!nIWj$AtPJfiki^mr`b7gF058f9Ujj?D#D{d2-Fz93QVWM%+KJ zbude=Hu&v?zt!3C(A{X8lL<2Lylwf_U$)Z=?p2%D>?w=4SaoA+v`V_2)ugi&QRZ6m zEaU#wF8y7lynsRLQ*Tcy+eE`d7H64j8Eg512G8HQq&e*-KE}$*pMMLu3e8A*-q~=U z{7on9kuS*9Yn}U6a%kfD@hyE`@@rDlk7lxHh_deNMi{fw8HT;W5S3p%c5}b&5A4CS z{c22PXl(o^cqbv*9Go{BgHtL`(MZWIG3BK^TP(bZGCB7+JG5_Ox4yU%{A9Bwy)aJB zgeW8|6aVms?sgJY&J*PP{`@jg;$BMF--ALk+Qn$R$=Hz6YdLDUpZY*Yvx;y#krw_@`A!)5vIskvSKcSsZm!MS#uWj6CK`P+AVl} z8l6f6qYd4hDk0X-nvNc5uY&QC%{7+maW~VahX`d$H1M^9AIHMMsp^kDM2_k_rYead zOo}`a;Z?YAK1KOwmLZ3sa=s;f!(`mi$ZU2#V{7+o)Y7Otz;!;nlk>S@lFL?Z{=`Dx(nF{QU}S=x4x|VKjYg7kw)o* ztplo>8iUId+4NZ`%2bP~1V@_}}U5qW0q_p;`HF`peEq~76 zT%sLP)!TfPG{e}>9vqXe^3aR++6%j;NenpY8$8 zrVm<54u*3w(xwsSv0^DX@_yO(KfGQKr>q)dKG7G17a+9D)4qwSTqD<- z)El2J?r7$ItLDS<%&67ycO6L|v8gt_D%+X`@Mdvv@;8N-o0GPxV&W;UeS&5v-#o#( zVo=1_S|79)o-T7wkp>!-E7141RC#rS>Eu1QQA959SMZAC%Fq;bg@xKzXgc%GvE5-v zZQfR;{hHJ3-a=+SG~Wbkomo3BE^B<%T==rItkdqHuI%q-_tn(Y++pdqtZ0`!RUtMN z(zr;TXyimoW?XiwJLpTn*~FCs4BF?y_rE3>5Bs3D=)hiOHj47KtGzKA1wlxUhF$Q~ zk$31(iw@w$V%qqDAQ?TRt2%_G&w%zIN@hGbey!5?yA5-HyT0(aZh4{dvE!?J@#e-d z8(%wJi=E{3Wxd{U6ILAz&9s%&{9l%p0&aNIdr1n0nr?1OMND7D5pV2KTp?yQXiP3j zO~;9I+@f7GBaOqhJ&4OyEMxn@OM1r5jfJC#bchq07RrQkkrDJZl_XcEuWxcZNYxPW zndBJX93>1l)XPl}9QOHId_Z7b6t0?9t3p-FAX*i+F6AZ8vq@c5<`!>UC3mdUI9g6@ z7-l<(6a2<+MnaY@7jA{QLa?CSIi+W$l~YFa+R;C+sIbk{PO+Rxx(pY)rLL^7><^tq zy8aQsIs%~i@Ky)?$4}H!g-CKuTf<18$DeYpY>dz-yb@L>#Ov23W2W=h#~%HmN5C4X zFDbl!q9it=Br^EiGrnA0;am6zAaD>y4$cb~*JH~F2Ny;D-r-v|n!bI7D;MXSmqLom zIz~NI!5m+%LTIXtbR;^m_Ktap z#xoD$8xpJjQSQO+V&ArF3xfMn>e%cwxyWp{@bD(gRTlG^udC=Xa;V0iOCottBzBLj z*wuOCj7~viJayb$t>3vd)Hri;#(KTKm@8eg*V{Vl>fsm{Pz8N9hUt`6Mvh-9m8)?3 z>2|T8Oz^BE4c`>!rSFr(D<7F&4s|4ceNO$Ws@G~-xB(rQGfcnJ81kbk?9GCOed!Rp z>`1jS`O{++E5^D@nreGKQl1mBgi8P3FaB1B(zwq(2o!e{MuJA4S-k(;mg;6Q+RboF z1Y4>=PQdOOCMLMTRuaB*Uz6m#>W2KhW(#XYE20p2k>h;m<_Wq}Ev|*3(G&U^K^sy5 zCP=--nO*F=A5z_&&s44Iah0S5WKETYjQc(XIlb%eSNesH__Wt=fTE7K1&vs;mN-Ql z@I#r66Wa2`G|tC%iTs?DnhG8=gPa^UVKTh5>?u0;Y=qhEr@7^oTjU1l}9m=?cmj_pu0hPv!(!j8f3 z?dcz4P%}oW-rKW1oS|lnJCfM*NmBw2jvay~tTslFfA&R&T$_CM9Ut0lcq7JFDtc;O zzl=$lF~9q;*b#EaQOkN;o90j&qwMgJf84>&&)#(fVqX7#CiDR7pzm@1*c^Wq&Cfmr znVe&wM+w7?%+@B|N8c4CTW+!oy}b?~o%=(}J6d{?YD z^`%Z(;Ab8#$YM^b(V4etw)zzH5FuU{dY`<)^t*p7KNl%+yPy2ghtKjb3Pclc!zK;!6xXsFjjryC^ z^K*)>78I_L>vt2322xMw<_18{0i{`v0FGdF%}(vAC$)?S`dXg-w0@cam;wu@{}PL4 z_JrlZE%OqK44Y*=ico5wx4(4DaR#bllvCK|(+aBM6viT^nKO%7AX1rBZqF)@baa+ zCxbfx<$eT+ct7%@IHme*40z^A{v|g|iSPsgzPTR>#JEm)S;(c#5R?#)Y70cZpY=vo zpn_Sy9J*KK^Ig7Bz|%OnIgc;!0zfQy5jl8~m&C7+fq;O>b$Eg@DBv;>37%k>ikT*b zyMdD8F!5JUkQdDBgg|2W1PJc(&CQX$pqk3*iT6i_LE#P@i9pom1H4OrNDeJn_1XJ! zcK8gmLCoP4CyuK0Io}5rHakKYfpeOWqY!YTle{{GJ{Sj#dAxv7z8_hlW*g55ED-Q@^Bqi4LLBxgH;^pm*TRqsn1mLdRev!;y&o~g zz8|{6sEUGA!$0nn9|4!zKLf1ayaNnf<%#bNxfyrKJO>8da%aOt6lL#6S$2=U5M6Q0 zem}oTW7*wn*Y(>U!-ds<`!$$HZO2f9I>ikTPxP@zqC|4>K?*#68Ao|O-%onOV(zFK zixZ;qt(w1ex68wc!+p-d3Z<#OtWO5>JI__dK?*=9I=C# z7wgY|n@74D5&!WllExqIp|snl8Wa0sI;H$9_ko!HimE6m0hZs^O4}ZYbt4iip18~% zEFSM;iXNzR6LRMrlRyMm8rb&h?pMCxoZN6OlD&9vy^}s@cD<7b&LexSIle9}c#1Vv ze0I6SQQk?LNh^Kqxfz3OpBL+^!}5>)XYV%Fm?1BGhjEW!Nl|grcR&n5iRZm9Ajk^^ zWEQ`|W}W^8{Ku#$VGwXn`vRRdn$-AnrgTo3u^#lE<3pGc=P}o+Q2wTHAvgli z@Qkl@)9_ibZUC_u>*a$@@`{6M{i@gn&)DXB)q1i?j2g1j*EM8f<}D05G@e<$(o8XcCIPbYE6##Qc}BkBoG@G7o%`DC6&FSY}}tg&L0aTeC+tG zEjGz&mUYYq1O9ebuns`jF&?isCG(k%4q$`dKx!3)Lz(c6nH^{;g~xDqt|UdRE_Jbu zMyvz{+}@1!MANaL;jozs{*DQe#?IF3bv<8xn@x^}ez%cgdufd7|B8iD8uG%mMOc&B zAtBZ!kk)2}tHy5VfEISNTEQEyXR*UM5 zU%o-(mZr#JwiLbf;XJAp_)T*8(eBkz<%(9#db&=}<-sU=vg#5YOHR0=j#y)2jh~Qi z@8yBso1y^(unY??uV7~}-1VrL2N>zNs~dBv5_x-XbXb{@=#!(KkK)Li1=3^R*OSrsPKe z{)O7-l&;K9~5uKYegU?1-uTzXUSf>mkd&kog{hw_Px-5c)ISAZR8fCN5}`ii|x zj!%Ba5FXgkhm?^(qU$&y;tu_$7Qkn{oAOiXYWMpUoH!sJ%yEM-zR^NNyAJ@!@b^16 z$%?@lwfoVfKUjZYXVD?~;79_Za~p#N-Fokc6t8McqG6D+TZx{2Y9*^Nnsj~eX&pX6 zPhPQN(s2Y=ZV*=Hp&PxLsQT7wXfWd1-W0#%N(0;382T*Ma->5yb}*a7l2c!r zJF$se;51JpIP8Uy zlJA1CN4ea)ecr|Dr!zLqIuoET@RXr1(Alov;$LU$O;%a4T8M&pVg5p3QEO-$+#^KsGWqu+57p|(>#<#92#p+j{vutTg6=1= z>E)64YB^nCN)KAmjxR5RV%plMVJt7zVH0k=}XP|6sVNZ0CH@#46lv>90nD<4u_9Pzo2_ntII;Gigx z^>M%Gp^U>lofj36As^`Up4X$`16hnPf3~^5aDCX#iPTJajBU8wZAnWKf3(<%7$N5I31+B|4Pk-<2TD{yH8`4^{^WZ-jKMb=Z? zU%W%-xQgJs7o&J$t#w?zYWXbXq;mn>k#p7EU_s}A4=Jki97VRdakt4rMT4nlNEZ~5 zcz?TliD%|a18mL0WyHB@ReCsYZ9j0S$({O-$>x$CoCtoj=+5h7C+_2Y z0%Hds2JT}Na#UpGkOOY;5F_^>57wtm7x-Q;7_qB#GKy2HP0~G)2`!cX$EpGLFgHIV~Ot(}?%6P3xY zoogk3CG!8ApK&~vc;I3f1bn^ux@{qMZBU+Xx+U&>)`Ltb`^&7BD&NsXEFPz?#~nk2 zEBDi~*u*mCV9U)9DJcYP_@6}UfA_2)P(}m zdT4C_laPN-P`!&GH%E^OtaizZ^|{){D3nT?(54ncLq@L@;INBZyZ)*y{p|K)M1x~2 zU!KWFs(vMdD4_wz=EEPbgdp(uK8k_fXfD&^Le0L!MpB`H7vYnB`U$1Ysq`=~Sg$>@ z*iUx(8gY(Hd~mt!hnCw0b6{(*J;fv+<4>91RdEyEAs+{PfQ)Z2DwEyRO5*O&xraEC zqqg%|A7fD$xSIiiwI-dpKy}5-M01!CtHBjoxTKF;vC7T!WhXk42-oY!51I@C8V_v9 zTZbX3j7U2hX2V>eldj%ZQnp3B|E?n0&Rph#twPbN*zlCwHYuiXu`MJ*nH*<;z=ts? zF$%rB_aT)Gee7g$CTyMBx$;LDFrW7Y(9MiRpUR)>N?CorJpIsvS^WX>iCdqv0W)x9j*R|6X!=S?saBfe)g2YmRna2J4dUZ#zykdWi6O$B3sQ{UhO+r< z6G{LcMg_%}_**v=#{^|rB6feOzIE?!&F!emCsly&?d{!?fA?_WzP_mrEJY;Uhfo401nTH8tT) ze!dzawJwBl!%ribD}ZUj-hn$SX;%Y2%*=zIRYc<7+tvPKZ!ncMl)d%`m?o?m4SnWY zbc=&_Tb2p{@>d^bek}!j;k%(yPWqbI9e|}l;{Rpk*~;QN9Xp-G-vBudZ?f(-i^>^n znaz;T>(bJAc7&p3`$47s)<37)9;<(Pp^FmND^Ip)Nu!|tGZ(H`!63G`iVZOeksVbM zCX5kaRdy2lIpnT3SOS@FL7BG3DFKUVxmeuN$)mwKr#guKB!U;0{`COnQA1W75qF|p z?f~W-sWqo`7Dflw!4o19{*iZ<-h>ZA6P}kHxl{co_Q}E5?V;TX@axbTs@@$lqhMFn zO3FNVHaz`FcD(W@E-88!D7o=HhfN*KoH^=#cLsPD-5Hp7>rsa|shS)0VTXD zzFoZy83)g*IcIU&b3N8t^DHGaiK3jui-4t23@%N<+O@&eOgoRXFj8xeG#gUu9kE$L zH5ublhx5ii)t&$*pCnYhbX)w}TdfPE%mGFAw~N#nzgUgX?Sw-ssh{F89>t->!`J@@ D2>!f+ diff --git a/plugins/hookgrabrope.smx b/plugins/hookgrabrope.smx new file mode 100644 index 0000000000000000000000000000000000000000..d115dd5bbaa29e1718484542790f9dd9e097f935 GIT binary patch literal 29969 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 ZyrtdW(3zj5*U*W+_H=Cz+~#Q#^FO^uc{~6B literal 0 HcmV?d00001 diff --git a/plugins/rtd_ultimate.smx b/plugins/rtd_ultimate.smx new file mode 100644 index 0000000000000000000000000000000000000000..94bfc183c89d7be31efc7c75c130a27f3f37f677 GIT binary patch literal 13651 zcmb`NbyQnT_wSM7r9dfAyp#$K#XZHLXn`WdO3~mD+yceg;_gtqK#RKtN^uWvNzmXf z0Rr4S&+mQL{r!E{&072H&&+(!p1sdmnK{Wiii%n~IM~=aLReTfU~H@>gxFYEs~G#| z^N)Y1i-m=c;e!uYSPX}lHin56u(AHpQDOM8A~x0!jAz1F4Ti@t{x!zFC}CrlKnu{n;A!rL0Vi{Jpr_Tp;D~W< z?(V?<(f&)0R_?aWmjCJguk_y$D<==f|Ma{2xL8?QS^uvV$jbdcEei*85a|C7S_7>d zFyVMCKilwF10DXE_aAfsI{g=cPS(!<)A`@I|5eyHIDa;G_^;gA;ve>2*bgA}*6s5- z_@&ohL-A~}<~?6833UUX?61(yKfQ{OXSCQgFZi7LsUj~39S!#@y!4-HFZ2t?sL0a4 z&SU?Uozif|4piaQaOLW&F286YbyVSSTTWSu3m5&a&X5pC?^~Hb41yo}gGSS(7FfSQ zO4`Q+;N25`qkh&MSDTla=>m^g_hr{%>y$4PzF3v~bu(s8oNaIV)0C5V=uZrp41w=< zLAJV>PZ0!CC`u+YJK5bY0&rJINrZ!c9s%ps9GlUSAyKkwfAOB{+%IYzDGh#{t*Q5wXVYpMD8Vm%;yM~2~9+H z7xho*u}d4Ijo*g49z*-k3d{5Gze>H*GY8Pe@qfR7%ul$p40TbGZEU=OQ z0uKRTDm+FINTNifP%QtX0oduHS@)SrB{19Q67f08ltP6PK>9-dNdTjhLN!XFKurE! zq)cm71ehx6B~j{3{!<}`mk3M_5mG1_vcUcj<_m<9B zbiq@})s*+vye2L3SJ^y=xk+K4lc~0iWI?$&o1X!$A{SXrKvmFbhW*BTYJ1FW z4Oi~-tgfX#AQQnd@@}??@1Ju` z{ymmZKi33v0t%;3U#c{Ru1jvr@|hwg2*G#^Sa$?2%q~xw@VqGu@Z`@;2XmeDZi*%+ zn;=ZtDecmw6-vn$QXGqo(}7&0ypCC=b+{jEl^&ERIeOXRpW;F9bOf?oL{tl#2y6pG z$}@VUfI8{xs#fraaj|(T76Qow^(ziI@?~6#@%A?Qz zY4NaITl2fN9ir8u2p@(*Z!gZ{Ka_tZ%KsYu`0Ho?#hV-8zB;16I*oQgd-HM}Q*#_& zsFNRNJw7yj2`l9~-nycuP2I79FV5ctO>2}oAGCcq{!jy^)HbR_a!}M-8NG6{Q#Dmy-0zo{wuseJ4M)xWX?FSr9DzQM!;?~8?vP97-@XZHf1 zum|j|K^rU%UDBn0&behi6v=@YDcZm58GUXaaPnxk$z)(`JAb%I_q89K32f|!oaeZl z4;xLhOI~AydJgvSLCs#=Sm*w|;x`j0((na*aWnZD1-D~t_83dFdNWy|*0%a_KbW|? zT&k(t$U}>3=+Mo9z7pMg>Y-;Oda1FAy2CcKNl~vY9L=h(gK^31Xt?aUG~AOh*Ro;lT$#@)@6z>w@*<&Ca}(dl#5E$k7~Mx2~0rwH!{0%oTh z*+*oocqE@8{|F7D@;cz#zK5yXRQ>hS-GzR7ugqR_Q&u*xmpv_4|J~GW*c#n`Y`4xB zbNQ=o=)}31KhV8F=aGm?&Z_kDEcb&HVaB#@iKQpB6^cYQ^WMtU$7$I>>V#%}@6EUUF*2}b%$xY$f@ae38*i49H77X066e??uV0xa2+D$FcBTWqs+AN>oG_Ha_+WjCJYhJjcX zb`48VrxM9xhd5%D+8)ymZEhw`neeR4W=L^y?RFTaYQ!I;21FWU3ON(eYt0Mv;NY8~ zF&%PGO|!q+O;oHH9upU%(Lr8t=U(!FAxmcIVlu7ue~i`!yg^PG-997DV{Fo=QD^DF zTsQonBy{O10UhN<`;co+viOvAv-0uE&fPezSdQfVLGpP~>$>Plk=K2z{!FEAJ9DZp zS)1S01zsp+%Ek3Ti5tgpML~)ztWiBl^oI28fDbC|oorPnud)c0z{*yt41ukUi+M+% zNpsKg_q>df@~W-qY8BW;{uL_Ar7VJ-C&r!E)(Q$hO5!h!W}iV`8~cvQAdfu8C5W?W zDnejiYPSw;D%)Z6xY^UQGR~at!X^amMn6E49^>?3qenu}o4SXT zY*x!xr#_O(OGDy~!!~9*-ei589jTWxz6UF}p}|*s<+1P~U;M)X2Ebz*Ubv5R?f$rY=FZfl===LPz!KYH5@*K4MaKG;p+)f= zROr8Y9H8T49T>~9&x*-h$=DYjI$DWI$yo;ZZTE-QQ*li*f_9o8r%N8=nK!JcmfatX zPkl+i?)&E{vNj0ut>59J2#@hatZdGTcvE}-k{+UMX+P#zg5Qw_HY2i3@G;(XZ&oYG z4w2+zRNyC;*uw~#>YNa(wg#f8TAEJ*xcv<@eA)+l9t5wy3QUL(x0hraWL-H`>@Kg( zh;;VEX!wd$dAoW3gq!K!@Os^Te14t^%WBV>l5)9H|6Fv<{YRWc&cfb2_*5#t@Ut7d z^n|n5jJLJhWc2cvkqNxEqENE-Dh@Y!?J&_m*n3~dVB=kfoodl#W3hvHm`ZLyno;e~;i#pl}P(s9>s!t%OQpB|zIcdaaD9H-5a`VdnwlrA@> zGg@Ranv?5OajcYXF{NH1)j6=^s|UoD0(>^{YIQeJf!~bnQO-0H3`ti?AJ6EPXh!k0 z3VUn`RZMv8P83msb9o2c6kW@P!QXZz9KP)(l9))3+y*Q2}gORu%)*x1(I%7IN_et?}2*YDjySnIVj z+a~SQWyReM(RQit;dLPMfS#!-oW3TE@i4PX9vS>goGYskP&Zh8#DP{@d2t&aK%nonDyGZ+zu0#Zo7Vt1_*sw!{xvizv z--e0do-6J~&BV87?l8v>HYBNolqM-zi2wa?1n%X{J2^Y7@9vWvnR-{AT~NAz$Yj;- z;be6IfAiz?YUl8&``fq%j=fyI-tC}YE|qpQ93!KVSmOyNw-nw z_9{KaBStDy1EQ)_y3WP8X_z-LusxU^T0xRHC1mxuWi(d&RJKI~tZ7*Uf(7ru#U{aTYg=wl8&nu zk366rJkdMvcy_8X=AMI8Hn|Y+IuP)={62hYQkJ7vr14w&z2uPCp+zm`B$Yt#- zhkfjWim@eJNxe$+!G3c!Br{1s1E94Fbjk9i)9npMTIL>c`d(8>32AFW7T_>1SY=!X z|E!2-P9aRErH6H<*4TD7aM&SJPwcuV z#srG*5#v?ln6gLGF=jEmH$9J(u&NLvYzI`f<#NMm%E0<^Gh=&^qYNxYMm6Yh^>>)( z5=1m~h&r;4Qfw0H~Q$8YLOr?bkUb$00Y zv^HiWx$dJ)oT@J974k&&(n?&ve&d-WWVSq)7emB7lD@x*_iZN4rONQCl@l=F&?*z# zK(9OFDKwJqc=&EXeu8xnZaMDw+&=TCA;@tdv^79}HtJA7qtf*Z+E!=z<#;5clIP4I zqTJ#>MF_U0hbT#;Zw!BBYY{l#>)F5te!WuC5^ZH~5iw($DJ=ZHqvpzLn%StK>@IB~ zEL9q!BxdN#ktC!#f0MrZ$}ZxYhsGjTa=;JWZCtrs{?kUy9hS_g4y~Oxrg|KZMRHT5 zlxfFCruUtOW3zetiHL{0(da@7QX!`)Z5R^&*$oB|EEg5O#~-Qe`|baQxp5(^D0wrAW5}uL+=0 z$%4TBW{Bq9el&-VXFQ7UKIi9Ed9i&`O$p@Cd_LigO`B+gI*jwa13y{LI~*;weBrto zEoRIU1}K2z4ZYdT%Wr#bz{F+NP-j<4$YW+~*xbZ#KqSYR0;npy4t`mg%UnC2E zR!sPF*6a1u!uI{_tpR_6@XqS-&j1Lgqrv65R9>M697d^G97c((_U3n3uH4viAf5o*keuypP#}HjACUD#VvIhTr#K7gact?##$hb3y$Q;sAkLhx zK46zPfepvBA@`2j)2V!%trcJ(Jxgy+`jh$5aQ{t*e)qz5cjwGQN!8P2Z}ypx1%(q! z*Rq~14T&pGFS~(}^!cH6(aiL$U+oWLYO@DiF9gI43(~KfMEOMxU(ja#T2{OHb)qF& zlGb~q=NLPknP6q$q~CHqygwJ1;y53uw@^DGwK-+fy!*hpr(9@qHC<90eXfjfgrb`$`cO)A6)u+Np5otSx4QX$?5~o=wRlcp^vT@XC;TthT+Dqw(_hG_!eS3 zB#~pL8>4=P=M^@C+W0meT*--sgNR>xWp4bcv{}>hx}$c@7GeUbk9ac^cEu*GOTJmT zSU7lQ7~_ldT9*)6V;Z9l33j*MLLkHS4ZV}^+UnClcu=W4gJ(`i|`*hG;S6(IluMWRyht(l4Sh;k@wh``Q5m&V9!cRw81-ApC4F>&{_nPYEKUlLVYv20RU$vS)t z6;lw~jEH;#A^e>4o<&}+h+IfD)F4>J?OdCsEQN@ouog5eo5VwtzmCm~A?4n90!$)*&rSZ%)%t&r^S|@CEB|)a z%65I2|Nkl8zj+PaYeHux$mhnP6KxF*1@SqJMSt>dCsMGE>FF02GG{AEBxjZ;o_PPN z_VLhB`tjS-r2D!a8~w0Oq=7~LN8s&3{n=boX?0*oX<@!3n=f?xFK#5w;hZUq>d<6~ zap#>9M+##3)S1MUa8|~+yJ>Xw-Cv#UQDuh+3e~>ER&lv+@`6yRcS@^oShU--2i%)L z5%Fs2V}(Zb^ZW@8spgaMrmV13#ks*BKlh_Ad!WJIUO`)LUr;O4nj9O5QW4@ko*3t0 zrB&`Nn0VXL=i)9bI4gp$H$CGeNYKBf)}Af#oM@|p$xH;tq&RR&VJ65}6B^!;v_i!b z7ejC)4vZiT>$Z$0uV3Ng%D*9`;=n7M+tzZ+jOS73W+QP>4r`z#d%(|%zv=qbC)h`0 z$-wMTkCljHDOIrCHYeK@x)puMCps{sG5Jl>w8rz}BJ0FY1Ij!%K3w?jj1qS5Y~frs zKh)an2Yv0vP}!rnmHG3`_`L@XCb}E!b;KMv6W=3(t^{MAON1BvYOgM;?qDS+Ij6J2 z-Vu|K1ulh=B6A+TD5kvPmoH{iQ(w)AE5agW$%O5jk*{#;=*Bh7QSwP&+> zu(MX3Hep3=Z^2KiDNUZ1tKCa&7fq4$7fomqoL5Oo`mjClBt21+WcGAG(^8s@afJGA zT}O_WEZ}@yK(3OE5d@IyPU9O-cxn3Gv5?uTo3DXXe}V9P)T`Ed(K~$-KOSNUfma+3Y~@J706YRw!b-}(mmJ>PJ{%wjSWayO931k z{y?v|NpL9fGTx4%bq%pbw(9e+1qV_iOeLDh)VHD&HS@X-B(5Z|y(Tk6M}|K9>>p3% zcZ|qS)d>8&CG`FHdO$NHAapWU6j2bM=%)We;>kC1tiNVkd&2xi zQ(8j*A>-3)Ra<|Ht#Up$#wawWB1HlY@yJs&8BX(|xd-z6V_MwCk;^DMo zolzyV4RZE5a-hgOK>n)l)q0=kd@63uJ5%ZA)ZGUY<>Q_n<%$U@C17%hF2tHdP{d$Z2i8*m{07CVTn8riaCn zN+?vydfuOubcZOHoPeYH6_!(r*;i-WSPiPxUIrEz4$lK>YQhOZ2b}OAzaR+F519&9ZF|AI^{*GgTETd?iz- zSnaoC=^$D<`AH7ic8>ULb^H+Xd*dspvwJAazyo*FvytR@x6^#BcbyU?HRpw`&-7=mZ=NlUyrA=SQU`&bMEWK-%WwvcT<~+ z^M6>ca&(=OS17pz5YASvErjhRHc3b9sy3PSoX0kGMDHS-X2LyZGI90Z{aPG{Lg!%< zGi^>naOb~U^&RT&zwEv%v963)jD8&cR#3irZ2OL7_xXT3nbVW9j@Ps*MSgO2RoC9m z&Sno!w@JV8jpSyFL{}eOAH*;f;3cwznNHJ0S43O<-qlinO0%X(r>N%?;MVqZbn$#3 zI**M%YD)KJhE9=Au@1^GYM%XrwBOvOq*`Eko=TJMM3@Q&ql|Ud6pIDcx})AKn|zb7 zAAq%TKHiOqJo)||vs@1@Mma_KNJTF%8;E`#e(gs5Wts4cK9AW)Ls-+~){ZKDJ=AsT zGF*Y0L*Vm=o|>H#{Ka|Y4GTg}|BaK4X?`?`J?iR{-EQpD)P(9{I|bHkVgkvc9cKVOKyC{TJ0|7z?Z@5B@y&=$bBHkJZ8yy$qR$W1c2CY_Di>2VF|FoS*OL>VN3DP2ONE=aA5+2WoWSa#F-czv+t6r~TEi zTA!g4=L-@_N#?J%(Ep?23B;qbxGC5|9jO9WmXdjm^ccCEMOwsH)dT9jzjxZWh}nw% zJB|~KW0j=gS^S(?SblKn*<*_ElbiBX9?r@U2e%5P$tw%|DHWY(PJcHUN^40R7i2RO z=JoV>%ggw8rKc1~AyUy7HR@3;+SvgHUPH?D=4p#6nOfG@wq)Vy{;$7uqQsp{*suia zc^1YWZyVUWn4YJn+N+UxIYjn8%4Mb)W$1N!wr7Y>~xW4KRJyRPQ#pBkal~Z3@G>R+^oK4KRZD#i#mNDA4 zt4xGiW_4r>H!Cj8?mK9P=0qI_^tv#{^g%rayxEqhWWQT$htt{yMBM~BnzazDjYN>P z${0D*Jul^f1-Zd~g@5^=0)5=2V_!$Mrdwd>HIoR1N7vOSzT|5O3pIa~A=UroD}Z)Q zLnhDCt3H+Ok7*-Y_6!$ZIZ~Xgrn0nM)bAs`wqk-Ga1hoNj&lQ(tw%9J)T}FZ=bEHt zqF+7fIeXO{z}T|zs6f~%kv`h8&`)3Li*r&(b9BV5ha#cHdpgFXHd7m9S;~1mV|KZO zxI}h@;znK=Q-+Q)>4|>(8es6*-QH3wP5+pxY&|j zgBBrLO~PyQM+o&aFBbuRFth;Fn37_6?&1gB(WIACVaXervyKT7G{Um_Li?+fcd3JO zW;!vdZ@f1lAGgAh{+D28MO{vYOvKV|VML6t;FsS9;*lvR;fuPer2I4^C_}0P+?-l- zVPN{&scdtTFPU1qxW<+=uen&>PZO=eFJChSZ(03jqM=LsKIYu*2SI0rJKJN`Jn1>) zwBq|+%+yPo*5)d@Unr< zr4(m9)3qG+X%gN<3lB-Lo}O=FSx^@@IfKZ!4$G;JUmbS$-WcV_%bRs4?&CIi zxV7e2^jBJr2_QSnxAFG06n(h{Vt4zWM!FeWg1m5>qpEpr1#9LOxQt1R3wmtg=%19Y zYz$NMH^ic|EPsw2M;J*~MK7HISuC+`*<4GnhLE@`i?cHP!PG*q2-yN>|*WsfxDWv6@v-Mtj4?=!(*T;%9)H^$= zMu_yQ&y4KE*!ys>g!1x^rRvA6arO_f_&OGS83^~2=<#Z#>*Z-SjeE&%K>FgCdHuFo1 zVnZ#&>BdIFD{Tb$&qEW@kiGsPySFPzZEY>=o0(bf015m$rDv~Ey_y;H@+PK%%cS4U zzZwAPQk4#O!vw`Or>;PcJp#=RD50T$2A4vuiU98q1%8i^Y(8s!l`bOmUP~*^CgX!v zkgX5@uPA^*J}@#s2biLg{rAs1W*Mh!$d4}lH00^@Rmoe@9<`Yb9of)kX@Pq-rnyvP zCQj{KRtx>CeM*73>{QC}0D5rWxS`1FSi{qE8f6SSDjLyC zV>=kyh&Ed|3y70e9wPm;fd1WcO4LlD=2MJrdo2lta#*; zZ!ziT1vVxi5^1v@{>JspU&DzZ@sV$Fv;~L6!h>ScIkQyyfjS`C{)sA_x5E@@uIv7u44n*3~x)MVO4hm%+4Qm zjEbUnD^cF3*UkZL!Ro$1${Xf@ws@)awUIsWxvL4)p!iJ<;52SlZ1xm_w3c>mV>$JS z*uC0{P9KB2NacD+>8p?U!`6HQ$Iclt;;$U)B_0y20)E^SZQFv_;LRd79XHJ0m*OtO zXC6cRY0*Q22gg7d0X&6egq`W|jtu|vfP9gtw+H|h8SZ_&JFX^{CN>0Hk_=spxSu)9 z4GLz^s1=V;dT_!6$GO0|e_fT^Mt1b}5%@%$7)`?=hk$4=W6n?tf)}H2eB{~ja*ENo z5Y;P!JNgY~lvGzP<(Tr}X}}=h$Z-$?M~lB2#ff0Q-}(S3MB~Eq(72@?8E(x{TeWMk zZ1Jpa_i%R=iRYkkY)${ljV|bOgqXLVlnp!60SK6cU&zz!>d4 zX1*AV9`YCse||@>!3+Z?oshL*BpsSpV{4jWX=&*mEi_vN@f2ye4E<~I?u2P1k|bHO zaxWF5CF$aWMX*9dj=nBEXrsWq;zQ~3+Jz&!N#qE;=>1fbRFp95ktAN$%G!NHb=;ki zlHgfpFgAj_(+=^wQ|}W+)$3dU@B-JlgjQ9$v8$kyOe+(26ekB8hRuLIicbye&-o%b z!|;jph$mwO3%B!u3(p3#Xe=hX%o8%MJT$yNCrlCI=PxO^#3`lCzQNqo*_UfKur^+@ z6qW?OK4X^}eZCDGWWVq1NxIK$I?N)_)4D6Ei6F*G#T5J@35?Jl1h~*{Fna?q=Q4OZ zaLlfC>Q+E>bml{{@jY=O`N-u5Og}xG!$FfmRdZ+9;hkgHmsC}K;y7p=m!~L#PU9$c zFku!cn)N#%T52H}hz4FOeEPb;5*L$}jj#AqN)tJ+M0G^8L(?gZ=-5WH`(dFnJIxU~ zQyp(&Zl%u@gO&Q35UD{CLHF4^RNhH@y+IAp(vG;Soq|WKy0FfY{=iQ!=Wz=Q`kkpy zhBw=?q*DI0E@^Hr59cnB;WGaS1PS=9uNonGO5xbsX+x%ncRP)ZM{{CsBx4*QX#o@W zf9A0ZCtEXv%6~#|^>yxo)Sob+2*djJekBj$qS$(H8xjK%iX1cu3&Fc5$8-K|Uu`07 zBAc?tsHz+LA<;t;TsE=1u-=V8@;UY6pherPmh9cUs2Dyi-$qb?15Pg+Y+v#MIl7*1 za<5hqi;Zx8FNJfXqWNYl^n0X_q6j^TVVl!B*YzRl4PB%3v%h_%#=-7tAYtpu+*eE} z+CdQ)Ko9O6PjqbO7*td^(k2wQbL{=y0r~2w``_TZn-2&I1kKODAn;q5kMPY;It25C z9WJV5eJCiRG$$CWxWBK#a>vlbjCxrHK$wjWQ!6Ve;u^5DscmCHaMZ@kbG;lM-Sh;D zN$!dYMBJ`zFW8c z-;s09jHZ7BRg+G=MGQs*w@2JAl#qk-WYI~r_v|LafhFKKH<_%F^YDjU*7wjSmiGyS zHDEDv%X@wd^Al&OthwRcBqtDG(0{`il4H&}Nv{U};~tud?oD}jL3zV5ui0iW5V-Q` zF#l5d0bsFsM$t?HVoGBYVV? ztmGd=Mh{%p!XdXi4JeO@5& ze}JNPA-%%mqBQy`8Eg-f#IGng!EZxW0>3ni!{wV|6gMcet2TKIC25Ummt1LN_Id}&+dR=1vX$!O6dzzY(!<^lpMI+() z*CqpjrBrj8+t|5zZiWM#y)uYe-BC`T4dwg#)4tMdY;eQ^)luRTNH}tw7y6$6I~nFn z+DUZF6Gjl2f@V3o?1z24K=R@MG&i({?plAu+8Bkx#!q(o}Y49GlR@f+%0_ z`V@WqFc#QEhoaGio$tkxP1gdX@zJVwWRI1C`+nxo^L1!TB+tF5E(q3d!zFE_7R5u` zbAS<pYe)qPx)GbVsv5>wXoq9xf8fgl9;k&YN< z&$*b1a!rI{cPQ;g$2@_e$xs4zC7t)``$Q;`3>$3TaY>TIP;d#VlcG!s!8;I$sO-NJ zVl%R%>5QDpnLRpb!rQ{Vz`gBU>oi92@sSyffAJBodg4u4_0Zt0gnQ?9Cllf!W>4kr z6zDVxzOpwb;UjKiY$6k-^tRQ?2C-@f~;D@w$JkVh(?j?-lEnK}7qt3J2BgZT|hT5w&P zykLAw4c>gdom3-w@O<001{D)o2pU{P@+9a%S9|}cC1|{jY{jS&smYp@#p$_cnw7;3 zxEorO#i_Wji3LtIlnQ&8Xn;A3cWNw$9qH@Butge(S^x3`v5Knvu|n9B^DZyoExW1S zz{`-$dHdt+sI8Ztnt937TScm={_8uFRFc0Ll1v8f#WqMrsX1SWLE1l{w|gI5ac?Y+ zQb!ICxJn<*t^03qj{RWZL=PovN_qAt69Xfbe)vDA(YgO2>r^c(o#)R~;~`xd_axvf zV0|mn@^So(BD>Y;n2a=;8(i?5h zgG2W)L9Z@S8kLYbaBE~?{Bo{ayfu4(!3f3oQLdsAV;1$34;!sn>M?B0$gfK(8_iE1 z?J0;xbgvVlyFUl@N4!1I>!)~5zipKBVt>a#9a5SXSA0A&s4u;U5)R`+2Mcby>MPf7 zU9d6Zk^IiTsgqq$xb(AAe)2W_nz=<;;GFlL1H@%pQcmoer=Nwqub<=wz8MG5>QK!n zHIwguAIE((P^&-0@rs{}GT2y!`2JFXHa_fG1U+}nnHsG}`t!J2dY=^4i4b|%qnfJt zk`{SA3Nd<1Rb23P;gT+;7_(*c3-)#5=bSS5FW8+(Bk2Ywx&=k5mBGj9GS8W@#k8E` zyN%z)YPd=_E{s?gL~<2{COngvIo6F=7El7lDb1eH%*t>oF=P7}BzVS1KRQW5$Jisc z1fE5F%!;#)dGtl{m5PLt(p#n~<)?7Xb*%nnVMG7k;R!e!bJRXVz_LPyXJACl{BR<8 zar6+%%OrFxVzD^t_0}n&&=JY|wjvJWUY0$ItlP_a*Lo(*zTd_@b`|HiC^n>kU&_sm zZ8$TUs6VOkJoO9aAD3e0;$u!3Y89w(2a#p)3&%B)aT~X*`6XfL2PfQ-by0_SVxJPB zsMpDr2Mx!qCWZ5|rdVQAg8~7q>kusd<-xrD1i-_Sao<;tYi2lCtG=%bfoS??H!p$o z_hiqyse!cjyw5TnwCTW#V$VO(-^Fzn>e%pIDThjxGYs^U-UoWB}BL%bXNS=}GdV39cUV~+GH|^%J=U(1F?k^B}1blT?=H}j0 QF(P8Tevdns_jLUK05q99-T(jq literal 0 HcmV?d00001 diff --git a/plugins/vip.smx b/plugins/vip.smx new file mode 100644 index 0000000000000000000000000000000000000000..938f47b2d388a2843bf11963af30d1979b764899 GIT binary patch literal 6159 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 Q06#p$=4TeJKYCaH4@qR4!~g&Q literal 0 HcmV?d00001 diff --git a/sql_userconnections.sp b/sql_userconnections.sp index b040c49..ad3a14e 100644 --- a/sql_userconnections.sp +++ b/sql_userconnections.sp @@ -1,6 +1,6 @@ #include #include -#define PLUGIN_VERSION "1.3" +#define PLUGIN_VERSION "1.4" public Plugin:myinfo = { name = "[ANY] User Control", @@ -13,6 +13,13 @@ public Plugin:myinfo = { int iPlayedTime[101] = {-1, ...}; new Handle:hDatabase = INVALID_HANDLE; +char g_SQL_TOTAL_GAMETIME[512] = "SELECT SUM(connect_duration) total FROM %s.user_connections WHERE connection_type LIKE 'disconnect' AND account_id = %d AND map LIKE '%s'"; +char g_SQL_CONNECT_INSERT[1024] = "INSERT INTO %s.user_connections (player_name, steam_id, connect_ip, account_id, timestamp, connection_type, connect_duration, reason, map) VALUES ('%s', '%s', '%s', '%d', CURRENT_TIMESTAMP, '%s', '%d', '', '%s')"; +char g_SQL_DISCONNECT_INSERT[1024] = "INSERT INTO %s.user_connections (player_name, steam_id, connect_ip, account_id, timestamp, connection_type, connect_duration, reason, map) VALUES ('%s', '', '', '%d', CURRENT_TIMESTAMP, '%s', '%d', '%s', '%s')"; + +Handle g_db_schema_convar = INVALID_HANDLE; +char g_db_schema[64] = ""; + //////////////////////////////////////////////////////////// public APLRes:AskPluginLoad2(Handle:hMyself, bool:bLate, String:strError[], iErr_Max){ RegPluginLibrary("usercontrol"); @@ -39,10 +46,23 @@ public Native_GetClientPlayerTime(Handle:plugin, numParams){ public OnPluginStart() { - VerifyTable(); StartSQL(); + g_db_schema_convar = CreateConVar("sm_ucontrol_db_schema", "", "set schema for posgress support, to mysql set empty convar"); CreateConVar("sm_ucontrol_version", PLUGIN_VERSION, "User Connection Version", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); HookEvent("player_disconnect", event_PlayerDisconnect, EventHookMode_Pre); + + HookConVarChange(g_db_schema_convar, OnDbSchemaChanged); +} + +public OnDbSchemaChanged(Handle:cvar, const String:oldVal[], const String:newVal[]) { + strcopy(g_db_schema, sizeof(g_db_schema), newVal); + LogMessage("[UC] db schema changed to %s", g_db_schema); +} + +public OnMapStart() { + char db_schema[64]; + GetConVarString(g_db_schema_convar, db_schema, sizeof(db_schema)); + strcopy(g_db_schema, sizeof(g_db_schema), db_schema); } StartSQL() { @@ -67,39 +87,6 @@ public int CopyString(const String:Source[], String:Buffer[]){ return EndPos; } -bool:VerifyTable() { - - decl String:error[255]; - decl String:query[512]; - query[0] = '\0'; - - new Handle:db = SQL_Connect("usercontrol", true, error, sizeof(error)); - if (db == INVALID_HANDLE) { - LogError("Could Not Connect to Database, error: %s", error); - return false; - } - - Format(query, sizeof(query), "%s%s%s%s%s%s%s%s%s%s", - "CREATE TABLE IF NOT EXISTS `user_connections` (", - " `player_name` VARCHAR(64) NOT NULL ,", - " `steam_id` VARCHAR(32) NOT NULL ,", - " `connect_ip` VARCHAR(15) NOT NULL ,", - " `account_id` BIGINT NOT NULL ,", - " `timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,", - " `map` VARCHAR(256) NOT NULL ,", - " `connection_type` VARCHAR(10) NOT NULL ,", - " `connect_duration` INT NOT NULL ", - ") ENGINE = MyISAM DEFAULT CHARSET=utf8mb4; "); - - new bool:success = SQL_FastQuery(db, query); - if(!success) { - SQL_GetError(db, error, sizeof(error)); - LogError("Unable to verify mysql_bans table:%s", query); - } - - CloseHandle(db); - return true; -} public T_SendQuery(Handle:owner, Handle:hndl, const String:error[], any:data) { if (hndl == INVALID_HANDLE) { @@ -120,7 +107,7 @@ int GetPlayTimeTotal(int client) { int AccountID = GetSteamAccountID(client, true); char Map[128]; GetCurrentMap(Map,sizeof(Map)); - Format(Query, sizeof(Query), "SELECT SUM(connect_duration) total FROM user_connections WHERE connection_type LIKE 'disconnect' AND account_id = %d AND map LIKE '%s'", AccountID, Map); + Format(Query, sizeof(Query), g_SQL_TOTAL_GAMETIME, g_db_schema, AccountID, Map); SQL_TQuery(hDatabase, GetPlayTimeTotalCallback, Query, GetClientUserId(client)); return 0; } @@ -277,18 +264,19 @@ public T_QueryPost(Handle:owner, Handle:hndl, const String:error[], any:hPayload if (StrEqual(ConnectionType, "connect")) { - Format(query, sizeof(query), "INSERT INTO user_connections (player_name, steam_id, connect_ip, account_id, timestamp, connection_type, map) VALUES ('%s', '%s', '%s', '%d', CURRENT_TIMESTAMP, '%s', '%s')", SQL_PlayerName, SteamID, ConnectionIP, AccountID, ConnectionType, SQL_Map); + Format(query, sizeof(query), g_SQL_CONNECT_INSERT, g_db_schema, SQL_PlayerName, SteamID, ConnectionIP, AccountID, ConnectionType, 0, SQL_Map); //LogMessage("New connection %s, %s(%s), U:1:%d", sUserData[4], sUserData[0], sUserData[2], iUserData[1]); LogMessage("Player connected: %s %s|U:1:%d|%s", PlayerName, SteamID, AccountID, ConnectionIP); } else { - Format(query, sizeof(query), "INSERT INTO user_connections (player_name, account_id, connection_type, connect_duration, reason, map) VALUES ('%s', '%d', '%s', '%d', '%s', '%s')", SQL_PlayerName, AccountID, ConnectionType, GameTime, SQL_Reason, SQL_Map); + Format(query, sizeof(query), g_SQL_DISCONNECT_INSERT, g_db_schema, SQL_PlayerName, AccountID, ConnectionType, GameTime, SQL_Reason, SQL_Map); //LogMessage("%s | U:1:%d disconnect from server, total game time %d seconds", sUserData[0], iUserData[1], iUserData[2]); LogMessage("Player disconnected: %s %s|U:1:%d|%s\nGame Time: %d sec. Reason: %s", PlayerName, SteamID, AccountID, ConnectionIP,GameTime, DisconnectReason); } //LogMessage(query); CloseHandle(hPayload); + //LogMessage(query); SQL_TQuery(hDatabase, T_SendQuery, query); return; } \ No newline at end of file