#include <amxmodx>
#include <cstrike>
#include <engine>
#include <hamsandwich>
#include <fakemeta_stocks>
#include <fakemeta_util>
#include <fun>
#include <next21_DR_core>

#define PLUGIN "n21_Deathrun_Snowballs"
#define VERSION "1.0"
#define AUTHOR "Psycrow"

#define get_gun_owner(%1)	get_pdata_cbase(%1, 41, 4)
#define SnowballVModel		"models/n21_deathrun/snowball/v_snowball.mdl"
#define SnowballPModel		"models/n21_deathrun/snowball/p_snowball.mdl"
#define SnowballWModel		"models/n21_deathrun/snowball/w_snowball.mdl"
#define g_wSmoke		"models/w_smokegrenade.mdl"

#define SoundHit		"n21_deathrun/snowball/impalehit.wav"
#define SoundLaunch		"n21_deathrun/snowball/impalelaunch1.wav"
#define SoundSplash		"n21_deathrun/snowball/splash.wav"
#define GLASS			"models/glassgibs.mdl"
#define RING			"sprites/shockwave.spr"
#define TRAIL			"sprites/laserbeam.spr"

#define SNOWDAMAGE	50.0
#define FREEZETIME	3.0
#define CHILLTIME	8.0
#define TERHEALTH	300.0
#define SNOWBALLSPEED	2000.0

#define FROST_R	0
#define FROST_G	206
#define FROST_B	209

#define TASK_REMOVE 1337

new ModeId, in_snowman
new g_frozen[33]
new g_glassSpr ,g_Spr, trailSpr

public plugin_precache()
{
	precache_model(SnowballVModel)
	precache_model(SnowballPModel)
	precache_model(SnowballWModel)
	precache_model(g_wSmoke)
	
	precache_sound(SoundHit)
	precache_sound(SoundLaunch)
	precache_sound(SoundSplash)
	
	g_glassSpr = precache_model(GLASS)
	g_Spr = precache_model(RING)
	trailSpr = precache_model(TRAIL)
}

public plugin_init()
{
	register_plugin(PLUGIN, VERSION, AUTHOR)
	
	ModeId = n21_dr_mode_registration("Снежки", "", 3, 0, 255, 255, 6)
		
	register_forward(FM_Touch, "fw_Touch", 1)
	register_forward(FM_SetModel, "fw_SetModel")
	register_forward(FM_EmitSound, "fw_EmitSound")
	register_forward(FM_PlayerPreThink, "fw_think")
	register_logevent("NewRound", 2, "1=Round_Start")
	RegisterHam(Ham_Spawn, "player", "hook_spawn_post", 1)
	RegisterHam(Ham_Item_Deploy,"weapon_smokegrenade","CurWeapon", 1)
	RegisterHam(Ham_Use,"func_button","UseButton",0)
	
	register_message(get_user_msgid("TextMsg"), "block_message")
	register_message(get_user_msgid("SendAudio"), "block_sound")
}

public client_connect(id)
	g_frozen[id] = false
	
public n21_dr_new_terr(id, mode)
{
	if(mode == ModeId)
	{
		in_snowman = id
	
		fm_strip_user_weapons(id)
		fm_give_item(id, "weapon_smokegrenade")
		cs_set_user_bpammo(id, CSW_SMOKEGRENADE, 999)
		client_cmd(id, "weapon_smokegrenade")
		set_pev(id, pev_viewmodel2, SnowballVModel)
		set_pev(id, pev_weaponmodel2, SnowballPModel)
		set_pev(id, pev_health, TERHEALTH)
		message_begin(MSG_ONE, get_user_msgid("HideWeapon"), _, id)
		write_byte((1<<0))
		message_end()
	}
}
	
public NewRound()
	in_snowman = 0

	
public CurWeapon(gun)
{
	new id = get_gun_owner(gun)
	
	if(ModeId == n21_dr_get_mode_id() && cs_get_user_team(id) == CS_TEAM_T)
	{
		set_pev(id, pev_viewmodel2, SnowballVModel)
		set_pev(id, pev_weaponmodel2, SnowballPModel)
	}
}	

public fw_think(id)
{
	if(!is_user_connected(id))
		return PLUGIN_CONTINUE
	
	if(!is_user_alive(id) || ModeId != n21_dr_get_mode_id() || !g_frozen[id])
		return PLUGIN_CONTINUE

	set_pev(id, pev_velocity, Float:{ 0.0, 0.0, 0.0 })

	return PLUGIN_CONTINUE
}

