Defib_Fix Defib_Fix[Left 4 Fix][28/02/2023]

https://forums.alliedmods.net/showthread.php?p=2647018
https://gitlab.com/vbgunz/ABM recommends it...
This commit is contained in:
Kolan Sh 2023-10-14 00:56:22 +03:00
parent 80d66d270e
commit 97c8624283
4 changed files with 420 additions and 0 deletions

View File

@ -0,0 +1,105 @@
"Games"
{
"left4dead2"
{
"Functions"
{
"CItemDefibrillator::OnActionComplete"
{
"offset" "CItemDefibrillator::OnActionComplete"
"hooktype" "entity"
"return" "int"
"this" "ignore"
"arguments"
{
"Reviver"
{
"type" "cbaseentity"
}
"DeathModel"
{
"type" "cbaseentity"
}
}
}
"CItemDefibrillator::OnStartAction"
{
"offset" "CItemDefibrillator::OnStartAction"
"hooktype" "entity"
"return" "int"
"this" "ignore"
"arguments"
{
"BackpackItemActionType"
{
type "int"
}
"Reviver"
{
"type" "cbaseentity"
}
"DeathModel"
{
"type" "cbaseentity"
}
"somefloat"
{
"type" "float"
}
}
}
"CTerrorPlayer::GetPlayerByCharacter"
{
"signature" "CTerrorPlayer::GetPlayerByCharacter"
"callconv" "cdecl"
"return" "cbaseentity"
"this" "ignore"
"arguments"
{
"CharacterIndex"
{
"type" "int"
}
}
}
"CSurvivorDeathModel::Create"
{
"signature" "CSurvivorDeathModel::Create"
"callconv" "thiscall"
"return" "cbaseentity"
"this" "entity"
}
}
"Offsets"
{
"CItemDefibrillator::OnActionComplete"
{
"linux" "456"
"windows" "454"
}
"CItemDefibrillator::OnStartAction"
{
"linux" "451"
"windows" "449"
}
}
"Signatures"
{
"CTerrorPlayer::GetPlayerByCharacter"
{
"library" "server"
"linux" "@_ZN13CTerrorPlayer20GetPlayerByCharacterE21SurvivorCharacterType"
"windows" "\x55\x8B\xEC\x8B\x45\x08\x83\xEC\x08\x83\xF8\x08"
/* 55 8B EC 8B 45 08 83 EC 08 83 F8 08 */
}
"CSurvivorDeathModel::Create"
{
"library" "server"
"linux" "@_ZN19CSurvivorDeathModel6CreateEP13CTerrorPlayer"
"windows" "\x55\x8B\xEC\x57\x8B\x7D\x08\x85\xFF\x75\x2A\x33\xC0\x5F\x5D\xC3\x8B\x87\x38\x01\x00\x00"
/* 55 8B EC 57 8B 7D 08 85 FF 75 ? 33 C0 5F 5D C3 8B 87 38 01 00 00 */
}
}
}
}
//some gamedata from here https://github.com/Satanic-Spirit/defib-fix/blob/master/defibfix.txt credit to whoever

View File

