2019-09-05 12:10:02 +02:00
|
|
|
#pragma semicolon 1
|
|
|
|
#pragma newdecls required
|
|
|
|
|
|
|
|
#include <basic>
|
|
|
|
#include <sourcemod>
|
|
|
|
#include <sdkhooks>
|
|
|
|
#include <sdktools>
|
2019-09-05 19:45:20 +02:00
|
|
|
#include <dhooks>
|
2019-09-05 12:10:02 +02:00
|
|
|
|
2019-09-10 16:33:50 +02:00
|
|
|
#pragma semicolon 1
|
|
|
|
#pragma newdecls required
|
|
|
|
|
2019-09-05 12:10:02 +02:00
|
|
|
public Plugin myinfo =
|
|
|
|
{
|
|
|
|
name = "ZItemKnockback",
|
|
|
|
author = "BotoX",
|
|
|
|
description = "",
|
|
|
|
version = "0.0",
|
|
|
|
url = ""
|
|
|
|
};
|
|
|
|
|
2019-09-05 19:45:20 +02:00
|
|
|
Handle hFireBulletDetour;
|
2019-09-10 16:33:50 +02:00
|
|
|
bool g_bLateLoad = false;
|
2019-09-05 19:45:20 +02:00
|
|
|
|
|
|
|
int g_LastAttacker = 0;
|
|
|
|
int g_LastVictim = 0;
|
|
|
|
|
2019-09-10 16:33:50 +02:00
|
|
|
// maps from edict index to object index
|
|
|
|
char g_EntityIdxToItemIdx[2048];
|
|
|
|
|
|
|
|
enum struct SItem
|
|
|
|
{
|
|
|
|
bool m_Test;
|
|
|
|
}
|
|
|
|
SItem g_Items[255];
|
|
|
|
|
2019-09-05 12:10:02 +02:00
|
|
|
public void OnPluginStart()
|
|
|
|
{
|
2019-09-05 19:45:20 +02:00
|
|
|
Handle hGameData = LoadGameConfigFile("ZItemKnockback.games");
|
|
|
|
if(!hGameData)
|
|
|
|
SetFailState("Failed to load ZItemKnockback gamedata.");
|
|
|
|
|
|
|
|
hFireBulletDetour = DHookCreateFromConf(hGameData, "CCSPlayer__FireBullet");
|
|
|
|
if(!hFireBulletDetour)
|
|
|
|
SetFailState("Failed to setup detour for CCSPlayer__FireBullet");
|
|
|
|
delete hGameData;
|
|
|
|
|
|
|
|
if(!DHookEnableDetour(hFireBulletDetour, false, Detour_OnFireBullet))
|
|
|
|
SetFailState("Failed to detour CCSPlayer__FireBullet.");
|
2019-09-10 16:33:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
|
|
|
{
|
|
|
|
g_bLateLoad = late;
|
|
|
|
return APLRes_Success;
|
|
|
|
}
|
2019-09-05 19:45:20 +02:00
|
|
|
|
2019-09-10 16:33:50 +02:00
|
|
|
public void OnMapStart()
|
|
|
|
{
|
|
|
|
bool bLate = g_bLateLoad;
|
|
|
|
g_bLateLoad = false;
|
|
|
|
|
|
|
|
char sMapName[PLATFORM_MAX_PATH];
|
|
|
|
GetCurrentMap(sMapName, sizeof(sMapName));
|
|
|
|
|
|
|
|
char sConfigFile[PLATFORM_MAX_PATH];
|
|
|
|
BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/ZItemKnockback/%s.cfg", sMapName);
|
|
|
|
if(!FileExists(sConfigFile))
|
|
|
|
{
|
|
|
|
LogMessage("Could not find mapconfig: \"%s\"", sConfigFile);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
LogMessage("Found mapconfig: \"%s\"", sConfigFile);
|
|
|
|
|
|
|
|
KeyValues KvConfig = new KeyValues("items");
|
|
|
|
if(!KvConfig.ImportFromFile(sConfigFile))
|
|
|
|
{
|
|
|
|
delete KvConfig;
|
|
|
|
LogError("ImportFromFile() failed!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
KvConfig.Rewind();
|
|
|
|
|
|
|
|
if(!KvConfig.GotoFirstSubKey())
|
|
|
|
{
|
|
|
|
delete KvConfig;
|
|
|
|
LogError("GotoFirstSubKey() failed!");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
char sSection[64];
|
|
|
|
KvConfig.GetSectionName(sSection, sizeof(sSection));
|
|
|
|
|
|
|
|
} while(KvConfig.GotoNextKey(false));
|
|
|
|
|
|
|
|
delete KvConfig;
|
|
|
|
|
|
|
|
/* Late Load */
|
2019-09-05 19:45:20 +02:00
|
|
|
for(int client = 1; client <= MaxClients; client++)
|
|
|
|
{
|
|
|
|
if(IsClientInGame(client))
|
|
|
|
OnClientPutInServer(client);
|
|
|
|
}
|
2019-09-05 12:10:02 +02:00
|
|
|
}
|
|
|
|
|
2019-09-10 16:33:50 +02:00
|
|
|
|
2019-09-05 12:10:02 +02:00
|
|
|
public void OnClientPutInServer(int client)
|
|
|
|
{
|
|
|
|
SDKHook(client, SDKHook_WeaponEquipPost, OnWeaponEquip);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Action OnWeaponEquip(int client, int entity)
|
|
|
|
{
|
|
|
|
if(!IsValidEntity(entity))
|
|
|
|
return;
|
|
|
|
|
|
|
|
char sClassname[64];
|
|
|
|
GetEntityClassname(entity, sClassname, sizeof(sClassname));
|
|
|
|
if(strcmp(sClassname, "weapon_knife", false) != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
int HammerID = GetEntProp(entity, Prop_Data, "m_iHammerID");
|
|
|
|
if(!HammerID)
|
|
|
|
return;
|
|
|
|
|
2019-09-05 19:45:20 +02:00
|
|
|
CheckChildren(client, entity);
|
2019-09-05 12:10:02 +02:00
|
|
|
}
|
|
|
|
|
2019-09-05 19:45:20 +02:00
|
|
|
void CheckChildren(int client, int parent)
|
2019-09-05 12:10:02 +02:00
|
|
|
{
|
|
|
|
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));
|
|
|
|
|
2019-09-05 19:45:20 +02:00
|
|
|
char sTargetname[64];
|
|
|
|
GetEntPropString(entity, Prop_Data, "m_iName", sTargetname, sizeof(sTargetname));
|
|
|
|
|
|
|
|
PrintToChatAll("%d child: \"%s\" %d (%s)", client, sClassname, entity, sTargetname);
|
|
|
|
|
2019-09-05 12:10:02 +02:00
|
|
|
if(!strncmp(sClassname, "func_physbox", 12, false) || !strcmp(sClassname, "func_breakable", false))
|
|
|
|
{
|
2019-09-05 19:45:20 +02:00
|
|
|
SDKHook(entity, SDKHook_OnTakeDamage, OnTakeDamage);
|
|
|
|
PrintToChatAll("Hooking \"%s\" %d (%s) OnTakeDamage", sClassname, entity, sTargetname);
|
2019-09-05 12:10:02 +02:00
|
|
|
}
|
|
|
|
else if(!strcmp(sClassname, "trigger_push", false))
|
|
|
|
{
|
|
|
|
AcceptEntityInput(entity, "Kill");
|
2019-09-05 19:45:20 +02:00
|
|
|
PrintToChatAll("Killing \"%s\" %d (%s)", sClassname, entity, sTargetname);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CheckChildren(client, entity);
|
2019-09-05 12:10:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-10 16:33:50 +02:00
|
|
|
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])
|
2019-09-05 19:45:20 +02:00
|
|
|
{
|
2019-09-10 16:33:50 +02:00
|
|
|
// 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
|
2019-09-05 19:45:20 +02:00
|
|
|
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])
|
2019-09-05 12:10:02 +02:00
|
|
|
{
|
|
|
|
if(attacker <= 0 || attacker > MAXPLAYERS)
|
2019-09-05 19:45:20 +02:00
|
|
|
return Plugin_Continue;
|
2019-09-05 12:10:02 +02:00
|
|
|
|
2019-09-05 19:45:20 +02:00
|
|
|
int client = victim;
|
|
|
|
while((client = GetEntPropEnt(client, Prop_Data, "m_pParent")) != INVALID_ENT_REFERENCE)
|
|
|
|
{
|
|
|
|
if(client >= 1 && client <= MAXPLAYERS)
|
|
|
|
break;
|
|
|
|
}
|
2019-09-05 12:10:02 +02:00
|
|
|
|
2019-09-05 19:45:20 +02:00
|
|
|
if(client <= 0)
|
|
|
|
return Plugin_Handled;
|
|
|
|
|
2019-09-10 16:33:50 +02:00
|
|
|
// fix multiple penetration
|
2019-09-05 19:45:20 +02:00
|
|
|
if(g_LastAttacker == attacker && g_LastVictim == client)
|
|
|
|
return Plugin_Handled;
|
|
|
|
|
|
|
|
victim = client;
|
|
|
|
|
2019-09-10 16:33:50 +02:00
|
|
|
g_LastAttacker = attacker;
|
|
|
|
g_LastVictim = victim;
|
2019-09-05 12:10:02 +02:00
|
|
|
|
2019-09-10 16:33:50 +02:00
|
|
|
SDKHooks_TakeDamage(victim, inflictor, attacker, damage, damagetype, weapon, damageForce, damagePosition);
|
2019-09-05 19:45:20 +02:00
|
|
|
return Plugin_Handled;
|
2019-09-05 12:10:02 +02:00
|
|
|
}
|