#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <zombieplague>
#include <xs>

#define CustomItem(%0) (pev(%0, pev_impulse) == WEAPON_SPECIAL_CODE)
#define Get_WeaponState(%0) get_pdata_int(%0, m_iWeaponState, linux_diff_weapon)
#define Set_WeaponState(%0,%1) set_pdata_int(%0, m_iWeaponState, %1, linux_diff_weapon)

enum
{
	STATE_UNSIL = 0,
	STATE_SILENCER
};

#define TASKID_INVISIBLE 25780
#define TASKID_REMOVEGLOW 25820
#define PDATA_SAFE 2

#define WEAPON_ANIM_IDLE 0
#define WEAPON_ANIM_SHOOT random_num(1,3)
#define WEAPON_ANIM_RELOAD 4
#define WEAPON_ANIM_DRAW 5
#define WEAPON_ANIM_SILENCER 6
#define WEAPON_ANIM_UNSIL 7 // +7

// From model: Frames/FPS
#define WEAPON_ANIM_IDLE_TIME 2/16.0
#define WEAPON_ANIM_SHOOT_TIME 31/20.0
#define WEAPON_ANIM_RELOAD_TIME 114/37.0
#define WEAPON_ANIM_DRAW_TIME 41/40.0
#define WEAPON_ANIM_SILENCE_TIME 61/30.0

#define WEAPON_SPECIAL_CODE 12525
#define WEAPON_REFERENCE "weapon_m4a1"

#define WEAPON_ITEM_NAME "M4A1 Silver"
#define WEAPON_ITEM_COST 0

#define WEAPON_MODEL_VIEW "models/x/v_m4a1s.mdl"
#define WEAPON_MODEL_PLAYER "models/x/p_m4a1s.mdl"
#define WEAPON_MODEL_WORLD "models/x/w_m4a1s.mdl"
#define WEAPON_BODY 0

#define WEAPON_SOUND_SHOOT "weapons/m4a1-1.wav"
#define WEAPON_SOUND_SHOOT_UNSIL "weapons/m4a1_unsil-1.wav"

#define WEAPON_MAX_CLIP 30
#define WEAPON_DEFAULT_AMMO 180

#define WEAPON_RATE 0.0975
#define WEAPON_PUNCHANGLE 0.832
#define WEAPON_DAMAGE 1.386 + 2.0

#define WEAPON_RATE_UNSIL 0.0975
#define WEAPON_PUNCHANGLE_UNSIL 0.98
#define WEAPON_DAMAGE_UNSIL 1.592 + 2.0

// Invisible
#define INVISIBLE_DAMAGE_ACTIVE 2000.0
#define INVISIBLE_AMOUNT 0.0
#define INVISIBLE_TIME 5.0

// Linux extra offsets
#define linux_diff_weapon 4
#define linux_diff_player 5

// CWeaponBox
#define m_rgpPlayerItems_CWeaponBox 34

// CBaseAnimating
#define m_flLastEventCheck 38

// CBasePlayerItem
#define m_pPlayer 41
#define m_pNext 42
#define m_iId 43

// CBasePlayerWeapon
#define m_flNextPrimaryAttack 46
#define m_flNextSecondaryAttack 47
#define m_flTimeWeaponIdle 48
#define m_iPrimaryAmmoType 49
#define m_iClip 51
#define m_fInReload 54
#define m_iWeaponState 74

// CBaseMonster
#define m_flNextAttack 83

// CBasePlayer
#define m_rpgPlayerItems 367
#define m_pActiveItem 373
#define m_rgAmmo 376

new g_iszAllocString_Entity,
	g_iszAllocString_ModelView, 
	g_iszAllocString_ModelPlayer, 

	HamHook: g_HamHook_TraceAttack[4],

	g_iItemID;

