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

#define MAX_PLAYERS  32

#define WEAPONKEY     101010

#define RELOAD_TIME   3.5

#define ITEM_NAME "MG42"
#define COST 0

#define ANIM_SHOOT1        1
#define ANIM_SHOOT2        2
#define ANIM_RELOAD   3
#define ANIM_DRAW       4

#define AMMO_CLIP        95
#define AMMO_BP           200

#define WPN_DAMAGE  0.86
#define WPN_RECOIL      0.7
#define WPN_SPEED      0.8

#define BODY_MG42 0

#define V_MODEL      "models/v_mg42.mdl"
#define P_MODEL      "models/p_mg42.mdl"
#define W_MODEL      "models/w_mg42.mdl"
#define SHELL_MODEL  "models/rshell.mdl"

#define SPRITE_SMOKE "sprites/smokepuff.spr"

#define FIRE_SOUND   "weapons/mg42-1.wav"

#define write_coord_f(%1)	                                  engfunc(EngFunc_WriteCoord,%1)

new const GUNSHOT_DECALS[] = { 41, 42, 43, 44, 45 }

new const TRACE_ATTACK[ ] [ ] = 
{
         "func_breakable" , 
	"func_wall" , 
	"func_door" ,
	"func_plat" , 
	"func_rotating" , 
	"worldspawn"
}

new const wpnlist_txt[] = "weapon_mg42"

new const hud[][] = 
{ 
	"sprites/640hud7.spr",
	"sprites/640hud110.spr"
}

new const Sound[ ] [ ] =  
{
	"weapons/mg42_clipin1.wav",
	"weapons/mg42_clipin2.wav",
	"weapons/mg42_clipout.wav",
	"weapons/mg42_close.wav",
	"weapons/mg42_open.wav"
}

new 
g_itemid,
g_has_mg42[33],
g_orign_mg42, 
g_clip_ammo[33],
g_weapon_TmpClip[33],
oldweap[33],
Float:cl_pushangle[MAX_PLAYERS + 1][3],
smoke,
shell,
gmsgWeaponList

public plugin_init()
{
	register_plugin("Weapon MG42", "1.0", "PaXaN-ZOMBIE")
	register_message(get_user_msgid("DeathMsg"), "message_DeathMsg")
	register_event("CurWeapon","CurrentWeapon","be","1=1")

	RegisterHam(Ham_Item_AddToPlayer, "weapon_m249", "HAM_AddToPlayer")
	RegisterHam(Ham_Item_Deploy, "weapon_m249", "HAM_Item_Deploy_Post",1)
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_m249", "HAM_PrimaryAttack")
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_m249", "HAM_PrimaryAttack_Post", 1)
	RegisterHam(Ham_Item_PostFrame, "weapon_m249", "HAM_ItemPostFrame");
	RegisterHam(Ham_Weapon_Reload, "weapon_m249", "HAM_Reload");
	RegisterHam(Ham_Weapon_Reload, "weapon_m249", "HAM_Reload_Post", 1);
	RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage")
	
	static i 
	new iLen = sizeof TRACE_ATTACK
	for(i = 0 ; i < iLen ; i++)
	      RegisterHam( Ham_TraceAttack , TRACE_ATTACK[ i ] , "fw_TraceAttack" , 1 ) 


	register_forward(FM_SetModel, "fw_SetModel")
	register_forward(FM_UpdateClientData, "Fw_UpdateClientData_Post", 1)
	register_forward(FM_PlaybackEvent, "Fw_PlaybackEvent")
	
	gmsgWeaponList = get_user_msgid("WeaponList")
	
	register_clcmd("admin_get_mg42","give_MG42")
	
	g_itemid = zp_register_extra_item(ITEM_NAME, COST, ZP_TEAM_HUMAN)
}

public plugin_precache()
{
	precache_model(V_MODEL)
	precache_model(P_MODEL)
	precache_model(W_MODEL)

	precache_sound(FIRE_SOUND)

	smoke = precache_model(SPRITE_SMOKE) 
	shell = precache_model(SHELL_MODEL) 
	
	register_clcmd("weapon_mg42", "weapon_hook")
	
	new iFile 
	new iLenFile = sizeof Sound
	
	for( iFile = 0 ; iFile < iLenFile; iFile++ )
	precache_sound( Sound[ iFile ] ) 
	
	new sFile[64]
	formatex(sFile, charsmax(sFile), "sprites/%s.txt", wpnlist_txt)
	precache_generic(sFile)
	
	for(new i = 0; i < sizeof(hud); i++)
	{
		precache_generic(hud[i])
	}
}

