/* Biohazard mod
*   
*  by Cheap_Suit
*
*  This program is free software; you can redistribute it and/or modify it
*  under the terms of the GNU General Public License as published by the
*  Free Software Foundation; either version 2 of the License, or (at
*  your option) any later version.
*
*  This program is distributed in the hope that it will be useful, but
*  WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
*  General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program; if not, write to the Free Software Foundation,
*  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*  In addition, as a special exception, the author gives permission to
*  link the code of this program with the Half-Life Game Engine ("HL
*  Engine") and Modified Game Libraries ("MODs") developed by Valve,
*  L.L.C ("Valve"). You must obey the GNU General Public License in all
*  respects for all of the code used other than the HL Engine and MODs
*  from Valve. If you modify this file, you may extend this exception
*  to your version of the file, but you are not obligated to do so. If
*  you do not wish to do so, delete this exception statement from your
*  version.
*/	

/*Version 1.95
* - Removed roundstart sound.
* - Removed spawn backpack removal.
* - Removed unnecessary codes.
* - Changed armor detection.
*/

#define VERSION	"1.95"

#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
#include <cstrike>
#include <hamsandwich>
#include <xs>
#tryinclude "biohazard.cfg"

#if AMXX_VERSION_NUM < 180
	#assert AMX Mod X v1.8.0 or greater library required!
#elseif !defined _biohazardcfg_included
	#assert Biohazard configuration file required!
#endif

#define OFFSET_DEATH	 	444
#define OFFSET_TEAM 		114
#define OFFSET_ARMOR 		112
#define OFFSET_NVG 		129
#define OFFSET_PRIMARYWEAPON 	116
#define OFFSET_CLIPAMMO 	51
#define OFFSET_CLIPAMMO_LINUX 	4

#define OFFSET_AMMO_AWP 	377
#define OFFSET_AMMO_SCOUT 	378
#define OFFSET_AMMO_M249 	379
#define OFFSET_AMMO_FAMAS 	380
#define OFFSET_AMMO_M3 		381
#define OFFSET_AMMO_USP 	382
#define OFFSET_AMMO_FIVESEVEN 	383
#define OFFSET_AMMO_DEAGLE 	384
#define OFFSET_AMMO_P228 	385
#define OFFSET_AMMO_GLOCK18 	386

#define AMMOID_FLASHBANG 	11
#define AMMOID_HEGRENADE 	12
#define AMMOID_SGGRENADE 	13
#define AMMOID_C4		14

#define TASKID_STRIPNGIVE	698
#define TASKID_STARTROUND 	153
#define TASKID_NEWROUND		641
#define TASKID_BALANCETEAM 	375
#define TASKID_UPDATESCR	264
#define TASKID_SETZOMBIE	635
#define TASKID_SPAWNDELAY	786
#define TASKID_GIVENADES	922

#define EQUIP_PRI		(1<<0)
#define EQUIP_SEC		(1<<1)
#define EQUIP_GREN		(1<<2)
#define EQUIP_ALL		(1<<0 | 1<<1 | 1<<2)

#define HAS_NVG 		(1<<0)
#define ATTRIB_BOMB 		(1<<1)
#define DMG_HEGRENADE 		(1<<24)
#define AMMOID_NULL 		(1<<0 | 1<<AMMOID_FLASHBANG | 1<<AMMOID_HEGRENADE | 1<<AMMOID_SGGRENADE | 1<<AMMOID_C4)
#define AMMOWP_NULL 		(1<<0 | 1<<CSW_KNIFE | 1<<CSW_FLASHBANG | 1<<CSW_HEGRENADE | 1<<CSW_SMOKEGRENADE | 1<<CSW_C4)

#define MAX_SPAWNS		128
#define MAX_AMMO		200
#define IMPULSE_FLASHLIGHT	100
#define MODEL_CLASSNAME		"player_model"

#define reset_user_primary(%1)   set_pdata_int(%1, OFFSET_PRIMARYWEAPON, 0)
#define set_weapon_ammo(%1,%2)   set_pdata_int(%1, OFFSET_CLIPAMMO, %2, OFFSET_CLIPAMMO_LINUX)
#define set_user_deaths(%1,%2)   set_pdata_int(%1, OFFSET_DEATH, %2)
#define is_player_alive(%1)      ((1 <= %1 <= g_maxplayers) && is_user_alive(%1))
#define _random(%1) 		 random_num(0, %1 - 1)

new cvar_regen_dly1, cvar_regen_dly2, cvar_randomspawn, cvar_zombie_spd, cvar_skyname, cvar_autobalance[2], cvar_starttime, 
    cvar_lights, cvar_zombie_def, cvar_zombie_hp, cvar_blocknightvision, cvar_killbonus, cvar_gamedescription, cvar_enabled, 
    cvar_autonvg, cvar_maxzombies, cvar_customsounds, cvar_hpbonus, cvar_knockback_hp, cvar_flashbang, cvar_weaponsmenu,
    cvar_zombie_atk, cvar_knockback_duck, cvar_hedmg_multi, cvar_zombie_regen, cvar_zombie_resist, cvar_buytime, cvar_ammo,
    cvar_zombie_instant, cvar_winsounds, cvar_botquota
	
new bool:g_brestorevel, Float:g_vecvel[3], bool:g_roundstarted, g_maxplayers, g_spawncount, bool:g_infecting, bool:g_gamestarted, 
    Float:g_spawns[MAX_SPAWNS+1][9], g_zombieoftheround, g_fwd_spawn, bool:g_usingknifemodel, bool:g_usingplayermodel, g_equipmenu, 
    g_primmenu, g_secmenu, g_fwd_result, g_fwd_infect, g_fwd_teamwin, g_fwd_gamestart, g_fwd_infect2, CsTeams:g_winningteam,
    bool:g_czero, g_netclient_pdata, g_botclient_pdata, g_buyzone, Float:g_buytime

new bool:g_zombie[33], Float:g_regendelay[33], g_victim[33], bool:g_showmenu[33], g_weapons[33][2], bool:g_falling[33], g_lastteam[33],
    g_modelent[33], g_weaponent[33]

public plugin_precache()
{
	register_plugin("Biohazard", VERSION, "cheap_suit")
	register_cvar("bh_version", VERSION, FCVAR_SPONLY|FCVAR_SERVER)
	set_cvar_string("bh_version", VERSION)
	
	cvar_enabled = register_cvar("bh_enabled", "1")
	if(!get_pcvar_num(cvar_enabled)) return
	
	g_usingplayermodel = (strlen(g_zombie_model) > 0) ? true : false
	g_usingknifemodel  = (strlen(g_zombie_claws) > 0) ? true : false
	if(g_usingplayermodel) precache_model(g_zombie_model)
	if(g_usingknifemodel)  precache_model(g_zombie_claws)
	
	new i
	for(i = 0; i < sizeof g_zombie_miss_sounds; i++) precache_sound(g_zombie_miss_sounds[i])
	for(i = 0; i < sizeof g_zombie_hit_sounds;  i++) precache_sound(g_zombie_hit_sounds[i])
	for(i = 0; i < sizeof g_scream_sounds;	    i++) precache_sound(g_scream_sounds[i])
	for(i = 0; i < sizeof g_zombie_die_sounds;  i++) precache_sound(g_zombie_die_sounds[i])
	for(i = 0; i < sizeof g_zombie_win_sounds;  i++) precache_sound(g_zombie_win_sounds[i])
	
	g_fwd_spawn = register_forward(FM_Spawn, "fwd_spawn")
	new zone = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_bomb_target"))
	if(zone) dllfunc(DLLFunc_Spawn, zone), set_pev(zone, pev_solid, SOLID_NOT)
	
	g_buyzone = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "func_buyzone"))
	if(g_buyzone) dllfunc(DLLFunc_Spawn, g_buyzone), set_pev(g_buyzone, pev_solid, SOLID_NOT)
	
	#if FOG_ENABLE
	new fog = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_fog"))
	if(fog)
	{
		new DENSITY[10]
		formatex(DENSITY, 9, "0.00%d", clamp(FOG_DENSITY, 1, 99))
		
		fm_set_kvd(fog, "density", DENSITY, "env_fog")
		fm_set_kvd(fog, "rendercolor", FOG_COLOR, "env_fog")
	}
	#endif
}