public fw_SetModel(entity, model[])
{
	if (ModeId != n21_dr_get_mode_id()) 
		return FMRES_IGNORED
	
	if (!equali(model, g_wSmoke)) 
		return FMRES_IGNORED
	
	new className[33]
	pev(entity, pev_classname, className, 32)
	
	if(equal(className, "weaponbox") || equal(className, "armoury_entity") || equal(className, "grenade"))
	{
		entity_set_float(entity, EV_FL_nextthink, get_gametime() + 99999.9)
		new Float:Sonic[3]
		pev(entity, pev_velocity, Sonic)
		xs_vec_normalize(Sonic, Sonic)
		xs_vec_mul_scalar(Sonic, SNOWBALLSPEED, Sonic)
		set_pev(entity, pev_velocity, Sonic)
		set_pev(entity, pev_gravity, 0.5)
		set_pev(entity, pev_friction, 0.0)
		set_beamfollow(entity,10,10,Float:{0.0, 200.0, 200.0},170)
		engfunc(EngFunc_SetModel, entity, SnowballWModel)
		
		set_pev(entity, pev_movetype, MOVETYPE_NOCLIP)
		set_task(0.1, "change_solid", entity)
		
		return FMRES_SUPERCEDE
		
	}
	
	return FMRES_IGNORED
}

public change_solid(ent)
{
	if(is_valid_ent(ent))
		set_pev(ent, pev_movetype, MOVETYPE_BOUNCE)
}

public fw_EmitSound(ent, channel, sample[], Float:volume, Float:attn, flags, pitch)
{
	if(equal(sample, "weapons/grenade_hit1.wav") || equal(sample, "weapons/grenade_hit2.wav") || equal(sample, "weapons/grenade_hit3.wav"))
	{
		set_pev(ent, pev_velocity, {0.0, 0.0, 0.0})	
		set_pev(ent,pev_movetype,MOVETYPE_NONE)
		set_rendering(ent)
		emit_sound(ent, channel, SoundSplash, volume, attn, flags, pitch)
		if(!task_exists(ent+TASK_REMOVE))
			set_task(5.0,"Remove_Snowball",ent+TASK_REMOVE)
		
		return FMRES_SUPERCEDE
	}
	return PLUGIN_CONTINUE
}

public hook_spawn_post(id)
{
	if(g_frozen[id])
	{
		set_pev(id, pev_renderfx, kRenderFxGlowShell)
		set_pev(id, pev_rendercolor, Float:{ 0.0, 0.0, 0.0 })
		set_pev(id, pev_rendermode, kRenderNormal)
		set_pev(id, pev_renderamt, 25.0)
		g_frozen[id] = false
	}
}

public Remove_Snowball(lol)
{
	new ent = lol - TASK_REMOVE	
	
	if(ent && ModeId == n21_dr_get_mode_id())
		if(is_valid_ent(ent))
			remove_entity(ent)
}

public n21_dr_set_mode(id, mode)
	if(mode == ModeId)
	{	
		in_snowman = id
		fm_strip_user_weapons(id)
		fm_give_item(id, "weapon_smokegrenade")
		cs_set_user_bpammo(id, CSW_SMOKEGRENADE, 999)
		client_cmd(id, "weapon_smokegrenade")
		set_pev(id, pev_viewmodel2, SnowballVModel)
		set_pev(id, pev_weaponmodel2, SnowballPModel)
		set_pev(id, pev_health, TERHEALTH)
		message_begin(MSG_ONE, get_user_msgid("HideWeapon"), _, id)
		write_byte((1<<0))
		message_end()

		new Players[32] 
		new Count, i	
		
		get_players(Players, Count, "ahe","CT") 
	     
		for (i=0; i<Count; i++)
			ham_strip_weapon(Players[i],"weapon_usp")
	}

public UseButton(ent, id, idactivator, use_type, Float:value)
{
	if(!is_user_connected(id))
		return HAM_SUPERCEDE  
	
	if(in_snowman == id)
		return HAM_SUPERCEDE  
		
	return HAM_IGNORED   
}