public plugin_init()
{
	register_plugin("[ZP] Weapon: M4A1 Silver", "1.0", "xUnicorn (t3rkecorejz) / Batcoh: Code base");

	g_iItemID = zp_register_extra_item(WEAPON_ITEM_NAME, WEAPON_ITEM_COST, ZP_TEAM_HUMAN);

	register_forward(FM_UpdateClientData,	"FM_Hook_UpdateClientData_Post", true);
	register_forward(FM_SetModel, 			"FM_Hook_SetModel_Pre", false);

	RegisterHam(Ham_Spawn,					"player",			"CPlayer__Spawn_Post", true);
	RegisterHam(Ham_Item_Holster,			WEAPON_REFERENCE,	"CWeapon__Holster_Post", true);
	RegisterHam(Ham_Item_Deploy,			WEAPON_REFERENCE,	"CWeapon__Deploy_Post", true);
	RegisterHam(Ham_Item_PostFrame,			WEAPON_REFERENCE,	"CWeapon__PostFrame_Pre", false);
	RegisterHam(Ham_Weapon_Reload,			WEAPON_REFERENCE,	"CWeapon__Reload_Pre", false);
	RegisterHam(Ham_Weapon_WeaponIdle,		WEAPON_REFERENCE,	"CWeapon__WeaponIdle_Pre", false);
	RegisterHam(Ham_Weapon_PrimaryAttack,	WEAPON_REFERENCE,	"CWeapon__PrimaryAttack_Pre", false);
	RegisterHam(Ham_Weapon_SecondaryAttack,	WEAPON_REFERENCE,	"CWeapon__SecondaryAttack_Pre", false);
	
	g_HamHook_TraceAttack[0] = RegisterHam(Ham_TraceAttack,		"func_breakable",	"CEntity__TraceAttack_Pre", false);
	g_HamHook_TraceAttack[1] = RegisterHam(Ham_TraceAttack,		"info_target",		"CEntity__TraceAttack_Pre", false);
	g_HamHook_TraceAttack[2] = RegisterHam(Ham_TraceAttack,		"player",			"CEntity__TraceAttack_Pre", false);
	g_HamHook_TraceAttack[3] = RegisterHam(Ham_TraceAttack,		"hostage_entity",	"CEntity__TraceAttack_Pre", false);
	
	fm_ham_hook(false);
}

public plugin_precache()
{
	// Precache models
	engfunc(EngFunc_PrecacheModel, WEAPON_MODEL_VIEW);
	engfunc(EngFunc_PrecacheModel, WEAPON_MODEL_PLAYER);
	engfunc(EngFunc_PrecacheModel, WEAPON_MODEL_WORLD);

	// Precache sounds
	engfunc(EngFunc_PrecacheSound, WEAPON_SOUND_SHOOT);
	engfunc(EngFunc_PrecacheSound, WEAPON_SOUND_SHOOT_UNSIL);
	
	UTIL_PrecacheSoundsFromModel(WEAPON_MODEL_VIEW);

	// Other
	g_iszAllocString_Entity = engfunc(EngFunc_AllocString, WEAPON_REFERENCE);
	g_iszAllocString_ModelView = engfunc(EngFunc_AllocString, WEAPON_MODEL_VIEW);
	g_iszAllocString_ModelPlayer = engfunc(EngFunc_AllocString, WEAPON_MODEL_PLAYER);
}

// [ Amxx ]
#if AMXX_VERSION_NUM < 183
	public client_disconnect(iPlayer)
#else
	public client_disconnected(iPlayer)
#endif
{
	UTIL_SetRendering(iPlayer);
	set_pev(iPlayer, pev_iuser2, 0);
}

public zp_extra_item_selected(iPlayer, iItem)
{
	if(iItem == g_iItemID)
		Command_GiveWeapon(iPlayer);
}

