Skip to content

Commit 7c5520e

Browse files
authored
[l4d2_jockey_jumpcap_patch] Update (#916)
* [l4d2_jockey_jumpcap_patch] Update 1) Code refactoring 2) Replaced the unreliable timer after shove with a game time check * Fix compile
1 parent 9e5b56e commit 7c5520e

1 file changed

Lines changed: 89 additions & 57 deletions

File tree

addons/sourcemod/scripting/l4d2_jockey_jumpcap_patch.sp

Lines changed: 89 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -4,111 +4,143 @@
44
#include <sourcemod>
55
#include <dhooks>
66

7-
#define Z_JOCKEY 5
8-
#define TEAM_SURVIVOR 2
9-
#define TEAM_INFECTED 3
7+
#define Z_JOCKEY 5
108

11-
#define GAMEDATA "l4d2_si_ability"
9+
#define TEAM_SURVIVOR 2
10+
#define TEAM_INFECTED 3
1211

13-
Handle hCLeap_OnTouch;
12+
#define GAMEDATA "l4d2_si_ability"
13+
#define L4D2_MAXPLAYERS 32
1414

15-
bool blockJumpCap[MAXPLAYERS + 1];
15+
enum struct eShovedInfo
16+
{
17+
int eiUserId;
18+
float efBlockUntil;
19+
}
20+
21+
ConVar g_hCvarJumpCapBlockTime = null;
22+
23+
Handle g_hCLeap_OnTouch = null;
24+
25+
eShovedInfo g_esShovedInfo[L4D2_MAXPLAYERS + 1];
1626

1727
public Plugin myinfo =
1828
{
1929
name = "L4D2 Jockey Jump-Cap Patch",
2030
author = "Visor, A1m`",
2131
description = "Prevent Jockeys from being able to land caps with non-ability jumps in unfair situations",
22-
version = "1.4",
32+
version = "1.6",
2333
url = "https://github.com/SirPlease/L4D2-Competitive-Rework"
2434
};
2535