public fw_Touch(Touched, Toucher)
{
	if(ModeId != n21_dr_get_mode_id())
		return FMRES_IGNORED
		
	if(!is_user_connected(Touched) || !is_valid_ent(Toucher))
		return FMRES_IGNORED
	
	new classname[64]
	entity_get_string(Toucher, EV_SZ_classname, classname, 63)
	if(!equali(classname, "grenade"))
		return FMRES_IGNORED

	entity_get_string(Touched, EV_SZ_classname, classname, 63)
	if(!equali(classname, "player"))
		return FMRES_IGNORED

	if(g_frozen[Touched] || cs_get_user_team(Touched) != CS_TEAM_CT)
		return FMRES_SUPERCEDE
		
	remove_entity(Toucher)
	
	new Float:originF[3]
	entity_get_vector(Touched, EV_VEC_origin, originF)
	
	emit_sound(Touched, CHAN_BODY, SoundHit, 1.0, ATTN_NORM, 0, PITCH_NORM)
	
	if(pev(Touched, pev_health) > SNOWDAMAGE)
	{
		//new attacker = pev(Toucher,pev_owner)
					
		//ExecuteHam(Ham_TakeDamage, Touched, 0, attacker, SNOWDAMAGE, DMG_ALWAYSGIB | DMG_BULLET)
		set_pev(Touched, pev_health, pev(Touched, pev_health) - SNOWDAMAGE)
					
		engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
		write_byte(TE_BEAMCYLINDER)
		engfunc(EngFunc_WriteCoord, originF[0])
		engfunc(EngFunc_WriteCoord, originF[1])
		engfunc(EngFunc_WriteCoord, originF[2])
		engfunc(EngFunc_WriteCoord, originF[0])
		engfunc(EngFunc_WriteCoord, originF[1])
		engfunc(EngFunc_WriteCoord, originF[2]+385.0)
		write_short(g_Spr)
		write_byte(0)
		write_byte(0)
		write_byte(4)
		write_byte(60)
		write_byte(0)
		write_byte(0)
		write_byte(100)
		write_byte(200)
		write_byte(200)
		write_byte(0)
		message_end()
				
		engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
		write_byte(TE_BEAMCYLINDER)
		engfunc(EngFunc_WriteCoord, originF[0])
		engfunc(EngFunc_WriteCoord, originF[1])
		engfunc(EngFunc_WriteCoord, originF[2])
		engfunc(EngFunc_WriteCoord, originF[0])
		engfunc(EngFunc_WriteCoord, originF[1])
		engfunc(EngFunc_WriteCoord, originF[2]+470.0)
		write_short(g_Spr)
		write_byte(0)
		write_byte(0)
		write_byte(4)
		write_byte(60)
		write_byte(0)
		write_byte(0)
		write_byte(100)
		write_byte(200)
		write_byte(200)
		write_byte(0)
		message_end()
				
		engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
		write_byte(TE_BEAMCYLINDER)
		engfunc(EngFunc_WriteCoord, originF[0])
		engfunc(EngFunc_WriteCoord, originF[1])
		engfunc(EngFunc_WriteCoord, originF[2])
		engfunc(EngFunc_WriteCoord, originF[0])
		engfunc(EngFunc_WriteCoord, originF[1])
		engfunc(EngFunc_WriteCoord, originF[2]+555.0)
		write_short(g_Spr)
		write_byte(0)
		write_byte(0)
		write_byte(4)
		write_byte(60)
		write_byte(0)
		write_byte(0)
		write_byte(100)
		write_byte(200)
		write_byte(200)
		write_byte(0)
		message_end()
	}
	else
	{
		unfrozen(Touched)
		ExecuteHam(Ham_Killed, Touched, Touched, 0)
		return FMRES_IGNORED
	}

	g_frozen[Touched] = true
	if(pev(Touched, pev_flags) & FL_ONGROUND)
		set_pev(Touched, pev_gravity, 999999.9)
	else
		set_pev(Touched, pev_gravity, 0.000001)
	
	set_pev(Touched, pev_flags, pev(Touched, pev_flags) | FL_FROZEN)
	//entity_set_int(Touched, EV_INT_solid, SOLID_NOT)
	message_begin(MSG_ONE, get_user_msgid("ScreenFade"), _, Touched)
	write_short(0)
	write_short(0)
	write_short(0x0004)
	write_byte(0)
	write_byte(50)
	write_byte(200)
	write_byte(100)
	message_end()

	message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("Damage"), _, Touched)
	write_byte(0)
	write_byte(0)
	write_long(DMG_DROWN)
	write_coord(0)
	write_coord(0)
	write_coord(0)
	message_end()

	set_pev(Touched, pev_renderfx, kRenderFxGlowShell)
	set_pev(Touched, pev_rendercolor, Float:{ 0.0, 100.0, 200.0 })
	set_pev(Touched, pev_rendermode, kRenderNormal)
	set_pev(Touched, pev_renderamt, 25.0)
	set_task(FREEZETIME, "unfrozen", Touched)
	
	return FMRES_IGNORED
}

