Skip to content

Commit

Permalink
修复牛儿子创不动同样生还的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
cH1yoi committed Dec 22, 2024
1 parent 795c59a commit cf6f48f
Show file tree
Hide file tree
Showing 6 changed files with 371 additions and 1 deletion.
104 changes: 104 additions & 0 deletions addons/sourcemod/gamedata/charger_collision_patch.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
"Games"
{
"left4dead2"
{
"MemPatches"
{
/**
* This patch prevents marking survivors.
* --
* Example:
* Reversed code of default behavior: pCharge->CCharge.m_hitSurvivors[pPlayer->CTerrorPlayer.m_survivorCharacter] = 1;
* New behavior when patch is enabled: pCharge->CCharge.m_hitSurvivors[pPlayer->CTerrorPlayer.m_survivorCharacter] = 0;
**/
"CCharge::HandleCustomCollision()::MarkSurvivor"
{
"signature" "CCharge::HandleCustomCollision"
"linux"
{
"offset" "333"
"verify" "\x01"
"patch" "\x00"

}
"windows"
{
"offset" "305"
"verify" "\x01"
"patch" "\x00"
}
}
}
"Functions"
{
"Lux::ThrowImpactedSurvivor"
{
"signature" "ThrowImpactedSurvivor"
"callconv" "cdecl"
"return" "int"
"this" "ignore"
"arguments"
{
"attacker"
{
"type" "cbaseentity"
}
"victim"
{
"type" "cbaseentity"
}
"charge_progress"
{
"type" "float"
}
"should_damage"
{
"type" "bool"
}
}
}
}
"Signatures"
{
/*
* credit from here for sigs/remarks for finding or outdate sigs
* https://github.com/SilvDev/Left4DHooks/blob/main/sourcemod/gamedata/left4dhooks.l4d2.txt
* https://github.com/Psykotikism/L4D1-2_Signatures/blob/main/l4d2/gamedata/l4d2_signatures.txt
*/

/*
* CTerrorPlayer::Fling(Vector const&,PlayerAnimEvent_t,CBaseCombatCharacter *,float)
*
* Vector: how target is supposed to fly, Animevent is "76" for chargerbounce, CBasePlayer is attacker, float is Incap Animation time
*
* Find via CCharge::HandleCustomCollision (strings) -> ThrowImpactedSurvivor (strings, structure) -> Fling (feel it out)
*
*/
"CCharge::HandleCustomCollision"
{
"library" "server"
"linux" "@_ZN7CCharge21HandleCustomCollisionEP11CBaseEntityRK6VectorS4_P10CGameTraceP9CMoveData"
"windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x33\x2A\x89\x2A\x2A\x8B\x2A\x2A\x53\x8B\x2A\x89\x2A\x2A\x8B\x2A\x2A\x2A\x2A\x2A\x56\x8B"
/* ? ? ? ? ? ? ? ? ? ? ? ? ? ? 33 ? 89 ? ? 8B ? ? 53 8B ? 89 ? ? 8B ? ? ? ? ? 56 8B */
}
/*
* ThrowImpactedSurvivor(CTerrorPlayer *, CTerrorPlayer *, float, bool)
* Search: "charger_impact"
*/
"ThrowImpactedSurvivor"
{
"library" "server"
"linux" "@_Z21ThrowImpactedSurvivorP13CTerrorPlayerS0_fb"
"windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x53\x56\x57\x8B\x2A\x2A\x8B\x2A\x2A\x2A\x2A\x2A\xC1\x2A\x2A\x2A\x2A\x74\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x2A\x8B\x2A\x2A\x2A\x2A\x2A\x8B"
/* ? ? ? ? ? ? 53 56 57 8B ? ? 8B ? ? ? ? ? C1 ? ? ? ? 74 ? ? ? ? ? ? ? ? 8B ? ? ? ? ? 8B */
}
"CBaseEntity::SetAbsVelocity"
{
"library" "server"
"linux" "@_ZN11CBaseEntity14SetAbsVelocityERK6Vector"
"windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x56\x8B\x75\x08\xF3\x0F\x10\x06\x57\x8B\xF9"
/* ? ? ? ? ? ? 56 8B 75 08 F3 0F 10 06 57 8B F9 */
}
}
}
}
Binary file not shown.
257 changes: 257 additions & 0 deletions addons/sourcemod/scripting/Charger_Collision_patch.sp
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
/*
* Fixes for gamebreaking bugs and stupid gameplay aspects
* Copyright (C) 2022 LuxLuma
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

#pragma semicolon 1

#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <dhooks>
#include <sourcescramble>

#pragma newdecls required

#define GAMEDATA "charger_collision_patch"
#define CHARGE_MARKSURVIVOR_KEY "CCharge::HandleCustomCollision()::MarkSurvivor"
#define CHARGE_ISINCAPPED_KEY "CCharge::HandleCustomCollision()::IsIncap"
#define PLUGIN_VERSION "2.0"


#define IMPACT_SND_INTERVAL 0.1

enum struct ChargerCharge
{
int m_Index;
float m_NextImpactSND;
bool m_MarkHit[MAXPLAYERS+1];

void Reset()
{
this.m_NextImpactSND = 0.0;
for(int i; i <= MAXPLAYERS; ++i)
{
this.m_MarkHit[i] = false;
}
}
}

ChargerCharge g_ChargerCharge[MAXPLAYERS+1];

MemoryPatch Charge_MarkSurvivor;
Handle g_hSetAbsVelocity;


public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
if(GetEngineVersion() != Engine_Left4Dead2)
{
strcopy(error, err_max, "Plugin only supports Left 4 Dead 2");
return APLRes_SilentFailure;
}
return APLRes_Success;
}

public Plugin myinfo =
{
name = "[L4D2]Charger_Collision_Patch",
author = "Lux",
description = "Fixes charger only allow to his 1 survivor index & allows colliding same target more than once",
version = PLUGIN_VERSION,
url = "forums.alliedmods.net/showthread.php?p=2647017"
};


public void OnPluginStart()
{
CreateConVar("charger_collision_patch_version", PLUGIN_VERSION, "", FCVAR_NOTIFY|FCVAR_DONTRECORD);

for(int i; i <= MAXPLAYERS; ++i)
{
g_ChargerCharge[i].m_Index = i;
}

Handle hGamedata = LoadGameConfigFile(GAMEDATA);
if(hGamedata == null)
{
SetFailState("Failed to load \"%s.txt\" gamedata.", GAMEDATA);
}

Charge_MarkSurvivor = MemoryPatch.CreateFromConf(hGamedata, CHARGE_MARKSURVIVOR_KEY);
if(!Charge_MarkSurvivor.Validate())
{
SetFailState("Failed to validate patch \"%s\"", CHARGE_MARKSURVIVOR_KEY);
}

Handle hDetour;
hDetour = DHookCreateFromConf(hGamedata, "Lux::ThrowImpactedSurvivor");
if(!hDetour)
{
SetFailState("Failed to find 'Lux::ThrowImpactedSurvivor' signature");
}

StartPrepSDKCall(SDKCall_Entity);
if(!PrepSDKCall_SetFromConf(hGamedata, SDKConf_Signature, "CBaseEntity::SetAbsVelocity"))
{
SetFailState("Error finding the 'CBaseEntity::SetAbsVelocity' signature.");
}

PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_Pointer);
g_hSetAbsVelocity = EndPrepSDKCall();
if(g_hSetAbsVelocity == null)
{
SetFailState("Unable to prep SDKCall 'CBaseEntity::SetAbsVelocity'");
}

if(!DHookEnableDetour(hDetour, false, ThrowImpactedSurvivor))
{
SetFailState("Failed to detour 'Lux::ThrowImpactedSurvivor'");
}

if(Charge_MarkSurvivor.Enable())
{
PrintToServer("[%s] Enabled \"%s\" patch", GAMEDATA, CHARGE_MARKSURVIVOR_KEY);
}

delete hGamedata;

HookEvent("round_start", RoundStart);
HookEvent("charger_charge_start", ClearMarkedSurvivors, EventHookMode_Pre);
HookEvent("charger_charge_end", ClearMarkedSurvivors, EventHookMode_Pre);
AddNormalSoundHook(ImpactSNDHook);

for(int i = 1; i <= MaxClients; ++i)
{
if(IsClientInGame(i))
OnClientPutInServer(i);
}
}

public MRESReturn ThrowImpactedSurvivor(Handle hReturn, Handle hParams)
{
int iCharger = DHookGetParam(hParams, 1);
int iVictim = DHookGetParam(hParams, 2);
bool ShouldDamage = DHookGetParam(hParams, 4);

//sanity check everything avoids conflicts
if(!ShouldDamage)
return MRES_Ignored;

if(iCharger < 1 || iCharger > MaxClients ||
GetClientTeam(iCharger) != 3 || !IsPlayerAlive(iCharger))
{
return MRES_Ignored;
}

int iAbility = GetEntPropEnt(iCharger, Prop_Send, "m_customAbility");
if(iAbility == -1 || !HasEntProp(iAbility, Prop_Send, "m_isCharging"))
{
return MRES_Ignored;
}

if(!GetEntProp(iAbility, Prop_Send, "m_isCharging", 1))
return MRES_Ignored;

int iCarryVictim = GetEntPropEnt(iCharger, Prop_Send, "m_carryVictim");
if(iCarryVictim == -1)
{
DHookSetReturn(hReturn, 1);
return MRES_Supercede;
}

if(iCarryVictim == iVictim)
{
//PrintToChatAll("illegal damage on %N from %N", iVictim, iCharger);
g_ChargerCharge[iCharger].m_NextImpactSND = GetGameTime() + IMPACT_SND_INTERVAL;
DHookSetReturn(hReturn, 1);
return MRES_Supercede;
}

//Set velocity to 0 so impulse velocity does not account for current velocity
static float vecNoVel[3] = {0.0, 0.0, 0.0};
SDKCall(g_hSetAbsVelocity, iVictim, vecNoVel);

g_ChargerCharge[iCharger].m_NextImpactSND = GetGameTime() + IMPACT_SND_INTERVAL;
if(g_ChargerCharge[iCharger].m_MarkHit[iVictim])
{
DHookSetParam(hParams, 4, false);
DHookSetReturn(hReturn, 1);
return MRES_ChangedHandled;
}
g_ChargerCharge[iCharger].m_MarkHit[iVictim] = true;
return MRES_Ignored;
}

public Action ImpactSNDHook(int clients[MAXPLAYERS], int &numClients, char sample[PLATFORM_MAX_PATH], int &iCharger, int &channel, float &volume, int &level, int &pitch, int &flags, char soundEntry[PLATFORM_MAX_PATH], int &seed)
{
if(iCharger < 1 || iCharger > MaxClients ||
GetClientTeam(iCharger) != 3 || !IsPlayerAlive(iCharger))
{
return Plugin_Continue;
}

int iAbility = GetEntPropEnt(iCharger, Prop_Send, "m_customAbility");
if(iAbility == -1 || !HasEntProp(iAbility, Prop_Send, "m_isCharging"))
{
return Plugin_Continue;
}

if(!GetEntProp(iAbility, Prop_Send, "m_isCharging", 1))
return Plugin_Continue;

if(g_ChargerCharge[iCharger].m_NextImpactSND > GetGameTime())
{
if(StrContains(sample, "player/charger/hit/charger_smash_0", false) != -1)
return Plugin_Handled;
}

return Plugin_Continue;
}

public void OnClientPutInServer(int client)
{
SDKHook(client, SDKHook_SpawnPost, OnSpawnPost);
}

public void OnSpawnPost(int client)
{
g_ChargerCharge[client].Reset();
for(int i; i <= MAXPLAYERS; ++i)
{
g_ChargerCharge[i].m_MarkHit[client] = false;
}
}

public void RoundStart(Event event, const char[] eventName, bool dontBroadcast)
{
for(int i; i <= MAXPLAYERS; ++i)
{
g_ChargerCharge[i].Reset();
}
}

public void ClearMarkedSurvivors(Event event, const char[] eventName, bool dontBroadcast)
{
int iCharger = GetClientOfUserId(event.GetInt("userid"));
if(iCharger < 1)
return;

for(int i; i <= MAXPLAYERS; ++i)
{
g_ChargerCharge[iCharger].m_MarkHit[i] = false;
}
}
3 changes: 3 additions & 0 deletions cfg/cfgogl/advanced8v8/confogl_plugins.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ sm plugins load optional/l4d_superversus.smx
// 药丸发光
sm plugins load optional/l4d2_random_glow_item.smx

// 修复牛牛创不动同样生还
sm plugins load fixes/Charger_Collision_patch.smx

// 分算法
sm plugins load optional/l4d2_solidhealthmedkits.smx
sm plugins load optional/l4d3_scoremod_DRDK_remake2.smx
Expand Down
3 changes: 3 additions & 0 deletions cfg/cfgogl/zonemod6v6/confogl_plugins.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@ sm plugins load optional/l4d_CreateSurvivorBot.smx
// 多人多克插件
sm plugins load optional/l4d_superversus.smx

// 修复牛牛创不动同样生还
sm plugins load fixes/Charger_Collision_patch.smx

// 药丸发光
sm plugins load optional/l4d2_random_glow_item.smx
5 changes: 4 additions & 1 deletion cfg/cfgogl/zonemod8v8/confogl_plugins.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,7 @@ sm plugins load optional/l4d_CreateSurvivorBot.smx
sm plugins load optional/l4d_superversus.smx

// 药丸发光
sm plugins load optional/l4d2_random_glow_item.smx
sm plugins load optional/l4d2_random_glow_item.smx

// 修复牛牛创不动同样生还
sm plugins load fixes/Charger_Collision_patch.smx

0 comments on commit cf6f48f

Please sign in to comment.