Skip to content

Commit 9e5b56e

Browse files
authored
Add commands for rock throws (#902)
* l4d2_tank_attack_control: Commands for rock throws Feature: - Three commands (!underhand !overhand !overonehand) for each rock throw sequence. * l4d2_tank_attack_control: Update translations for commands
1 parent 1bac1df commit 9e5b56e

3 files changed

Lines changed: 146 additions & 44 deletions

File tree

1.34 KB
Binary file not shown.

addons/sourcemod/scripting/l4d2_tank_attack_control.sp

Lines changed: 143 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -15,54 +15,105 @@
1515
//50 - underhand (+use),
1616
//51 - 2handed overhand (+reload)
1717

18+
bool g_bQueuedCommandThrow[MAXPLAYERS+1];
1819
int g_iQueuedThrow[MAXPLAYERS + 1];
1920
ConVar g_hBlockPunchRock;
2021
ConVar g_hBlockJumpRock;
2122
ConVar hOverhandOnly;
22-
23-
float throwQueuedAt[MAXPLAYERS + 1];
23+
bool g_bBlockJumpRock;
24+
bool g_bOverhandOnly;
2425

2526
public 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

60111
void 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

74125
public 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

141200
bool 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+
}

addons/sourcemod/translations/l4d2_tank_attack_control.phrases.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
}
77
"Reload"
88
{
9-
"en" "{olive}Reload{default} = {blue}2 Handed Overhand{default}"
9+
"en" "{olive}Reload{default}/{olive}!overhand{default} = {blue}2 Handed Overhand{default}"
1010
}
1111
"Use"
1212
{
13-
"en" "{olive}Use{default} = {blue}Underhand{default}"
13+
"en" "{olive}Use{default}/{olive}!underhand{default} = {blue}Underhand{default}"
1414
}
1515
"M2"
1616
{
17-
"en" "{olive}M2{default} = {blue}1 Handed Overhand{default}"
17+
"en" "{olive}M2{default}/{olive}!overonehand{default} = {blue}1 Handed Overhand{default}"
1818
}
1919
}

0 commit comments

Comments
 (0)