206 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			SourcePawn
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			SourcePawn
		
	
	
	
	
	
#pragma semicolon 1
 | 
						|
#pragma newdecls required
 | 
						|
 | 
						|
#include <basic>
 | 
						|
#include <sourcemod>
 | 
						|
#include <sdkhooks>
 | 
						|
#include <sdktools>
 | 
						|
#include <dhooks>
 | 
						|
 | 
						|
#pragma semicolon 1
 | 
						|
#pragma newdecls required
 | 
						|
 | 
						|
public Plugin myinfo =
 | 
						|
{
 | 
						|
	name 			= "ZItemKnockback",
 | 
						|
	author 			= "BotoX",
 | 
						|
	description 	= "",
 | 
						|
	version 		= "0.0",
 | 
						|
	url 			= ""
 | 
						|
};
 | 
						|
 | 
						|
Handle hFireBulletDetour;
 | 
						|
bool g_bLateLoad = false;
 | 
						|
 | 
						|
int g_LastAttacker = 0;
 | 
						|
int g_LastVictim = 0;
 | 
						|
 | 
						|
// maps from edict index to object index
 | 
						|
char g_EntityIdxToItemIdx[2048];
 | 
						|
 | 
						|
enum struct SItem
 | 
						|
{
 | 
						|
	bool m_Test;
 | 
						|
}
 | 
						|
SItem g_Items[255];
 | 
						|
 | 
						|
public void OnPluginStart()
 | 
						|
{
 | 
						|
	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.");
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
	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 */
 | 
						|
	for(int client = 1; client <= MaxClients; client++)
 | 
						|
	{
 | 
						|
		if(IsClientInGame(client))
 | 
						|
			OnClientPutInServer(client);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
	CheckChildren(client, entity);
 | 
						|
}
 | 
						|
 | 
						|
void CheckChildren(int client, int parent)
 | 
						|
{
 | 
						|
	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));
 | 
						|
 | 
						|
		PrintToChatAll("%d child: \"%s\" %d (%s)", client, sClassname, entity, sTargetname);
 | 
						|
 | 
						|
		if(!strncmp(sClassname, "func_physbox", 12, false) || !strcmp(sClassname, "func_breakable", false))
 | 
						|
		{
 | 
						|
			SDKHook(entity, SDKHook_OnTakeDamage, OnTakeDamage);
 | 
						|
			PrintToChatAll("Hooking \"%s\" %d (%s) OnTakeDamage", sClassname, entity, sTargetname);
 | 
						|
		}
 | 
						|
		else if(!strcmp(sClassname, "trigger_push", false))
 | 
						|
		{
 | 
						|
			AcceptEntityInput(entity, "Kill");
 | 
						|
			PrintToChatAll("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])
 | 
						|
{
 | 
						|
	if(attacker <= 0 || attacker > MAXPLAYERS)
 | 
						|
		return Plugin_Continue;
 | 
						|
 | 
						|
	int client = victim;
 | 
						|
	while((client = GetEntPropEnt(client, Prop_Data, "m_pParent")) != INVALID_ENT_REFERENCE)
 | 
						|
	{
 | 
						|
		if(client >= 1 && client <= MAXPLAYERS)
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	if(client <= 0)
 | 
						|
		return Plugin_Handled;
 | 
						|
 | 
						|
	// fix multiple penetration
 | 
						|
	if(g_LastAttacker == attacker && g_LastVictim == client)
 | 
						|
		return Plugin_Handled;
 | 
						|
 | 
						|
	victim = client;
 | 
						|
 | 
						|
	g_LastAttacker = attacker;
 | 
						|
	g_LastVictim = victim;
 | 
						|
 | 
						|
	SDKHooks_TakeDamage(victim, inflictor, attacker, damage, damagetype, weapon, damageForce, damagePosition);
 | 
						|
	return Plugin_Handled;
 | 
						|
}
 |