#include <amxmodx>
#include <cstrike>
#include <engine>
#include <fakemeta>
#include <fun>
#include <hamsandwich>
#include <zombieplague>

#define KNIFE_NAME								ARRAY_knife_name[knife]
#define KNIFE_DESC								ARRAY_knife_desc[knife]
#define KNIFE_SPEED								ARRAY_knife_speed[knife]
#define KNIFE_GRAV								ARRAY_knife_grav[knife]
#define KNIFE_JUMP								ARRAY_knife_jump[knife]
#define KNIFE_KNOCK								ARRAY_knife_knock[knife]
#define KNIFE_DMG								ARRAY_knife_dmg[knife]
#define KNIFE_PRIMATTRATE						ARRAY_knife_primattrate[knife]
#define KNIFE_SECATTRATE						ARRAY_knife_secattrate[knife]
#define KNIFE_FLAGS								ARRAY_knife_flags[knife]
#define KNIFE_HITSOUNDS							ARRAY_knife_hitsounds[knife]
#define KNIFE_SLASHSOUNDS						ARRAY_knife_slashsounds[knife]
#define KNIFE_MODEL_V							ARRAY_knife_model_v[knife]
#define KNIFE_MODEL_P							ARRAY_knife_model_p[knife]
#define KNIFE_SOUND_DEPLOY						ARRAY_knife_sound_deploy[knife]
#define KNIFE_SOUND_HIT(%1)						ARRAY_knife_sound_hit[knife][%1]
#define KNIFE_SOUND_HITWALL						ARRAY_knife_sound_hitwall[knife]
#define KNIFE_SOUND_SLASH(%1)					ARRAY_knife_sound_slash[knife][%1]
#define KNIFE_SOUND_STAB						ARRAY_knife_sound_stab[knife]
#define KNIFE_SAVED_AUTHID						ARRAY_knife_saved_authid[i]
#define KNIFE_SAVED_ID							ARRAY_knife_saved_id[i]
#define KNIFES_TOTAL							INT_knifes_total
#define KNIFES_TOTAL_SAVED						INT_knifes_total_saved
#define KNIFE_SURV								INT_knife_surv
#define KNIFE_USER(%1)							PSZ_knife{%1}

#define KNIFE_SURVIVOR							9

#define USE_STOPPED								0

#define m_pPlayer								41
#define m_flNextPrimaryAttack					46
#define m_flNextSecondaryAttack					47

#define m_pActiveItem							373

#define LINUXDIFF								5
#define LINUXDIFFWEAP							4

#define get_user_weapon_entity(%1)				get_pdata_cbase(%1, m_pActiveItem, LINUXDIFF)
#define get_weapon_owner(%1)					get_pdata_cbase(%1, m_pPlayer, LINUXDIFFWEAP)
#define get_weapon_nextprimatt(%1)				get_pdata_float(%1, m_flNextPrimaryAttack, LINUXDIFFWEAP)
#define get_weapon_nextsecatt(%1)				get_pdata_float(%1, m_flNextSecondaryAttack, LINUXDIFFWEAP)
#define set_weapon_nextprimatt(%1,%2)			set_pdata_float(%1, m_flNextPrimaryAttack, %2, LINUXDIFFWEAP)
#define set_weapon_nextsecatt(%1,%2)			set_pdata_float(%1, m_flNextSecondaryAttack, %2, LINUXDIFFWEAP)

#define register_menu(%1,%2,%3)					register_menucmd(register_menuid(%1), %2, %3)

#define MENU_KNIFES_KEYS						MENU_KEY_1 | MENU_KEY_2 | MENU_KEY_3 | MENU_KEY_4 | MENU_KEY_5 | MENU_KEY_6 | MENU_KEY_7 | MENU_KEY_8 | MENU_KEY_9 | MENU_KEY_0
#define MENU_KNIFES								"/knife"

new PSZ_knife[33 char]