public weapon_hook(id)
{
    	engclient_cmd(id, "weapon_m249")
    	return PLUGIN_HANDLED
}

public client_connect(id) 
{
	g_has_mg42[id] = false
}

public client_disconnect(id) 
{
	g_has_mg42[id] = false
}

public zp_user_humanized_post(id) 
{
	g_has_mg42[id] = false
}

public zp_user_infected_post(id) 
{
	g_has_mg42[id] = false
}

public zp_extra_item_selected(id, itemid) 
{
	if(itemid != g_itemid) 
		return PLUGIN_CONTINUE
		
	give_MG42(id)
	
	return PLUGIN_CONTINUE
}

public give_MG42(id)
{
	drop_weapons(id, 1);
	new iWep2 = give_item(id,"weapon_m249")
	if( iWep2 > 0 )
	{
		cs_set_weapon_ammo(iWep2, AMMO_CLIP)
		cs_set_user_bpammo (id, CSW_M249, AMMO_BP)
		UTIL_PlayWeaponAnimation(id,ANIM_DRAW)

		message_begin(MSG_ONE, gmsgWeaponList, {0,0,0}, id)
		write_string("weapon_mg42")
		write_byte(3)
		write_byte(200)
		write_byte(-1)
		write_byte(-1)
		write_byte(0)
		write_byte(4)
		write_byte(CSW_M249)
		message_end()
	}
	g_has_mg42[id] = true
}

public HAM_AddToPlayer(weapon, id)
{
	if(!is_valid_ent(weapon) || !is_user_connected(id))
		return HAM_IGNORED;
	if(entity_get_int(weapon, EV_INT_impulse))
	{
		g_has_mg42[id] = true
		entity_set_int(weapon, EV_INT_impulse, 0)

		message_begin(MSG_ONE, gmsgWeaponList, {0,0,0}, id)
		write_string("weapon_mg42")
		write_byte(3)
		write_byte(200)
		write_byte(-1)
		write_byte(-1)
		write_byte(0)
		write_byte(4)
		write_byte(CSW_M249)
		message_end()

		return HAM_HANDLED;
	}
	else
	{
		message_begin(MSG_ONE, gmsgWeaponList, {0,0,0}, id)
		write_string("weapon_m249")
		write_byte(3)
		write_byte(200)
		write_byte(-1)
		write_byte(-1)
		write_byte(0)
		write_byte(4)
		write_byte(CSW_M249)
		message_end()
	}
	return HAM_IGNORED;
}

public fw_TraceAttack(iEnt, iAttacker, Float:damage, Float:fDir[3], ptr, iDamageType)
{
	if(!is_user_connected(iAttacker) || !is_user_alive(iAttacker))
	return HAM_IGNORED;
	
	if(get_user_weapon(iAttacker) != CSW_M249 || !g_has_mg42[iAttacker])

		return HAM_IGNORED

	static Float:flEnd[3]
	get_tr2(ptr, TR_vecEndPos, flEnd)
	
	if(iEnt)
	{
		message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
		write_byte(TE_DECAL)
		write_coord_f(flEnd[0])
		write_coord_f(flEnd[1])
		write_coord_f(flEnd[2])
		write_byte(GUNSHOT_DECALS[random_num (0, sizeof GUNSHOT_DECALS -1)])
		write_short(iEnt)
		message_end()
	}
	else
	{
		message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
		write_byte(TE_WORLDDECAL)
		write_coord_f(flEnd[0])
		write_coord_f(flEnd[1])
		write_coord_f(flEnd[2])
		write_byte(GUNSHOT_DECALS[random_num (0, sizeof GUNSHOT_DECALS -1)])
		message_end()
	}
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
	write_byte(TE_GUNSHOTDECAL)
	write_coord_f(flEnd[0])
	write_coord_f(flEnd[1])
	write_coord_f(flEnd[2])
	write_short(iAttacker)
	write_byte(GUNSHOT_DECALS[random_num (0, sizeof GUNSHOT_DECALS -1)])
	message_end()
	
	message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
	write_byte(TE_SPRITE)
	engfunc(EngFunc_WriteCoord, flEnd[0])
	engfunc(EngFunc_WriteCoord, flEnd[1]) 
	engfunc(EngFunc_WriteCoord, flEnd[2] + 5)
	write_short(smoke)
	write_byte(4)
	write_byte(130)
	message_end()

	return HAM_IGNORED
}