public Command_GiveWeapon(iPlayer)
{
	static iEntity; iEntity = engfunc(EngFunc_CreateNamedEntity, g_iszAllocString_Entity);
	if(iEntity <= 0) return 0;

	set_pev(iEntity, pev_impulse, WEAPON_SPECIAL_CODE);
	ExecuteHam(Ham_Spawn, iEntity);
	UTIL_DropWeapon(iPlayer, 1);

	if(!ExecuteHamB(Ham_AddPlayerItem, iPlayer, iEntity))
	{
		set_pev(iEntity, pev_flags, pev(iEntity, pev_flags) | FL_KILLME);
		return 0;
	}

	ExecuteHamB(Ham_Item_AttachToPlayer, iEntity, iPlayer);
	set_pdata_int(iEntity, m_iClip, WEAPON_MAX_CLIP, linux_diff_weapon);
	Set_WeaponState(iEntity, STATE_UNSIL);

	new iAmmoType = m_rgAmmo + get_pdata_int(iEntity, m_iPrimaryAmmoType, linux_diff_weapon);
	if(get_pdata_int(iPlayer, m_rgAmmo, linux_diff_player) < WEAPON_DEFAULT_AMMO)
		set_pdata_int(iPlayer, iAmmoType, WEAPON_DEFAULT_AMMO, linux_diff_player);

	emit_sound(iPlayer, CHAN_ITEM, "items/gunpickup2.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM);
	return 1;
}

// [ Fakemeta ]
public FM_Hook_UpdateClientData_Post(iPlayer, SendWeapons, CD_Handle)
{
	if(!is_user_alive(iPlayer)) return;

	static iItem; iItem = get_pdata_cbase(iPlayer, m_pActiveItem, linux_diff_player);
	if(pev_valid(iItem) != PDATA_SAFE || !CustomItem(iItem)) return;

	set_cd(CD_Handle, CD_flNextAttack, get_gametime() + 0.001);
}

public FM_Hook_SetModel_Pre(iEntity)
{
	static i, szClassName[32], iItem;
	pev(iEntity, pev_classname, szClassName, charsmax(szClassName));

	if(!equal(szClassName, "weaponbox")) return FMRES_IGNORED;

	for(i = 0; i < 6; i++)
	{
		iItem = get_pdata_cbase(iEntity, m_rgpPlayerItems_CWeaponBox + i, linux_diff_weapon);

		if(iItem > 0 && CustomItem(iItem))
		{
			engfunc(EngFunc_SetModel, iEntity, WEAPON_MODEL_WORLD);
			set_pev(iEntity, pev_body, WEAPON_BODY);
			
			return FMRES_SUPERCEDE;
		}
	}

	return FMRES_IGNORED;
}

public FM_Hook_PlaybackEvent_Pre() return FMRES_SUPERCEDE;

public FM_Hook_TraceLine_Post(const Float: vecOrigin1[3], const Float: vecOrigin2[3], iFrag, iAttacker, iTrace)
{
	if(iFrag & IGNORE_MONSTERS) return FMRES_IGNORED;

	new pHit = get_tr2(iTrace, TR_pHit);
	new Float: vecEndPos[3]; get_tr2(iTrace, TR_vecEndPos, vecEndPos);

	if(pHit > 0) if(pev(pHit, pev_solid) != SOLID_BSP) return FMRES_IGNORED;

	new iPointContents = engfunc(EngFunc_PointContents, vecEndPos);
	if(iPointContents == CONTENTS_SKY || iPointContents == CONTENTS_WATER) return FMRES_IGNORED;

	// Decal
	engfunc(EngFunc_MessageBegin, MSG_PAS, SVC_TEMPENTITY, vecEndPos, 0);
	write_byte(TE_GUNSHOTDECAL);
	engfunc(EngFunc_WriteCoord, vecEndPos[0]);
	engfunc(EngFunc_WriteCoord, vecEndPos[1]);
	engfunc(EngFunc_WriteCoord, vecEndPos[2]);
	write_short(pHit > 0 ? pHit : 0);
	write_byte(random_num(41, 45));
	message_end();

	// Tracer
	new Float: vecOrigin[3];
	UTIL_GetWeaponPosition(iAttacker, vecOrigin, 10.0, 11.0, -10.5);

	new Float: vecVelocity[3];
	vecVelocity[0] = vecEndPos[0] - vecOrigin[0];
	vecVelocity[1] = vecEndPos[1] - vecOrigin[1];
	vecVelocity[2] = vecEndPos[2] - vecOrigin[2];

	xs_vec_normalize(vecVelocity, vecVelocity);
	xs_vec_mul_scalar(vecVelocity, 4096.0, vecVelocity);

	message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
	write_byte(TE_USERTRACER);
	engfunc(EngFunc_WriteCoord, vecOrigin[0]);
	engfunc(EngFunc_WriteCoord, vecOrigin[1]);
	engfunc(EngFunc_WriteCoord, vecOrigin[2]);
	engfunc(EngFunc_WriteCoord, vecVelocity[0]);
	engfunc(EngFunc_WriteCoord, vecVelocity[1]);
	engfunc(EngFunc_WriteCoord, vecVelocity[2]);
	write_byte(20); // Life
	write_byte(0); // Color
	write_byte(5); // Lenght
	message_end();

	// Streak Splash
	new Float:vecPlaneNormal[3]; get_tr2(iTrace, TR_vecPlaneNormal, vecPlaneNormal);

	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, vecEndPos, 0);
	write_byte(TE_STREAK_SPLASH);
	engfunc(EngFunc_WriteCoord, vecEndPos[0]);
	engfunc(EngFunc_WriteCoord, vecEndPos[1]);
	engfunc(EngFunc_WriteCoord, vecEndPos[2]);
	engfunc(EngFunc_WriteCoord, vecPlaneNormal[0] * random_float(25.0, 30.0));
	engfunc(EngFunc_WriteCoord, vecPlaneNormal[1] * random_float(25.0, 30.0));
	engfunc(EngFunc_WriteCoord, vecPlaneNormal[2] * random_float(25.0, 30.0));
	write_byte(0); // Color
	write_short(random_num(10, 12)); // Count
	write_short(3); // Speed
	write_short(75); // Speed noice
	message_end();

	return FMRES_IGNORED;
}