new Float:ARRAY_knife_speed[10]
new Float:ARRAY_knife_grav[10]
new Float:ARRAY_knife_jump[10]
new Float:ARRAY_knife_knock[10]
new Float:ARRAY_knife_dmg[10]
new Float:ARRAY_knife_primattrate[10]
new Float:ARRAY_knife_secattrate[10]
new ARRAY_knife_flags[10]
new ARRAY_knife_hitsounds[10]
new ARRAY_knife_slashsounds[10]
new ARRAY_knife_name[10][64]
new ARRAY_knife_desc[10][64]
new ARRAY_knife_model_v[10][64]
new ARRAY_knife_model_p[10][64]
new ARRAY_knife_sound_deploy[10][64]
new ARRAY_knife_sound_hit[10][4][64]
new ARRAY_knife_sound_hitwall[10][64]
new ARRAY_knife_sound_slash[10][2][64]
new ARRAY_knife_sound_stab[10][64]
new ARRAY_knife_saved_authid[1024][32]
new ARRAY_knife_saved_id[1024]

new INT_knifes_total
new INT_knifes_total_saved
new INT_knife_surv

new Float:FL_gravity
new Float:FL_gravity_surv

public plugin_precache()
{
	register_srvcmd("register_knife", "SRVCMD__register_knife")
	
	server_cmd("exec addons/amxmodx/configs/cso_knifes.cfg")
	server_exec()
}

public SRVCMD__register_knife()
{
	new data[17][64]
	read_argv(1, data[0], 63)
	read_argv(2, data[1], 63)
	read_argv(3, data[2], 63)
	read_argv(4, data[3], 63)
	read_argv(5, data[4], 63)
	read_argv(6, data[5], 63)
	read_argv(7, data[6], 63)
	read_argv(8, data[7], 63)
	read_argv(9, data[8], 63)
	read_argv(10, data[9], 63)
	read_argv(11, data[10], 63)
	read_argv(12, data[11], 63)
	read_argv(13, data[12], 63)
	read_argv(14, data[13], 63)
	read_argv(15, data[14], 63)
	read_argv(16, data[15], 63)
	read_argv(17, data[16], 63)
	
	for (new i = 0; i < 17; i++) remove_quotes(data[i])
	
	new knife
	(data[9][0] == 'S') ? (knife = KNIFE_SURVIVOR) : (knife = KNIFES_TOTAL)
	
	formatex(KNIFE_NAME, 63, data[0])
	formatex(KNIFE_DESC, 63, data[1])
	KNIFE_SPEED = floatstr(data[2])
	KNIFE_GRAV = floatstr(data[3])
	KNIFE_JUMP = floatstr(data[4])
	KNIFE_KNOCK = floatstr(data[5])
	KNIFE_DMG = floatstr(data[6])
	KNIFE_PRIMATTRATE = floatstr(data[7])
	KNIFE_SECATTRATE = floatstr(data[8])
	if (data[9][0] > 0 && knife != KNIFE_SURVIVOR) KNIFE_FLAGS = read_flags(data[9])
	
	formatex(KNIFE_MODEL_V, 63, data[10])
	precache_model(KNIFE_MODEL_V)
	formatex(KNIFE_MODEL_P, 63, data[11])
	precache_model(KNIFE_MODEL_P)
	formatex(KNIFE_SOUND_DEPLOY, 63, data[12])
	precache_sound(KNIFE_SOUND_DEPLOY)
	if (containi(data[13], ",") != -1)
	{
		KNIFE_HITSOUNDS = 2
		strtok(data[13], KNIFE_SOUND_HIT(0), 63, KNIFE_SOUND_HIT(1), 63, ',')
		precache_sound(KNIFE_SOUND_HIT(0))
		precache_sound(KNIFE_SOUND_HIT(1))
	}
	else
	{
		KNIFE_HITSOUNDS = 1
		formatex(KNIFE_SOUND_HIT(0), 63, data[13])
		precache_sound(KNIFE_SOUND_HIT(0))
	}
	formatex(KNIFE_SOUND_HITWALL, 63, data[14])
	precache_sound(KNIFE_SOUND_HITWALL)
	if (containi(data[15], ",") != -1)
	{
		KNIFE_SLASHSOUNDS = 2
		strtok(data[15], KNIFE_SOUND_SLASH(0), 63, KNIFE_SOUND_SLASH(1), 63, ',')
		precache_sound(KNIFE_SOUND_SLASH(0))
		precache_sound(KNIFE_SOUND_SLASH(1))
	}
	else
	{
		KNIFE_SLASHSOUNDS = 1
		formatex(KNIFE_SOUND_SLASH(0), 63, data[15])
		precache_sound(KNIFE_SOUND_SLASH(0))
	}
	formatex(KNIFE_SOUND_STAB, 63, data[16])
	precache_sound(KNIFE_SOUND_STAB)
	
	if (knife != KNIFE_SURVIVOR) KNIFES_TOTAL++
	else KNIFE_SURV = 1
}