public plugin_init()
{
	if(!get_pcvar_num(cvar_enabled)) return
	
	cvar_gamedescription  = register_cvar("bh_gamedescription",   "Biohazard")
	cvar_skyname	      = register_cvar("bh_skyname", 	      "night")
	cvar_lights	      = register_cvar("bh_lights",	      "d")
	cvar_blocknightvision = register_cvar("bh_block_nvg",	      "1")
	cvar_starttime	      = register_cvar("bh_starttime", 	      "10.0")
	cvar_randomspawn      = register_cvar("bh_randomspawn",       "1")
	cvar_customsounds     = register_cvar("bh_customsounds",      "1")
	cvar_winsounds	      = register_cvar("bh_winsounds", 	      "1")
	cvar_autonvg	      = register_cvar("bh_autonvg",	      "1")
	cvar_killbonus	      = register_cvar("bh_zombie_kill_bonus", "2")
	cvar_buytime          = register_cvar("bh_buytime",           "0")
	cvar_weaponsmenu      = register_cvar("bh_weaponsmenu",       "0")
	cvar_ammo             = register_cvar("bh_ammo", 	      "1")
	cvar_hedmg_multi      = register_cvar("bh_hedmg_multi",       "1.0")
	cvar_maxzombies       = register_cvar("bh_maxzombies", 	      "25")
	cvar_flashbang 	      = register_cvar("bh_flashbang", 	      "1")
	cvar_zombie_instant   = register_cvar("bh_zombie_instant",    "1")
	cvar_zombie_hp	      = register_cvar("bh_zombie_hp", 	      "135")
	cvar_knockback_hp     = register_cvar("bh_zombie_kb_hp",      "90")
	cvar_knockback_duck   = register_cvar("bh_zombie_kb_duck",    "1")
	cvar_hpbonus          = register_cvar("bh_zombie_hp_bonus",   "65")
	cvar_zombie_resist    = register_cvar("bh_zombie_resist",     "1")
	cvar_zombie_spd       = register_cvar("bh_zombie_speed",      "280.0")
	cvar_zombie_atk       = register_cvar("bh_zombie_atk_multi",  "2.0")
	cvar_zombie_def       = register_cvar("bh_zombie_def_multi",  "0.087")
	cvar_zombie_regen     = register_cvar("bh_zombie_regen",      "1")
	cvar_regen_dly1       = register_cvar("bh_zombie_regendly1",  "2.0")
	cvar_regen_dly2       = register_cvar("bh_zombie_regendly2",  "0.25")
	cvar_botquota	      = get_cvar_pointer("bot_quota")
	cvar_autobalance[0]   = get_cvar_pointer("mp_autoteambalance")
	cvar_autobalance[1]   = get_pcvar_num(cvar_autobalance[0])
	set_pcvar_num(cvar_autobalance[0], 0)

	register_clcmd("nightvision", "cmd_nightvision")
	register_clcmd("chooseteam",  "cmd_chooseteam")
	register_clcmd("say guns",    "cmd_enablemenu")
	register_clcmd("say /guns",   "cmd_enablemenu")
	register_clcmd("amx_infect",  "cmd_infectuser", ADMIN_BAN, "<name or #userid>")

	RegisterHam(Ham_Use,	     	     "func_tank",       "bacon_use")
	RegisterHam(Ham_Use,	     	     "func_tankmortar", "bacon_use")
	RegisterHam(Ham_Use,	     	     "func_tankrocket", "bacon_use")
	RegisterHam(Ham_Use,	     	     "func_tanklaser",  "bacon_use")
	RegisterHam(Ham_Touch,	    	     "weaponbox",       "bacon_touch_weapon")
	RegisterHam(Ham_Touch,	  	     "armoury_entity",  "bacon_touch_weapon")
	RegisterHam(Ham_Touch,	  	     "weapon_shield",   "bacon_touch_weapon")
	RegisterHam(Ham_Item_Deploy, 	     "weapon_knife",    "bacon_item_deploy_post", 	  1)
	RegisterHam(Ham_Item_AttachToPlayer, "weapon_knife", 	"bacon_item_attachtoplayer_post", 1)

	unregister_forward(FM_Spawn, 		g_fwd_spawn)
	register_forward(FM_PlayerPreThink,	"fwd_playerprethink")
	register_forward(FM_PlayerPostThink,	"fwd_playerpostthink")
	register_forward(FM_CmdStart,		"fwd_cmdstart")
	register_forward(FM_EmitSound,		"fwd_emitsound")
	register_forward(FM_GetGameDescription, "fwd_gamedescription")
	register_forward(FM_CreateNamedEntity,	"fwd_createnamedentity")
	register_forward(FM_Sys_Error,		"fwd_sys_error")
	register_forward(FM_PlayerPreThink,	"fwd_playerprethink_post", 1)
	register_forward(FM_TraceLine,		"fwd_traceline_post", 	   1)
	register_forward(FM_TraceHull, 		"fwd_tracehull_post", 	   1)

	register_message(get_user_msgid("AmmoX"), 	"msg_ammox")
	register_message(get_user_msgid("CurWeapon"), 	"msg_curweapon")
	register_message(get_user_msgid("TextMsg"), 	"msg_textmsg")
	register_message(get_user_msgid("SendAudio"), 	"msg_sendaudio")
	register_message(get_user_msgid("StatusIcon"), 	"msg_statusicon")
	register_message(get_user_msgid("ScoreAttrib"), "msg_scoreattrib")
	register_message(get_user_msgid("DeathMsg"), 	"msg_deathmsg")
	register_message(get_user_msgid("ScreenFade"), 	"msg_screenfade")
	register_message(get_user_msgid("TeamInfo"), 	"msg_teaminfo")
	register_message(get_user_msgid("ClCorpse"), 	"msg_clcorpse")
	
	register_event("TextMsg",   "event_textmsg",   "a",  "2=#Game_will_restart_in")
	register_event("HLTV",      "event_newround",  "a",  "1=0", "2=0")
	register_event("Damage",    "event_damage",    "be")
	register_event("Battery",   "event_battery",   "be")

	register_logevent("logevent_round_start", 2, "1=Round_Start")
	register_logevent("logevent_round_end",   2, "1=Round_End")
	
	g_fwd_infect 	= CreateMultiForward("event_infect", 	ET_CONTINUE, FP_CELL, FP_CELL)
	g_fwd_infect2 	= CreateMultiForward("event_infect2", 	ET_CONTINUE, FP_CELL)
	g_fwd_teamwin 	= CreateMultiForward("event_teamwin", 	ET_CONTINUE, FP_CELL)
	g_fwd_gamestart = CreateMultiForward("event_gamestart", ET_CONTINUE)
	g_maxplayers 	= get_maxplayers()
	
	register_dictionary("biohazard.txt")
	build_menu(), get_spawnpoints()

	new modname[7]; get_modname(modname, 6)
	g_czero = equal(modname,"czero") ? true : false
}

public pdata_init(id)
{
	RegisterHamFromEntity(Ham_TakeDamage, id, "bacon_takedamage")
	RegisterHamFromEntity(Ham_Spawn,      id, "bacon_spawn_post", 1)
}

public build_menu()
{
	new title[32]
	formatex(title, 31, "%L", LANG_SERVER, "MENU_TITLE1")
	g_equipmenu = menu_create(title, "menu_equip", 0)
		
	formatex(title, 31, "%L", LANG_SERVER, "MENU_TITLE2")
	g_primmenu  = menu_create(title,    "menu_prim", 0)
	
	formatex(title, 31, "%L", LANG_SERVER, "MENU_TITLE3")
	g_secmenu   = menu_create(title,  "menu_sec",  0)

	new name[32]
	formatex(name, 31, "%L", LANG_SERVER, "MENU_NEWWEAPONS")
	menu_additem(g_equipmenu, name, "1", 0, -1)
	
	formatex(name, 31, "%L", LANG_SERVER, "MENU_PREVSETUP")
	menu_additem(g_equipmenu, name, "2", 0, -1)
	
	formatex(name, 31, "%L", LANG_SERVER, "MENU_DONTSHOW")
	menu_additem(g_equipmenu, name, "3", 0, -1)
	
	static i, num[3]
	for(i = 1; i < sizeof g_primmenunames; i++)
	{
		formatex(num, 2, "%d", i)
		menu_additem(g_primmenu, g_primmenunames[i], num, 0, -1)
	}
	
	for(i = 1; i < sizeof g_secmenunames; i++)
	{
		formatex(num, 2, "%d", i)
		menu_additem(g_secmenu, g_secmenunames[i], num, 0, -1)
	}
	return PLUGIN_HANDLED
}