// [ HamSandwich ]
public CPlayer__Spawn_Post(iPlayer)
{
	if(!is_user_connected(iPlayer)) return;

	UTIL_SetRendering(iPlayer);
	set_pev(iPlayer, pev_iuser2, 0);
}

public CWeapon__Holster_Post(iItem)
{
	if(!CustomItem(iItem)) return;
	static iPlayer; iPlayer = get_pdata_cbase(iItem, m_pPlayer, linux_diff_weapon);
	
	set_pdata_float(iItem, m_flNextPrimaryAttack, 0.0, linux_diff_weapon);
	set_pdata_float(iItem, m_flNextSecondaryAttack, 0.0, linux_diff_weapon);
	set_pdata_float(iItem, m_flTimeWeaponIdle, 0.0, linux_diff_weapon);
	set_pdata_float(iPlayer, m_flNextAttack, 0.0, linux_diff_player);
}

public CWeapon__Deploy_Post(iItem)
{
	if(!CustomItem(iItem)) return;
	
	static iPlayer; iPlayer = get_pdata_cbase(iItem, m_pPlayer, linux_diff_weapon);

	set_pev_string(iPlayer, pev_viewmodel2, g_iszAllocString_ModelView);
	set_pev_string(iPlayer, pev_weaponmodel2, g_iszAllocString_ModelPlayer);

	UTIL_SendWeaponAnim(iPlayer, Get_WeaponState(iItem) ? WEAPON_ANIM_DRAW : WEAPON_ANIM_DRAW + WEAPON_ANIM_UNSIL);

	set_pdata_float(iPlayer, m_flNextAttack, WEAPON_ANIM_DRAW_TIME, linux_diff_player);
	set_pdata_float(iItem, m_flTimeWeaponIdle, WEAPON_ANIM_DRAW_TIME, linux_diff_weapon);
}