public plugin_init()
{
	register_plugin("[CSO] Knifes", "Omega", "WPMG Team")
	
	RegisterHam(Ham_Spawn,					"player",			"CPlayer__Spawn_Post",			1)
	RegisterHam(Ham_Item_Deploy,			"weapon_knife",		"CKNIFE__Deploy_Post",			1)
	RegisterHam(Ham_Use,					"func_tank",		"CStationary__Use_Post",		1)
	RegisterHam(Ham_Use,					"func_tankmortar",	"CStationary__Use_Post",		1)
	RegisterHam(Ham_Use,					"func_tankrocket",	"CStationary__Use_Post",		1)
	RegisterHam(Ham_Use,					"func_tanklaser",	"CStationary__Use_Post",		1)
	RegisterHam(Ham_Weapon_PrimaryAttack,	"weapon_knife",		"CKNIFE__PrimaryAttack_Post",	1)
	RegisterHam(Ham_Weapon_SecondaryAttack,	"weapon_knife",		"CKNIFE__SecondaryAttack_Post",	1)
	RegisterHam(Ham_TakeDamage,				"player",			"CPlayer__TakeDamage")
	RegisterHam(Ham_TakeDamage,				"player",			"CPlayer__TakeDamage_Post",		1)
	RegisterHam(Ham_Player_PreThink,		"player",			"CPlayer__PreThink")
	
	register_forward(FM_EmitSound,								"CEntity__EmitSound")
	
	register_srvcmd("load_knife", "SRVCMD__load_knife")
	register_clcmd("/knife", "CMD__knife")
	
	register_menu(MENU_KNIFES, MENU_KNIFES_KEYS, "MENU__Knifes")
}

public plugin_cfg()
{
	server_cmd("exec addons/amxmodx/configs/zombieplague.cfg")
	server_cmd("exec addons/amxmodx/configs/cso_knifes_saved.cfg")
	server_exec()
	
	FL_gravity = get_cvar_float("zp_human_gravity")
	FL_gravity_surv = get_cvar_float("zp_surv_gravity")
}

public client_putinserver(id)
{
	KNIFE_USER(id) = 0
	
	new authid[32]
	get_user_authid(id, authid, 31)
	
	if (authid[5] != '_' || authid[6] == 'I') get_user_ip(id, authid, 31, 1)
	
	for (new i = 0; i < KNIFES_TOTAL_SAVED; i++)
	{
		if (equal(authid, KNIFE_SAVED_AUTHID))
		{
			new knife = KNIFE_SAVED_ID
			(KNIFE_FLAGS > 0) ? (get_user_flags(id) & KNIFE_FLAGS) ? (KNIFE_USER(id) = knife) : (KNIFE_USER(id) = 0) : (KNIFE_USER(id) = knife)
			break
		}
	}
}