public plugin_cfg()
{
	new file[64]; get_configsdir(file, 63)
	format(file, 63, "%s/bh_cvars.cfg", file)
	if(file_exists(file)) server_cmd("exec %s", file), server_exec()
	
	new light[2]
	get_pcvar_string(cvar_lights, light, 1)
	
	if(strlen(light) > 0)
	{
		set_task(1.0, "task_lights", _, _, _, "b")
		
		set_cvar_num("sv_skycolor_r", 0)
		set_cvar_num("sv_skycolor_g", 0)
		set_cvar_num("sv_skycolor_b", 0)
	}
		
	new skyname[32]
	get_pcvar_string(cvar_skyname, skyname, 31)
		
	if(strlen(skyname) > 0)
		set_cvar_string("sv_skyname", skyname)
}

public plugin_end()
	set_pcvar_num(cvar_autobalance[0], cvar_autobalance[1]), destroyforwards()

public destroyforwards()
{
	DestroyForward(g_fwd_infect),  DestroyForward(g_fwd_infect2)
	DestroyForward(g_fwd_teamwin), DestroyForward(g_fwd_gamestart)
}

public plugin_natives()
{
	register_library("biohazardf")
	register_native("is_game_started",     "native_game_started")
	register_native("is_user_zombie",      "native_is_user_zombie")
	register_native("is_user_firstzombie", "native_is_user_firstzombie")
	register_native("infect_user",         "native_infect_user")
	register_native("firstzombie",         "native_first_zombie")
}

public client_connect(id)
{
	g_lastteam[id] = -1, remove_model(g_modelent[id])
	g_showmenu[id] = true, clear_clientdata(id)
}

public client_putinserver(id)
{
	if(!g_netclient_pdata) set_task(1.0, "task_netclient_pdata", id)
	if(g_czero && !g_botclient_pdata) set_task(1.0, "task_botclient_pdata", id)
}

public client_disconnect(id)
{
	remove_task(TASKID_SETZOMBIE + id), remove_task(TASKID_STRIPNGIVE + id)
	remove_task(TASKID_UPDATESCR + id), remove_task(TASKID_SPAWNDELAY + id)
	remove_task(TASKID_GIVENADES + id), remove_model(g_modelent[id])
}

public clear_clientdata(id)
{
	g_victim[id] = 0, g_regendelay[id] = 0.0
	g_lastteam[id] = 0, g_weaponent[id] = 0
	g_zombie[id] = false, g_falling[id] = false
}

public remove_model(ent)
{
	static id; id = pev(ent, pev_owner)
	if(pev_valid(ent)) engfunc(EngFunc_RemoveEntity, ent)
	g_modelent[id] = 0
}

public cmd_enablemenu(id)
{	
	if(!get_pcvar_num(cvar_weaponsmenu))
		return PLUGIN_CONTINUE
	
	client_print(id, print_chat, "%L", id, g_showmenu[id] == false ? "MENU_REENABLED" : "MENU_ALENABLED")
	g_showmenu[id] = true

	return PLUGIN_HANDLED_MAIN
}

public cmd_nightvision(id)
	return (!g_zombie[id] && get_pcvar_num(cvar_blocknightvision)) ? PLUGIN_HANDLED : PLUGIN_CONTINUE

public cmd_chooseteam(id)
	return g_zombie[id] ? PLUGIN_HANDLED : PLUGIN_CONTINUE

public cmd_infectuser(id, level, cid)
{
	if(!cmd_access(id, level, cid, 2))
		return PLUGIN_HANDLED_MAIN
	
	static arg1[32], target
	read_argv(1, arg1, 31)
	
	target = cmd_target(id, arg1, 0)
	if(!is_user_alive(target))
	{
		console_print(id, "%L", id, "CMD_INVALIDUSER")
		return PLUGIN_HANDLED_MAIN
	}
	
	if(!allow_infection())
	{
		console_print(id, "%L", id, "CMD_MAXZOMBIES")
		return PLUGIN_HANDLED_MAIN
	}
	
	if(!g_gamestarted)
	{
		console_print(id, "%L", id, "CMD_NOTSTARTED")
		return PLUGIN_HANDLED_MAIN
	}
	
	if(!g_zombie[target])
	{
		infect_user(target)
		
		static name[32]; get_user_name(target, name, 31)
		console_print(id, "%L", id, "CMD_INFECTED", name)
	}
	return PLUGIN_HANDLED_MAIN
}

public msg_teaminfo(msgid, dest, id)
{
	if(!g_gamestarted)
		return PLUGIN_CONTINUE
	
	static team[4]; get_msg_arg_string(2, team, 3)
	if(team[0] != 'U' || team[1] != 'N' || team[2] != 'A')
		return PLUGIN_CONTINUE

	id = get_msg_arg_int(1)
	if(is_user_alive(id) || g_lastteam[id] == -1)
		return PLUGIN_CONTINUE
	
	id = randomly_pick_zombie()
	if(id)
	{
		if(!g_zombie[id])
		{
			infect_user(id)
			
			static name[32]
			get_user_name(id, name, 31)

			set_hudmessage(_, _, _, _, _, 1)
			show_hudmessage(0, "%L", LANG_PLAYER, "INFECTED_HUD", name)
		}
		else
		{
			cs_set_user_team2(id, CS_TEAM_CT)
			set_pev(id, pev_deadflag, DEAD_DISCARDBODY)
		}
		return PLUGIN_HANDLED
	}
	return PLUGIN_CONTINUE
}

public msg_screenfade(msgid, dest, id)
{
	if(!get_pcvar_num(cvar_flashbang) || !is_user_connected(id))
		return PLUGIN_CONTINUE
	
	if(!g_zombie[id] || !is_user_alive(id))
	{
		static data[4]
		data[0] = get_msg_arg_int(4); data[1] = get_msg_arg_int(5)
		data[2] = get_msg_arg_int(6); data[3] = get_msg_arg_int(7)
		
		if(data[0] == 255 && data[1] == 255 && data[2] == 255 && data[3] > 199)
			return PLUGIN_HANDLED
	}
	return PLUGIN_CONTINUE
}

public msg_scoreattrib(msgid, dest, id)
{
	static attrib; attrib = get_msg_arg_int(2)
	if(attrib == ATTRIB_BOMB)
		set_msg_arg_int(2, ARG_BYTE, 0)
}

public msg_deathmsg(msgid, dest, id) 
{
	static killer; killer = get_msg_arg_int(1)
	static victim; victim = get_msg_arg_int(2)
	if(!is_user_connected(killer))
		return PLUGIN_CONTINUE
	
	if(g_zombie[killer]) 
		set_msg_arg_string(4, g_zombie_weapname)

	else if(g_zombie[victim])
		set_pev(killer, pev_frags, pev(killer, pev_frags) + float(get_pcvar_num(cvar_killbonus)))

	return PLUGIN_CONTINUE
}

public msg_statusicon(msgid, dest, id)
{
	if(!is_user_connected(id))
		return PLUGIN_CONTINUE
	
	static icon[8]; get_msg_arg_string(2, icon, 7)
	if(icon[0] == 'c' && icon[1] == '4' || equal(icon, "defuser"))
		return PLUGIN_HANDLED
	
	return PLUGIN_CONTINUE
}

public msg_sendaudio(msgid, dest, id)
{
	static audiocode [22]; get_msg_arg_string(2, audiocode, 21)
	if(equal(audiocode[7], "terwin") && get_pcvar_num(cvar_winsounds))
		set_msg_arg_string(2, g_zombie_win_sounds[_random(sizeof g_zombie_win_sounds)])
	
	return PLUGIN_CONTINUE
}

public msg_textmsg(msgid, dest, id)
{
	if(get_msg_arg_int(1) != 4)
		return PLUGIN_CONTINUE
	
	static txtmsg[25], winmsg[32]
	get_msg_arg_string(2, txtmsg, 24)
	
	if(equal(txtmsg[1], "Game_bomb_drop"))
		return PLUGIN_HANDLED

	else if(equal(txtmsg[1], "Terrorists_Win"))
	{
		formatex(winmsg, 31, "%L", LANG_SERVER, "WIN_ZOMBIES")
		set_msg_arg_string(2, winmsg)
		
		g_winningteam = CS_TEAM_T
	}
	else if(equal(txtmsg[1], "Target_Saved") || equal(txtmsg[1], "CTs_Win"))
	{
		formatex(winmsg, 31, "%L", LANG_SERVER, "WIN_SURVIVORS")
		set_msg_arg_string(2, winmsg)
		
		g_winningteam = CS_TEAM_CT
	}
	return PLUGIN_CONTINUE
}

