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:
parent
80d66d270e
commit
97c8624283
|
@ -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
|
Binary file not shown.
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
};
|
Loading…
Reference in New Issue