public client_disconnect(id)
{
	new authid[32], i
	get_user_authid(id, authid, 31)
	
	if (authid[5] != '_' || authid[6] == 'I') get_user_ip(id, authid, 31, 1)
	
	for (i = 0; i < KNIFES_TOTAL_SAVED; i++)
	{
		if (equal(authid, KNIFE_SAVED_AUTHID))
		{
			KNIFE_SAVED_ID = KNIFE_USER(id)
			return
		}
	}
	
	i = KNIFES_TOTAL_SAVED
	
	formatex(KNIFE_SAVED_AUTHID, 31, authid)
	KNIFE_SAVED_ID = KNIFE_USER(id)
	KNIFES_TOTAL_SAVED++
}

public plugin_end()
{
	delete_file("addons/amxmodx/configs/cso_knifes_saved.cfg")
	
	new file, data[64], i
	file = fopen("addons/amxmodx/configs/cso_knifes_saved.cfg", "at")
	
	for (i = 0; i < KNIFES_TOTAL_SAVED; i++)
	{
		formatex(data, 63, "load_knife ^"%s^" ^"%d^"^n", KNIFE_SAVED_AUTHID, KNIFE_SAVED_ID)
		fputs(file, data)
	}
	
	fclose(file)
}

public SRVCMD__load_knife()
{
	new data[2][32], i
	read_argv(1, data[0], 31)
	read_argv(2, data[1], 31)
	for (i = 0; i < 2; i++) remove_quotes(data[i])
	
	i = KNIFES_TOTAL_SAVED
	
	formatex(KNIFE_SAVED_AUTHID, 31, data[0])
	KNIFE_SAVED_ID = str_to_num(data[1])
	KNIFES_TOTAL_SAVED++
}

public CPlayer__Spawn_Post(id)
{
	if (!is_user_alive(id)) return
	if (zp_get_user_zombie(id)) return
	
	new entity = get_user_weapon_entity(id)
	
	if (!is_valid_ent(entity)) return
	if (cs_get_weapon_id(entity) != CSW_KNIFE) return
	
	FUNC__replace_knife_models(id)
}

public CKNIFE__Deploy_Post(entity)
{
	if (cs_get_weapon_id(entity) != CSW_KNIFE) return
	
	new id = get_weapon_owner(entity)
	
	if (zp_get_user_zombie(id)) return
	
	FUNC__replace_knife_models(id)
}

public CStationary__Use_Post(entity, caller, activator, use_type)
{
	if (use_type != USE_STOPPED) return
	if (!is_user_connected(caller)) return
	if (zp_get_user_zombie(caller)) return
	if (get_user_weapon(caller) != CSW_KNIFE) return
	
	FUNC__replace_knife_models(caller)
}

public CKNIFE__PrimaryAttack_Post(entity)
{
	new id = get_weapon_owner(entity)
	
	if (zp_get_user_zombie(id)) return
	
	new knife
	(KNIFE_SURV && zp_get_user_survivor(id)) ? (knife = KNIFE_SURVIVOR) : (knife = KNIFE_USER(id))
	
	set_weapon_nextprimatt(entity, get_weapon_nextprimatt(entity) * KNIFE_PRIMATTRATE)
	set_weapon_nextsecatt(entity, get_weapon_nextsecatt(entity) * KNIFE_PRIMATTRATE)
}

public CKNIFE__SecondaryAttack_Post(entity)
{
	new id = get_weapon_owner(entity)
	
	if (zp_get_user_zombie(id)) return
	
	new knife
	(KNIFE_SURV && zp_get_user_survivor(id)) ? (knife = KNIFE_SURVIVOR) : (knife = KNIFE_USER(id))
	
	set_weapon_nextprimatt(entity, get_weapon_nextprimatt(entity) * KNIFE_SECATTRATE)
	set_weapon_nextsecatt(entity, get_weapon_nextsecatt(entity) * KNIFE_SECATTRATE)
}

public CPlayer__TakeDamage(victim, inflictor, attacker, Float:damage)
{
	if (inflictor != attacker || victim == attacker) return
	if (!is_user_connected(attacker)) return
	if (zp_get_user_zombie(attacker)) return
	if (get_user_weapon(attacker) != CSW_KNIFE) return
	
	new knife
	(KNIFE_SURV && zp_get_user_survivor(attacker)) ? (knife = KNIFE_SURVIVOR) : (knife = KNIFE_USER(attacker))
	
	SetHamParamFloat(4, damage * KNIFE_DMG)
}