public fw_SetModel(entity, model[])
{
	if(!is_valid_ent(entity))
		return FMRES_IGNORED;
		
	static szClassName[33]
	entity_get_string(entity, EV_SZ_classname, szClassName, charsmax(szClassName))
	
	if(!equal(szClassName, "weaponbox"))
		return FMRES_IGNORED;
		
	static iOwner
	iOwner = entity_get_edict(entity, EV_ENT_owner)
	
	if(equal(model, "models/w_m249.mdl"))
	{
		static iStoredSVDID
		iStoredSVDID = find_ent_by_owner(-1, "weapon_m249", entity)
		
		if(!is_valid_ent(iStoredSVDID))
			return FMRES_IGNORED;
			
		if(g_has_mg42[iOwner])
		{
			entity_set_int(iStoredSVDID, EV_INT_impulse, WEAPONKEY)
			g_has_mg42[iOwner] = false
			entity_set_model(entity, W_MODEL)
			set_pev(entity, pev_body, BODY_MG42)
			return FMRES_SUPERCEDE;
		}
	}
	return FMRES_IGNORED;
}

public HAM_Item_Deploy_Post(weapon_ent)
{
	new id = pev(weapon_ent,pev_owner)
	if (!is_user_connected(id) || zp_get_user_zombie(id) || zp_get_user_survivor(id))
		return;
	static weaponid
	weaponid = cs_get_weapon_id(weapon_ent)
	replace_weapon_models(id, weaponid)
	UTIL_PlayWeaponAnimation(id,ANIM_DRAW)
}

public HAM_PrimaryAttack(weapon)
{
	new Player = get_pdata_cbase(weapon, 41, 4)
	
	if (!g_has_mg42[Player])
		return;
		
	g_clip_ammo[Player] = cs_get_weapon_ammo(weapon)
}

public HAM_PrimaryAttack_Post(Weapon, shell_index)
{
	new Player = get_pdata_cbase(Weapon, 41, 4)
	
	new szClip, szAmmo
	get_user_weapon(Player, szClip, szAmmo)
	
	if(g_has_mg42[Player])
	{
		if (!g_clip_ammo[Player])
			return		
		
		new Float:push[3]
		pev(Player,pev_punchangle,push)
		xs_vec_sub(push,cl_pushangle[Player],push)
		
		xs_vec_mul_scalar(push, WPN_RECOIL,push)
		xs_vec_add(push,cl_pushangle[Player],push)
		set_pev(Player,pev_punchangle,push)
		
		emit_sound(Player, CHAN_WEAPON, FIRE_SOUND, VOL_NORM, ATTN_NORM, 0, PITCH_NORM)
		
		UTIL_PlayWeaponAnimation(Player, random_num(ANIM_SHOOT1, ANIM_SHOOT2))
		
		make_shell(Player)
	}
}

public fw_TakeDamage(victim, inflictor, attacker, Float:damage)
{
	if (victim != attacker && is_user_connected(attacker))
	{
		if(get_user_weapon(attacker) == CSW_M249)
		{
			if(g_has_mg42[attacker])
			{
					SetHamParamFloat(4, damage * WPN_DAMAGE)
			}
}
}
}

public Fw_PlaybackEvent(flags, invoker, eventid, Float:delay, Float:origin[3], Float:angles[3], Float:fparam1, Float:fparam2, iParam1, iParam2, bParam1, bParam2)
{
	if ((eventid != g_orign_mg42))
		return FMRES_IGNORED
		
	if (!(1 <= invoker <= get_maxplayers()))
		return FMRES_IGNORED
		
	playback_event(flags | FEV_HOSTONLY, invoker, eventid, delay, origin, angles, fparam1, fparam2, iParam1, iParam2, bParam1, bParam2)
	return FMRES_SUPERCEDE
}

public CurrentWeapon(id)
{
	if (zp_get_user_zombie(id) || zp_get_user_survivor(id))
		return;
	replace_weapon_models(id, read_data(2))
	
	if(read_data(2) != CSW_M249 || !g_has_mg42[id])
		return	
	static Float:iSpeed
	if(g_has_mg42[id])
	iSpeed = WPN_SPEED
	
	static weapon[32],Ent
	get_weaponname(read_data(2),weapon,31)
	Ent = find_ent_by_owner(-1,weapon,id)
	if(Ent)
	{
		static Float:Delay
		Delay = get_pdata_float( Ent, 46, 4) * iSpeed
		
		if (Delay > 0.0)
		{
			set_pdata_float(Ent, 46, Delay, 4)
          }
     }
}

