1+ #pragma semicolon 1
2+ #pragma newdecls required
3+
4+ #include <sourcemod>
5+ #include <left4dhooks>
6+
7+ #define PLUGIN_VERSION " 1.0"
8+ #define GAMEDATA_FILE " l4d2_fix_tank_rock_handoff"
9+
10+ Handle g_hCThrow_OnStunned = null ;
11+
12+ public Plugin myinfo =
13+ {
14+ name = " [L4D2] Fix Tank Rock Stuck" ,
15+ author = " Sir" ,
16+ description = " Cancels tank rocks that are in the middle of a throw when passing to another player/AI." ,
17+ version = PLUGIN_VERSION ,
18+ url = " https://github.com/SirPlease/L4D2-Competitive-Rework"
19+ };
20+
21+ public void OnPluginStart ()
22+ {
23+ GameData gd = new GameData (GAMEDATA_FILE );
24+ if (! gd ) SetFailState (" Missing gamedata \" " ... GAMEDATA_FILE ... " .txt\" " );
25+
26+ StartPrepSDKCall (SDKCall_Entity );
27+ if (! PrepSDKCall_SetFromConf (gd , SDKConf_Signature , " CThrow::OnStunned" ))
28+ {
29+ delete gd ;
30+ SetFailState (" Failed to find signature \" CThrow::OnStunned\" " );
31+ }
32+ PrepSDKCall_AddParameter (SDKType_Float , SDKPass_Plain );
33+ g_hCThrow_OnStunned = EndPrepSDKCall ();
34+ delete gd ;
35+
36+ if (g_hCThrow_OnStunned == null )
37+ SetFailState (" Failed to prep SDKCall for CThrow::OnStunned" );
38+
39+ HookEvent (" player_bot_replace" , Event_PlayerBotReplace , EventHookMode_Post );
40+ HookEvent (" bot_player_replace" , Event_BotPlayerReplace , EventHookMode_Post );
41+ }
42+
43+ /* Covers Player to Player passes (including forced) */
44+ public void L4D_OnReplaceTank (int oldTank , int newTank )
45+ {
46+ CancelTankThrow (newTank );
47+ }
48+
49+ /* Covers Player to Bot passes */
50+ void Event_PlayerBotReplace (Event event , const char [] name , bool dontBroadcast )
51+ {
52+ int bot = GetClientOfUserId (event .GetInt (" bot" ));
53+
54+ if (bot > 0 && IsTank (bot ))
55+ CancelTankThrow (bot );
56+ }
57+
58+ /* Covers Bot to Player passes (as we do in some plugins) */
59+ void Event_BotPlayerReplace (Event event , const char [] name , bool dontBroadcast )
60+ {
61+ int player = GetClientOfUserId (event .GetInt (" player" ));
62+
63+ if (player > 0 && IsTank (player ))
64+ CancelTankThrow (player );
65+ }
66+
67+ void CancelTankThrow (int tank )
68+ {
69+ if (! IsTank (tank ))
70+ return ;
71+
72+ int ability = GetEntPropEnt (tank , Prop_Send , " m_customAbility" );
73+ if (ability == - 1 )
74+ return ;
75+
76+ SDKCall (g_hCThrow_OnStunned , ability , 0.0 );
77+ }
78+
79+ bool IsTank (int client )
80+ {
81+ if (client <= 0 || client > MaxClients || IsClientInGame (client ))
82+ return false ;
83+
84+ if (GetClientTeam (client ) != L4D_TEAM_INFECTED )
85+ return false ;
86+
87+ return GetEntProp (client , Prop_Send , " m_zombieClass" ) == L4D2_ZOMBIE_CLASS_TANK ;
88+ }
0 commit comments