public unfrozen(Touched)
{
	if(!is_user_alive(Touched))
		return PLUGIN_CONTINUE
	
	//entity_set_int(Touched, EV_INT_solid, SOLID_SLIDEBOX)
	set_pev(Touched, pev_flags, pev(Touched, pev_flags) & ~FL_FROZEN)
	g_frozen[Touched] = false
	set_pev(Touched, pev_gravity, 1.0)
	set_pev(Touched, pev_renderfx, kRenderFxGlowShell)
	set_pev(Touched, pev_rendercolor, Float:{ 0.0, 0.0, 0.0 })
	set_pev(Touched, pev_rendermode, kRenderNormal)
	set_pev(Touched, pev_renderamt, 25.0)

	message_begin(MSG_ONE, get_user_msgid("ScreenFade"), _, Touched)
	write_short((1<<12))
	write_short(0)
	write_short(0x0000)
	write_byte(0)
	write_byte(50)
	write_byte(200)
	write_byte(100)
	message_end()
	
	emit_sound(Touched, CHAN_BODY, SoundLaunch, 1.0, ATTN_NORM, 0, PITCH_NORM)

	new origin[3]
	get_user_origin(Touched, origin)

	message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
	write_byte(TE_BREAKMODEL)
	write_coord(origin[0])
	write_coord(origin[1])
	write_coord(origin[2] + 24)
	write_coord(16)
	write_coord(16)
	write_coord(16)
	write_coord(random_num(-50, 50))
	write_coord(random_num(-50, 50))
	write_coord(25)
	write_byte(10)
	write_short(g_glassSpr)
	write_byte(10)
	write_byte(25)
	write_byte(0x01)
	message_end()
	
	return PLUGIN_CONTINUE
}

set_beamfollow(ent,life,width,Float:rgb[3],brightness)
{
	//clear_beamfollow(ent);

	message_begin(MSG_BROADCAST,SVC_TEMPENTITY);
	write_byte(TE_BEAMFOLLOW);
	write_short(ent); // entity
	write_short(trailSpr); // sprite
	write_byte(life); // life
	write_byte(width); // width
	write_byte(floatround(rgb[0])); // red
	write_byte(floatround(rgb[1])); // green
	write_byte(floatround(rgb[2])); // blue
	write_byte(brightness); // brightness
	message_end();
}

public block_message()
{
	if(ModeId != n21_dr_get_mode_id())
		return PLUGIN_CONTINUE

	if(get_msg_args() != 5 || get_msg_argtype(5) != ARG_STRING)
	{
		return PLUGIN_CONTINUE
	}

	new arg5[20]
	get_msg_arg_string(5, arg5, 19)
	if(equal(arg5, "#Fire_in_the_hole"))
	{
		return PLUGIN_HANDLED
	}

	return PLUGIN_CONTINUE
}

public block_sound(msgid, msg_dest, msg_entity)
{
	if(ModeId != n21_dr_get_mode_id())
		return PLUGIN_CONTINUE

	if(get_msg_args() != 3 || get_msg_argtype(2) != ARG_STRING)
	{
		return PLUGIN_HANDLED
	}
	
	new arg2[20]
	get_msg_arg_string(2,arg2,19)
	if(equal(arg2[1], "!MRAD_FIREINHOLE"))
	{
		return PLUGIN_HANDLED
	}
	
	return PLUGIN_CONTINUE
}

stock ham_strip_weapon(id,weapon[])
{
	if(!equal(weapon,"weapon_",7)) return 0
 
	new wId = get_weaponid(weapon)
	if(!wId) return 0
 
	new wEnt
	while((wEnt = engfunc(EngFunc_FindEntityByString,wEnt,"classname",weapon)) && pev(wEnt,pev_owner) != id) {}
	if(!wEnt) return 0
 
	if(get_user_weapon(id) == wId) ExecuteHamB(Ham_Weapon_RetireWeapon,wEnt)
 
	if(!ExecuteHamB(Ham_RemovePlayerItem,id,wEnt)) return 0
	ExecuteHamB(Ham_Item_Kill,wEnt)
 
	set_pev(id,pev_weapons,pev(id,pev_weapons) & ~(1<<wId))
     
	return 1
}
