#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <zombiereloaded>

#pragma semicolon 1
#pragma newdecls required

ConVar g_hCVar_PushNadesEnabled;
ConVar g_hCVar_PushStrength;
ConVar g_hCVar_PushScale;

int g_iToolsActiveWeapon;
int g_iToolsVelocity;

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Plugin myinfo =
{
	name 		= "PushNades",
	author 		= "Neon",
	description = "Push Zombies away from the Human that threw the HE-Grenade",
	version 	= "2.0",
	url 		= "https://steamcommunity.com/id/n3ontm"
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnPluginStart()
{
	g_hCVar_PushNadesEnabled = CreateConVar("sm_hegrenade_push_enabled", "0", "Enable PushBack for HE-Grenades", 0, true, 0.0, true, 1.0);
	g_hCVar_PushScale = CreateConVar("sm_hegrenade_push_scale", "0", "Make the push scale with the distance to the explosion", 0, true, 0.0, true, 1.0);
	g_hCVar_PushStrength = CreateConVar("sm_hegrenade_push_strength", "500", "How strong the HE-Grenade pushes back");

	g_iToolsActiveWeapon = FindSendPropInfo("CBasePlayer", "m_hActiveWeapon");
	g_iToolsVelocity = FindDataMapInfo(0, "m_vecAbsVelocity");

	AutoExecConfig();
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void OnClientPutInServer(int client)
{
	SDKHook(client, SDKHook_OnTakeDamageAlivePost, DamageOnTakeDamageAlivePost);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public void DamageOnTakeDamageAlivePost(int victim, int attacker, int inflictor, float damage, int damagetype, int weapon, const float damageForce[3], const float damagePosition[3], int damagecustom)
{
	char sWeapon[64];
	if (inflictor == attacker)
	{
		weapon = WeaponsGetActiveWeaponIndex(attacker);
		if (weapon > 0)
			GetEdictClassname(weapon, sWeapon, sizeof(sWeapon));
	}
	else
        GetEdictClassname(inflictor, sWeapon, sizeof(sWeapon));

	if (!StrEqual(sWeapon, "hegrenade_projectile"))
		return;

	if (!g_hCVar_PushNadesEnabled.BoolValue)
		return;

	if (!IsValidClient(attacker, false) || !IsValidClient(victim, false))
		return;

	if (!IsPlayerAlive(attacker) || !ZR_IsClientHuman(attacker))
		return;

	if (!IsPlayerAlive(victim) || !ZR_IsClientZombie(victim))
		return;

	float fVictimLoc[3];
	float fAttackerLoc[3];

	GetClientAbsOrigin(victim, fVictimLoc);
	GetClientAbsOrigin(attacker, fAttackerLoc);

	float fPushVector[3];
	MakeVectorFromPoints(fAttackerLoc, fVictimLoc, fPushVector);
	NormalizeVector(fPushVector, fPushVector);
	ScaleVector(fPushVector, g_hCVar_PushStrength.FloatValue);

	float fVelocity[3];
	GetEntDataVector(victim, g_iToolsVelocity, fVelocity);
	AddVectors(fPushVector, fVelocity, fVelocity);

	SetEntDataVector(victim, g_iToolsVelocity, fVelocity);
}
/*
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public Action OnHEDetonate(Event hEvent, const char[] sEvent, bool bDontBroadcast)
{
	if (!GetConVarBool(g_hCVar_PushNadesEnabled))
		return Plugin_Continue;

	float fNadeOrigin[3];
	fNadeOrigin[0] = hEvent.GetFloat("x");
	fNadeOrigin[1] = hEvent.GetFloat("y");
	fNadeOrigin[2] = hEvent.GetFloat("z");

	int iOwner = GetClientOfUserId(hEvent.GetInt("userid"));

	if (!IsValidClient(iOwner, false))
		return Plugin_Continue;

	if (!IsPlayerAlive(iOwner) || !ZR_IsClientHuman(iOwner))
		return Plugin_Continue;

	for (int client = 1; client <= MaxClients; client++)
	{
		if (IsValidClient(client, false))
		{
			if (IsPlayerAlive(client) && ZR_IsClientZombie(client))
			{
				float fZombieOrigin[3];
				GetClientAbsOrigin(client, fZombieOrigin);

				float fDistance = GetVectorDistance(fZombieOrigin, fNadeOrigin, false);
				float fMaxRange = GetConVarFloat(g_hCVar_PushRange);

				if (fDistance <= fMaxRange)
				{
					float fOwnerOrigin[3];
					GetClientAbsOrigin(iOwner, fOwnerOrigin);

					float fPushVector[3];
					MakeVectorFromPoints(fOwnerOrigin, fZombieOrigin, fPushVector);

					float fCurrentVector[3];
					//GetEntPropVector(iOwner, Prop_Data, "m_vecVelocity", fCurrentVector);

					float fPushStrength = GetConVarFloat(g_hCVar_PushStrength);

					float fDistanceScalingFactor = 1.0;
					if (GetConVarBool(g_hCVar_PushScale))
						fDistanceScalingFactor = 1.0 - ((1.0/fMaxRange) * fDistance);


					NormalizeVector(fPushVector, fPushVector);
					fPushVector[0] *= fPushStrength * fDistanceScalingFactor;
					fPushVector[1] *= fPushStrength * fDistanceScalingFactor;
					fPushVector[2] *= fPushStrength * fDistanceScalingFactor;

					fPushVector[0] += fCurrentVector[0];
					fPushVector[1] += fCurrentVector[1];
					fPushVector[2] += fCurrentVector[2];

					TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, fPushVector);
				}
			}
		}
	}
	return Plugin_Continue;
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int KnockbackFindExplodingGrenade(float fLoc[3])
{
	char sClassname[64];

	int iMaxEntities = GetMaxEntities();
	for (int i = MaxClients; i <= iMaxEntities; i++)
	{
		if (!IsValidEdict(i))
			continue;

		GetEdictClassname(i, sClassname, sizeof(sClassname));
		if (!StrEqual(sClassname, "hegrenade_projectile", false))
			continue;

		int iTakeDamage = GetEntProp(i, Prop_Data, "m_takedamage");
		if (iTakeDamage == 0)
        {
			GetEntPropVector(i, Prop_Send, "m_vecOrigin", fLoc);
			return i;
		}
	}
	return -1;
}
*/
//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
stock int IsValidClient(int client, bool nobots = true)
{
	if (client <= 0 || client > MaxClients || !IsClientConnected(client) || (nobots && IsFakeClient(client)))
		return false;

	return IsClientInGame(client);
}

//----------------------------------------------------------------------------------------------------
// Purpose:
//----------------------------------------------------------------------------------------------------
public int WeaponsGetActiveWeaponIndex(int client)
{
	return GetEntDataEnt2(client, g_iToolsActiveWeapon);
}