Skip to content

Commit c318e2f

Browse files
committed
Add pushback immunity / extensive burn native
1 parent b5d9e87 commit c318e2f

File tree

3 files changed

+106
-4
lines changed

3 files changed

+106
-4
lines changed

gamedata/tf2.utils.nosoop.txt

+14
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,20 @@
147147
}
148148
"Signatures"
149149
{
150+
"CTFPlayerShared::IsImmuneToPushback()"
151+
{
152+
// contains unique ref to string "spunup_push_force_immunity"
153+
"library" "server"
154+
"linux" "@_ZNK15CTFPlayerShared18IsImmuneToPushbackEv"
155+
"windows" "\x55\x8B\xEC\x51\x56\x8B\xF1\x57\x6A\x1C"
156+
}
157+
"CTFPlayerShared::Burn()"
158+
{
159+
// contains unique ref to string "afterburn_immunity"
160+
"library" "server"
161+
"linux" "@_ZN15CTFPlayerShared4BurnEP9CTFPlayerP13CTFWeaponBasef"
162+
"windows" "\x55\x8B\xEC\x83\xEC\x08\x56\x8B\xF1\x8B\x8E\x90\x01\x00\x00\x8B\x01"
163+
}
150164
"CTFPlayer::GetEntityForLoadoutSlot()"
151165
{
152166
// called a few blocks after function with unique x-ref string "enable_misc2_noisemaker"

scripting/include/tf2utils.inc

+24
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,30 @@ native float TF2Util_GetPlayerBurnDuration(int client);
131131
*/
132132
native void TF2Util_SetPlayerBurnDuration(int client, float duration);
133133

134+
/**
135+
* Sets a client on fire. This is effectively the same as `TF2_IgnitePlayer` but with the
136+
* additional ability to set the weapon (allowing attribute modifiers to take effect).
137+
*
138+
* @param client Target client index.
139+
* @param attacker Attacker client index, or INVALID_ENT_REFERENCE for none.
140+
* @param duration Duration of fire, in seconds.
141+
* @param weapon Weapon entity, or INVALID_ENT_REFERENCE for none.
142+
*
143+
* @note As of Jungle Inferno, fire duration is capped to 10 seconds.
144+
* @error Invalid clients, or non-weapon entity.
145+
*/
146+
native void TF2Util_IgnitePlayer(int client, int attacker, float duration,
147+
int weapon = INVALID_ENT_REFERENCE);
148+
149+
/**
150+
* Returns true if the given player is immune to pushback.
151+
*
152+
* @param client Client index.
153+
*
154+
* @error Invalid client or not in game.
155+
*/
156+
native bool TF2Util_IsPlayerImmuneToPushback(int client);
157+
134158
/**
135159
* Returns the player's respawn time override, if any. This is the number of seconds that a
136160
* player will spend waiting to be respawned after their last death (CTFPlayer::m_flDeathTime).

scripting/tf2utils.sp

+68-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
#include <stocksoup/memory>
1313

14-
#define PLUGIN_VERSION "0.17.0"
14+
#define PLUGIN_VERSION "0.18.0"
1515
public Plugin myinfo = {
1616
name = "TF2 Utils",
1717
author = "nosoop",
@@ -40,6 +40,8 @@ Handle g_SDKCallIsEntityWearable;
4040
Handle g_SDKCallPlayerEquipWearable;
4141

4242
Handle g_SDKCallPointInRespawnRoom;
43+
Handle g_SDKCallPlayerSharedImmuneToPushback;
44+
Handle g_SDKCallPlayerSharedBurn;
4345

4446
Address offs_ConditionNames;
4547
Address offs_CTFPlayer_aObjects;
@@ -77,6 +79,9 @@ public APLRes AskPluginLoad2(Handle self, bool late, char[] error, int maxlen) {
7779
CreateNative("TF2Util_SetPlayerConditionProvider", Native_SetPlayerConditionProvider);
7880
CreateNative("TF2Util_GetPlayerBurnDuration", Native_GetPlayerBurnDuration);
7981
CreateNative("TF2Util_SetPlayerBurnDuration", Native_SetPlayerBurnDuration);
82+
CreateNative("TF2Util_IgnitePlayer", Native_IgnitePlayer);
83+
CreateNative("TF2Util_IsPlayerImmuneToPushback", Native_IsPlayerImmuneToPushback);
84+
8085
CreateNative("TF2Util_GetPlayerRespawnTimeOverride", Native_GetPlayerRespawnTimeOverride);
8186
CreateNative("TF2Util_SetPlayerRespawnTimeOverride", Native_SetPlayerRespawnTimeOverride);
8287

@@ -145,6 +150,19 @@ public void OnPluginStart() {
145150
PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain);
146151
g_SDKCallPlayerSharedGetMaxHealth = EndPrepSDKCall();
147152

153+
StartPrepSDKCall(SDKCall_Raw);
154+
PrepSDKCall_SetFromConf(hGameConf, SDKConf_Signature, "CTFPlayerShared::Burn()");
155+
PrepSDKCall_AddParameter(SDKType_CBasePlayer, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL);
156+
PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer, VDECODE_FLAG_ALLOWNULL);
157+
PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain);
158+
g_SDKCallPlayerSharedBurn = EndPrepSDKCall();
159+
160+
StartPrepSDKCall(SDKCall_Raw);
161+
PrepSDKCall_SetFromConf(hGameConf, SDKConf_Signature,
162+
"CTFPlayerShared::IsImmuneToPushback()");
163+
PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_Plain);
164+
g_SDKCallPlayerSharedImmuneToPushback = EndPrepSDKCall();
165+
148166
StartPrepSDKCall(SDKCall_Entity);
149167
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
150168
PrepSDKCall_SetFromConf(hGameConf, SDKConf_Virtual, "CBaseEntity::GetMaxHealth()");
@@ -364,9 +382,7 @@ int Native_GetMaxHealthBoost(Handle plugin, int nParams) {
364382
ThrowNativeError(SP_ERROR_NATIVE, "Client index %d is invalid", client);
365383
}
366384

367-
Address offs_Shared = view_as<Address>(GetEntSendPropOffs(client, "m_Shared", true));
368-
369-
return SDKCall(g_SDKCallPlayerSharedGetMaxHealth, GetEntityAddress(client) + offs_Shared,
385+
return SDKCall(g_SDKCallPlayerSharedGetMaxHealth, GetPlayerSharedAddress(client),
370386
bIgnoreAttributes, bIgnoreOverheal);
371387
}
372388

@@ -530,6 +546,19 @@ int Native_GetWeaponMaxClip(Handle plugin, int nParams) {
530546
return SDKCall(g_SDKCallWeaponGetMaxClip, entity);
531547
}
532548

549+
// bool(int client);
550+
int Native_IsPlayerImmuneToPushback(Handle plugin, int nParams) {
551+
int client = GetNativeCell(1);
552+
553+
if (!(0 < client <= MaxClients)) {
554+
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d index is not valid", client);
555+
} else if (!IsClientInGame(client)) {
556+
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not in game", client);
557+
}
558+
559+
return SDKCall(g_SDKCallPlayerSharedImmuneToPushback, GetPlayerSharedAddress(client));
560+
}
561+
533562
// bool(const float[3] position, int entity, bool bRestrictToSameTeam)
534563
int Native_IsPointInRespawnRoom(Handle plugin, int nParams) {
535564
if (IsNativeParamNullVector(1)) {
@@ -677,6 +706,37 @@ any Native_SetPlayerBurnDuration(Handle plugin, int numParams) {
677706
SetEntDataFloat(client, pOffsSharedBurnDuration, duration);
678707
}
679708

709+
// void(int client, int attacker, float duration, int weapon = INVALID_ENT_REFERENCE);
710+
any Native_IgnitePlayer(Handle plugin, int numParams) {
711+
int client = GetNativeCell(1);
712+
int attacker = GetNativeCell(2);
713+
float duration = GetNativeCell(3);
714+
int weapon = GetNativeCell(4);
715+
716+
if (!(0 < client <= MaxClients)) {
717+
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d index is not valid", client);
718+
} else if (!IsClientInGame(client)) {
719+
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not in game", client);
720+
}
721+
722+
if (attacker != INVALID_ENT_REFERENCE) {
723+
if (!(0 < attacker <= MaxClients)) {
724+
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d index is not valid", attacker);
725+
} else if (!IsClientInGame(attacker)) {
726+
return ThrowNativeError(SP_ERROR_NATIVE, "Client %d is not in game", attacker);
727+
}
728+
}
729+
730+
if (weapon != INVALID_ENT_REFERENCE) {
731+
if (!IsValidEntity(weapon) || !IsEntityWeapon(weapon)) {
732+
return ThrowNativeError(SP_ERROR_NATIVE, "Entity %d is not a valid weapon", weapon);
733+
}
734+
}
735+
736+
SDKCall(g_SDKCallPlayerSharedBurn, GetPlayerSharedAddress(client), attacker, weapon,
737+
duration);
738+
}
739+
680740
// float(int client);
681741
any Native_GetPlayerRespawnTimeOverride(Handle plugin, int numParams) {
682742
int client = GetNativeCell(1);
@@ -730,6 +790,10 @@ static Address GetConditionData(int client, TFCond cond) {
730790
return pCondMemory + view_as<Address>(view_as<int>(cond) * sizeof_TFCondInfo);
731791
}
732792

793+
static Address GetPlayerSharedAddress(int client) {
794+
return GetEntityAddress(client) + FindSendPropInfo("CTFPlayer", "m_Shared");
795+
}
796+
733797
static bool IsConditionValid(TFCond cond) {
734798
return 0 <= view_as<any>(cond) < g_nConditions;
735799
}

0 commit comments

Comments
 (0)