@ -0,0 +1,285 @@
/*
* Fixes for gamebreaking bugs and stupid gameplay aspects
* Copyright (C) 2019 LuxLuma acceliacat@gmail.com
*
* 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>
#pragma newdecls required
#define GAMEDATA "defib_fix"
#define PLUGIN_VERSION "2.0.1"
GlobalForward g_hForward_SurvivorDeathModelCreated;
Handle hOnActionComplete;
Handle hOnStartAction;
bool g_bFixChar;
int g_iCurrentDeathModel;
int g_iDeathModelOwner[2048+1];
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;
}
g_hForward_SurvivorDeathModelCreated = new GlobalForward("L4D2_OnSurvivorDeathModelCreated", ET_Event, Param_Cell, Param_Cell);
RegPluginLibrary("Defib_Fix");
return APLRes_Success;
}
public Plugin myinfo =
{
name = "[L4D2]Defib_Fix",
author = "Lux",
description = "Fixes defibbing from failing when defibbing an alive character index",
version = PLUGIN_VERSION,
url = "forums.alliedmods.net/showthread.php?p=2647018"
};
public void OnPluginStart()
{
Handle hGamedata = LoadGameConfigFile(GAMEDATA);
if(hGamedata == null)
SetFailState("Failed to load \"%s.txt\" gamedata.", GAMEDATA);
hOnActionComplete = DHookCreateFromConf(hGamedata, "CItemDefibrillator::OnActionComplete");
if(hOnActionComplete == null)
SetFailState("Failed to make hook for 'CItemDefibrillator::OnActionComplete'");
hOnStartAction = DHookCreateFromConf(hGamedata, "CItemDefibrillator::OnStartAction");
if(hOnStartAction == null)
SetFailState("Failed to make hook for 'CItemDefibrillator::OnStartAction'");
Handle hDetour;
hDetour = DHookCreateFromConf(hGamedata, "CTerrorPlayer::GetPlayerByCharacter");
if(!hDetour)
SetFailState("Failed to find 'CTerrorPlayer::GetPlayerByCharacter' signature");
if(!DHookEnableDetour(hDetour, false, GetPlayerByCharacter))
SetFailState("Failed to detour 'CTerrorPlayer::GetPlayerByCharacter'");
hDetour = DHookCreateFromConf(hGamedata, "CSurvivorDeathModel::Create");
if(!hDetour)
SetFailState("Failed to find 'CSurvivorDeathModel::Create' signature");
if(!DHookEnableDetour(hDetour, false, DeathModelCreatePre))
SetFailState("Failed to detour 'CSurvivorDeathModel::Create'");
if(!DHookEnableDetour(hDetour, true, DeathModelCreatePost))
SetFailState("Failed to detour 'CSurvivorDeathModel::Create'");
delete hGamedata;
CreateConVar("defib_fix_version", PLUGIN_VERSION, "", FCVAR_NOTIFY|FCVAR_DONTRECORD);
}
public void OnEntityCreated(int iEntity, const char[] sClassname)
{
if(sClassname[0] != 'w' || !StrEqual(sClassname, "weapon_defibrillator", false))
return;
DHookEntity(hOnActionComplete, false, iEntity, _, OnActionCompletePre);
DHookEntity(hOnActionComplete, true, iEntity, _, OnActionCompletePost);
DHookEntity(hOnStartAction, false, iEntity, _, OnStartActionPre);
}
public MRESReturn OnActionCompletePre(Handle hReturn, Handle hParams)
{
int iDeathModel = DHookGetParam(hParams, 2);
if(!iDeathModel)
return MRES_Ignored;
if(IsAllSurvivorsAlive())//rare case
{
KillAllDeathModels();
DHookSetReturn(hReturn, 0);
return MRES_Supercede;
}
g_iCurrentDeathModel = iDeathModel;
g_bFixChar = true;
return MRES_Ignored;
}
public MRESReturn OnActionCompletePost(Handle hReturn, Handle hParams)
{
if(IsAllSurvivorsAlive())
KillAllDeathModels();
g_bFixChar = false;//just incase
return MRES_Ignored;
}
public MRESReturn GetPlayerByCharacter(Handle hReturn, Handle hParams)
{
if(!g_bFixChar)
return MRES_Ignored;
g_bFixChar = false;
static int iChar[MAXPLAYERS+1];
int iCurrentChar = GetClientOfUserId(g_iDeathModelOwner[g_iCurrentDeathModel]);
if(iCurrentChar > 0 && IsClientInGame(iCurrentChar) && !IsPlayerAlive(iCurrentChar) && GetClientTeam(iCurrentChar) == 2)//check if owner of model death model is dead
{
DHookSetReturn(hReturn, iCurrentChar);
return MRES_Supercede;
}
iCurrentChar = DHookGetParam(hParams, 1);
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i) && !IsPlayerAlive(i) && GetClientTeam(i) == 2)
{
iChar[i] = GetEntProp(i, Prop_Send, "m_survivorCharacter", 1);
if(iCurrentChar == iChar[i])//if found player same char type
{
DHookSetReturn(hReturn, i);
return MRES_Supercede;
}
}
else
{
iChar[i] = -1;
}
}
int iFoundPlayer;
iCurrentChar = ConvertToInternalCharacter(iCurrentChar);
for(int i = 1; i <= MaxClients; i++)
{
if(iChar[i] != -1)
iFoundPlayer = i;//fallback incase noone matches
if(iCurrentChar == iChar[i])
{
iFoundPlayer = i;
break;
}
}
if(!iFoundPlayer)
return MRES_Ignored;//better safe than sorry
DHookSetReturn(hReturn, iFoundPlayer);
return MRES_Supercede;
}
public MRESReturn OnStartActionPre(Handle hReturn, Handle hParams)
{
if(IsAllSurvivorsAlive())
{
KillAllDeathModels();
DHookSetReturn(hReturn, 0);
return MRES_Supercede;
}
return MRES_Ignored;
}
int g_iTempClient;
public MRESReturn DeathModelCreatePost(int pThis, Handle hReturn)
{
int iDeathModel = DHookGetReturn(hReturn);
if(!iDeathModel)
return MRES_Ignored;
float vPos[3];
GetClientAbsOrigin(g_iTempClient, vPos);
TeleportEntity(iDeathModel, vPos, NULL_VECTOR, NULL_VECTOR);
g_iDeathModelOwner[iDeathModel] = GetClientUserId(g_iTempClient);
Call_StartForward(g_hForward_SurvivorDeathModelCreated);
Call_PushCell(g_iTempClient);
Call_PushCell(iDeathModel);
Call_Finish();
return MRES_Ignored;
}
public MRESReturn DeathModelCreatePre(int pThis)
{
g_iTempClient = pThis;
}
public void OnEntityDestroyed(int iEntity)
{
if(iEntity < 1)
return;
g_iDeathModelOwner[iEntity] = 0;
}
int ConvertToInternalCharacter(int iChar)
{
switch(iChar)
{
case 4:
{
return 0;
}
case 5:
{
return 1;
}
case 6:
{
return 3;
}
case 7:
{
return 2;
}
case 9:
{
return 8;
}
}
return iChar;// some people set survivors to 8 or 9 index so revive them too
}
bool IsAllSurvivorsAlive()
{
for(int i = 1; i <= MaxClients; i++)// rare case it could happen
{
if(IsClientInGame(i) && !IsPlayerAlive(i) && GetClientTeam(i) == 2)
{
return false;
}
}
return true;
}
void KillAllDeathModels()
{
int i = INVALID_ENT_REFERENCE;
while((i = FindEntityByClassname(i, "survivor_death_model")) != INVALID_ENT_REFERENCE)
{
AcceptEntityInput(i, "Kill");
}
}

View File

@ -0,0 +1,30 @@
/*
* https://github.com/LuxLuma/Left-4-fix/tree/master/left%204%20fix/Defib_Fix
*/
#if defined _Defib_Fix_included
#endinput
#endif
#define _Defib_Fix_included
/**
* @Note only called if Defib_Fix is installed
*
* Deathmodels are "survivor_death_model" that can be used with defibrillator.
*
* @param iClient Client Index who died.
* @param iDeathModel Entity Index of Deathmodel for client who died
* @no return
*/
forward void L4D2_OnSurvivorDeathModelCreated(int iClient, int iDeathModel);
public SharedPlugin __pl_Defib_Fix =
{
name = "Defib_Fix",
file = "Defib_Fix.smx",
#if defined REQUIRE_PLUGIN
required = 1,
#else
required = 0,
#endif
};