2019-09-27 21:50:07 +02:00
|
|
|
#pragma semicolon 1
|
|
|
|
#pragma newdecls required
|
|
|
|
|
|
|
|
#include <sourcemod>
|
|
|
|
#include <sdkhooks>
|
|
|
|
#include <sdktools>
|
|
|
|
#include <dhooks>
|
|
|
|
#include <cstrike>
|
2019-10-08 18:39:31 +02:00
|
|
|
#include <CSSFixes>
|
2019-09-27 21:50:07 +02:00
|
|
|
#include <zombiereloaded>
|
|
|
|
|
|
|
|
public Plugin myinfo =
|
|
|
|
{
|
|
|
|
name = "DamageProxy",
|
|
|
|
author = "BotoX",
|
|
|
|
description = "",
|
2019-10-17 12:05:26 +02:00
|
|
|
version = "0.2",
|
2019-09-27 21:50:07 +02:00
|
|
|
url = ""
|
|
|
|
};
|
|
|
|
|
|
|
|
bool g_bLateLoad = false;
|
2019-11-28 15:15:32 +01:00
|
|
|
bool g_bHasCSSFixes = true;
|
2019-09-27 21:50:07 +02:00
|
|
|
|
|
|
|
Handle g_hFireBulletDetour;
|
|
|
|
int g_hVelocityModifier;
|
2019-09-28 16:13:59 +02:00
|
|
|
int g_hActiveWeapon;
|
2019-09-27 21:50:07 +02:00
|
|
|
|
|
|
|
int g_LastAttacker = 0;
|
|
|
|
int g_LastVictim = 0;
|
|
|
|
|
|
|
|
char g_iPhysboxToClient[2048];
|
|
|
|
|
|
|
|
int g_iSpecialKnife[MAXPLAYERS + 1];
|
|
|
|
bool g_bNoSlowdown[MAXPLAYERS + 1];
|
2019-09-28 21:50:44 +02:00
|
|
|
bool g_bRestoreHP[MAXPLAYERS + 1];
|
2019-09-28 16:13:59 +02:00
|
|
|
bool g_bFullKnife[MAXPLAYERS + 1];
|
2019-09-27 21:50:07 +02:00
|
|
|
|
|
|
|
KeyValues g_Config;
|
|
|
|
|
|
|
|
public void OnPluginStart()
|
|
|
|
{
|
|
|
|
Handle hGameData = LoadGameConfigFile("DamageProxy.games");
|
|
|
|
if(!hGameData)
|
|
|
|
SetFailState("Failed to load DamageProxy gamedata.");
|
|
|
|
|
|
|
|
g_hFireBulletDetour = DHookCreateFromConf(hGameData, "CCSPlayer__FireBullet");
|
|
|
|
if(!g_hFireBulletDetour)
|
|
|
|
SetFailState("Failed to setup detour for CCSPlayer__FireBullet");
|
2019-09-28 16:13:59 +02:00
|
|
|
|
2019-09-27 21:50:07 +02:00
|
|
|
delete hGameData;
|
|
|
|
|
|
|
|
if(!DHookEnableDetour(g_hFireBulletDetour, false, Detour_OnFireBullet))
|
|
|
|
SetFailState("Failed to detour CCSPlayer__FireBullet.");
|
|
|
|
|
|
|
|
g_hVelocityModifier = FindSendPropInfo("CCSPlayer", "m_flVelocityModifier");
|
|
|
|
if(g_hVelocityModifier == -1)
|
|
|
|
SetFailState("Couldn't find CCSPlayer::m_flVelocityModifier");
|
2019-09-28 16:13:59 +02:00
|
|
|
|
|
|
|
g_hActiveWeapon = FindSendPropInfo("CBaseCombatCharacter", "m_hActiveWeapon");
|
|
|
|
if(g_hActiveWeapon == -1)
|
|
|
|
SetFailState("Couldn't find CBaseCombatCharacter::m_hActiveWeapon");
|
2019-10-08 18:39:31 +02:00
|
|
|
|
|
|
|
PhysboxToClientMap(g_iPhysboxToClient, true);
|
|
|
|
}
|
|
|
|
|
2019-11-28 15:15:32 +01:00
|
|
|
public void OnLibraryRemoved(const char[] name)
|
|
|
|
{
|
|
|
|
if(StrEqual(name, "CSSFixes"))
|
|
|
|
g_bHasCSSFixes = false;
|
|
|
|
}
|
|
|
|
|
2019-10-08 18:39:31 +02:00
|
|
|
public void OnPluginEnd()
|
|
|
|
{
|
2019-11-28 15:15:32 +01:00
|
|
|
if(g_bHasCSSFixes)
|
|
|
|
PhysboxToClientMap(g_iPhysboxToClient, false);
|
2019-09-27 21:50:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
|
|
|
{
|
|
|
|
g_bLateLoad = late;
|
|
|
|
return APLRes_Success;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void OnMapStart()
|
|
|
|
{
|
|
|
|
bool bLate = g_bLateLoad;
|
|
|
|
g_bLateLoad = false;
|
|
|
|
|
|
|
|
if(g_Config)
|
|
|
|
delete g_Config;
|
|
|
|
|
|
|
|
char sMapName[PLATFORM_MAX_PATH];
|
|
|
|
GetCurrentMap(sMapName, sizeof(sMapName));
|
|
|
|
|
|
|
|
char sConfigFile[PLATFORM_MAX_PATH];
|
|
|
|
BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/damageproxy/%s.cfg", sMapName);
|
|
|
|
if(!FileExists(sConfigFile))
|
|
|
|
{
|
|
|
|
LogMessage("Could not find mapconfig: \"%s\"", sConfigFile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
LogMessage("Found mapconfig: \"%s\"", sConfigFile);
|
|
|
|
|
|
|
|
g_Config = new KeyValues("items");
|
|
|
|
if(!g_Config.ImportFromFile(sConfigFile))
|
|
|
|
{
|
|
|
|
delete g_Config;
|
|
|
|
LogError("ImportFromFile() failed!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
g_Config.Rewind();
|
|
|
|
|
|
|
|
if(!bLate)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Late Load */
|
|
|
|
for(int client = 1; client <= MaxClients; client++)
|
|
|
|
{
|
|
|
|
if(!IsClientInGame(client))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
OnClientPutInServer(client);
|
|
|
|
|
|
|
|
int iKnife = GetPlayerWeaponSlot(client, CS_SLOT_KNIFE);
|
|
|
|
if(iKnife > 0)
|
|
|
|
OnWeaponEquipped(client, iKnife);
|
|
|
|
}
|
2019-10-17 12:05:26 +02:00
|
|
|
|
|
|
|
int entity = INVALID_ENT_REFERENCE;
|
|
|
|
while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE)
|
|
|
|
{
|
|
|
|
char sClassname[64];
|
|
|
|
if(GetEntityClassname(entity, sClassname, sizeof(sClassname)))
|
|
|
|
OnEntitySpawned(entity, sClassname);
|
|
|
|
}
|
2019-09-27 21:50:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public void OnClientPutInServer(int client)
|
|
|
|
{
|
|
|
|
g_iSpecialKnife[client] = 0;
|
|
|
|
g_bNoSlowdown[client] = false;
|
2019-09-29 01:13:55 +02:00
|
|
|
g_bRestoreHP[client] = false;
|
2019-09-28 16:13:59 +02:00
|
|
|
g_bFullKnife[client] = false;
|
2019-09-27 21:50:07 +02:00
|
|
|
|
|
|
|
if(g_Config)
|
|
|
|
{
|
|
|
|
SDKHook(client, SDKHook_WeaponEquipPost, OnWeaponEquipped);
|
|
|
|
SDKHook(client, SDKHook_WeaponDropPost, OnWeaponDropped);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void OnWeaponEquipped(int client, int entity)
|
|
|
|
{
|
|
|
|
if(!g_Config)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(!IsValidEntity(entity))
|
|
|
|
return;
|
|
|
|
|
|
|
|
char sClassname[64];
|
|
|
|
GetEntityClassname(entity, sClassname, sizeof(sClassname));
|
|
|
|
if(strcmp(sClassname, "weapon_knife", false) != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int iHammerID = GetEntProp(entity, Prop_Data, "m_iHammerID");
|
|
|
|
if(!iHammerID)
|
|
|
|
return;
|
|
|
|
|
2019-09-28 03:19:25 +02:00
|
|
|
char sHammerID[16] = "z";
|
|
|
|
if(ZR_IsClientHuman(client))
|
|
|
|
sHammerID[0] = 'h';
|
|
|
|
IntToString(iHammerID, sHammerID[1], sizeof(sHammerID) - 1);
|
2019-09-27 21:50:07 +02:00
|
|
|
|
|
|
|
g_Config.Rewind();
|
|
|
|
if(!g_Config.JumpToKey(sHammerID))
|
|
|
|
return;
|
|
|
|
|
2019-09-28 16:13:59 +02:00
|
|
|
float fKnockbackScale = g_Config.GetFloat("KnockbackScale", 1.0);
|
|
|
|
ZR_SetClientKnockbackScale(client, fKnockbackScale);
|
2019-09-27 21:50:07 +02:00
|
|
|
|
2019-09-29 01:13:55 +02:00
|
|
|
float fKnockbackMaxForce = g_Config.GetFloat("KnockbackMaxForce", 0.0);
|
2019-10-08 18:39:31 +02:00
|
|
|
if(fKnockbackMaxForce > 0.0)
|
2019-09-29 01:13:55 +02:00
|
|
|
ZR_SetClientKnockbackMaxForce(client, fKnockbackMaxForce);
|
|
|
|
|
|
|
|
float fKnockbackMaxVel = g_Config.GetFloat("KnockbackMaxVel", -1.0);
|
|
|
|
if(fKnockbackMaxVel >= 0.0)
|
|
|
|
ZR_SetClientKnockbackMaxVelocity(client, fKnockbackMaxVel);
|
|
|
|
|
2019-09-27 21:50:07 +02:00
|
|
|
g_bNoSlowdown[client] = view_as<bool>(g_Config.GetNum("NoSlowDown", 0));
|
|
|
|
|
2019-09-28 21:49:27 +02:00
|
|
|
g_bRestoreHP[client] = view_as<bool>(g_Config.GetNum("RestoreHP", 1));
|
|
|
|
|
2019-09-28 16:13:59 +02:00
|
|
|
g_bFullKnife[client] = view_as<bool>(g_Config.GetNum("FullKnife", 0));
|
|
|
|
|
2019-09-27 21:50:07 +02:00
|
|
|
g_iSpecialKnife[client] = entity;
|
|
|
|
|
|
|
|
CheckChildren(client, entity);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void OnWeaponDropped(int client, int entity)
|
|
|
|
{
|
|
|
|
if(entity == g_iSpecialKnife[client])
|
|
|
|
{
|
|
|
|
ZR_SetClientKnockbackScale(client, 1.0);
|
2019-09-29 01:13:55 +02:00
|
|
|
ZR_SetClientKnockbackMaxForce(client, 0.0);
|
|
|
|
ZR_SetClientKnockbackMaxVelocity(client, -1.0);
|
2019-09-27 21:50:07 +02:00
|
|
|
g_iSpecialKnife[client] = 0;
|
|
|
|
g_bNoSlowdown[client] = false;
|
2019-09-28 21:49:27 +02:00
|
|
|
g_bRestoreHP[client] = false;
|
2019-09-28 16:13:59 +02:00
|
|
|
g_bFullKnife[client] = false;
|
2019-09-27 21:50:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-17 12:05:26 +02:00
|
|
|
public void OnEntitySpawned(int entity, const char[] classname)
|
|
|
|
{
|
|
|
|
if(!g_Config)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(entity < 0 || entity >= sizeof(g_iPhysboxToClient))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if(!IsValidEntity(entity))
|
|
|
|
return;
|
|
|
|
|
|
|
|
int iHammerID = GetEntProp(entity, Prop_Data, "m_iHammerID");
|
|
|
|
if(!iHammerID)
|
|
|
|
return;
|
|
|
|
|
|
|
|
char sHammerID[16] = "_";
|
|
|
|
IntToString(iHammerID, sHammerID[1], sizeof(sHammerID) - 1);
|
|
|
|
|
|
|
|
g_Config.Rewind();
|
|
|
|
if(!g_Config.JumpToKey(sHammerID))
|
|
|
|
return;
|
|
|
|
|
|
|
|
int iTeam = g_Config.GetNum("Team", 0);
|
|
|
|
|
|
|
|
if(iTeam >= 1 && iTeam <= 3)
|
|
|
|
{
|
|
|
|
g_iPhysboxToClient[entity] = -iTeam;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-27 21:50:07 +02:00
|
|
|
public void OnEntityDestroyed(int entity)
|
|
|
|
{
|
|
|
|
if(entity >= 0 && entity < sizeof(g_iPhysboxToClient))
|
|
|
|
g_iPhysboxToClient[entity] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CheckChildren(int client, int parent)
|
|
|
|
{
|
|
|
|
bool bKillPush = view_as<bool>(g_Config.GetNum("KillPush", 1));
|
|
|
|
|
|
|
|
int entity = INVALID_ENT_REFERENCE;
|
|
|
|
while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE)
|
|
|
|
{
|
|
|
|
if(GetEntPropEnt(entity, Prop_Data, "m_pParent") != parent)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
char sClassname[64];
|
|
|
|
GetEntityClassname(entity, sClassname, sizeof(sClassname));
|
|
|
|
|
|
|
|
char sTargetname[64];
|
|
|
|
GetEntPropString(entity, Prop_Data, "m_iName", sTargetname, sizeof(sTargetname));
|
|
|
|
|
|
|
|
int iTemplateLoc = FindCharInString(sTargetname, '&', true);
|
|
|
|
if(iTemplateLoc != -1)
|
|
|
|
sTargetname[iTemplateLoc] = 0;
|
|
|
|
|
|
|
|
// -1 = Never kill
|
|
|
|
// 0 = Default
|
|
|
|
// 1 = Always kill
|
|
|
|
int iKill = 0;
|
|
|
|
if(sTargetname[0])
|
|
|
|
iKill = g_Config.GetNum(sTargetname, 0);
|
|
|
|
|
|
|
|
PrintToConsoleAll("%d child: \"%s\" %d (%s) kill:%d", client, sClassname, entity, sTargetname, iKill);
|
|
|
|
|
|
|
|
if(!strncmp(sClassname, "func_physbox", 12, false) || !strcmp(sClassname, "func_breakable", false))
|
|
|
|
{
|
|
|
|
g_iPhysboxToClient[entity] = client;
|
|
|
|
SDKHook(entity, SDKHook_OnTakeDamage, OnTakeDamage);
|
|
|
|
|
|
|
|
PrintToConsoleAll("Hooking \"%s\" %d (%s) OnTakeDamage", sClassname, entity, sTargetname);
|
|
|
|
}
|
|
|
|
else if((bKillPush && !strcmp(sClassname, "trigger_push", false)) || iKill > 0)
|
|
|
|
{
|
|
|
|
if((bKillPush || iKill > 0) && iKill >= 0)
|
|
|
|
{
|
|
|
|
AcceptEntityInput(entity, "Kill");
|
|
|
|
PrintToConsoleAll("Killing \"%s\" %d (%s)", sClassname, entity, sTargetname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CheckChildren(client, entity);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2])
|
|
|
|
{
|
|
|
|
// because knifes don't call FireBullet we reset it here too
|
|
|
|
g_LastAttacker = 0;
|
|
|
|
g_LastVictim = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
public MRESReturn Detour_OnFireBullet(int pThis, Handle hReturn, Handle hParams)
|
|
|
|
{
|
|
|
|
// need to reset it per fired bullet else only one of the shotgun pellets would be able to hit the same player
|
|
|
|
g_LastAttacker = 0;
|
|
|
|
g_LastVictim = 0;
|
|
|
|
return MRES_Handled;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Action OnTakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype, int &weapon, float damageForce[3], float damagePosition[3], int damagecustom)
|
|
|
|
{
|
|
|
|
if(attacker <= 0 || attacker > MAXPLAYERS)
|
|
|
|
return Plugin_Continue;
|
|
|
|
|
|
|
|
int client = g_iPhysboxToClient[victim];
|
|
|
|
if(client <= 0)
|
|
|
|
{
|
|
|
|
PrintToConsoleAll("!!! %d client = %d no physbox !!!", victim, client);
|
|
|
|
return Plugin_Continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int knife = g_iSpecialKnife[client];
|
|
|
|
if(knife <= 0)
|
|
|
|
{
|
|
|
|
PrintToConsoleAll("!!! %d client = %d no knife !!!", victim, client);
|
|
|
|
return Plugin_Continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// fix multiple penetration
|
|
|
|
if(g_LastAttacker == attacker && g_LastVictim == client)
|
|
|
|
return Plugin_Handled;
|
|
|
|
|
|
|
|
g_LastAttacker = attacker;
|
2019-09-29 10:45:16 +02:00
|
|
|
g_LastVictim = client;
|
2019-09-27 21:50:07 +02:00
|
|
|
|
2019-09-29 01:13:55 +02:00
|
|
|
int flags = ZR_KNOCKBACK_CUSTOM | ZR_KNOCKBACK_SCALE | ZR_KNOCKBACK_LIMITFORCE | ZR_KNOCKBACK_LIMITVEL;
|
2019-09-28 16:13:59 +02:00
|
|
|
|
2019-09-29 10:45:16 +02:00
|
|
|
if(g_bFullKnife[client])
|
2019-09-28 16:13:59 +02:00
|
|
|
{
|
|
|
|
char sWeaponClassname[64];
|
|
|
|
if(inflictor == attacker)
|
|
|
|
{
|
|
|
|
int iWeapon = GetClientActiveWeapon(attacker);
|
|
|
|
if(iWeapon > 0)
|
|
|
|
GetEdictClassname(iWeapon, sWeaponClassname, sizeof(sWeaponClassname));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
GetEdictClassname(inflictor, sWeaponClassname, sizeof(sWeaponClassname));
|
|
|
|
|
|
|
|
if(StrEqual(sWeaponClassname, "weapon_knife"))
|
2019-09-29 01:13:55 +02:00
|
|
|
flags &= ~(ZR_KNOCKBACK_SCALE | ZR_KNOCKBACK_LIMITFORCE | ZR_KNOCKBACK_LIMITVEL);
|
2019-09-28 16:13:59 +02:00
|
|
|
}
|
|
|
|
|
2019-09-28 21:49:27 +02:00
|
|
|
float flVelocityModifier;
|
2019-09-27 21:50:07 +02:00
|
|
|
if(g_bNoSlowdown[client])
|
|
|
|
flVelocityModifier = GetEntDataFloat(client, g_hVelocityModifier);
|
|
|
|
|
2019-09-28 21:49:27 +02:00
|
|
|
int iClientHealth;
|
|
|
|
if(g_bRestoreHP[client])
|
|
|
|
iClientHealth = GetClientHealth(client);
|
|
|
|
|
2019-09-29 01:13:55 +02:00
|
|
|
// Don't damage kevlar.
|
|
|
|
damagetype |= DMG_RADIATION;
|
|
|
|
|
2019-09-29 10:45:16 +02:00
|
|
|
SDKHooks_TakeDamage(client, inflictor, attacker, damage, damagetype, weapon, damageForce, damagePosition, flags);
|
2019-09-27 21:50:07 +02:00
|
|
|
|
2019-09-28 21:49:27 +02:00
|
|
|
if(g_bNoSlowdown[client])
|
|
|
|
SetEntDataFloat(client, g_hVelocityModifier, flVelocityModifier, true);
|
|
|
|
|
|
|
|
if(g_bRestoreHP[client])
|
|
|
|
SetEntityHealth(client, iClientHealth);
|
2019-09-27 21:50:07 +02:00
|
|
|
|
2019-09-28 21:19:41 +02:00
|
|
|
return Plugin_Continue;
|
2019-09-27 21:50:07 +02:00
|
|
|
}
|
2019-09-28 16:13:59 +02:00
|
|
|
|
|
|
|
stock int GetClientActiveWeapon(int client)
|
|
|
|
{
|
|
|
|
return GetEntDataEnt2(client, g_hActiveWeapon);
|
|
|
|
}
|