#include <amxmodx>
#include <fakemeta>
#include <cstrike>
#include <hamsandwich>
#include <naxe_jailbreak>

new g_iForwardIndex
new g_pWeaponA[33]
new Float:cl_pushangle[33][3]

new P_MODEL[] = "models/topmasters_jb/days_mode/wet_mondey/p_water.mdl"
new V_MODEL[] = "models/topmasters_jb/days_mode/wet_mondey/v_water.mdl"

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

	precache_model("sprites/topmasters/waterstream.spr")
	precache_sound("weapons/watercannon_shoot1.wav")

	new iFile
	if((iFile = fopen(V_MODEL, "rt"))) {
		new szSoundPath[64], iNumSeq, iSeqIndex, iEvent, iNumEvents, iEventIndex

		fseek(iFile, 164, 0)
		fread(iFile, iNumSeq, 4)
		fread(iFile, iSeqIndex, 4)

		for(new k, i; i < iNumSeq; i++) {
			fseek(iFile, iSeqIndex + 48 + 176 * i, 0)
			fread(iFile, iNumEvents, 4)
			fread(iFile, iEventIndex, 4)
			fseek(iFile, iEventIndex + 176 * i, 0)

			for(k = 0; k < iNumEvents; k++) {
				fseek(iFile, iEventIndex + 4 + 76 * k, 0)
				fread(iFile, iEvent, 4)
				fseek(iFile, 4, 1)

				if(iEvent != 5004) continue

				fread_blocks(iFile, szSoundPath, 64, 1)

				if(strlen(szSoundPath)) {
					strtolower(szSoundPath)
					precache_sound(szSoundPath)
				}
			}
		}
	}
	fclose(iFile)
}

public plugin_init() {
	register_plugin("Weapon Water", "0.0.1", "Shurik07");

	register_srvcmd("jail_add_wg", "CmdAddWG")

	register_forward(FM_UpdateClientData, "UpdateClientData", 1)
	register_forward(FM_CmdStart, "CmdStart")
	register_forward(FM_Touch, "Touch")
	register_forward(FM_Think, "Think")

	RegisterHam(Ham_Item_Deploy, "weapon_m249", "DeployPost", 1)
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_m249", "PrimaryAttackPre")
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_m249", "PrimaryAttackPost", 1)
	RegisterHam(Ham_Item_PostFrame, "weapon_m249", "PostFramePre")
	RegisterHam(Ham_Weapon_Reload, "weapon_m249", "ReloadPre")
	RegisterHam(Ham_Weapon_Reload, "weapon_m249", "ReloadPost", 1)
	RegisterHam(Ham_TraceAttack, "player", "TraceAttackPre")
}

public CmdAddWG(id) {
	new int[3]; read_argv(1, int, 2)
	id = str_to_num(int)

	g_pWeaponA[id] = true
	new ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "weapon_m249"))

	if(!pev_valid(ent)) return 0

	set_pev(ent, pev_spawnflags, (1<<30))
	dllfunc(DLLFunc_Spawn, ent)

	if(!ExecuteHamB(Ham_AddPlayerItem, id, ent)) {
		if(pev_valid(ent)) set_pev(ent, pev_flags, pev(ent, pev_flags) | (1<<30))

		return 0
	}
	ExecuteHamB(Ham_Item_AttachToPlayer, ent, id)
	cs_set_weapon_ammo(ent, 100)
	cs_set_user_bpammo(id, 20, 9999)
	return 1
}

public OnRoundStartPre() {
	for(new i = 1; i <= MaxClients; i++) {
		if(!is_user_connected(i) || !g_pWeaponA[i]) continue

		g_pWeaponA[i] = false
	}
}

public OnPlayerConnected(id) g_pWeaponA[id] = false

public UpdateClientData(id, SendWeapons, CD_Handle) {
	if(!g_pWeaponA[id]) return 1

	static Float:fGametime;
	fGametime = get_gametime();

	set_cd(CD_Handle, CD_flNextAttack, fGametime + 0.001);
	return 2
}

public PlayBackEvent(flags, invoker, eventindex, Float:delay, Float:origin[3], Float:fvangles[3], Float:fparam1, Float:fparam2, iParam1, iParam2, bParam1, bParam2) return 4

public CmdStart(id, UC_Handle, SeeD) {
	if(!is_user_alive(id) || get_user_weapon(id) != 20 || !g_pWeaponA[id]) return

	static szClip, szAmmo
	get_user_weapon(id, szClip, szAmmo)

	if(!szClip) return

	static Float:i_flNextAttack; i_flNextAttack = get_pdata_float(id, 83);
	static bsButtons, i_Buttons;

	i_Buttons = get_uc(UC_Handle, UC_Buttons) 
	bsButtons = pev(id, pev_oldbuttons)

	if((i_Buttons & (1<<0)) && !(bsButtons & (1<<0))) {
		if(i_flNextAttack > 0.0) return

		set_pdata_float(id, 83, 0.3) 
		UTIL_SenwWeaponAnim(id, 1) 
	}
	else if((bsButtons & (1<<0)) && !(i_Buttons & (1<<0))) {
		set_pdata_float(id, 83, 0.0) 
		UTIL_SenwWeaponAnim(id, 3) 
	}
}