public CWeapon__PostFrame_Pre(iItem)
{
	if(!CustomItem(iItem)) return HAM_IGNORED;

	if(get_pdata_int(iItem, m_fInReload, linux_diff_weapon) == 1)
	{
		static iPlayer; iPlayer = get_pdata_cbase(iItem, m_pPlayer, linux_diff_weapon);
		
		static iClip; iClip = get_pdata_int(iItem, m_iClip, linux_diff_weapon);
		static iAmmoType; iAmmoType = m_rgAmmo + get_pdata_int(iItem, m_iPrimaryAmmoType, linux_diff_weapon);
		static iAmmo; iAmmo = get_pdata_int(iPlayer, iAmmoType, linux_diff_player);
		static j; j = min(WEAPON_MAX_CLIP - iClip, iAmmo);

		set_pdata_int(iItem, m_iClip, iClip + j, linux_diff_weapon);
		set_pdata_int(iPlayer, iAmmoType, iAmmo - j, linux_diff_player);
		set_pdata_int(iItem, m_fInReload, 0, linux_diff_weapon);
	}

	return HAM_IGNORED;
}

public CWeapon__Reload_Pre(iItem)
{
	if(!CustomItem(iItem)) return HAM_IGNORED;

	static iClip; iClip = get_pdata_int(iItem, m_iClip, linux_diff_weapon);
	if(iClip >= WEAPON_MAX_CLIP) return HAM_SUPERCEDE;

	static iPlayer; iPlayer = get_pdata_cbase(iItem, m_pPlayer, linux_diff_weapon);
	static iAmmoType; iAmmoType = m_rgAmmo + get_pdata_int(iItem, m_iPrimaryAmmoType, linux_diff_weapon);
	if(get_pdata_int(iPlayer, iAmmoType, linux_diff_player) <= 0) return HAM_SUPERCEDE;

	set_pdata_int(iItem, m_iClip, 0, linux_diff_weapon);
	ExecuteHam(Ham_Weapon_Reload, iItem);
	set_pdata_int(iItem, m_iClip, iClip, linux_diff_weapon);
	set_pdata_int(iItem, m_fInReload, 1, linux_diff_weapon);

	UTIL_SendWeaponAnim(iPlayer, Get_WeaponState(iItem) ? WEAPON_ANIM_RELOAD : WEAPON_ANIM_RELOAD + WEAPON_ANIM_UNSIL);

	set_pdata_float(iItem, m_flNextPrimaryAttack, WEAPON_ANIM_RELOAD_TIME, linux_diff_weapon);
	set_pdata_float(iItem, m_flNextSecondaryAttack, WEAPON_ANIM_RELOAD_TIME, linux_diff_weapon);
	set_pdata_float(iItem, m_flTimeWeaponIdle, WEAPON_ANIM_RELOAD_TIME, linux_diff_weapon);
	set_pdata_float(iPlayer, m_flNextAttack, WEAPON_ANIM_RELOAD_TIME, linux_diff_player);

	return HAM_SUPERCEDE;
}

public CWeapon__WeaponIdle_Pre(iItem)
{
	if(!CustomItem(iItem) || get_pdata_float(iItem, m_flTimeWeaponIdle, linux_diff_weapon) > 0.0) return HAM_IGNORED;
	static iPlayer; iPlayer = get_pdata_cbase(iItem, m_pPlayer, linux_diff_weapon);

	UTIL_SendWeaponAnim(iPlayer, Get_WeaponState(iItem) ? WEAPON_ANIM_IDLE : WEAPON_ANIM_IDLE + WEAPON_ANIM_UNSIL);
	set_pdata_float(iItem, m_flTimeWeaponIdle, WEAPON_ANIM_IDLE_TIME, linux_diff_weapon);

	return HAM_SUPERCEDE;
}