public CPlayer__TakeDamage_Post(victim, inflictor, attacker, Float:damage)
{
	if (inflictor != attacker || victim == attacker) return
	if (!is_user_connected(attacker)) return
	if (zp_get_user_zombie(attacker)) return
	if (get_user_weapon(attacker) != CSW_KNIFE) return
	
	client_print(attacker, print_center, "%d", floatround(damage, floatround_floor))
	
	new Float:velocity[3], Float:newvelocity[3]
	entity_get_vector(victim, EV_VEC_velocity, velocity)
	
	new Float:victim_origin[3], Float:attacker_origin[3]
	entity_get_vector(victim, EV_VEC_origin, victim_origin)
	entity_get_vector(attacker, EV_VEC_origin, attacker_origin)
	
	newvelocity[0] = victim_origin[0] - attacker_origin[0]
	newvelocity[1] = victim_origin[1] - attacker_origin[1]
	
	new Float:largestnum = 0.0
	
	if (0 <= floatcmp(floatabs(newvelocity[0]), floatabs(newvelocity[1])) <= 1)
	{
		if (floatabs(newvelocity[0]) > 0) largestnum = floatabs(newvelocity[0])
	}
	else
	{
		if (floatabs(newvelocity[1]) > 0) largestnum = floatabs(newvelocity[1])
	}
	
	newvelocity[0] /= largestnum
	newvelocity[1] /= largestnum
	
	new knife
	(KNIFE_SURV && zp_get_user_survivor(attacker)) ? (knife = KNIFE_SURVIVOR) : (knife = KNIFE_USER(attacker))
	
	velocity[0] = newvelocity[0] * KNIFE_KNOCK * 3000 / get_distance_f(victim_origin, attacker_origin)
	velocity[1] = newvelocity[1] * KNIFE_KNOCK * 3000 / get_distance_f(victim_origin, attacker_origin)
	if(newvelocity[0] <= 20.0 || newvelocity[1] <= 20.0)
		newvelocity[2] = random_float(200.0 , 275.0)
	
	newvelocity[0] += velocity[0]
	newvelocity[1] += velocity[1]
	entity_set_vector(victim, EV_VEC_velocity, newvelocity)
}

public CPlayer__PreThink(id)
{
	if (!is_user_alive(id)) return
	if (zp_get_user_zombie(id)) return
	if (get_user_weapon(id) != CSW_KNIFE)
	{
		if (zp_get_user_survivor(id)) set_user_gravity(id, FL_gravity_surv)
		else set_user_gravity(id, FL_gravity)
		return
	}
	
	new knife
	(KNIFE_SURV && zp_get_user_survivor(id)) ? (knife = KNIFE_SURVIVOR) : (knife = KNIFE_USER(id))
	
	set_user_maxspeed(id, KNIFE_SPEED)
	set_user_gravity(id, KNIFE_GRAV)
	
	if (!(entity_get_int(id, EV_INT_button) & IN_JUMP)) return
	if (entity_get_int(id, EV_INT_oldbuttons) & IN_JUMP) return
	
	new flags = entity_get_int(id, EV_INT_flags)
	
	if (!(flags & FL_ONGROUND)) return
	if (flags & FL_WATERJUMP) return
	if (entity_get_int(id, EV_INT_waterlevel) > 1) return
	
	new Float:velocity[3]
	entity_get_vector(id, EV_VEC_velocity, velocity)
	
	velocity[2] += KNIFE_JUMP
	entity_set_vector(id, EV_VEC_velocity, velocity)
	entity_set_int(id, EV_INT_gaitsequence, 6)
}