public DeployPost(ent) {
	if(pev_valid(ent) != 2) return

	static id; id = get_pdata_cbase(ent, 41, 4)

	if(!g_pWeaponA[id]) return

	set_pev(id, pev_viewmodel2, V_MODEL)
	set_pev(id, pev_weaponmodel2, P_MODEL)

	set_pdata_float(id, 83, 1.0)
	set_pdata_float(ent, 48, 1.0, 4)

	UTIL_SenwWeaponAnim(id, 5)
}

public PrimaryAttackPre(ent) {
	if(pev_valid(ent) != 2) return

	static id; id = get_pdata_cbase(ent, 41, 4)

	if(!g_pWeaponA[id] || !get_pdata_int(ent, 51, 4)) return

	UTIL_SenwWeaponAnim(id, 1) 

	pev(id, pev_punchangle, cl_pushangle[id])
	g_iForwardIndex = register_forward(FM_PlaybackEvent, "PlayBackEvent")
}

public PrimaryAttackPost(ent) {
	if(pev_valid(ent) != 2) return

	static id; id = get_pdata_cbase(ent, 41, 4)

	if(!g_pWeaponA[id] || !get_pdata_int(ent, 51, 4)) return

	emit_sound(id, 1, "weapons/watercannon_shoot1.wav", 1.0, 0.80, 0, 100)
	UTIL_SenwWeaponAnim(id, 2)

	new Float:Push[3]
	pev(id, pev_punchangle, Push)

	Push[0] = Push[0] - cl_pushangle[id][0];
	Push[1] = Push[1] - cl_pushangle[id][1];
	Push[2] = Push[2] - cl_pushangle[id][2]

	Push[0] = Push[0] * 0.001
	Push[1] = Push[1] * 0.001
	Push[2] = Push[2] * 0.001

	Push[0] = Push[0] + cl_pushangle[id][0];
	Push[1] = Push[1] + cl_pushangle[id][1];
	Push[2] = Push[2] + cl_pushangle[id][2]

	set_pev(id, pev_punchangle, Push)

	static Float:vf_Forward[3], Float:vf_vAngle[3], Float:vf_Source[3]

	UTIL_Weapon_Position(id, vf_Source, 50.0, 4.0, -4.0)

	global_get(glb_v_forward, vf_Forward)
	pev(id, pev_v_angle, vf_vAngle)

	static Float:VelocitySR[3]
	VelocitySR[0] = 500.0 * vf_Forward[0], VelocitySR[1] = 500.0 * vf_Forward[1], VelocitySR[2] = 500.0 * vf_Forward[2]
	FlameCreate(vf_Source, VelocitySR, id)

	set_pdata_float(ent, 46, 0.07, 4)
	set_pdata_float(ent, 48, 4.0, 4)

	unregister_forward(FM_PlaybackEvent, g_iForwardIndex)
}