public msg_ammox(msgid, dest, id)
{
	static ammotype; ammotype = get_pcvar_num(cvar_ammo)
	if(!is_user_alive(id) || g_zombie[id] || ammotype != 1)
		return PLUGIN_CONTINUE
	
	static ammoid; ammoid = get_msg_arg_int(1)
	static bammo; bammo = get_msg_arg_int(2)
	
	if(!(AMMOID_NULL & (1<<ammoid)) && bammo != MAX_AMMO)
		set_msg_arg_int(2, ARG_BYTE, MAX_AMMO)

	return PLUGIN_CONTINUE
}

public msg_curweapon(msgid, dest, id)
{
	if(!is_user_alive(id) || !get_msg_arg_int(1))
		return PLUGIN_CONTINUE
	
	static weapon; weapon = get_msg_arg_int(2)
	if(g_zombie[id])
	{
		if(weapon != CSW_KNIFE && !task_exists(TASKID_STRIPNGIVE + id))
			set_task(0.2, "task_stripngive", TASKID_STRIPNGIVE + id)
		
		return PLUGIN_CONTINUE
	}
	else if(AMMOWP_NULL & (1<<weapon)) return PLUGIN_CONTINUE

	static ammotype; ammotype = get_pcvar_num(cvar_ammo)
	if(!ammotype) return PLUGIN_CONTINUE
	
	static max_clip; max_clip = get_weapon_maxclip(weapon)
	switch(ammotype)
	{
		case 1:
		{
			static ammo; ammo = get_user_bpammo(id, weapon)
			if(ammo < max_clip) set_user_bpammo(id, weapon, MAX_AMMO)
		}
		case 2:
		{
			static clip; clip = get_msg_arg_int(3)
			if(clip != max_clip) set_msg_arg_int(3, ARG_BYTE, max_clip)
			
			if(!pev_valid(g_weaponent[id]) || (pev_valid(g_weaponent[id])
			&& cs_get_weapon_id(g_weaponent[id]) != weapon))
			{
				static weaponname[32]; get_weaponname(weapon, weaponname, 31)
				g_weaponent[id] = fm_find_ent_by_owner(-1, weaponname, id)
			}
			
			if(clip < 1 && pev_valid(g_weaponent[id]))
				set_weapon_ammo(g_weaponent[id], max_clip)
		}
	}
	return PLUGIN_CONTINUE
}

public msg_clcorpse(msgid, dest, id)
{
	id = get_msg_arg_int(12)
	if(!g_zombie[id])
		return PLUGIN_CONTINUE

	static ent; ent = fm_find_ent_by_owner(-1, MODEL_CLASSNAME, id)
	if(pev_valid(ent))
	{
		static model[64]
		pev(ent, pev_model, model, 63)
		set_msg_arg_string(1, model)
	}
	return PLUGIN_CONTINUE
}

public logevent_round_start()
{
	g_roundstarted = true
	if(get_pcvar_num(cvar_weaponsmenu))
	{
		static id, CsTeams:team
		for(id = 1; id <= g_maxplayers; id++) if(is_user_alive(id))
		{
			team = cs_get_user_team(id)
			if(team == CS_TEAM_T || team == CS_TEAM_CT)
				g_showmenu[id] == true ? menu_display(id, g_equipmenu, 0) : equipweapon(id, EQUIP_ALL)
		}
	}
}

public logevent_round_end()
{
	g_gamestarted = false, g_roundstarted = false
	remove_task(TASKID_BALANCETEAM), remove_task(TASKID_STARTROUND)

	set_task(1.5, "task_balanceteam", TASKID_BALANCETEAM)
	
	if(g_winningteam > CS_TEAM_UNASSIGNED)
	{
		static _msg_screenfade, color[][] = { {}, { 0, 0, 0 }, { 254, 254, 254 } }
		if(!_msg_screenfade) _msg_screenfade = get_user_msgid("ScreenFade")
		
		message_begin(MSG_ALL, _msg_screenfade)
		write_short((1<<12) * 1)
		write_short((1<<12) * 5)
		write_short(1)
		write_byte(color[_:g_winningteam][0])
		write_byte(color[_:g_winningteam][1])
		write_byte(color[_:g_winningteam][2])
		write_byte(255)
		message_end()

		ExecuteForward(g_fwd_teamwin, g_fwd_result, g_winningteam)
		g_winningteam = CS_TEAM_UNASSIGNED
	}
}

public event_textmsg()
{
	static seconds[5]; read_data(3, seconds, 4)
	static Float:tasktime; tasktime = float(str_to_num(seconds)) - 0.5
	remove_task(TASKID_BALANCETEAM), set_task(tasktime, "task_balanceteam", TASKID_BALANCETEAM)
}

public event_newround()
{
	static buytime; buytime = get_pcvar_num(cvar_buytime)
	if(buytime) g_buytime = buytime + get_gametime()
	
	g_gamestarted = false, g_roundstarted = false
	remove_task(TASKID_NEWROUND), remove_task(TASKID_STARTROUND)
	
	set_task(0.1, "task_newround", TASKID_NEWROUND)
	set_task(get_pcvar_float(cvar_starttime), "task_startround", TASKID_STARTROUND)
}

public event_battery(id)
{
	static armor; armor = read_data(1)
	if(armor > 0)
	{
		if(!is_user_alive(id) || !g_zombie[id])
			return PLUGIN_CONTINUE
		
		static CsArmorType:armortype
		cs_get_user_armor2(id, armortype)
		
		if(armortype != CS_ARMOR_NONE)
			cs_set_user_armor2(id, 0, CS_ARMOR_NONE)
	}
	return PLUGIN_CONTINUE
}

public event_damage(victim)
{
	if(!is_user_alive(victim) || !g_gamestarted)
		return PLUGIN_CONTINUE
	
	if(g_zombie[victim])
	{
		g_regendelay[victim] = get_gametime() + get_pcvar_float(cvar_regen_dly1)
		return PLUGIN_CONTINUE
	}
	
	static attacker; attacker = get_user_attacker(victim)
	if(!is_user_alive(attacker) || !g_zombie[attacker] || g_infecting)
		return PLUGIN_CONTINUE
	
	g_infecting = true
	if(g_victim[attacker] == victim)
	{
		static Float:frags; pev(attacker, pev_frags, frags)
		static deaths; deaths = cs_get_user_deaths(victim)
		set_pev(attacker, pev_frags, frags  + 1.0)
		set_user_deaths(victim, deaths + 1)
					
		static _msg_deathmsg
		if(!_msg_deathmsg) _msg_deathmsg = get_user_msgid("DeathMsg")
		
		message_begin(MSG_BROADCAST, _msg_deathmsg)
		write_byte(attacker)
		write_byte(victim)
		write_byte(0)
		write_string("infection")
		message_end()
					
		infect_user(victim)
		ExecuteForward(g_fwd_infect, g_fwd_result, attacker, victim)

		static params[2]; params[0] = attacker, params[1] = victim
		set_task(0.2, "task_updatescore", TASKID_UPDATESCR, params, 2)
		
		g_victim[attacker] = 0
	}
	g_infecting = false
	
	return PLUGIN_CONTINUE
}

public fwd_emitsound(id, channel, sample[], Float:volume, Float:attn, flag, pitch)
{	
	if(sample[6] == 'n' && sample[7] == 'v' && sample[8] == 'g')
		return FMRES_SUPERCEDE
	
	if(!is_user_connected(id) || !g_zombie[id])
		return FMRES_IGNORED
	
	if(sample[8] == 'k' && sample[9] == 'n' && sample[10] == 'i' && get_pcvar_num(cvar_customsounds))
	{
		if(sample[14] == 's' && sample[15] == 'l' && sample[16] == 'a')
		{
			emit_sound(id, channel, g_zombie_miss_sounds[_random(sizeof g_zombie_miss_sounds)], volume, attn, flag, pitch)
			return FMRES_SUPERCEDE
		}
		else if(sample[14] == 'h' && sample[15] == 'i' && sample[16] == 't' || sample[14] == 's' && sample[15] == 't' && sample[16] == 'a')
		{
			if(sample[17] == 'w' && sample[18] == 'a' && sample[19] == 'l')
				emit_sound(id, channel, g_zombie_miss_sounds[_random(sizeof g_zombie_miss_sounds)], volume, attn, flag, pitch)
			else
				emit_sound(id, channel, g_zombie_hit_sounds[_random(sizeof g_zombie_hit_sounds)], volume, attn, flag, pitch)
			
			return FMRES_SUPERCEDE
		}
	}			
	else if(sample[7] == 'd' && (sample[8] == 'i' && sample[9] == 'e' || sample[12] == '6'))
	{
		emit_sound(id, channel, g_zombie_die_sounds[_random(sizeof g_zombie_die_sounds)], volume, attn, flag, pitch)
		return FMRES_SUPERCEDE
	}
	return FMRES_IGNORED
}

