1515//50 - underhand (+use),
1616//51 - 2handed overhand (+reload)
1717
18+ bool g_bQueuedCommandThrow [MAXPLAYERS +1 ];
1819int g_iQueuedThrow [MAXPLAYERS + 1 ];
1920ConVar g_hBlockPunchRock ;
2021ConVar g_hBlockJumpRock ;
2122ConVar hOverhandOnly ;
22-
23- float throwQueuedAt [ MAXPLAYERS + 1 ] ;
23+ bool g_bBlockJumpRock ;
24+ bool g_bOverhandOnly ;
2425
2526public Plugin myinfo =
2627{
2728 name = " Tank Attack Control" ,
28- author = " vintik, CanadaRox, Jacob, Visor" ,
29+ author = " vintik, CanadaRox, Jacob, Visor, Forgetest " ,
2930 description = " " ,
30- version = " 0.7.2 " ,
31+ version = " 0.8 " ,
3132 url = " https://github.com/SirPlease/L4D2-Competitive-Rework"
3233}
3334
34- public void OnPluginStart ( )
35+ public APLRes AskPluginLoad2 ( Handle myself , bool late , char [] error , int err_max )
3536{
36- LoadTranslations (" l4d2_tank_attack_control.phrases" );
37- char sGame [256 ];
38- GetGameFolderName (sGame , sizeof (sGame ));
39- if (! StrEqual (sGame , " left4dead2" , false ))
37+ if (GetEngineVersion () != Engine_Left4Dead2 )
4038 {
41- SetFailState (" Plugin supports Left 4 dead 2 only!" );
39+ strcopy (error , err_max , " Plugin supports Left 4 dead 2 only!" );
40+ return APLRes_SilentFailure ;
4241 }
43-
42+ return APLRes_Success ;
43+ }
44+
45+ public void OnPluginStart ()
46+ {
47+ LoadTranslations (" l4d2_tank_attack_control.phrases" );
48+
4449 //future-proof remake of the confogl feature (could be used with lgofnoc)
4550 g_hBlockPunchRock = CreateConVar (" l4d2_block_punch_rock" , " 1" , " Block tanks from punching and throwing a rock at the same time" );
4651 g_hBlockJumpRock = CreateConVar (" l4d2_block_jump_rock" , " 0" , " Block tanks from jumping and throwing a rock at the same time" );
4752 hOverhandOnly = CreateConVar (" tank_overhand_only" , " 0" , " Force tank to only throw overhand rocks." );
4853
49- HookEvent (" round_start" , RoundStartEvent , EventHookMode_PostNoCopy );
54+ g_hBlockJumpRock .AddChangeHook (OnConVarChanged );
55+ hOverhandOnly .AddChangeHook (OnConVarChanged );
56+ GetCvars ();
57+
5058 HookEvent (" tank_spawn" , TankSpawn_Event );
59+
60+ RegConsoleCmd (" sm_underhand" , Cmd_sm_underhand );
61+ RegConsoleCmd (" sm_overhand" , Cmd_sm_overhand );
62+ RegConsoleCmd (" sm_overonehand" , Cmd_sm_overonehand );
5163}
5264
53- void RoundStartEvent ( Event hEvent , const char [] sEventName , bool bDontBroadcast )
65+ void OnConVarChanged ( ConVar convar , const char [] oldValue , const char [] newValue )
5466{
55- for (int i = 1 ; i <= MaxClients ; i ++ ) {
56- throwQueuedAt [i ] = 0.0 ;
57- }
67+ GetCvars ();
68+ }
69+
70+ void GetCvars ()
71+ {
72+ g_bBlockJumpRock = g_hBlockJumpRock .BoolValue ;
73+ g_bOverhandOnly = hOverhandOnly .BoolValue ;
74+ }
75+
76+ public void OnClientConnected (int client )
77+ {
78+ g_bQueuedCommandThrow [client ] = false ;
79+ }
80+
81+ Action Cmd_sm_underhand (int client , int args )
82+ {
83+ if (! client || ! IsClientInGame (client ) || ! IsTank (client ))
84+ return Plugin_Continue ;
85+
86+ g_bQueuedCommandThrow [client ] = true ;
87+ g_iQueuedThrow [client ] = 2 ; //underhand
88+ return Plugin_Handled ;
89+ }
90+
91+ Action Cmd_sm_overhand (int client , int args )
92+ {
93+ if (! client || ! IsClientInGame (client ) || ! IsTank (client ))
94+ return Plugin_Continue ;
95+
96+ g_bQueuedCommandThrow [client ] = true ;
97+ g_iQueuedThrow [client ] = 3 ; //two hand overhand
98+ return Plugin_Handled ;
99+ }
100+
101+ Action Cmd_sm_overonehand (int client , int args )
102+ {
103+ if (! client || ! IsClientInGame (client ) || ! IsTank (client ))
104+ return Plugin_Continue ;
105+
106+ g_bQueuedCommandThrow [client ] = true ;
107+ g_iQueuedThrow [client ] = 1 ; //one hand overhand
108+ return Plugin_Handled ;
58109}
59110
60111void TankSpawn_Event (Event event , const char [] name , bool dontBroadcast )
61112{
62- int tank = GetClientOfUserId (GetEventInt ( event , " userid" ));
63- if (IsFakeClient (tank )) return ;
113+ int tank = GetClientOfUserId (event . GetInt ( " userid" ));
114+ if (! tank || ! IsClientInGame ( tank ) || IsFakeClient (tank )) return ;
64115
65- if (GetConVarBool ( hOverhandOnly ) == false )
116+ if (g_bOverhandOnly == false )
66117 {
67118 CPrintToChat (tank , " %t " , " Title" );
68119 CPrintToChat (tank , " %t " , " Reload" );
@@ -73,38 +124,47 @@ void TankSpawn_Event(Event event, const char[] name, bool dontBroadcast)
73124
74125public Action OnPlayerRunCmd (int client , int &buttons , int &impulse , float vel [3 ], float angles [3 ], int &weapon )
75126{
76- if (! IsClientInGame (client ) || IsFakeClient (client ) || GetClientTeam (client ) != L4D2Team_Infected
77- || GetEntProp (client , Prop_Send , " m_zombieClass" ) != L4D2Infected_Tank )
78- return Plugin_Continue ;
127+ bool bCommandThrow = g_bQueuedCommandThrow [client ];
128+ g_bQueuedCommandThrow [client ] = false ;
129+
130+ if (! IsClientInGame (client ) || IsFakeClient (client ) || ! IsTank (client ))
131+ return Plugin_Continue ;
79132
80133 //if tank
81134 if ((buttons & IN_JUMP ) && ShouldCancelJump (client ))
82135 {
83136 buttons &= ~ IN_JUMP ;
84137 }
85138
86- if (GetConVarBool ( hOverhandOnly ) == false )
139+ if (bCommandThrow )
87140 {
88- if (buttons & IN_RELOAD )
89- {
90- g_iQueuedThrow [client ] = 3 ; //two hand overhand
91- buttons |= IN_ATTACK2 ;
92- }
93- else if (buttons & IN_USE )
141+ buttons |= IN_ATTACK2 ;
142+ }
143+ else
144+ {
145+ if (g_bOverhandOnly == false )
94146 {
95- g_iQueuedThrow [client ] = 2 ; //underhand
96- buttons |= IN_ATTACK2 ;
147+ if (buttons & IN_RELOAD )
148+ {
149+ g_iQueuedThrow [client ] = 3 ; //two hand overhand
150+ buttons |= IN_ATTACK2 ;
151+ }
152+ else if (buttons & IN_USE )
153+ {
154+ g_iQueuedThrow [client ] = 2 ; //underhand
155+ buttons |= IN_ATTACK2 ;
156+ }
157+ else
158+ {
159+ g_iQueuedThrow [client ] = 1 ; //one hand overhand
160+ }
97161 }
98162 else
99163 {
100- g_iQueuedThrow [client ] = 1 ; //one hand overhand
164+ g_iQueuedThrow [client ] = 3 ; // two hand overhand
101165 }
102166 }
103- else
104- {
105- g_iQueuedThrow [client ] = 3 ; // two hand overhand
106- }
107-
167+
108168 return Plugin_Continue ;
109169}
110170
@@ -119,11 +179,10 @@ public Action L4D_OnCThrowActivate(int ability)
119179
120180 if (GetClientButtons (client ) & IN_ATTACK )
121181 {
122- if (GetConVarBool ( g_hBlockPunchRock ) )
182+ if (g_hBlockPunchRock . BoolValue )
123183 return Plugin_Handled ;
124184 }
125185
126- throwQueuedAt [client ] = GetGameTime ();
127186 return Plugin_Continue ;
128187}
129188
@@ -140,9 +199,52 @@ public Action L4D2_OnSelectTankAttack(int client, int &sequence)
140199
141200bool ShouldCancelJump (int client )
142201{
143- if (! GetConVarBool ( g_hBlockJumpRock ) )
202+ if (! g_bBlockJumpRock )
144203 {
145204 return false ;
146205 }
147- return ( 1.5 > GetGameTime () - throwQueuedAt [ client ] );
206+ return IsTankThrowingRock ( client );
148207}
208+
209+ bool IsTankThrowingRock (int client )
210+ {
211+ int ability = GetEntPropEnt (client , Prop_Send , " m_customAbility" );
212+ if (ability == - 1 )
213+ return false ;
214+
215+ return CThrow__IsActive (ability ) || CThrow__SelectingTankAttack (ability );
216+ }
217+
218+ bool IsTank (int client )
219+ {
220+ return GetClientTeam (client ) == L4D2Team_Infected && GetEntProp (client , Prop_Send , " m_zombieClass" ) == L4D2Infected_Tank ;
221+ }
222+
223+ CountdownTimer CThrow__GetThrowTimer (int ability )
224+ {
225+ static int s_iOffs_m_throwTimer = - 1 ;
226+ if (s_iOffs_m_throwTimer == - 1 )
227+ s_iOffs_m_throwTimer = FindSendPropInfo (" CThrow" , " m_hasBeenUsed" ) + 4 ;
228+
229+ return view_as <CountdownTimer >(
230+ GetEntityAddress (ability ) + view_as <Address >(s_iOffs_m_throwTimer )
231+ );
232+ }
233+
234+ bool CThrow__IsActive (int ability )
235+ {
236+ CountdownTimer ct = CThrow__GetThrowTimer (ability );
237+ if (! CTimer_HasStarted (ct ))
238+ return false ;
239+
240+ return ! CTimer_IsElapsed (ct );
241+ }
242+
243+ bool CThrow__SelectingTankAttack (int ability )
244+ {
245+ static int s_iOffs_m_bSelectingAttack = - 1 ;
246+ if (s_iOffs_m_bSelectingAttack == - 1 )
247+ s_iOffs_m_bSelectingAttack = FindSendPropInfo (" CThrow" , " m_hasBeenUsed" ) + 28 ;
248+
249+ return GetEntData (ability , s_iOffs_m_bSelectingAttack , 1 ) > 0 ;
250+ }
0 commit comments