FlameCreate(Float:origin[], Float:velocity[], id) {
	static ent;

	if((ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_sprite")))) {
		static temp[3]

		set_pev(ent, pev_origin, origin)
		set_pev(ent, pev_classname, "szWaterClass")

		set_pev(ent, pev_movetype, 5)
		set_pev(ent, pev_solid, 3)
		set_pev(ent, pev_flags, (1<<0))

		engfunc(EngFunc_VecToAngles, velocity, temp)
		set_pev(ent, pev_angles, temp)

		engfunc(EngFunc_SetModel, ent, "sprites/topmasters/waterstream.spr")
		engfunc(EngFunc_SetOrigin, ent, origin)
		engfunc(EngFunc_SetSize, ent, Float:{ 0.0, 0.0, 0.0 }, Float:{ 0.0, 0.0, 0.0 })

		set_pev(ent, pev_velocity, velocity)
		set_pev(ent, pev_rendermode, kRenderTransAdd)
		set_pev(ent, pev_gravity, 0.01)
		set_pev(ent, pev_renderamt, 255.0)
		set_pev(ent, pev_scale, 0.3)
		set_pev(ent, pev_iuser1, id)

		set_pev(ent, pev_nextthink, get_gametime() + 0.2)
	}
}

public PostFramePre(ent) {
	if(pev_valid(ent) != 2) return

	static id; id = get_pdata_cbase(ent, 41, 4)

	if(!is_user_connected(id) || !g_pWeaponA[id]) return

	static iClip; iClip = get_pdata_int(ent, 51, 4)
	static iAmmoType; iAmmoType = 376 + get_pdata_int(ent, 49, 4)
	static iBpAmmo; iBpAmmo  = get_pdata_int(id, iAmmoType)

	if(get_pdata_int(ent, 54, 4) && get_pdata_float(id, 83, 4) <= 4.0) {
		static j; j = min(100 - iClip, iBpAmmo)

		set_pdata_int(ent, 51, iClip + j, 4)
		set_pdata_int(id, iAmmoType, iBpAmmo-j)
		set_pdata_int(ent, 54, 0, 4)
	}
}

public ReloadPre(ent) {
	if(pev_valid(ent) != 2) return 1

	static id; id = get_pdata_cbase(ent, 41, 4)

	if(!is_user_connected(id) || !g_pWeaponA[id]) return 1
	if(!get_pdata_int(id, 376 + get_pdata_int(ent, 49, 4)) || get_pdata_int(ent, 51) >= 100) return 4

	return 1
}

public ReloadPost(ent) {
	if(pev_valid(ent) != 2) return 1

	static id; id = get_pdata_cbase(ent, 41, 4)

	if(!g_pWeaponA[id]) return 1
	if(!get_pdata_int(id, 376 + get_pdata_int(ent, 49, 4)) || get_pdata_int(ent, 51) >= 100) return 4

	set_pdata_float(id, 83, 4.0)
	set_pdata_float(ent, 48, 4.0, 4)

	UTIL_SenwWeaponAnim(id, 4)
	return 1
}

public TraceAttackPre(ent, attacker, Float:flDamage) {
	if(is_user_connected(attacker) && g_pWeaponA[attacker]) return 4

	return 1
}

public Touch(ent, other) {
	if(!pev_valid(ent)) return 1

	static g_classname[32]
	pev(ent, pev_classname, g_classname, 31)

	if(!equali(g_classname, "szWaterClass")) return 1

	static Float:flOrigin[3]
	pev(ent, pev_origin, flOrigin)

	set_pev(ent, pev_movetype, 0)
	set_pev(ent, pev_solid, 0)

	static victim
	victim  = -1
	while((victim = engfunc(EngFunc_FindEntityInSphere, victim, flOrigin, 35.0)) != 0) {
		if(!is_user_alive(victim) || !pev(victim, pev_takedamage)) continue

		ExecuteHamB(Ham_TakeDamage, victim, ent, pev(ent, pev_iuser1), 15.0, (1<<9))
	}
	engfunc(EngFunc_RemoveEntity, ent)
	return 1
}

public Think(ent) {
	if(!pev_valid(ent)) return 1

	static g_classname[32]
	pev(ent, pev_classname, g_classname, 31)

	if(!equali(g_classname, "szWaterClass")) return 1

	if(pev(ent, pev_waterlevel) > 1) engfunc(EngFunc_RemoveEntity, ent)

	set_pev(ent, pev_nextthink, get_gametime() + 0.017)
	static Float:fv_Frame, Float:fv_Scale

	pev(ent, pev_frame, fv_Frame)
	pev(ent, pev_scale, fv_Scale)

	if(!pev(ent, pev_movetype)) {
		fv_Frame += 0.65

		if(fv_Scale <= 1.5) fv_Scale += 0.01
		if(fv_Frame > 21.0) { 
			engfunc(EngFunc_RemoveEntity, ent)
			return 1
		}
	} else {
		fv_Frame += 0.8

		if(fv_Frame >= 21.0) set_pev(ent, pev_movetype, 0)
		if(fv_Scale <= 1.5) fv_Scale += 0.05
	}
	set_pev(ent, pev_scale, fv_Scale)
	set_pev(ent, pev_frame, fv_Frame)
	return 1
}

stock fm_find_ent_by_owner(ent, name[], owner) {
	while((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", name)) && pev(ent, pev_owner) != owner) { }
	return ent
}

stock UTIL_SenwWeaponAnim(id, seq) {
	set_pev(id, pev_weaponanim, seq)

	message_begin(8, 35, .player = id)
	write_byte(seq)
	write_byte(pev(id, pev_body))
	message_end()
}

stock UTIL_Weapon_Position(id, Float:fOrigin[], Float:add_forward, Float:add_right, Float:add_up) {
	static Float:Angles[3],Float:ViewOfs[3], Float:vAngles[3], Float:Forward[3], Float:Right[3], Float:Up[3]

	pev(id, pev_v_angle, vAngles)
	pev(id, pev_origin, fOrigin)
	pev(id, pev_view_ofs, ViewOfs)

	fOrigin[0] = fOrigin[0] + ViewOfs[0]
	fOrigin[1] = fOrigin[1] + ViewOfs[1]
	fOrigin[2] = fOrigin[2] + ViewOfs[2]

	pev(id, pev_angles, Angles)

	Angles[0] =  vAngles[0]

	engfunc(EngFunc_MakeVectors, Angles)

	global_get(glb_v_forward, Forward)
	global_get(glb_v_right, Right)
	global_get(glb_v_up, Up)

	Forward[0] = Forward[0] * add_forward
	Forward[1] = Forward[1] * add_forward
	Forward[2] = Forward[2] * add_forward

	Right[0] = Right[0] * add_right
	Right[1] = Right[1] * add_right
	Right[2] = Right[2] * add_right

	Up[0] = Up[0] * add_up
	Up[1] = Up[1] * add_up
	Up[2] = Up[2] * add_up

	fOrigin[0] = fOrigin[0] + Forward[0] + Right[0] + Up[0]
	fOrigin[1] = fOrigin[1] + Forward[1] + Right[1] + Up[1]
	fOrigin[2] = fOrigin[2] + Forward[2] + Right[2] + Up[2]
}