2636
public void OnPluginStart()
37+
{
38+
InitGameData();
39+
40+
g_hCvarJumpCapBlockTime = CreateConVar(
41+
"l4d2_jumpcap_block_time",
42+
"3.0",
43+
"Sets the block duration for jockey jumpcaps (in seconds)",
44+
_, true, 1.0, true, 10.0
45+
);
46+
47+
HookEvent("round_start", Event_Reset, EventHookMode_PostNoCopy);
48+
HookEvent("round_end", Event_Reset, EventHookMode_PostNoCopy);
49+
HookEvent("player_shoved", Event_PlayerShoved);
50+
}
51+
52+
void InitGameData()
2753
{
2854
Handle hGamedata = LoadGameConfigFile(GAMEDATA);
2955

3056
if (!hGamedata) {
3157
SetFailState("Gamedata '%s.txt' missing or corrupt.", GAMEDATA);
3258
}
33-
34-
int iCleapOnTouch = GameConfGetOffset(hGamedata, "CBaseAbility::OnTouch");
35-
if (iCleapOnTouch == -1) {
59+
60+
int iCleapOnTouchOffset = GameConfGetOffset(hGamedata, "CBaseAbility::OnTouch");
61+
if (iCleapOnTouchOffset == -1) {
3662
SetFailState("Failed to get offset 'CBaseAbility::OnTouch'.");
3763
}
3864

39-
hCLeap_OnTouch = DHookCreate(iCleapOnTouch, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, CLeap_OnTouch);
40-
DHookAddParam(hCLeap_OnTouch, HookParamType_CBaseEntity);
41-
42-
HookEvent("round_start", ResetEvent, EventHookMode_PostNoCopy);
43-
HookEvent("round_end", ResetEvent, EventHookMode_PostNoCopy);
44-
HookEvent("player_shoved", OnPlayerShoved);
45-
65+
g_hCLeap_OnTouch = DHookCreate(iCleapOnTouchOffset, HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, CLeap_OnTouch);
66+
DHookAddParam(g_hCLeap_OnTouch, HookParamType_CBaseEntity);
67+
4668
delete hGamedata;
4769
}
4870

49-
void ResetEvent(Event hEvent, const char[] name, bool dontBroadcast)
71+
void Event_Reset(Event hEvent, const char[] sEventName, bool bDontBroadcast)
5072
{
51-
for (int i = 0; i <= MAXPLAYERS; i++) {
52-
blockJumpCap[i] = false;
73+
for (int i = 0; i <= L4D2_MAXPLAYERS; i++) {
74+
g_esShovedInfo[i].eiUserId = 0;
75+
g_esShovedInfo[i].efBlockUntil = 0.0;
5376
}
5477
}
5578

56-
public void OnEntityCreated(int entity, const char[] classname)
79+
public void OnEntityCreated(int iEntity, const char[] sClassName)
5780
{
58-
if (strcmp(classname, "ability_leap") == 0) {
59-
DHookEntity(hCLeap_OnTouch, false, entity);
81+
if (strcmp(sClassName, "ability_leap") == 0) {
82+
DHookEntity(g_hCLeap_OnTouch, false, iEntity);
6083
}
6184
}
6285

63-
void OnPlayerShoved(Event hEvent, const char[] name, bool dontBroadcast)
86+
void Event_PlayerShoved(Event hEvent, const char[] sEventName, bool bDontBroadcast)
6487
{
65-
int shovee = GetClientOfUserId(hEvent.GetInt("userid"));
66-
int shover = GetClientOfUserId(hEvent.GetInt("attacker"));
67-
68-
if (IsSurvivor(shover) && IsJockey(shovee)) {
69-
blockJumpCap[shovee] = true;
70-
CreateTimer(3.0, ResetJumpcapState, shovee, TIMER_FLAG_NO_MAPCHANGE);
88+
int iShover = GetClientOfUserId(hEvent.GetInt("attacker"));
89+
if (!IsSurvivor(iShover)) {
90+
return;
7191
}
72-
}
7392

74-
Action ResetJumpcapState(Handle hTimer, any jockey)
75-
{
76-
blockJumpCap[jockey] = false;
77-
return Plugin_Handled;
93+
int iShoveeUserId = hEvent.GetInt("userid");
94+
int iShovee = GetClientOfUserId(iShoveeUserId);
95+
if (IsJockey(iShovee)) {
96+
g_esShovedInfo[iShovee].eiUserId = iShoveeUserId;
97+
g_esShovedInfo[iShovee].efBlockUntil = GetGameTime() + g_hCvarJumpCapBlockTime.FloatValue;
98+
}
7899
}
79100

80-
MRESReturn CLeap_OnTouch(int ability, Handle hParams)
101+
MRESReturn CLeap_OnTouch(int iAbility, DHookParam hParams)
81102
{
82-
int jockey = GetEntPropEnt(ability, Prop_Send, "m_owner");
83-
if (IsJockey(jockey) && !IsFakeClient(jockey)) {
84-
int survivor = DHookGetParam(hParams, 1);
85-
if (IsSurvivor(survivor)) {
86-
if (!IsAbilityActive(ability) && blockJumpCap[jockey]) {
87-
return MRES_Supercede;
88-
}
89-
}
103+
int iJockey = GetEntPropEnt(iAbility, Prop_Send, "m_owner");
104+
if (!IsJockey(iJockey) || IsFakeClient(iJockey)) {
105+
return MRES_Ignored;
106+
}
107+
108+
int iSurvivor = hParams.Get(1);
109+
if (!IsSurvivor(iSurvivor)) {
110+
return MRES_Ignored;
111+
}
112+
113+
if (!IsAbilityActive(iAbility) && IsJumpBlocked(iJockey)) {
114+
return MRES_Supercede;
90115
}
116+
91117
return MRES_Ignored;
92118
}
93119

94-
bool IsAbilityActive(int ability)
120+
bool IsJumpBlocked(int iClient)
121+
{
122+
return (g_esShovedInfo[iClient].eiUserId == GetClientUserId(iClient)
123+
&& g_esShovedInfo[iClient].efBlockUntil >= GetGameTime());
124+
}
125+
126+
bool IsAbilityActive(int iAbility)
95127
{
96-
return view_as<bool>(GetEntProp(ability, Prop_Send, "m_isLeaping", 1));
128+
return (GetEntProp(iAbility, Prop_Send, "m_isLeaping", 1) > 0);
97129
}
98130

99-
bool IsJockey(int client)
131+
bool IsJockey(int iClient)
100132
{
101-
return (client > 0
102-
&& client <= MaxClients
103-
&& IsClientInGame(client)
104-
&& GetClientTeam(client) == TEAM_INFECTED
105-
&& GetEntProp(client, Prop_Send, "m_zombieClass") == Z_JOCKEY);
133+
return (iClient > 0
134+
&& iClient <= MaxClients
135+
&& IsClientInGame(iClient)
136+
&& GetClientTeam(iClient) == TEAM_INFECTED
137+
&& GetEntProp(iClient, Prop_Send, "m_zombieClass") == Z_JOCKEY);
106138
}
107139

108-
bool IsSurvivor(int client)
140+
bool IsSurvivor(int iClient)
109141
{
110-
return (client > 0
111-
&& client <= MaxClients
112-
&& IsClientInGame(client)
113-
&& GetClientTeam(client) == TEAM_SURVIVOR);
142+
return (iClient > 0
143+
&& iClient <= MaxClients
144+
&& IsClientInGame(iClient)
145+
&& GetClientTeam(iClient) == TEAM_SURVIVOR);
114146
}

0 commit comments

Comments
 (0)