public CWeapon__PrimaryAttack_Pre(iItem)
{
	if(!CustomItem(iItem)) return HAM_IGNORED;

	if(get_pdata_int(iItem, m_iClip, linux_diff_weapon) == 0)
	{
		ExecuteHam(Ham_Weapon_PlayEmptySound, iItem);
		set_pdata_float(iItem, m_flNextPrimaryAttack, 0.2, linux_diff_weapon);

		return HAM_SUPERCEDE;
	}

	static iPlayer; iPlayer = get_pdata_cbase(iItem, m_pPlayer, linux_diff_weapon);

	static fw_TraceLine; fw_TraceLine = register_forward(FM_TraceLine, "FM_Hook_TraceLine_Post", true);
	static fw_PlayBackEvent; fw_PlayBackEvent = register_forward(FM_PlaybackEvent, "FM_Hook_PlaybackEvent_Pre", false);
	fm_ham_hook(true);

	ExecuteHam(Ham_Weapon_PrimaryAttack, iItem);

	unregister_forward(FM_TraceLine, fw_TraceLine, true);
	unregister_forward(FM_PlaybackEvent, fw_PlayBackEvent);
	fm_ham_hook(false);

	static Float:vecPunchangle[3];
	pev(iPlayer, pev_punchangle, vecPunchangle);
	vecPunchangle[0] *= Get_WeaponState(iItem) ? WEAPON_PUNCHANGLE : WEAPON_PUNCHANGLE_UNSIL;
	vecPunchangle[1] *= Get_WeaponState(iItem) ? WEAPON_PUNCHANGLE : WEAPON_PUNCHANGLE_UNSIL;
	vecPunchangle[2] *= Get_WeaponState(iItem) ? WEAPON_PUNCHANGLE : WEAPON_PUNCHANGLE_UNSIL;
	set_pev(iPlayer, pev_punchangle, vecPunchangle);

	UTIL_SendWeaponAnim(iPlayer, Get_WeaponState(iItem) ? WEAPON_ANIM_SHOOT : WEAPON_ANIM_SHOOT + WEAPON_ANIM_UNSIL);
	emit_sound(iPlayer, CHAN_WEAPON, Get_WeaponState(iItem) ? WEAPON_SOUND_SHOOT : WEAPON_SOUND_SHOOT_UNSIL, VOL_NORM, ATTN_NORM, 0, PITCH_NORM);

	set_pdata_float(iItem, m_flNextPrimaryAttack, Get_WeaponState(iItem) ? WEAPON_RATE : WEAPON_RATE_UNSIL, linux_diff_weapon);
	set_pdata_float(iItem, m_flNextSecondaryAttack, Get_WeaponState(iItem) ? WEAPON_RATE : WEAPON_RATE_UNSIL, linux_diff_weapon);
	set_pdata_float(iItem, m_flTimeWeaponIdle, WEAPON_ANIM_SHOOT_TIME, linux_diff_weapon);

	return HAM_SUPERCEDE;
}

public CWeapon__SecondaryAttack_Pre(iItem)
{
	if(!CustomItem(iItem)) return HAM_IGNORED;

	static iPlayer; iPlayer = get_pdata_cbase(iItem, m_pPlayer, linux_diff_weapon);

	UTIL_SendWeaponAnim(iPlayer, Get_WeaponState(iItem) ? WEAPON_ANIM_SILENCER + WEAPON_ANIM_UNSIL : WEAPON_ANIM_SILENCER);
	Set_WeaponState(iItem, Get_WeaponState(iItem) ? STATE_UNSIL : STATE_SILENCER);

	set_pdata_float(iItem, m_flNextPrimaryAttack, WEAPON_ANIM_SILENCE_TIME, linux_diff_weapon);
	set_pdata_float(iItem, m_flNextSecondaryAttack, WEAPON_ANIM_SILENCE_TIME, linux_diff_weapon);
	set_pdata_float(iItem, m_flTimeWeaponIdle, WEAPON_ANIM_SILENCE_TIME, linux_diff_weapon);

	return HAM_SUPERCEDE;
}