public CEntity__EmitSound(id, channel, const sample[], Float:volume, Float:attn, flags, pitch)
{
	if (!is_user_connected(id)) return FMRES_IGNORED
	if (zp_get_user_zombie(id)) return FMRES_IGNORED
	
	if (sample[8] == 'k' && sample[9] == 'n' && sample[10] == 'i')
	{
		new knife
		(KNIFE_SURV && zp_get_user_survivor(id)) ? (knife = KNIFE_SURVIVOR) : (knife = KNIFE_USER(id))
		if (sample[14] == 'd') emit_sound(id, channel, KNIFE_SOUND_DEPLOY, volume, attn, flags, pitch)
		else if (sample[14] == 'h')
		{
			if (sample[17] == 'w') emit_sound(id, channel, KNIFE_SOUND_HITWALL, volume, attn, flags, pitch)
			else emit_sound(id, channel, (KNIFE_HITSOUNDS > 1) ? KNIFE_SOUND_HIT(random_num(0, 1)) : KNIFE_SOUND_HIT(0), volume, attn, flags, pitch)
		}
		else
		{
			if (sample[15] == 'l') emit_sound(id, channel, (KNIFE_SLASHSOUNDS > 1) ? KNIFE_SOUND_SLASH(random_num(0, 1)) : KNIFE_SOUND_SLASH(0), volume, attn, flags, pitch)
			else emit_sound(id, channel, KNIFE_SOUND_STAB, volume, attn, flags, pitch)
		}
		return FMRES_SUPERCEDE
	}
	
	return FMRES_IGNORED
}

public CMD__knife(id)
{
	if (zp_has_round_started() == 1) return PLUGIN_HANDLED
	return SHOWMENU__Knifes(id)
}

public SHOWMENU__Knifes(id)
{
	new len, menu[500], keys, flags
	len += formatex(menu, 499, "\yВыберите Ножик:^n^n")
	flags = get_user_flags(id)
	
	for (new knife = 0; knife < KNIFES_TOTAL; knife++)
	{
		if (KNIFE_FLAGS)
		{
			if (flags & KNIFE_FLAGS)
			{
				keys |= (1 << knife)
				if (KNIFE_USER(id) == knife) len += formatex(menu[len], 499 - len, "\r%d.\d %s %s^n", knife + 1, KNIFE_NAME, KNIFE_DESC)
				else len += formatex(menu[len], 499 - len, "\r%d.\w %s \r%s^n", knife + 1, KNIFE_NAME, KNIFE_DESC)
			}
			else
				len += formatex(menu[len], 499 - len, "\d%d. %s \r%s^n", knife + 1, KNIFE_NAME, KNIFE_DESC)
		}
		else
		{
			keys |= (1 << knife)
			if (KNIFE_USER(id) == knife) len += formatex(menu[len], 499 - len, "\r%d.\d %s %s^n", knife + 1, KNIFE_NAME, KNIFE_DESC)
			else len += formatex(menu[len], 499 - len, "\r%d.\w %s \w%s^n", knife + 1, KNIFE_NAME, KNIFE_DESC)
		}
	}
	
	keys |= MENU_KEY_0
	len += formatex(menu[len], 499 - len, "^n\r0.\w Выход")
	
	return show_menu(id, keys, menu, -1, MENU_KNIFES)
}

public MENU__Knifes(id, key)
{
	if (zp_has_round_started() == 1) return PLUGIN_HANDLED
	if (key != 9)
		if (KNIFE_USER(id) != key)
		{
			KNIFE_USER(id) = key
			if (is_user_alive(id) && !zp_get_user_zombie(id))
				if (get_user_weapon(id) == CSW_KNIFE)
					FUNC__replace_knife_models(id)
		}
	return PLUGIN_HANDLED
}

public FUNC__replace_knife_models(id)
{
	new knife
	(KNIFE_SURV && zp_get_user_survivor(id)) ? (knife = KNIFE_SURVIVOR) : (knife = KNIFE_USER(id))
	
	entity_set_string(id, EV_SZ_viewmodel, KNIFE_MODEL_V)
	entity_set_string(id, EV_SZ_weaponmodel, KNIFE_MODEL_P)
}