public fwd_cmdstart(id, handle, seed)
{
	if(!is_user_alive(id) || !g_zombie[id])
		return FMRES_IGNORED
	
	static impulse; impulse = get_uc(handle, UC_Impulse)
	if(impulse == IMPULSE_FLASHLIGHT)
	{
		set_uc(handle, UC_Impulse, 0)
		return FMRES_SUPERCEDE
	}
	return FMRES_IGNORED
}

public fwd_playerprethink(id)
{
	if(!is_user_alive(id))
		return FMRES_IGNORED
	
	static flag; flag = pev(id, pev_flags)
	if(get_pcvar_num(cvar_zombie_resist))
	{
		if(flag & FL_ONGROUND)
		{
			pev(id, pev_velocity, g_vecvel)
			g_brestorevel = true
		}
	}

	if(g_zombie[id])
	{
		if(!(flag & FL_ONGROUND))
		{
			static Float:fallvelocity; pev(id, pev_flFallVelocity, fallvelocity)
			g_falling[id] = fallvelocity >= 350.0 ? true : false
		}
		
		if(get_pcvar_num(cvar_zombie_regen))
		{
			static Float:health; pev(id, pev_health, health)
			static Float:zombiehp; zombiehp = float(get_pcvar_num(cvar_zombie_hp))
			if(health < zombiehp)
			{
				static Float:gametime; gametime = get_gametime()
				if(g_regendelay[id] < gametime)
				{
					set_pev(id, pev_health, health + 1.0)
					g_regendelay[id] = gametime + get_pcvar_float(cvar_regen_dly2)
				}
			}
		}
		
		static ent; ent = g_modelent[id]
		if(pev_valid(ent))
		{
			if(!(pev(ent, pev_effects) & EF_NODRAW))
			{
				if(pev(id, pev_rendermode) != kRenderTransTexture)
					set_pev(id, pev_rendermode, kRenderTransTexture)
				
				if(pev(id, pev_renderamt) != 0.0)
					set_pev(id, pev_renderamt, 0.0)
			}
		}
	}
	return FMRES_IGNORED
}

public fwd_playerprethink_post(id)
{
	if(!g_brestorevel)
		return FMRES_IGNORED

	g_brestorevel = false
		
	static flag; flag = pev(id, pev_flags)
	if(!(flag & FL_ONTRAIN))
	{
		static ent; ent = pev(id, pev_groundentity)
		if(pev_valid(ent) && (flag & FL_CONVEYOR))
		{
			static Float:vectemp[3]
			pev(id, pev_basevelocity, vectemp)
			xs_vec_add(g_vecvel, vectemp, g_vecvel)
		}
			
		if(g_zombie[id]) 
		{
			static Float:health; pev(id, pev_health, health)
			static Float:kbhp; kbhp = float(get_pcvar_num(cvar_knockback_hp))
			if(get_pcvar_num(cvar_knockback_duck))
			{
				if(pev(id, pev_flags) & FL_DUCKING)
					set_pev(id, pev_velocity, g_vecvel)
				else if(health > kbhp) 
					set_pev(id, pev_velocity, g_vecvel)
			}
			else if(health > kbhp) set_pev(id, pev_velocity, g_vecvel)
		}
		return FMRES_HANDLED
	}
	return FMRES_IGNORED
}

public fwd_playerpostthink(id)
{ 
	if(!is_user_alive(id)) 
		return FMRES_IGNORED
	
	if(g_falling[id] && pev(id, pev_flags) & FL_ONGROUND)
		set_pev(id, pev_watertype, CONTENTS_WATER), g_falling[id] = false
	
	if(get_pcvar_num(cvar_buytime))
	{
		if(g_buytime > get_gametime() && pev_valid(g_buyzone) && !g_zombie[id])
			dllfunc(DLLFunc_Touch, g_buyzone, id)
	}
	return FMRES_IGNORED
}
	
public fwd_spawn(ent)
{
	if(!pev_valid(ent)) 
		return FMRES_IGNORED
	
	static objective_ents[][] = 
	{ 
		"func_bomb_target",    "info_bomb_target", 
		"hostage_entity",      "monster_scientist", 
		"func_hostage_rescue", "info_hostage_rescue",
		"info_vip_start",      "func_vip_safetyzone", 
		"func_escapezone",     "func_buyzone"
	}

	static classname[32], i
	pev(ent, pev_classname, classname, 31)

	for(i = 0; i < sizeof objective_ents; ++i)
	{
		if(equal(classname, objective_ents[i]))
		{
			engfunc(EngFunc_RemoveEntity, ent)
			return FMRES_SUPERCEDE
		}
	}
	return FMRES_IGNORED
}

public fwd_gamedescription() 
{ 
	static gamename[32]
	get_pcvar_string(cvar_gamedescription, gamename, 31)
	forward_return(FMV_STRING, gamename)
	
	return FMRES_SUPERCEDE
}  

public fwd_traceline_post(Float:start[3], Float:end[3], nomonsters, id, trace)
{
	if(g_gamestarted || !is_player_alive(id))
		return FMRES_IGNORED
	
	static target; target = get_tr2(trace, TR_pHit)
	if(is_player_alive(target))
		set_tr2(trace, TR_flFraction, 1.0)

	return FMRES_IGNORED
}

public fwd_tracehull_post(Float:start[3], Float:end[3], nomonsters, hull, id, trace)
{
	if(g_gamestarted || !is_player_alive(id))
		return FMRES_IGNORED

	static target; target = get_tr2(trace, TR_pHit)
	if(is_player_alive(target))
		set_tr2(trace, TR_flFraction, 1.0)
	
	return FMRES_IGNORED
}

public fwd_createnamedentity(entclassname)
{
	static classname[10]; engfunc(EngFunc_SzFromIndex, entclassname, classname, 9)
	return (classname[7] == 'c' && classname[8] == '4') ? FMRES_SUPERCEDE : FMRES_IGNORED
}

public fwd_sys_error()
	destroyforwards()

public bacon_item_attachtoplayer_post(ent, id)
{
	if(is_user_alive(id) && g_zombie[id])
		weapon_deployed(id)
}

public bacon_item_deploy_post(ent)
{
	static id; id = pev(ent, pev_owner)
	if(is_user_alive(id) && g_zombie[id])
		weapon_deployed(id)
}

public weapon_deployed(id)
{
	set_pev(id, pev_weaponmodel2, "")
	if(g_usingknifemodel) 
		set_pev(id, pev_viewmodel2, g_zombie_claws)
	
	set_pev(id, pev_maxspeed, get_pcvar_float(cvar_zombie_spd))
}

public bacon_use(ent, caller, activator, use_type, Float:value)
	return (use_type == 2 && is_player_alive(caller) && g_zombie[caller]) ? HAM_SUPERCEDE : HAM_IGNORED

public bacon_takedamage(victim, inflictor, attacker, Float:damage, damagetype)
{
	if(damagetype & DMG_GENERIC || victim == attacker || !is_user_alive(victim) || !is_user_connected(attacker))
		return HAM_IGNORED

	if(!g_gamestarted || (!g_zombie[victim] && !g_zombie[attacker]) || ((damagetype & DMG_HEGRENADE) && g_zombie[attacker]))
	{
		SetHamParamFloat(4, 0.0)
		return HAM_HANDLED
	}
	
	static CsTeams:team[2]; team[0] = cs_get_user_team(attacker), team[1] = cs_get_user_team(victim)
	if(team[0] == team[1]) return HAM_IGNORED
	
	if(!g_zombie[attacker])
	{
		damage *= (damagetype & DMG_HEGRENADE) ? get_pcvar_float(cvar_hedmg_multi) : get_pcvar_float(cvar_zombie_def)
		SetHamParamFloat(4, damage)

		return HAM_HANDLED
	}
	else 
	{
		if(get_user_weapon(attacker) != CSW_KNIFE)
			SetHamParamFloat(4, 0.0)
		else
		{
			static bool:infect; infect = allow_infection()
			if(!get_pcvar_num(cvar_zombie_instant))
			{
				static Float:health; pev(victim, pev_health, health)
				if(health > damage)  infect = false
			}   	else if(g_infecting) infect = false
			g_victim[attacker] = infect ? victim : 0
			damage *= get_pcvar_float(cvar_zombie_atk)
			SetHamParamFloat(4, infect ? 0.0 : damage)
		}
		return HAM_HANDLED
	}
	return HAM_IGNORED
}