public HAM_ItemPostFrame(weapon_entity) 
{
	new id = pev(weapon_entity, pev_owner)
	if (!is_user_connected(id))
		return HAM_IGNORED;
		
	if (!g_has_mg42[id])
		return HAM_IGNORED;
		
	new Float:flNextAttack = get_pdata_float(id, 83, 5)
	new iBpAmmo = cs_get_user_bpammo(id, CSW_M249);
	new iClip = get_pdata_int(weapon_entity, 51, 4)
	new fInReload = get_pdata_int(weapon_entity,54, 4)
	
	if( fInReload && flNextAttack <= 0.0 )
	{
		new j = min(AMMO_CLIP - iClip, iBpAmmo)
		set_pdata_int(weapon_entity, 51, iClip + j, 4)
		cs_set_user_bpammo(id, CSW_M249, iBpAmmo-j);
		set_pdata_int(weapon_entity, 54, 0, 4)
		fInReload = 0
	}
	return HAM_IGNORED;
}

public HAM_Reload(weapon_entity) 
{
	new id = pev(weapon_entity, pev_owner)
	if (!is_user_connected(id))
		return HAM_IGNORED;
		
	if (!g_has_mg42[id])
		return HAM_IGNORED;
		
	g_weapon_TmpClip[id] = -1;
	
	new iBpAmmo = cs_get_user_bpammo(id, CSW_M249);
	new iClip = get_pdata_int(weapon_entity, 51, 4)
	
	if (iBpAmmo <= 0)
		return HAM_SUPERCEDE;
		
	if (iClip >= AMMO_CLIP)
		return HAM_SUPERCEDE;
		
	g_weapon_TmpClip[id] = iClip;
	return HAM_IGNORED;
}

public HAM_Reload_Post(weapon_entity) 
{
	new id = pev(weapon_entity, pev_owner)
	
	if (!is_user_connected(id))
		return HAM_IGNORED;
		
	if (!g_has_mg42[id])
		return HAM_IGNORED;
		
	if (g_weapon_TmpClip[id] == -1)
		return HAM_IGNORED;
		
	set_pdata_int(weapon_entity, 51, g_weapon_TmpClip[id], 4)
	set_pdata_float(weapon_entity,48, RELOAD_TIME,4)
	set_pdata_float(id, 83, RELOAD_TIME, 5)
	set_pdata_int(weapon_entity, 54, 1, 4)
	UTIL_PlayWeaponAnimation(id, ANIM_RELOAD)
	return HAM_IGNORED;
}

public Fw_UpdateClientData_Post(Player, SendWeapons, CD_Handle)
{
	if(!is_user_alive(Player) || (get_user_weapon(Player) != CSW_M249 || !g_has_mg42[Player]))
		return FMRES_IGNORED
	
	set_cd(CD_Handle, CD_flNextAttack, halflife_time () + 0.001)
	return FMRES_HANDLED
}

replace_weapon_models(id, weaponid)
{
	switch (weaponid)
	{
		case CSW_M249:
		{
			if(g_has_mg42[id])
			{
				set_pev(id, pev_viewmodel2, V_MODEL)
				set_pev(id, pev_weaponmodel2, P_MODEL)
				if(oldweap[id] != CSW_M249) 
				{
					UTIL_PlayWeaponAnimation(id, ANIM_DRAW)
					set_pdata_float(id, 51, 1.0, 4)

					message_begin(MSG_ONE, gmsgWeaponList, {0,0,0}, id)
					write_string("weapon_mg42")
					write_byte(3)
					write_byte(200)
					write_byte(-1)
					write_byte(-1)
					write_byte(0)
					write_byte(4)
					write_byte(CSW_M249)
					message_end()
				}
			}
		}
	}
	oldweap[id] = weaponid
}