public CEntity__TraceAttack_Pre(iVictim, iAttacker, Float: flDamage)
{
	if(!is_user_connected(iAttacker)) return;

	static iItem; iItem = get_pdata_cbase(iAttacker, m_pActiveItem, linux_diff_player);
	if(iItem <= 0 || !CustomItem(iItem)) return;

	flDamage *= (Get_WeaponState(iItem) ? WEAPON_DAMAGE : WEAPON_DAMAGE_UNSIL);

	SetHamParamFloat(3, flDamage);

	if(pev(iAttacker, pev_iuser2) == 0)
	{
		if(pev(iItem, pev_fuser2) < INVISIBLE_DAMAGE_ACTIVE)
		{
			set_pev(iItem, pev_fuser2, pev(iItem, pev_fuser2) + flDamage);
		}
		else
		{
			UTIL_SetRendering(iVictim, kRenderFxGlowShell, 255, 255, 255, kRenderNormal, 25.0);

			set_pev(iItem, pev_fuser2, 0.0);
			set_pev(iAttacker, pev_iuser2, 1);

			if(zp_get_user_zombie(iVictim)) {
				UTIL_SetRendering(iAttacker, kRenderFxGlowShell, 0, 0, 0, kRenderTransAlpha, INVISIBLE_AMOUNT);
			}

			message_begin(MSG_ONE, get_user_msgid("ScreenFade"), {0,0,0}, iAttacker);
			write_short(0); // Duration
			write_short(0); // Hold time
			write_short(0x0004); // Flags
			write_byte(255); // Red
			write_byte(255); // Green
			write_byte(255); // Blue
			write_byte(60); // Amount
			message_end();

			client_print(iAttacker, print_center, "*** Вы стали невидимы! ***");

			if(!task_exists(iAttacker + TASKID_INVISIBLE))
				set_task(INVISIBLE_TIME, "CTask__RemoveInvis", iAttacker + TASKID_INVISIBLE);

			if(!task_exists(iVictim + TASKID_REMOVEGLOW))
				set_task(INVISIBLE_TIME, "CTtask__RemoveGlow", iVictim + TASKID_REMOVEGLOW);
		}
	}
}

// [ Other ]
public fm_ham_hook(bool: bEnabled)
{
	if(bEnabled)
	{
		EnableHamForward(g_HamHook_TraceAttack[0]);
		EnableHamForward(g_HamHook_TraceAttack[1]);
		EnableHamForward(g_HamHook_TraceAttack[2]);
		EnableHamForward(g_HamHook_TraceAttack[3]);
	}
	else 
	{
		DisableHamForward(g_HamHook_TraceAttack[0]);
		DisableHamForward(g_HamHook_TraceAttack[1]);
		DisableHamForward(g_HamHook_TraceAttack[2]);
		DisableHamForward(g_HamHook_TraceAttack[3]);
	}
}

public CTask__RemoveInvis(iTask)
{
	new iPlayer = iTask - TASKID_INVISIBLE;

	if(!is_user_alive(iPlayer))
	{
		remove_task(iTask);
		return;
	}

	UTIL_SetRendering(iPlayer);
	set_pev(iPlayer, pev_iuser2, 0);

	message_begin(MSG_ONE, get_user_msgid("ScreenFade"), {0,0,0}, iPlayer);
	write_short(0); // Duration
	write_short(0); // Hold time
	write_short(0); // Flags
	write_byte(0); // Red
	write_byte(0); // Green
	write_byte(0); // Blue
	write_byte(255); // Amount
	message_end();

	client_print(iPlayer, print_center, "*** Невидимость закончилась! ***");

	remove_task(iTask);
}

public CTtask__RemoveGlow(iTask)
{
	new iPlayer = iTask - TASKID_REMOVEGLOW;

	if(!is_user_alive(iPlayer))
	{
		remove_task(iTask);
		return;
	}

	UTIL_SetRendering(iPlayer);

	remove_task(iTask);
}

// [ Stocks ]
stock UTIL_SendWeaponAnim(iPlayer, iAnim)
{
	set_pev(iPlayer, pev_weaponanim, iAnim);

	message_begin(MSG_ONE, SVC_WEAPONANIM, _, iPlayer);
	write_byte(iAnim);
	write_byte(0);
	message_end();
}