public bacon_spawn_post(id) if(is_user_alive(id))
{
	if(g_zombie[id])
	{
		clear_clientdata(id), reset_user_model(id)
		if(g_usingknifemodel)
		{
			static viewmodel[32]
			pev(id, pev_viewmodel2, viewmodel, 31)
			if(equal(viewmodel, g_zombie_claws))
			{
				static weapon; weapon = fm_find_ent_by_owner(-1, "weapon_knife", id)
				ExecuteHamB(Ham_Item_Deploy, weapon)
			}
		}
	}
	set_task(0.3, "task_spawned", TASKID_SPAWNDELAY + id)
}

public bacon_touch_weapon(ent, id)
	return (is_player_alive(id) && g_zombie[id]) ? HAM_SUPERCEDE : HAM_IGNORED

public task_spawned(taskid)
{
	static id; id = taskid - TASKID_SPAWNDELAY
	if(is_user_alive(id))
	{
		if(g_gamestarted)
		{
			static CsTeams:team; team = cs_get_user_team(id)
			if(team == CS_TEAM_T) cs_set_user_team2(id, CS_TEAM_CT)
		}
		
		if(get_pcvar_num(cvar_weaponsmenu) && g_roundstarted && g_showmenu[id])
			menu_display(id, g_equipmenu, 0)
	}
}

public task_lights()
{
	static light[2]
	get_pcvar_string(cvar_lights, light, 1)
	engfunc(EngFunc_LightStyle, 0, light)
}

public task_setzombie(taskid)
{
	static id; id = taskid - TASKID_SETZOMBIE
	set_zombie_attibutes(id)
}

public task_updatescore(params[])
{
	if(!g_gamestarted) return
	
	static attacker; attacker = params[0]
	static victim; victim = params[1]
	
	if(!is_user_connected(attacker))
		return
	
	static frags, deaths, team
	frags  = get_user_frags(attacker)
	deaths = cs_get_user_deaths(attacker)
	team   = get_user_team(attacker)
	
	static msg_scoreinfo
	if(!msg_scoreinfo) msg_scoreinfo = get_user_msgid("ScoreInfo")
	
	message_begin(MSG_BROADCAST, msg_scoreinfo)
	write_byte(attacker)
	write_short(frags)
	write_short(deaths)
	write_short(0)
	write_short(team)
	message_end()
	
	if(!is_user_connected(victim))
		return
	
	frags  = get_user_frags(victim)
	deaths = cs_get_user_deaths(victim)
	team   = get_user_team(victim)
	
	message_begin(MSG_BROADCAST, msg_scoreinfo)
	write_byte(victim)
	write_short(frags)
	write_short(deaths)
	write_short(0)
	write_short(team)
	message_end()
}

public task_stripngive(taskid)
{
	static id; id = taskid - TASKID_STRIPNGIVE
	if(is_user_alive(id))
	{
		fm_strip_user_weapons(id), reset_user_primary(id)
		bacon_give_weapon(id, "weapon_knife")
	}
}

public task_newround()
{
	static players[32], num, i, id, newzombie
	get_players(players, num, "a")

	newzombie = players[_random(num)]
	if(num > 2 && is_user_connected(g_zombieoftheround))
	{
		while(g_zombieoftheround == newzombie)
			newzombie = players[_random(num)]
	}
	g_zombieoftheround = newzombie

	for(i = 0; i < num; i++)
	{
		id = players[i]
		client_print(id, print_chat, "%L %L", id, "SCAN_RESULTS", id, g_zombieoftheround == id ? "SCAN_INFECTED" : "SCAN_CLEAN")
	}
	
	if(get_pcvar_num(cvar_randomspawn))
		randomly_place_everyone()
}

public task_startround()
{
	static players[32], num, i, id, newzombie
	get_players(players, num, "a")
	
	if(num > 2 && !is_user_alive(g_zombieoftheround))
	{
		newzombie = players[_random(num)]
		while(g_zombieoftheround == newzombie)
			newzombie = players[_random(num)]
		
		g_zombieoftheround = newzombie
	}
	
	if(!g_zombieoftheround) return
	
	for(i = 0; i < num; i++)
	{
		id = players[i]
		id == g_zombieoftheround ? infect_user(id) : cs_set_user_team2(id, CS_TEAM_CT)
	}
	
	static name[32]
	get_user_name(g_zombieoftheround, name, 31)

	set_hudmessage(_, _, _, _, _, 1)
	show_hudmessage(0, "%L", LANG_PLAYER, "INFECTED_HUD", name)
	client_print(0, print_chat, "%L", LANG_PLAYER, "INFECTED_TXT", name)
	
	g_gamestarted = true, ExecuteForward(g_fwd_gamestart, g_fwd_result)
}

public task_balanceteam()
{
	static players[CsTeams:3][32], count[CsTeams:3], i, id, CsTeams:team
	get_players(players[CS_TEAM_UNASSIGNED], count[CS_TEAM_UNASSIGNED])
	count[CS_TEAM_T] = 0, count[CS_TEAM_CT] = 0
	
	for(i = 0; i < count[CS_TEAM_UNASSIGNED]; i++)
	{
		id = players[CS_TEAM_UNASSIGNED][i], team = cs_get_user_team(id)
		if(team == CS_TEAM_T || team == CS_TEAM_CT)
			players[team][count[team]++] = id
	}

	if(abs(count[CS_TEAM_T] - count[CS_TEAM_CT]) <= 1) return

	static maxplayers; maxplayers = (count[CS_TEAM_T] + count[CS_TEAM_CT]) / 2
	if(count[CS_TEAM_T] > maxplayers)
	{
		for(i = 0; i < (count[CS_TEAM_T] - maxplayers); i++)
			cs_set_user_team(players[CS_TEAM_T][i], CS_TEAM_CT)
	}
	else
	{
		for(i = 0; i < (count[CS_TEAM_CT] - maxplayers); i++)
			cs_set_user_team(players[CS_TEAM_CT][i], CS_TEAM_T)
	}
}

public task_givenades(taskid)
{
	static id, i; id = taskid - TASKID_GIVENADES
	if(is_user_alive(id) && (strlen(g_grenades[0]) > 0))
	{
		for(i = 0; i < sizeof g_grenades; i++)
			bacon_give_weapon(id, g_grenades[i])
	}
}

public task_netclient_pdata(id) if(!g_netclient_pdata && is_user_connected(id))
{
	if(!g_czero || !(pev(id, pev_flags) & FL_FAKECLIENT) || !get_pcvar_num(cvar_botquota))
		pdata_init(id), g_netclient_pdata = 1
}

public task_botclient_pdata(id) if(!g_botclient_pdata && is_user_connected(id))
{
	if((pev(id,pev_flags) & FL_FAKECLIENT) && get_pcvar_num(cvar_botquota))
		pdata_init(id), g_botclient_pdata = 1
}

public infect_user(id)
{
	if(!is_user_alive(id)) return

	static _msg_scoreattrib
	if(!_msg_scoreattrib) _msg_scoreattrib = get_user_msgid("ScoreAttrib")
	
	message_begin(MSG_BROADCAST, _msg_scoreattrib)
	write_byte(id)
	write_byte(0)
	message_end()
	
	static sound; sound = _random(sizeof g_scream_sounds)
	emit_sound(id, CHAN_STATIC, g_scream_sounds[sound], VOL_NORM, ATTN_NONE, 0, PITCH_NORM)
	
	menu_cancel(id), cs_set_user_team2(id, CS_TEAM_T)
	set_task(0.1, "task_setzombie", TASKID_SETZOMBIE + id)
}

public menu_equip(id, menu, item)
{
	if(item < 0) return PLUGIN_CONTINUE
	
	static cmd[2], name[64], access, callback, key
	menu_item_getinfo(menu, item, access, cmd, 1, name, 63, callback), key = str_to_num(cmd)
	
	switch(key)
	{
		case 1: menu_display(id, g_primmenu, 0)
		case 2: (g_weapons[id][0] > 0) ? equipweapon(id, EQUIP_ALL) : menu_display(id, g_primmenu, 0)
		case 3:
		{
			if(g_weapons[id][0] > 0)
			{
				g_showmenu[id] = false
				client_print(id, print_chat, "%L", id, "MENU_CMDENABLE")
				equipweapon(id, EQUIP_ALL)
			}
			else    menu_display(id, g_primmenu, 0)
		}
	}
	return PLUGIN_HANDLED
}