public message_DeathMsg(msg_id, msg_dest, id)
{
	static szTruncatedWeapon[33], iAttacker, iVictim
	
	get_msg_arg_string(4, szTruncatedWeapon, charsmax(szTruncatedWeapon))
	
	iAttacker = get_msg_arg_int(1)
	iVictim = get_msg_arg_int(2)
	
	if(!is_user_connected(iAttacker) || iAttacker == iVictim)
		return PLUGIN_CONTINUE
	
	if(equal(szTruncatedWeapon, "m249") && get_user_weapon(iAttacker) == CSW_M249)
	{
		if(g_has_mg42[iAttacker])
			set_msg_arg_string(4, "mp40")		
	}
	
	return PLUGIN_CONTINUE
}

stock UTIL_PlayWeaponAnimation(const Player, const Sequence)
{
	set_pev(Player, pev_weaponanim, Sequence)
	message_begin(MSG_ONE_UNRELIABLE, SVC_WEAPONANIM, .player = Player)
	write_byte(Sequence)
	write_byte(pev(Player, pev_body))
	message_end()
}

stock make_shell(Player)
{
	new  Float:upScale, Float:fwScale, Float:rgScale
	upScale = -10.0,
	fwScale = 15.0
	rgScale = 6.0
	
	static Float:vPunchAngle[ 3 ], Float:vAngle[ 3 ], xol
	xol = 1 + 2
   
	if( xol & 1 )   
	pev( Player, pev_v_angle, vAngle )
	   
	if( xol & 2 )
	pev( Player, pev_punchangle, vPunchAngle )
   
	xs_vec_add(vAngle, vPunchAngle, vAngle)
	engfunc( EngFunc_MakeVectors, vAngle );
   
	static Float:vVel[ 3 ], Float:vOrigin[ 3 ], Float:vViewOfs[ 3 ],
	i, Float:vShellOrigin[ 3 ],  Float:vShellVelocity[ 3 ], Float:vRight[ 3 ],
	Float:vUp[ 3 ], Float:vForward[ 3 ];
	pev( Player, pev_velocity, vVel );
	pev( Player, pev_view_ofs, vViewOfs );
	pev( Player, pev_angles, vAngle );
	pev( Player, pev_origin, vOrigin );
	global_get( glb_v_right, vRight );
	global_get( glb_v_up, vUp );
	global_get( glb_v_forward, vForward );
   
	for( i = 0; i < 3; i++ )
	{
		vShellOrigin[i] = vOrigin[ i ] + vViewOfs[ i ] + vUp[ i ] * upScale + vForward[i] * fwScale + vRight[ i ] * rgScale;
		vShellVelocity[i] = vVel[ i ] + vRight[ i ] * random_float( 50.0, 70.0 ) + vUp[i] * random_float( 100.0, 150.0 ) + vForward[ i ] * 25.0;
	}
   
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, vShellOrigin, 0)
	write_byte(TE_MODEL)
	engfunc(EngFunc_WriteCoord, vShellOrigin[0])
	engfunc(EngFunc_WriteCoord, vShellOrigin[1])
	engfunc(EngFunc_WriteCoord, vShellOrigin[2])   
	engfunc(EngFunc_WriteCoord, vShellVelocity[0])
	engfunc(EngFunc_WriteCoord, vShellVelocity[1])
	engfunc(EngFunc_WriteCoord, vShellVelocity[2])
	engfunc(EngFunc_WriteAngle, vAngle[1])
	write_short(shell)
	write_byte(1)
	write_byte(25)
	message_end()
}


stock drop_weapons(id, dropwhat)
{
	static weapons[32], num, i, weaponid
	num = 0
	get_user_weapons(id, weapons, num)
	for (i = 0; i < num; i++)
	{
		const PRIMARY_WEAPONS_BIT_SUM = (1<<CSW_SCOUT)|(1<<CSW_XM1014)|(1<<CSW_MAC10)|(1<<CSW_AUG)|(1<<CSW_UMP45)|(1<<CSW_SG550)|(1<<CSW_GALIL)|(1<<CSW_FAMAS)|(1<<CSW_AWP)|(1<<CSW_MP5NAVY)|(1<<CSW_M249)|(1<<CSW_M3)|(1<<CSW_M4A1)|(1<<CSW_TMP)|(1<<CSW_G3SG1)|(1<<CSW_SG552)|(1<<CSW_AK47)|(1<<CSW_P90)
		weaponid = weapons[i]
		if (dropwhat == 1 && ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM))
		{
			static wname[32]
			get_weaponname(weaponid, wname, sizeof wname - 1)
			engclient_cmd(id, "drop", wname)
		}
	}
}