stock UTIL_DropWeapon(iPlayer, iSlot)
{
	static iEntity, iNext, szWeaponName[32];
	iEntity = get_pdata_cbase(iPlayer, m_rpgPlayerItems + iSlot, linux_diff_player);

	if(iEntity > 0)
	{       
		do 
		{
			iNext = get_pdata_cbase(iEntity, m_pNext, linux_diff_weapon);

			if(get_weaponname(get_pdata_int(iEntity, m_iId, linux_diff_weapon), szWeaponName, charsmax(szWeaponName)))
				engclient_cmd(iPlayer, "drop", szWeaponName);
		} 
		
		while((iEntity = iNext) > 0);
	}
}

stock UTIL_PrecacheSoundsFromModel(const szModelPath[])
{
	new iFile;
	
	if((iFile = fopen(szModelPath, "rt")))
	{
		new szSoundPath[64];
		
		new iNumSeq, iSeqIndex;
		new iEvent, iNumEvents, iEventIndex;
		
		fseek(iFile, 164, SEEK_SET);
		fread(iFile, iNumSeq, BLOCK_INT);
		fread(iFile, iSeqIndex, BLOCK_INT);
		
		for(new k, i = 0; i < iNumSeq; i++)
		{
			fseek(iFile, iSeqIndex + 48 + 176 * i, SEEK_SET);
			fread(iFile, iNumEvents, BLOCK_INT);
			fread(iFile, iEventIndex, BLOCK_INT);
			fseek(iFile, iEventIndex + 176 * i, SEEK_SET);
			
			for(k = 0; k < iNumEvents; k++)
			{
				fseek(iFile, iEventIndex + 4 + 76 * k, SEEK_SET);
				fread(iFile, iEvent, BLOCK_INT);
				fseek(iFile, 4, SEEK_CUR);
				
				if(iEvent != 5004)
					continue;
				
				fread_blocks(iFile, szSoundPath, 64, BLOCK_CHAR);
				
				if(strlen(szSoundPath))
				{
					strtolower(szSoundPath);
					engfunc(EngFunc_PrecacheSound, szSoundPath);
				}
			}
		}
	}
	
	fclose(iFile);
}

stock UTIL_GetWeaponPosition(iPlayer, Float: vecOrigin[3], Float: flAddForward = 0.0, Float: flAddRight = 0.0, Float: flAddUp = 0.0)
{
	static Float: vecAngles[3], Float: vecViewOfs[3];
	static Float: vecDirShooting[3], Float: vecRight[3], Float: vecUp[3];
	
	pev(iPlayer, pev_origin, vecOrigin);
	pev(iPlayer, pev_view_ofs, vecViewOfs);
	
	xs_vec_add(vecOrigin, vecViewOfs, vecOrigin);
	pev(iPlayer, pev_v_angle, vecAngles);
	engfunc(EngFunc_MakeVectors, vecAngles);
	
	global_get(glb_v_forward, vecDirShooting);
	global_get(glb_v_right, vecRight);
	global_get(glb_v_up, vecUp);
	
	xs_vec_mul_scalar(vecDirShooting, flAddForward, vecDirShooting);
	xs_vec_mul_scalar(vecRight, flAddRight, vecRight);
	xs_vec_mul_scalar(vecUp, flAddUp, vecUp);
	
	vecOrigin[0] = vecOrigin[0] + vecDirShooting[0] + vecRight[0] + vecUp[0];
	vecOrigin[1] = vecOrigin[1] + vecDirShooting[1] + vecRight[1] + vecUp[1];
	vecOrigin[2] = vecOrigin[2] + vecDirShooting[2] + vecRight[2] + vecUp[2];
}

stock UTIL_SetRendering(iPlayer, iFx = 0, iRed = 255, iGreen = 255, iBlue = 255, iRender = 0, Float: flAmount = 16.0)
{
	static Float: flColor[3];
	
	flColor[0] = float(iRed);
	flColor[1] = float(iGreen);
	flColor[2] = float(iBlue);
	
	set_pev(iPlayer, pev_renderfx, iFx);
	set_pev(iPlayer, pev_rendercolor, flColor);
	set_pev(iPlayer, pev_rendermode, iRender);
	set_pev(iPlayer, pev_renderamt, flAmount);
}