public menu_prim(id, menu, item)
{
	if(item < 0) return PLUGIN_HANDLED
	
	static cmd[6], name[64], access, callback
	menu_item_getinfo(menu, item, access, cmd, 5, name, 63, callback)
	
	g_weapons[id][0] = str_to_num(cmd)
	equipweapon(id, EQUIP_PRI)
	menu_display(id, g_secmenu, 0)

	return PLUGIN_HANDLED
}

public menu_sec(id, menu, item)
{
	if(item < 0) return PLUGIN_HANDLED
	
	static cmd[6], name[64], access, callback
	menu_item_getinfo(menu, item, access, cmd, 5, name, 63, callback)
	
	g_weapons[id][1] = str_to_num(cmd)
	equipweapon(id, EQUIP_SEC)
	equipweapon(id, EQUIP_GREN)

	return PLUGIN_HANDLED
}

public randomly_place_everyone()
{
	if(g_spawncount <= 0) return
	
	static players[32], num, id, i, CsTeams:team
	get_players(players, num, "a")

	for(i = 0; i < num; i++)
	{
		id = players[i]
		team = cs_get_user_team(id)
		
		if(team != CS_TEAM_T && team != CS_TEAM_CT || pev(id, pev_iuser1))
			continue
		
		static spawn_index
		spawn_index = _random(g_spawncount)
	
		static Float:spawndata[3]
		spawndata[0] = g_spawns[spawn_index][0]
		spawndata[1] = g_spawns[spawn_index][1]
		spawndata[2] = g_spawns[spawn_index][2]
		
		if(!fm_is_hull_vacant(spawndata, HULL_HUMAN))
		{
			static i
			for(i = spawn_index + 1; i != spawn_index; i++)
			{
				if(i >= g_spawncount) i = 0

				spawndata[0] = g_spawns[i][0]
				spawndata[1] = g_spawns[i][1]
				spawndata[2] = g_spawns[i][2]

				if(fm_is_hull_vacant(spawndata, HULL_HUMAN))
				{
					spawn_index = i
					break
				}
			}
		}

		spawndata[0] = g_spawns[spawn_index][0]
		spawndata[1] = g_spawns[spawn_index][1]
		spawndata[2] = g_spawns[spawn_index][2]
		engfunc(EngFunc_SetOrigin, id, spawndata)

		spawndata[0] = g_spawns[spawn_index][3]
		spawndata[1] = g_spawns[spawn_index][4]
		spawndata[2] = g_spawns[spawn_index][5]
		set_pev(id, pev_angles, spawndata)

		spawndata[0] = g_spawns[spawn_index][6]
		spawndata[1] = g_spawns[spawn_index][7]
		spawndata[2] = g_spawns[spawn_index][8]
		set_pev(id, pev_v_angle, spawndata)

		set_pev(id, pev_fixangle, 1)
	}
}

public get_spawnpoints()
{
	static configdir[32]; get_configsdir(configdir, 31)
	static mapname[32]; get_mapname(mapname, 31)
	
	static csdmfile[64], line[64], data[10][6]
	formatex(csdmfile, 63, "%s/csdm/%s.spawns.cfg", configdir, mapname)

	if(file_exists(csdmfile))
	{
		static file; file = fopen(csdmfile, "rt")
		while(file && !feof(file))
		{
			fgets(file, line, 63)
			if(!line[0] || str_count(line,' ') < 2) continue

			parse(line, data[0], 5, data[1], 5, data[2], 5, data[3], 5, data[4], 5, data[5], 5, data[6], 5, data[7], 5, data[8], 5, data[9], 5)

			g_spawns[g_spawncount][0] = floatstr(data[0]), g_spawns[g_spawncount][1] = floatstr(data[1])
			g_spawns[g_spawncount][2] = floatstr(data[2]), g_spawns[g_spawncount][3] = floatstr(data[3])
			g_spawns[g_spawncount][4] = floatstr(data[4]), g_spawns[g_spawncount][5] = floatstr(data[5])
			g_spawns[g_spawncount][6] = floatstr(data[7]), g_spawns[g_spawncount][7] = floatstr(data[8])
			g_spawns[g_spawncount][8] = floatstr(data[9])
			
			if(g_spawncount++ >= MAX_SPAWNS) break
		}
		if(file) fclose(file)
	}
}

public native_is_user_zombie(plugin, params)
{
	if(params != 1) return 0
		
	static index; index = get_param(1)
	if(!index) return 0
	
	return g_zombie[index] == true ? 1 : 0
}

public native_infect_user(plugin, params)
{
	if(params != 1) return 0
		
	static index; index = get_param(1)
	if(is_user_alive(index) && allow_infection() && g_gamestarted)
	{
		infect_user(index)
		return 1
	}
	return 0
}

public native_is_user_firstzombie(plugin, params)
{
	if(params != 1) return 0
		
	static index; index = get_param(1)
	return index == g_zombieoftheround ? 1 : 0
}

public native_first_zombie(plugin)
	return g_zombieoftheround

public native_game_started(plugin)
	return g_gamestarted

stock bool:fm_is_hull_vacant(const Float:origin[3], hull)
{
	static tr; tr = 0; engfunc(EngFunc_TraceHull, origin, origin, 0, hull, 0, tr)
	return (!get_tr2(tr, TR_StartSolid) && !get_tr2(tr, TR_AllSolid) && get_tr2(tr, TR_InOpen)) ? true : false
}

stock fm_set_kvd(entity, const key[], const value[], const classname[] = "") 
{
	set_kvd(0, KV_ClassName, classname), set_kvd(0, KV_KeyName, key)
	set_kvd(0, KV_Value, value), set_kvd(0, KV_fHandled, 0)

	return dllfunc(DLLFunc_KeyValue, entity, 0)
}

stock fm_strip_user_weapons(index) 
{
	static stripent
	if(!pev_valid(stripent))
	{
		stripent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "player_weaponstrip"))
		dllfunc(DLLFunc_Spawn, stripent), set_pev(stripent, pev_solid, SOLID_NOT)
	}
	dllfunc(DLLFunc_Use, stripent, index)
	
	return 1
}

stock fm_set_entity_visibility(index, visible = 1)
	set_pev(index, pev_effects, visible == 1 ? pev(index, pev_effects) & ~EF_NODRAW : pev(index, pev_effects) | EF_NODRAW)

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

stock bacon_give_weapon(index, weapon[])
{
	if(!equal(weapon,"weapon_", 7)) return 0

	static ent; ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, weapon))
	if(!pev_valid(ent)) return 0
    
	set_pev(ent, pev_spawnflags, SF_NORESPAWN)
	dllfunc(DLLFunc_Spawn, ent)
   
	if(!ExecuteHamB(Ham_AddPlayerItem, index, ent))
	{
		if(pev_valid(ent)) set_pev(ent, pev_flags, pev(ent, pev_flags) | FL_KILLME)
		return 0
	}
	ExecuteHamB(Ham_Item_AttachToPlayer, ent, index)

	return 1
}

stock cs_set_user_team2(index, {CsTeams,_}:team, update = 1)
{
	set_pdata_int(index, OFFSET_TEAM, _:team)
	set_pev(index, pev_team, _:team)

	if(update)
	{
		static _msg_teaminfo; if(!_msg_teaminfo) _msg_teaminfo = get_user_msgid("TeamInfo")
		static teaminfo[][] = { "UNASSIGNED", "TERRORIST", "CT", "SPECTATOR" }
		
		message_begin(MSG_BROADCAST, _msg_teaminfo)
		write_byte(index)
		write_string(teaminfo[_:team])
		message_end()
	}
	return 1
}

stock cs_get_user_armor2(index, &CsArmorType:armortype)
{
	static armorvalue; pev(index, pev_armorvalue, armorvalue)
	armortype = CsArmorType:get_pdata_int(index, OFFSET_ARMOR)
	
	return armorvalue
}

stock cs_set_user_armor2(index, armorvalue, CsArmorType:armortype)
{
	set_pev(index, pev_armorvalue, armorvalue)
	set_pdata_int(index, OFFSET_ARMOR, _:armortype)
	
	return 1
}

stock get_weapon_maxclip(weapon) 
{
	static ammo
	switch(weapon)
	{
		case CSW_P228: 			 ammo = 13
		case CSW_GALI: 			 ammo = 35
		case CSW_USP: 			 ammo = 12
		case CSW_M249: 			 ammo = 100
		case CSW_M3: 			 ammo = 8
		case CSW_P90: 			 ammo = 50
		case CSW_SCOUT, CSW_AWP: 	 ammo = 10
		case CSW_XM1014, CSW_DEAGLE:	 ammo = 7
		case CSW_UMP45, CSW_FAMAS:	 ammo = 25
		case CSW_FIVESEVEN, CSW_GLOCK18, 
		CSW_G3SG1:			 ammo = 20
		case CSW_KNIFE, CSW_FLASHBANG, 
		CSW_SMOKEGRENADE, CSW_HEGRENADE, 
		CSW_C4:				 ammo = 0
		case CSW_SG552, CSW_AK47,
		CSW_MP5NAVY, CSW_M4A1, 
		CSW_MAC10, CSW_SG550, 
		CSW_AUG, CSW_ELITE, CSW_TMP:	 ammo = 30
		default:			 ammo = 0
	}
	return ammo
}

stock get_user_bpammo(index, weapon)
{
	static offset
	switch(weapon)
	{
		case CSW_AWP:   		     offset = OFFSET_AMMO_AWP
		case CSW_SCOUT, CSW_AK47, CSW_G3SG1: offset = OFFSET_AMMO_SCOUT
		case CSW_M249:  		     offset = OFFSET_AMMO_M249
		case CSW_FAMAS, CSW_M4A1, CSW_AUG, 
		CSW_SG550, CSW_GALI, CSW_SG552:	     offset = OFFSET_AMMO_FAMAS
		case CSW_M3, CSW_XM1014:	     offset = OFFSET_AMMO_M3
		case CSW_USP, CSW_UMP45, CSW_MAC10:  offset = OFFSET_AMMO_USP
		case CSW_FIVESEVEN, CSW_P90:	     offset = OFFSET_AMMO_FIVESEVEN
		case CSW_DEAGLE:		     offset = OFFSET_AMMO_DEAGLE
		case CSW_P228:			     offset = OFFSET_AMMO_P228
		case CSW_GLOCK18, CSW_TMP, CSW_ELITE, 
		CSW_MP5NAVY:			     offset = OFFSET_AMMO_GLOCK18
		default:			     offset = 0
	}
	return offset ? get_pdata_int(index, offset) : 0
}

stock set_user_bpammo(index, weapon, amount)
{
	static offset
	switch(weapon)
	{
		case CSW_AWP:   		     offset = OFFSET_AMMO_AWP
		case CSW_SCOUT, CSW_AK47, CSW_G3SG1: offset = OFFSET_AMMO_SCOUT
		case CSW_M249:  		     offset = OFFSET_AMMO_M249
		case CSW_FAMAS, CSW_M4A1, CSW_AUG, 
		CSW_SG550, CSW_GALI, CSW_SG552:	     offset = OFFSET_AMMO_FAMAS
		case CSW_M3, CSW_XM1014:	     offset = OFFSET_AMMO_M3
		case CSW_USP, CSW_UMP45, CSW_MAC10:  offset = OFFSET_AMMO_USP
		case CSW_FIVESEVEN, CSW_P90:	     offset = OFFSET_AMMO_FIVESEVEN
		case CSW_DEAGLE:		     offset = OFFSET_AMMO_DEAGLE
		case CSW_P228:			     offset = OFFSET_AMMO_P228
		case CSW_GLOCK18, CSW_TMP, CSW_ELITE, 
		CSW_MP5NAVY:			     offset = OFFSET_AMMO_GLOCK18
		default:			     offset = 0
	}
	
	if(offset) set_pdata_int(index, offset, amount)
	
	return 1
}

stock set_user_nvg(index)
{
	static nvg; nvg = get_pdata_int(index, OFFSET_NVG)
	if(!(nvg & HAS_NVG))
	{
		nvg |= HAS_NVG
		set_pdata_int(index, OFFSET_NVG, nvg)
	}
	return 1
}

stock str_count(str[], searchchar)
{
	static maxlen; maxlen = strlen(str)
	static i, count; count = 0
	
	for(i = 0; i <= maxlen; i++) if(str[i] == searchchar)
		count++

	return count
}

stock reset_user_model(index) 
{
	set_pev(index, pev_rendermode, kRenderNormal)
	set_pev(index, pev_renderamt, 0.0)

	if(pev_valid(g_modelent[index]))
		fm_set_entity_visibility(g_modelent[index], 0)
}

stock set_zombie_attibutes(index)
{
	if(!is_user_alive(index)) return

	cs_set_user_armor2(index, 0, CS_ARMOR_NONE), set_pev(index, pev_body, 0), g_zombie[index] = true
	
	if(!task_exists(TASKID_STRIPNGIVE + index))
		set_task(0.2, "task_stripngive", TASKID_STRIPNGIVE + index)
	
	if(g_usingplayermodel)
	{
		if(!pev_valid(g_modelent[index]))
		{
			static ent; ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
			if(pev_valid(ent))
			{
				engfunc(EngFunc_SetModel, ent, g_zombie_model)
				set_pev(ent, pev_classname, MODEL_CLASSNAME)
				set_pev(ent, pev_movetype, MOVETYPE_FOLLOW)
				set_pev(ent, pev_aiment, index)
				set_pev(ent, pev_owner, index)
				
				g_modelent[index] = ent
			}
		}
		else
		{
			fm_set_entity_visibility(g_modelent[index], 1)
			set_pev(g_modelent[index], pev_movetype, MOVETYPE_FOLLOW)
			set_pev(g_modelent[index], pev_aiment, index)
		}
	}

	static Float:health; health = float(get_pcvar_num(cvar_zombie_hp))
	static Float:bonus; bonus = float(get_pcvar_num(cvar_hpbonus))
	set_pev(index, pev_health, g_zombieoftheround == index ? health + bonus : health)
	
	set_user_nvg(index)
	if(get_pcvar_num(cvar_autonvg)) engclient_cmd(index, "nightvision")
	
	static effects; effects = pev(index, pev_effects)
	if(effects & EF_DIMLIGHT)
	{
		static msg_flashlight
		if(!msg_flashlight) msg_flashlight = get_user_msgid("Flashlight")
		
		message_begin(MSG_ONE, msg_flashlight, _, index)
		write_byte(0)
		write_byte(100)
		message_end()
	
		set_pev(index, pev_effects, effects & ~EF_DIMLIGHT)
	}
	ExecuteForward(g_fwd_infect2, g_fwd_result, index)
}

stock bool:allow_infection()
{
	static index, count[2], maxzombies; count[0] = 0, count[1] = 0
	for(index = 1; index <= g_maxplayers; index++)
	{
		if(is_user_connected(index) && g_zombie[index]) count[0]++
		else if(is_user_alive(index)) count[1]++
	}
	
	maxzombies = clamp(get_pcvar_num(cvar_maxzombies), 1, 31)
	return (count[0] < maxzombies && count[1] > 1) ? true : false
}

stock randomly_pick_zombie()
{
	static index, players[2][32], data[4]
	data[0] = 0, data[1] = 0, data[2] = 0, data[3] = 0
	
	for(index = 1; index <= g_maxplayers; index++)
	{
		if(!is_user_alive(index)) continue
		
		if(g_zombie[index]) data[0]++, players[0][data[2]++] = index
		else 		    data[1]++, players[1][data[3]++] = index
	}
	
	if(data[0] > 1 &&  data[1] < 1) return players[0][_random(data[2])]
	return (data[0] < 1 && data[1] > 1) ?  players[1][_random(data[3])] : 0
}

stock equipweapon(id, weapon)
{
	if(!is_user_alive(id)) return

	static weaponid
	
	if(weapon & EQUIP_PRI)
	{
		fm_strip_user_weapons(id), bacon_give_weapon(id, "weapon_knife")
		bacon_give_weapon(id, g_primweaponnames[g_weapons[id][0]])
		
		weaponid = get_weaponid(g_primweaponnames[g_weapons[id][0]])
		set_user_bpammo(id, weaponid, MAX_AMMO)
	}
	
	if(weapon & EQUIP_SEC)
	{
		bacon_give_weapon(id, g_secweaponnames[g_weapons[id][1]])
			
		weaponid = get_weaponid(g_secweaponnames[g_weapons[id][1]])
		set_user_bpammo(id, weaponid, MAX_AMMO)
	}
	
	if(weapon & EQUIP_GREN)
		set_task(0.1, "task_givenades", id + TASKID_GIVENADES)
}