Raised This Month: $51 Target: $400
 12% 

[ZP] Campo de fuerza


  
 
 
Thread Tools Display Modes
xLeoNNN
Veteran Member
Join Date: Sep 2010
Location: de_dust2
Old 05-13-2012 , 17:06   Re: [ZP] Campo de fuerza
#11

solo 2 ? que pasa con las demás ? ..
__________________
xLeoNNN is offline
Send a message via MSN to xLeoNNN
01ctrlfreak
Member
Join Date: Dec 2011
Location: Transilvania
Old 05-13-2012 , 17:16   Re: [ZP] Campo de fuerza
#12

Para que usar engine teniendo fakemeta ?

Mira...

Code:
case NADE_TYPE_BUBBLE:  // Burbuja         {             static duration, attacker             duration = pev(entity, PEV_FLARE_DURATION)             if (duration > 0)             {                 if (duration == 1)                 {                     engfunc(EngFunc_RemoveEntity, entity)                     return HAM_SUPERCEDE;                 }                                 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)             {                 engfunc(EngFunc_SetModel, entity, model_force_camp)                                 fm_set_rendering(entity, kRenderFxGlowShell, 255, 255, 255, kRenderTransAlpha, 32)                                 set_pev(entity, PEV_FLARE_DURATION, 1 + 15 / 5)                 set_pev(entity, pev_dmgtime, current_time + 0.1)                 set_pev(entity, pev_nextthink, get_gametime() + 0.1)             }             else             {                 attacker = pev(entity, pev_owner)                         g_bubble[attacker]--                                    set_pev(entity, pev_dmgtime, current_time + 0.5)             }         }

En lugar del touch creas un think...

Code:
public fw_think_bubble(entity) {     if (!pev_valid(entity)) return;         static model[64];     pev(entity, pev_model, model, charsmax(model))     if (equal(model, model_force_camp))     {         static e = -1                 new Float:centerF[3], Float:originF[3], Float:directionF[3], Float:proporcionF         pev(entity, pev_origin, centerF)                        while ((e = engfunc(EngFunc_FindEntityInSphere, e, centerF, 100.0)) != 0)         {             // Si no es un player o no es zombie, el campo de fuerza lo ignorará             if((e > g_maxplayers) || !g_zombie[e])                 continue;                         pev(e, pev_origin, originF)                         // Direccion             xs_vec_sub(originF, centerF, directionF)                         proporcionF = ((100.0 + 40.0) - vector_length(directionF)) / 10.0             xs_vec_mul_scalar(directionF, proporcionF, directionF)             set_pev(e, pev_velocity, directionF)         }                 set_pev(entity, pev_nextthink, get_gametime() + 0.1)            }

Lo registras...
Code:
register_forward(FM_Think, "fw_think_bubble")

La funcion "fw_think_bubble" se va a ejecutar siempre que detecte el model del campo de fuerza

Le das la ubicacion del model del campo de fuerza (model_force_camp) y listo... FM RLZ

Despues modificalo a tu gusto...
__________________
[IMG]http://img812.**************/img812/8081/bird51.gif[/IMG]

Last edited by 01ctrlfreak; 05-13-2012 at 17:24.
01ctrlfreak is offline
Send a message via MSN to 01ctrlfreak
Andreita
BANNED
Join Date: Apr 2012
Old 05-13-2012 , 18:03   Re: [ZP] Campo de fuerza
#13

No entiendo... Para que es ese code? o donde viene -.-

Last edited by Andreita; 05-13-2012 at 18:13.
Andreita is offline
xLeoNNN
Veteran Member
Join Date: Sep 2010
Location: de_dust2
Old 05-13-2012 , 21:43   Re: [ZP] Campo de fuerza
#14

Quote:
Originally Posted by Andreita View Post
No entiendo... Para que es ese code? o donde viene -.-
lee.
__________________
xLeoNNN is offline
Send a message via MSN to xLeoNNN
Andreita
BANNED
Join Date: Apr 2012
Old 05-13-2012 , 22:07   Re: [ZP] Campo de fuerza
#15

Esque Lo puse de muchas maneras y no me jala u.u Este es mi CODE
Alguien me puede ayudaar a meterlo u.u Esque intente mil formas... Porfa!

Code:
#include <amxmodx>
#include <amxmisc>
#include <fakemeta>
#include <hamsandwich>
#include <xs>

new g_type, g_enabled, g_recieved, bool:g_showrecieved, g_hudmsg1, g_hudmsg2
new const horas[] = { 00,01,02,03,04,05,06,07,08,09 }
new const horas2[] = { 10,11,12,13,14,15,16,17,18,19,20,21,22,23 }

new bool:g_happytime

// Access Flags Required (check CMDACCESS.INI for console commands)
const ACCESS_FLAG = ADMIN_BAN // to access the admin menu
const ACCESS_FLAG2 = ADMIN_RCON // to turn the mod on/off
const ACCESS_FLAG3 = ADMIN_BAN // to get admin models

// Player Models (randomly chosen if more than one)
new const model_nemesis[][] = { "[ZW]Nemesis" } // Nemesis
new const model_survivor[][] = { "[ZW]Survivor" } // Survivor
new const model_human[][] = { "[ZW]Humano2", "[ZW]Humano3" } // Human
new const model_admin[][] = { "[ZW]AdminH" } // Admin (human)
new const model_admin_zombie[][] = { "[ZW]AdminZ" } // Admin (zombie)

// Weapon Models
new const model_vknife_human[] = { "models/Zombie_Warface/VKnife_Human.mdl" }
new const model_vknife_nemesis[] = { "models/Zombie_Warface/VKnife_Nemesis.mdl" }
new const model_vmp5navy_survivor[] = { "models/Zombie_Warface/VMP5_Survivor.mdl" }
new const model_grenade_infect[] = { "models/Zombie_Warface/VGrenade_Infect.mdl" }
new const model_grenade_fire[] = { "models/Zombie_Warface/VGrenade_Fire.mdl" }
new const model_grenade_frost[] = { "models/Zombie_Warface/VGrenade_Frost.mdl" }
new const model_grenade_flare[] = { "models/Zombie_Warface/VGrenade_Flare.mdl" }
new const model_weapon_m4a1[] = { "models/Zombie_Warface/VM4a1.mdl" }
new const model_weapon_ump45[] = { "models/Zombie_Warface/VUmp.mdl" }
new const model_weapon_scout[] = { "models/Zombie_Warface/VScout.mdl" }
new const model_weapon_elite[] = { "models/Zombie_Warface/VElites.mdl" }
new const model_weapon_xm1014[] = { "models/Zombie_Warface/VXm1014.mdl" }
new const model_weapon_fiveseven[] = { "models/Zombie_Warface/VFiveseven.mdl" }
new const model_weapon_m3[] = { "models/Zombie_Warface/VM3.mdl" }
new const model_weapon_g3sg1[] = { "models/Zombie_Warface/VG3sg1.mdl" }
new const model_weapon_sg550[] = { "models/Zombie_Warface/VSg550.mdl" }
new const model_weapon_p228[] = { "models/Zombie_Warface/VP228.mdl" }
new const model_weapon_usp[] = { "models/Zombie_Warface/VUsp.mdl" }
new const model_weapon_deagle[] = { "models/Zombie_Warface/VDeagle.mdl" }
new const model_weapon_ak47[] = { "models/Zombie_Warface/VAk47.mdl" }
new const model_weapon_aug[] = { "models/Zombie_Warface/VAug.mdl" }
new const model_weapon_sg552[] = { "models/Zombie_Warface/VSg552.mdl" }
new const model_weapon_p90[] = { "models/Zombie_Warface/VP90.mdl" }
new const model_weapon_mac10[] = { "models/Zombie_Warface/VMac10.mdl" }
new const model_weapon_awp[] = { "models/Zombie_Warface/VAwp.mdl" }
new const model_weapon_glock18[] = { "models/Zombie_Warface/VGlock.mdl" }
new const model_weapon_famas[] = { "models/Zombie_Warface/VFamas.mdl" }
new const model_weapon_galil[] = { "models/Zombie_Warface/VGalil.mdl" }
new const model_weapon_m249[] = { "models/Zombie_Warface/VM249.mdl" }



// Grenade Sprites
new const sprite_grenade_trail[] = { "sprites/laserbeam.spr" }
new const sprite_grenade_ring[] = { "sprites/shockwave.spr" }
new const sprite_grenade_fire[] = { "sprites/flame.spr" }
new const sprite_grenade_smoke[] = { "sprites/black_smoke3.spr" }
new const sprite_grenade_glass[] = { "models/glassgibs.mdl" }

// Sounds (randomly chosen if more than one)
new const sound_win_zombies[][] = { "Zombie_Warface/zombie_win.wav" }
new const sound_win_humans[][] = { "Zombie_Warface/human_win.wav" }
new const sound_win_no_one[][] = { "Zombie_Warface/Win_No_One.wav" }
new const zombie_infect[][] = { "Zombie_Warface/Zombie_infec.wav", "Zombie_Warface/zombie_infec8.wav", "Zombie_Warface/zombie_infec7.wav" }
new const zombie_pain[][] = { "Zombie_Warface/zombie_pain7.wav", "zombie_Warface/zombie_pain8.wav" }
new const nemesis_pain[][] = { "Zombie_Warface/nemesis_pain1.wav", "Zombie_Warface/nemesis_pain2.wav", "Zombie_Warface/nemesis_pain3.wav" }
new const zombie_die[][] = { "Zombie_Warface/zombie_die1.wav", "Zombie_Warface/zombie_die2.wav", "Zombie_Warface/zombie_die3.wav", "zombie_Warface/Zombie_die4.wav", "Zombie_Warface/zombie_die5.wav" }
new const zombie_fall[][] = { "Zombie_Warface/zombie_fall1.wav" }
new const zombie_miss_slash[][] = { "Zombie_Warface/knife_slash1.wav", "Zombie_Warface/knife_slash2.wav" }
new const zombie_miss_wall[][] = { "Zombie_Warface/knife_hitwall1.wav" }
new const zombie_hit_normal[][] = { "Zombie_Warface/knife_hit1.wav", "Zombie_Warface/knife_hit2.wav", "Zombie_Warface/knife_hit3.wav", "Zombie_Warface/knife_hit4.wav" }
new const zombie_hit_stab[][] = { "Zombie_Warface/knife_stab.wav" }
new const zombie_idle[][] = { "Zombie_Warface/zombi_pre_idle_1.wav", "Zombie_Warface/zombi_pre_idle_2.wav", "Zombie_Warface/zombie_brains2.wav" }
new const zombie_idle_last[][] = { "Zombie_Warface/nil_thelast.wav" }
new const zombie_madness[][] = { "Zombie_Warface/zombie_madness1.wav" }
new const sound_nemesis[][] = { "Zombie_Warface/Nemesis.wav" }
new const sound_survivor[][] = { "Zombie_Warface/Survivor.wav" }
new const sound_swarm[][] = { "Zombie_Warface/Coming.wav" }
new const sound_multi[][] = { "Zombie_Warface/Multi.wav" }
new const sound_plague[][] = { "Zombie_Warface/nemesis1.wav", "Zombie_Warface/survivor1.wav" }
new const grenade_infect[][] = { "Zombie_Warface/grenade_infect.wav" }
new const grenade_infect_player[][] = { "Zombie_Warface/grenade_infec.wav" }
new const grenade_fire[][] = { "Zombie_Warface/grenade_explode.wav" }
new const grenade_fire_player[][] = { "Zombie_Warface/zombie_burn3.wav","Zombie_Warface/zombie_burn4.wav","Zombie_Warface/zombie_burn5.wav","Zombie_Warface/zombie_burn6.wav","Zombie_Warface/zombie_burn7.wav" }
new const grenade_frost[][] = { "Zombie_Warface/frostnova.wav" }
new const grenade_frost_player[][] = { "Zombie_Warface/impalehit.wav" }
new const grenade_frost_break[][] = { "Zombie_Warface/impalelaunch1.wav" }
new const grenade_flare[][] = { "Zombie_Warface/nvg_on.wav" }
new const sound_antidote[][] = { "Zombie_Warface/Antidote.mp3" }
new const sound_thunder[][] = { "Zombie_Warface/thunder1.wav", "Zombie_Warface/thunder2.wav" }

// Uncomment the following line to enable ambience sounds
#define AMBIENCE_SOUNDS

#if defined AMBIENCE_SOUNDS // Ambience Sounds List (only .wav and .mp3 formats supported)
// Infection Rounds
new const sound_ambience1[][] = { "zombie_warface/Ambience.wav" } // sounds (played randomly)
new const Float:sound_ambience1_duration[] = { 350.0 } // duration in seconds of each sound
// Nemesis Rounds
new const sound_ambience2[][] = { "zombie_warface/Mod_Survivor.mp3" }
new const Float:sound_ambience2_duration[] = { 250.0 }
// Survivor Rounds
new const sound_ambience3[][] = { "zombie_warface/Mod_Nemesis.mp3" }
new const Float:sound_ambience3_duration[] = { 250.0 }
// Swarm Rounds
new const sound_ambience4[][] = { "zombie_warface/Mod_Swarm.wav" }
new const Float:sound_ambience4_duration[] = { 250.0 }
// Plague Rounds
new const sound_ambience5[][] = { "zombie_warface/Mod_Plague.mp3" }
new const Float:sound_ambience5_duration[] = { 250.0 }
#endif

// Buy Menu: Primary and Secondary Weapons
new const g_primary_items[][] = { "weapon_mac10", "weapon_p90", "weapon_galil", "weapon_sg552", 
	"weapon_m249", "weapon_scout", "weapon_famas", "weapon_awp", "weapon_aug", "weapon_g3sg1", "weapon_m4a1","weapon_ak47", "weapon_xm1014"
,"weapon_sg550", "weapon_ump45", "weapon_m3" }
new const g_secondary_items[][] = { "weapon_glock18", "weapon_usp", "weapon_fiveseven", "weapon_p228", "weapon_elite", "weapon_deagle" }
new const lvlarmas[] = { 0, 9, 13, 23, 36, 74, 97, 126, 154, 176, 201, 234, 253, 295, 343, 421 }
new const lvlarmas2[] = { 0, 13, 53, 93, 164, 264 }
new const g_costgrenade[]= { 0, 10200, 32400, 93000 }  
new const Levels[554] = { 4, 24, 50, 60, 250, 340, 430, 504, 600, 1200, 1800, 2400, 3000, 3600, 4200, 4800, 5400,
	6000, 6600, 7200, 7800, 8400, 9000, 9600, 10200, 10800, 11400, 12000, 12600,
	13200, 13800, 14400, 15000, 15600, 16200, 16800, 17400, 18000, 18600, 19200, 19800,
	20400, 21000, 21600, 22200, 22800, 23400, 24000, 24600, 25200, 25800, 26400, 27000,
	27600, 28200, 28800, 29400, 30000, 30600, 31200, 31800, 32400, 33000, 33600, 34200,
	34800, 35400, 36000, 61000, 62000, 63000, 64000, 65000, 66000, 67000, 68000, 69000,
	70000, 71000, 72000, 73000, 74000, 75000, 76000, 77000, 78000, 79000, 80000, 81000,
	82000, 83000, 84000, 85000, 86000, 87000, 88000, 89000, 90000, 91000, 92000, 93000,
	94000, 95000, 96000, 97000, 98000, 99000, 100000, 101000, 102000, 103000, 104000,
	105000, 106000, 107000, 108000, 109000, 110000, 111000, 112000, 113000, 114000,
	115000, 116000, 117000, 118000, 119000, 120000, 121000, 122000, 123000, 124000,
	125000, 126000, 127000, 128000, 129000, 130000, 131000, 132000, 133000, 134000,
	135000, 136000, 137000, 138000, 139000, 140000, 141000, 142000, 143000, 144000,
	145000, 146000, 147000, 148000, 149000, 150000, 151000, 152000, 153000, 154000,
	155000, 156000, 157000, 158000, 159000, 160000, 161000, 162000, 163000, 164000,
	165000, 166000, 167000, 168000, 169000, 170000, 171000, 172000, 173000, 174000,
	175000, 176000, 177000, 178000, 179000, 180000, 181000, 182000, 183000, 184000,
	185000, 186000, 187000, 188000, 189000, 190000, 191000, 192000, 193000, 194000,
	195000, 196000, 197000, 198000, 199000, 200000, 201000, 202000, 203000, 204000,
	205000, 206000, 207000, 208000, 209000, 210000, 211000, 212000, 213000, 214000,
	215000, 216000, 217000, 218000, 219000, 220000, 221000, 222000, 223000, 224000,
	225000, 226000, 227000, 228000, 229000, 230000, 231000, 232000, 233000, 234000,
	235000, 236000, 237000, 238000, 239000, 240000, 241000, 242000, 243000, 244000,
	245000, 246000, 247000, 248000, 249000, 250000, 251000, 252000, 253000, 254000,
	255000, 256000, 257000, 258000, 259000, 260000, 261000, 262000, 263000, 264000,
	265000, 266000, 267000, 268000, 269000, 270000, 271000, 272000, 273000, 274000,
	275000, 276000, 277000, 278000, 279000, 280000, 281000, 282000, 283000, 284000,
	285000, 286000, 287000, 288000, 289000, 290000, 291000, 292000, 293000, 294000,
	295000, 296000, 297000, 298000, 299000, 300000, 301000, 302000, 303000, 304000,
	305000, 306000, 307000, 308000, 309000, 310000, 311000, 312000, 313000, 314000,
	315000, 316000, 317000, 318000, 319000, 320000, 321000, 322000, 323000, 324000,
	325000, 326000, 327000, 328000, 329000, 330000, 331000, 332000, 333000, 334000,
	335000, 336000, 337000, 338000, 339000, 340000, 341000, 342000, 343000, 344000,
	345000, 346000, 347000, 348000, 349000, 350000, 351000, 352000, 353000, 354000,
	355000, 356000, 357000, 358000, 359000, 360000, 361000, 362000, 363000, 364000,
	365000, 366000, 367000, 368000, 369000, 370000, 371000, 372000, 373000, 374000,
	375000, 376000, 377000, 378000, 379000, 380000, 381000, 382000, 383000, 384000,
	385000, 386000, 387000, 388000, 389000, 390000, 391000, 392000, 393000, 394000,
	395000, 396000, 397000, 398000, 399000, 400000, 401000, 402000, 403000, 404000,
	405000, 406000, 407000, 408000, 409000, 410000, 411000, 412000, 413000, 414000,
	415000, 416000, 417000, 418000, 419000, 420000, 421000, 422000, 423000, 424000,
	425000, 426000, 427000, 428000, 429000, 430000, 431000, 432000, 433000, 434000,
	435000, 436000, 437000, 438000, 439000, 440000, 441000, 442000, 443000, 444000,
	444000, 446000, 447000, 448000, 449000, 450000, 451000, 452000, 453000, 454000,
	455000, 456000, 457000, 458000, 459000, 460000, 461000, 462000, 463000, 464000,
	465000, 466000, 467000, 468000, 469000, 470000, 471000, 472000, 473000, 474000,
	475000, 476000, 477000, 478000, 479000, 480000, 481000, 482000, 483000, 484000,
	485000, 486000, 487000, 488000, 489000, 490000, 491000, 492000, 493000, 494000,
        495000, 496000, 497000, 498000, 499000, 530000, 540000, 550000, 560000, 570000,
        580000, 590000, 600000, 610000, 620000, 630000, 640000, 650000, 660000, 670000,
        680000, 690000, 700000, 710000, 720000, 730000, 740000, 750000, 760000, 770000,
        790000, 800000, 810000, 820000, 830000, 840000, 850000, 860000, 870000, 880000,
        890000, 900000, 910000, 920000, 930000, 940000, 950000, 960000, 970000, 980000,
        990000, 1000000 }
        


// Additional Items to give after buying all weapons (e.g. grenades)
// new const g_additional_items[][] = { "weapon_hegrenade", "weapon_flashbang", "weapon_smokegrenade" }

// Extra Items: Weapons and their costs
new const g_extra_names[][] = { "Molotov", "B.Hielo", "Bengala" }
new const g_extra_items[][] = { "weapon_hegrenade", "weapon_flashbang", "weapon_smokegrenade" }
new const g_extra_costs[] = { 6, 6, 6, 4333, 7000, 9999, 9500 }

// Extra Items: costs for Night Vision, Antidote, Zombie Madness, and Infection Bomb
new const g_extra_costs2[] = { 200, 430, 700, 999 }

// Weather Effects: uncomment a line to have the desired effect
//#define AMBIENCE_RAIN // Rain
//#define AMBIENCE_SNOW // Snow
//#define AMBIENCE_FOG // Fog

#if defined AMBIENCE_FOG // Fog Customization (if enabled)
new const FOG_DENSITY[] = "0.0018" // Density
new const FOG_COLOR[] = "128 128 128" // Color: Red Green Blue
#endif

// Sky Names (randomly chosen if more than one)
new const skynames[][] = { "hav" }

// Uncomment if you don't want the sky to be changed
//#define DONT_CHANGE_SKY

// Lightning Lights Cycle
new const lights_thunder1[][] = { "i" ,"j", "k", "l", "m", "n", "o", "n", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b", "a"}
new const lights_thunder2[][] = { "k", "l", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b", "a", "a", "b", "c", "d", "e", "d", "c", "b", "a"}
new const lights_thunder3[][] = { "b", "c", "d", "e", "f", "e", "d", "c", "i" ,"j", "k", "l", "m", "l", "k", "j", "i", "h", "g", "f", "e", "d", "c", "b", "a"}

// Decal List for Zombie Bloodstains/Footsteps
new const zombie_decals[] = { 99, 107, 108, 184, 185, 186, 187, 188, 189 }

// Knockback Power values for weapons
// Note: negative values will disable knockback power for the weapon
new const Float:kb_weapon_power[] = 
{
	-1.0,	// ---
	2.4,	// P228
	-1.0,	// ---
	6.5,	// SCOUT
	-1.0,	// ---
	8.0,	// XM1014
	-1.0,	// ---
	2.3,	// MAC10
	5.0,	// AUG
	-1.0,	// ---
	2.4,	// ELITE
	2.0,	// FIVESEVEN
	2.4,	// UMP45
	5.3,	// SG550
	5.5,	// GALIL
	5.5,	// FAMAS
	2.2,	// USP
	2.0,	// GLOCK18
	10.0,	// AWP
	2.5,	// MP5NAVY
	5.2,	// M249
	8.0,	// M3
	5.0,	// M4A1
	2.4,	// TMP
	6.5,	// G3SG1
	-1.0,	// ---
	5.3,	// DEAGLE
	5.0,	// SG552
	6.0,	// AK47
	-1.0,	// ---
	2.0	// P90
}

// Dynamic Stuff Limiters (increase if needed)
const MAX_EXTRA_ITEMS = 30
const MAX_ZOMBIE_CLASSSES = 20
const MAX_CSDM_SPAWNS = 128
const MAX_STATS_SAVED = 64
const MAX_MODELS_NEMESIS = 10
const MAX_MODELS_SURVIVOR = 10
const MAX_MODELS_HUMAN = 20
const MAX_MODELS_ADM_HUMAN = 10
const MAX_MODELS_ADM_ZOMBIE = 10

// Objective entites and anything that would affect plugin gameplay
new const g_objective_ents[][] = { "func_bomb_target", "info_bomb_target", "info_vip_start", "func_vip_safetyzone", "func_escapezone", "hostage_entity",
		"monster_scientist", "func_hostage_rescue", "info_hostage_rescue", "env_fog", "env_rain", "env_snow", "item_longjump", "func_vehicle" }

// ***************************************************************
// *** If you experience many SVC_BAD kicks, try the following ***
// ***************************************************************
// 1. Increase the delay between model changes here: (e.g. set it to 0.5)
const Float:MODELCHANGE_DELAY = 0.2
// 2. If the above doesn't help, uncomment the following line: (experimental!)
//#define HANDLE_MODELS_ON_SEPARATE_ENT

// Alternate: This makes the plugin set the model index serverside offset
// for accurate hitboxes and might also help with svc_bad (untested)
// Note: Make sure your models don't have messed up hitboxes, otherwise
// this setting may cause your server insane cpu usage and LAG!
//#define SET_MODELINDEX_OFFSET

// ---------------------------------------------------------------
// ------------------ Customization ends here!! ------------------
// ---------------------------------------------------------------

/*================================================================================
 [Offsets and Constants]
=================================================================================*/

// Plugin Version
new const PLUGIN_VERSION[] = "2.1.2^n Andreiita"

// Task offsets
enum (+= 100)
{
	TASK_MODEL = 2000,
	TASK_TEAM,
	TASK_SPAWN,
	TASK_BLOOD,
	TASK_NVISION,
	TASK_FLASH,
	TASK_CHARGE,
	TASK_SHOWHUD,
	TASK_NADES,
	TASK_MAKEZOMBIE,
	TASK_WELCOMEMSG,
	TASK_THUNDER_PRE,
	TASK_THUNDER,
	TASK_AMBIENCESOUNDS,
	TASK_LIGHTING
}

// IDs inside tasks
#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_NVISION (taskid - TASK_NVISION)
#define ID_FLASH (taskid - TASK_FLASH)
#define ID_CHARGE (taskid - TASK_CHARGE)
#define ID_SHOWHUD (taskid - TASK_SHOWHUD)

// Flare and flame tasks
#define FLARE_ENTITY args[0]
#define FLARE_DURATION args[1]
#define FLARE_R args[2]
#define FLARE_G args[3]
#define FLARE_B args[4]
#define FLAME_DURATION args[0]

// For player list menu handlers
#define PL_STARTID g_menu_data[id][0]
#define PL_ACTION g_menu_data[id][1]
#define PL_SELECTION (g_menu_data[id][0]+key+1)

// For weapon buy menu handlers
#define WPN_STARTID g_menu_data[id][2]
#define WPN_MAXIDS (sizeof g_primary_items)
#define WPN_SELECTION (g_menu_data[id][2]+key)
#define WPN_AUTO_ON g_menu_data[id][3]
#define WPN_AUTO_PRI g_menu_data[id][4]
#define WPN_AUTO_SEC g_menu_data[id][5]

// For extra items menu handlers
#define EXTRAS_STARTID g_menu_data[id][6]
#define EXTRAS_SELECTION (g_menu_data[id][6]+key)
#define EXTRAS_CUSTOM_STARTID (4+sizeof g_extra_names)

// For zombie class menu handlers
#define ZCLASSES_STARTID g_menu_data[id][7]
#define ZCLASSES_SELECTION (g_menu_data[id][7]+key)

// Combo 
#define TASK_COMBO 5546
new masd // Menu
new mcbasd // Menu Callback


// Menu selections
const MENU_KEY_AUTOSELECT = 7
const MENU_KEY_BACK = 7
const MENU_KEY_NEXT = 8
const MENU_KEY_EXIT = 9

// Hard coded extra items
enum
{
	EXTRA_NVISION = 0,
	EXTRA_ANTIDOTE,
	EXTRA_MADNESS,
	EXTRA_INFBOMB,
	EXTRA_WEAPONS_STARTID
}

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

// ZP Teams
enum
{
	ZP_TEAM_ANY = 0,
	ZP_TEAM_ZOMBIE,
	ZP_TEAM_HUMAN
}

// Zombie classes
const ZCLASS_NONE = -1

// HUD messages
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 = 0.06
const Float:HUD_SPECT_Y = 0.1
const Float:HUD_STATS_X = 0.0
const Float:HUD_STATS_Y = 0.18



// CS Offsets (win32)
const OFFSET_CSTEAMS = 114
const OFFSET_CSMONEY = 115
const OFFSET_NVGOGGLES = 129
const OFFSET_ZOOMTYPE = 363
const OFFSET_CSDEATHS = 444
const OFFSET_AWM_AMMO  = 377 
const OFFSET_SCOUT_AMMO = 378
const OFFSET_PARA_AMMO = 379
const OFFSET_FAMAS_AMMO = 380
const OFFSET_M3_AMMO = 381
const OFFSET_USP_AMMO = 382
const OFFSET_FIVESEVEN_AMMO = 383
const OFFSET_DEAGLE_AMMO = 384
const OFFSET_P228_AMMO = 385
const OFFSET_GLOCK_AMMO = 386
const OFFSET_FLASH_AMMO = 387
const OFFSET_HE_AMMO = 388
const OFFSET_SMOKE_AMMO = 389
const OFFSET_C4_AMMO = 390
const OFFSET_CLIPAMMO = 51
const OFFSET_MODELINDEX = 491 // by Orangutanz

const OFFSET_LINUX = 5 // offsets 5 higher in Linux builds
const OFFSET_LINUX_WEAPONS = 4 // weapon offsets are only 4 steps higher on Linux

// CS Teams
enum
{
	CS_TEAM_UNASSIGNED = 0,
	CS_TEAM_T,
	CS_TEAM_CT,
	CS_TEAM_SPECTATOR
}
new const TEAMNAMES[][] = { "UNASSIGNED", "TERRORIST", "CT", "SPECTATOR" }

// Some constants
const HIDE_MONEY = (1<<5)
const ATTRIB_BOMB = (1<<1)
const UNIT_SECOND = (1<<12)
const DMG_HEGRENADE = (1<<24)
const CS_NO_ZOOM = 0x5A
const HAS_NVGOGGLES = (1<<0)
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 PEV_SPEC_TARGET = pev_iuser2

// Max BP ammo for weapons
new const MAXBPAMMO[] = { -1, 52, -1, 90, 1, 32, 1, 100, 90, 1, 120, 100, 100, 90, 90, 90, 100, 120,
			30, 120, 200, 32, 90, 120, 90, 2, 35, 90, 90, -1, 100 }

// Max Clip for weapons
new const MAXCLIP[] = { -1, 13, -1, 10, -1, 7, -1, 30, 30, -1, 30, 20, 25, 30, 35, 25, 12, 20,
			10, 30, 40, 8, 30, 30, 20, -1, 7, 30, 30, -1, 50 }

// Amount of ammo to give when buying additional clips for weapons
new const BUYAMMO[] = { -1, 13, -1, 30, -1, 8, -1, 12, 30, -1, 30, 50, 12, 30, 30, 30, 12, 30,
			10, 30, 30, 8, 30, 30, 30, -1, 7, 30, 30, -1, 50 }

// Ammo IDs for weapons
new const AMMOID[] = { -1, 9, -1, 2, 12, 5, 14, 6, 4, 13, 10, 7, 6, 4, 4, 4, 6, 10,
			1, 10, 3, 5, 4, 10, 2, 11, 8, 4, 2, -1, 7 }

// Weapon IDs for ammo types
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 }

// Ammo Offsets for weapons
new const AMMOOFFSET[] = { -1, OFFSET_P228_AMMO, -1, OFFSET_SCOUT_AMMO, OFFSET_HE_AMMO, OFFSET_M3_AMMO, OFFSET_C4_AMMO,
			OFFSET_USP_AMMO, OFFSET_FAMAS_AMMO, OFFSET_SMOKE_AMMO, OFFSET_GLOCK_AMMO, OFFSET_FIVESEVEN_AMMO,
			OFFSET_USP_AMMO, OFFSET_FAMAS_AMMO, OFFSET_FAMAS_AMMO, OFFSET_FAMAS_AMMO, OFFSET_USP_AMMO,
			OFFSET_GLOCK_AMMO, OFFSET_AWM_AMMO, OFFSET_GLOCK_AMMO, OFFSET_PARA_AMMO, OFFSET_M3_AMMO,
			OFFSET_FAMAS_AMMO, OFFSET_GLOCK_AMMO, OFFSET_SCOUT_AMMO, OFFSET_FLASH_AMMO, OFFSET_DEAGLE_AMMO,
			OFFSET_FAMAS_AMMO, OFFSET_SCOUT_AMMO, -1, OFFSET_FIVESEVEN_AMMO }

// Primary and Secondary Weapon Names
new const WEAPONNAMES[][] = { "", "P228 Plateada", "", "Stalker Vss", "", "Super Serbu", "", "MAC-10 H&F", "Aug Tritaniun",
			"", "Dual Akimbo", "FiveseveN", "UMP Core", "Experimental Gun", "Galil F1", "Enfield .42",
			"Usp Tactical", "Glock", "Awp Aniquiladora", "Dual MP5", "Vulcanus Minigun",
			"Spass %100 DMG", "M6 Carabina", "TMP H&F", "Rifle De Precision", "", "Deagle Anaconda",
			"SG552 Recortada", "Ak.47 L&1", "", "Dual Kriss P90" }
// CS sounds
new const sound_flashlight[] = "items/flashlight1.wav"
new const sound_buyammo[] = "items/9mmclip1.wav"
new const sound_armorhit[] = "player/bhit_helmet-1.wav"

// Explosion radius for custom grenades
const Float:NADE_EXPLOSION_RADIUS = 240.0

// pev_ field used to store additional ammo on weapons
const PEV_ADDITIONAL_AMMO = pev_iuser1

// pev_ field used to store custom nade types and their values
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

// Weapon bitsums
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)

// Allowed weapons for zombies (added grenades/bomb for sub-plugin support, since they shouldn't be getting them aynway)
const ZOMBIE_ALLOWED_WEAPONS_BITSUM = (1<<CSW_KNIFE)|(1<<CSW_HEGRENADE)|(1<<CSW_FLASHBANG)|(1<<CSW_SMOKEGRENADE)|(1<<CSW_C4)

#if defined HANDLE_MODELS_ON_SEPARATE_ENT
// Classnames for separate model entities
new const MODEL_ENT_CLASSNAME[] = "player_model"
new const WEAPON_ENT_CLASSNAME[] = "weapon_model"
#endif

// Menu keys
const KEYSMENU = (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)

/*================================================================================
 [Global Variables]
=================================================================================*/

// Stupid compiler
#pragma unused g_models_targettime

// Player vars
new Lvl[33]
new g_damage_done[33]
new g_combo[33]
new g_MsgSync3
new g_zombie[33] // is zombie
new g_nemesis[33] // is nemesis
new g_survivor[33] // is surivor
new g_firstzombie[33] // is the first zombie
new g_lastzombie[33] // is last zombie
new g_lasthuman[33] // is last human
new g_frozen[33] // is frozen (can't move)
new g_nodamage[33] // has spawn protection/zombie madness
new g_respawn_as_zombie[33] // should respawn as zombie
new g_nvision[33] // has night vision
new g_nvisionenabled[33] // has night vision turned on
new g_zombieclass[33] // zombie class
new g_zombieclassnext[33] // zombie class for next infection
new g_flashlight[33] // has custom flashlight turned on
new g_flashbattery[33] = { 100, ... } // custom flashlight battery
new g_currentweapon[33] // current weapon the player is holding
new g_canbuy[33] // is allowed to buy a new weapon through the menu
new g_exp[33] // ammo pack count
new g_damagedealt[33] // damage dealt to zombies (used to calculate ammo packs reward)
new g_restorevel[33], Float:g_velocity[33][3] // Pain Shock Free vars
new Float:g_lastleaptime[33] // time leap was last used
new Float:g_lastflashtime[33] // time flashlight was last turned on/off
new g_switchingteam[33] // is switching team
new g_playermodel[33][32] // current model's short name [player][model]
new g_menu_data[33][8] // data for various menus
#if defined HANDLE_MODELS_ON_SEPARATE_ENT
new g_ent_playermodel[33] // player model entity
new g_ent_weaponmodel[33] // weapon model entity
#endif

// Game vars
new g_pluginenabled // ZP plugin enabled
new g_newround // new round starting
new g_endround // round ended
new g_nemround // nemesis round
new g_survround // survivor round
new g_swarmround // swarm round
new g_plagueround // plague round
new g_lastmode // last played mode
new g_scorezombies, g_scorehumans // team scores
new g_spawnCount // available spawn points counter
new Float:g_spawns[MAX_CSDM_SPAWNS][3] // spawn points data
new g_lights_i // lightning current lights counter
new Float:g_models_targettime // for adding delays between Model Change messages
new Float:g_teams_targettime // for adding delays between Team Change messages
new g_MsgSync, g_MsgSync2 // message sync objects
new g_trailSpr, g_exploSpr, g_flameSpr, g_smokeSpr, g_glassSpr // grenade sprites
new g_modname[32] // for formating the mod name
new g_freezetime // whether it's freeze time
new g_maxplayers // max players counter
new g_czero // whether we are running on a CZ server
new g_hamczbots // whether ham forwards are registered for CZ bots
new g_fwSpawn // spawn forward handle
new g_infbombcounter // to limit buying infection bombs

// Precached model indexes
new g_modelindex_nemesis[MAX_MODELS_NEMESIS]
new g_modelindex_survivor[MAX_MODELS_SURVIVOR]
new g_modelindex_human[MAX_MODELS_HUMAN]
new g_modelindex_admin[MAX_MODELS_ADM_HUMAN]
new g_modelindex_admin_zombie[MAX_MODELS_ADM_ZOMBIE]

// Some forward handlers
new g_fwRoundStart, g_fwRoundEnd, g_fwUserInfected_pre, g_fwUserInfected_post,
g_fwUserHumanized_pre, g_fwUserHumanized_post, g_fwExtraItemSelected, g_fwDummyResult

// Temporary Database vars (used to restore players stats in case they get disconnected)
new db_name[MAX_STATS_SAVED][32] // player name
new db_ammopacks[MAX_STATS_SAVED] // ammo pack count
new db_zombieclass[MAX_STATS_SAVED] // zombie class
new db_slot_i // additional saved slots counter (should start on maxplayers+1)

// Extra Items vars
new g_extraitem_name[MAX_EXTRA_ITEMS][32] // caption
new g_extraitem_cost[MAX_EXTRA_ITEMS] // cost
new g_extraitem_team[MAX_EXTRA_ITEMS] // team
new g_extraitem_i // loaded extra items counter

// Zombie Classes vars
new g_zclass_name[MAX_ZOMBIE_CLASSSES][32] // name
new g_zclass_info[MAX_ZOMBIE_CLASSSES][32] // description
new g_zclass_model[MAX_ZOMBIE_CLASSSES][32] // player model
new g_zclass_modelindex[MAX_ZOMBIE_CLASSSES] // model index
new g_zclass_clawmodel[MAX_ZOMBIE_CLASSSES][32] // claw model
new g_zclass_hp[MAX_ZOMBIE_CLASSSES] // health
new g_zclass_spd[MAX_ZOMBIE_CLASSSES] // speed
new g_zclass_lvl[MAX_ZOMBIE_CLASSSES] // level
new Float:g_zclass_grav[MAX_ZOMBIE_CLASSSES] // gravity
new Float:g_zclass_kb[MAX_ZOMBIE_CLASSSES] // knockback
new g_zclass_i // loaded zombie classes counter

// Message IDs vars
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

// CVAR pointers
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_cnvg, 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_cflash,
cvar_randspawn, cvar_multi, cvar_multichance, cvar_infammo, cvar_swarm, cvar_ammoinfect,
cvar_toggle, cvar_knockbackpower, cvar_freezeduration, 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_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_hudicons, cvar_flashshowall, cvar_rapides_awp, cvar_rapides_sg550, cvar_rapides_mac10, cvar_rapides_g3sg1, cvar_rapides_m3, cvar_rapides_ump45, cvar_rapides_scout, cvar_rapides_mp5navy, cvar_rapides_m249, cvar_rapides_m4a1, cvar_rapides_elite,
cvar_nvgcolor[3], cvar_nemnvgcolor[3], cvar_humnvgcolor[3], cvar_flashcolor[3]

/*================================================================================
 [Natives, Precache and Init]
=================================================================================*/

public plugin_natives()
{
	// Player specific natives
	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_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_infect_user", "native_infect_user", 1)
	register_native("zp_disinfect_user", "native_disinfect_user", 1)
	register_native("zp_respawn_user", "native_respawn_user", 1)
        register_native("mostrar_menu_zp", "native_mostrar_menu", 1)
	
	// Round natives
	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)
	
	// External additions natives
	register_native("zp_register_extra_item", "native_register_extra_item", 1)
	register_native("zp_register_zombie_class", "native_register_zombie_class", 1)
	
	// Load up the hard coded extra items
	native_register_extra_item2("nvision", g_extra_costs2[0], ZP_TEAM_HUMAN)
	native_register_extra_item2("antidote", g_extra_costs2[1], ZP_TEAM_ZOMBIE)
	native_register_extra_item2("madness", g_extra_costs2[2], ZP_TEAM_ZOMBIE)
	native_register_extra_item2("infbomb", g_extra_costs2[3], ZP_TEAM_ZOMBIE)
	for (new i = 0; i < sizeof g_extra_names; i++) // weapons
		native_register_extra_item2(g_extra_names[i], g_extra_costs[i], ZP_TEAM_HUMAN)
}

public plugin_precache()
{
	// To switch plugin on/off
	register_concmd("zp_toggle", "cmd_toggle", ACCESS_FLAG2, "<1/0> - Enable/Disable Zombie Plague (will restart the current map)")
	cvar_toggle = register_cvar("zp_on", "1")
	
	// Plugin disabled?
	if (!get_pcvar_num(cvar_toggle)) return;
	g_pluginenabled = true
	
	new i, playermodel[100]
	
	// Custom player models
	for (i = 0; i < sizeof model_nemesis; i++)
	{
		formatex(playermodel, sizeof playermodel - 1, "models/player/%s/%s.mdl", model_nemesis[i], model_nemesis[i])
		g_modelindex_nemesis[i] = engfunc(EngFunc_PrecacheModel, playermodel)
	}
	for (i = 0; i < sizeof model_survivor; i++)
	{
		formatex(playermodel, sizeof playermodel - 1, "models/player/%s/%s.mdl", model_survivor[i], model_survivor[i])
		g_modelindex_survivor[i] = engfunc(EngFunc_PrecacheModel, playermodel)
	}
	for (i = 0; i < sizeof model_human; i++)
	{
		formatex(playermodel, sizeof playermodel - 1, "models/player/%s/%s.mdl", model_human[i], model_human[i])
		g_modelindex_human[i] = engfunc(EngFunc_PrecacheModel, playermodel)
	}
	for (i = 0; i < sizeof model_admin; i++)
	{
		formatex(playermodel, sizeof playermodel - 1, "models/player/%s/%s.mdl", model_admin[i], model_admin[i])
		g_modelindex_admin[i] = engfunc(EngFunc_PrecacheModel, playermodel)
	}
	for (i = 0; i < sizeof model_admin_zombie; i++)
	{
		formatex(playermodel, sizeof playermodel - 1, "models/player/%s/%s.mdl", model_admin_zombie[i], model_admin_zombie[i])
		g_modelindex_admin_zombie[i] = engfunc(EngFunc_PrecacheModel, playermodel)
	}
	
	// Custom weapon models
	engfunc(EngFunc_PrecacheModel, model_vknife_human)
	engfunc(EngFunc_PrecacheModel, model_vknife_nemesis)
	engfunc(EngFunc_PrecacheModel, model_vmp5navy_survivor)
	engfunc(EngFunc_PrecacheModel, model_grenade_infect)
	engfunc(EngFunc_PrecacheModel, model_grenade_fire)
	engfunc(EngFunc_PrecacheModel, model_grenade_frost)
	engfunc(EngFunc_PrecacheModel, model_grenade_flare)
	engfunc(EngFunc_PrecacheModel, model_weapon_m4a1)
        engfunc(EngFunc_PrecacheModel, model_weapon_ump45)
        engfunc(EngFunc_PrecacheModel, model_weapon_p90) 
        engfunc(EngFunc_PrecacheModel, model_weapon_elite) 
        engfunc(EngFunc_PrecacheModel, model_weapon_famas) 
        engfunc(EngFunc_PrecacheModel, model_weapon_awp) 
        engfunc(EngFunc_PrecacheModel, model_weapon_m3) 
        engfunc(EngFunc_PrecacheModel, model_weapon_g3sg1) 
        engfunc(EngFunc_PrecacheModel, model_weapon_sg550) 
        engfunc(EngFunc_PrecacheModel, model_weapon_p228) 
        engfunc(EngFunc_PrecacheModel, model_weapon_usp) 
        engfunc(EngFunc_PrecacheModel, model_weapon_ak47) 
        engfunc(EngFunc_PrecacheModel, model_weapon_sg552) 
        engfunc(EngFunc_PrecacheModel, model_weapon_deagle) 
        engfunc(EngFunc_PrecacheModel, model_weapon_glock18) 
        engfunc(EngFunc_PrecacheModel, model_weapon_m249) 
        engfunc(EngFunc_PrecacheModel, model_weapon_scout) 
        engfunc(EngFunc_PrecacheModel, model_weapon_fiveseven) 
        engfunc(EngFunc_PrecacheModel, model_weapon_xm1014) 
        engfunc(EngFunc_PrecacheModel, model_weapon_mac10) 
        engfunc(EngFunc_PrecacheModel, model_weapon_aug) 
        engfunc(EngFunc_PrecacheModel, model_weapon_galil) 
	
	// Custom sounds
	for (i = 0; i < sizeof sound_win_zombies; i++)
		engfunc(EngFunc_PrecacheSound, sound_win_zombies[i])
	for (i = 0; i < sizeof sound_win_humans; i++)
		engfunc(EngFunc_PrecacheSound, sound_win_humans[i])
	for (i = 0; i < sizeof sound_win_no_one; i++)
		engfunc(EngFunc_PrecacheSound, sound_win_no_one[i])
	for (i = 0; i < sizeof zombie_infect; i++)
		engfunc(EngFunc_PrecacheSound, zombie_infect[i])
	for (i = 0; i < sizeof zombie_pain; i++)
		engfunc(EngFunc_PrecacheSound, zombie_pain[i])
	for (i = 0; i < sizeof nemesis_pain; i++)
		engfunc(EngFunc_PrecacheSound, nemesis_pain[i])
	for (i = 0; i < sizeof zombie_die; i++)
		engfunc(EngFunc_PrecacheSound, zombie_die[i])
	for (i = 0; i < sizeof zombie_fall; i++)
		engfunc(EngFunc_PrecacheSound, zombie_fall[i])
	for (i = 0; i < sizeof zombie_miss_slash; i++)
		engfunc(EngFunc_PrecacheSound, zombie_miss_slash[i])
	for (i = 0; i < sizeof zombie_miss_wall; i++)
		engfunc(EngFunc_PrecacheSound, zombie_miss_wall[i])
	for (i = 0; i < sizeof zombie_hit_normal; i++)
		engfunc(EngFunc_PrecacheSound, zombie_hit_normal[i])
	for (i = 0; i < sizeof zombie_hit_stab; i++)
		engfunc(EngFunc_PrecacheSound, zombie_hit_stab[i])
	for (i = 0; i < sizeof zombie_idle; i++)
		engfunc(EngFunc_PrecacheSound, zombie_idle[i])
	for (i = 0; i < sizeof zombie_idle_last; i++)
		engfunc(EngFunc_PrecacheSound, zombie_idle_last[i])	
	for (i = 0; i < sizeof zombie_madness; i++)
		engfunc(EngFunc_PrecacheSound, zombie_madness[i])
	for (i = 0; i < sizeof sound_nemesis; i++)
		engfunc(EngFunc_PrecacheSound, sound_nemesis[i])
	for (i = 0; i < sizeof sound_survivor; i++)
		engfunc(EngFunc_PrecacheSound, sound_survivor[i])
	for (i = 0; i < sizeof sound_swarm; i++)
		engfunc(EngFunc_PrecacheSound, sound_swarm[i])
	for (i = 0; i < sizeof sound_multi; i++)
		engfunc(EngFunc_PrecacheSound, sound_multi[i])
	for (i = 0; i < sizeof sound_plague; i++)
		engfunc(EngFunc_PrecacheSound, sound_plague[i])
	for (i = 0; i < sizeof grenade_infect; i++)
		engfunc(EngFunc_PrecacheSound, grenade_infect[i])
	for (i = 0; i < sizeof grenade_infect_player; i++)
		engfunc(EngFunc_PrecacheSound, grenade_infect_player[i])
	for (i = 0; i < sizeof grenade_fire; i++)
		engfunc(EngFunc_PrecacheSound, grenade_fire[i])
	for (i = 0; i < sizeof grenade_fire_player; i++)
		engfunc(EngFunc_PrecacheSound, grenade_fire_player[i])
	for (i = 0; i < sizeof grenade_frost; i++)
		engfunc(EngFunc_PrecacheSound, grenade_frost[i])
	for (i = 0; i < sizeof grenade_frost_player; i++)
		engfunc(EngFunc_PrecacheSound, grenade_frost_player[i])
	for (i = 0; i < sizeof grenade_frost_break; i++)
		engfunc(EngFunc_PrecacheSound, grenade_frost_break[i])
	for (i = 0; i < sizeof grenade_flare; i++)
		engfunc(EngFunc_PrecacheSound, grenade_flare[i])
	for (i = 0; i < sizeof sound_antidote; i++)
		engfunc(EngFunc_PrecacheSound, sound_antidote[i])
	for (i = 0; i < sizeof sound_thunder; i++)
		engfunc(EngFunc_PrecacheSound, sound_thunder[i])
	#if defined AMBIENCE_SOUNDS
	for (i = 0; i < sizeof sound_ambience1; i++)
	{
		if (equal(sound_ambience1[i][strlen(sound_ambience1[i])-4], ".mp3"))
		{
			formatex(playermodel, sizeof playermodel - 1, "sound/%s", sound_ambience1[i])
			engfunc(EngFunc_PrecacheGeneric, playermodel)
		}
		else
		{
			engfunc(EngFunc_PrecacheSound, sound_ambience1[i])
		}
	}
	for (i = 0; i < sizeof sound_ambience2; i++)
	{
		if (equal(sound_ambience2[i][strlen(sound_ambience2[i])-4], ".mp3"))
		{
			formatex(playermodel, sizeof playermodel - 1, "sound/%s", sound_ambience2[i])
			engfunc(EngFunc_PrecacheGeneric, playermodel)
		}
		else
		{
			engfunc(EngFunc_PrecacheSound, sound_ambience2[i])
		}
	}
	for (i = 0; i < sizeof sound_ambience3; i++)
	{
		if (equal(sound_ambience3[i][strlen(sound_ambience3[i])-4], ".mp3"))
		{
			formatex(playermodel, sizeof playermodel - 1, "sound/%s", sound_ambience3[i])
			engfunc(EngFunc_PrecacheGeneric, playermodel)
		}
		else
		{
			engfunc(EngFunc_PrecacheSound, sound_ambience3[i])
		}
	}
	for (i = 0; i < sizeof sound_ambience4; i++)
	{
		if (equal(sound_ambience4[i][strlen(sound_ambience4[i])-4], ".mp3"))
		{
			formatex(playermodel, sizeof playermodel - 1, "sound/%s", sound_ambience4[i])
			engfunc(EngFunc_PrecacheGeneric, playermodel)
		}
		else
		{
			engfunc(EngFunc_PrecacheSound, sound_ambience4[i])
		}
	}
	for (i = 0; i < sizeof sound_ambience5; i++)
	{
		if (equal(sound_ambience5[i][strlen(sound_ambience5[i])-4], ".mp3"))
		{
			formatex(playermodel, sizeof playermodel - 1, "sound/%s", sound_ambience5[i])
			engfunc(EngFunc_PrecacheGeneric, playermodel)
		}
		else
		{
			engfunc(EngFunc_PrecacheSound, sound_ambience5[i])
		}
	}
	#endif
	
	// CS sounds (just in case)
	engfunc(EngFunc_PrecacheSound, sound_flashlight)
	engfunc(EngFunc_PrecacheSound, sound_buyammo)
	engfunc(EngFunc_PrecacheSound, sound_armorhit)
	
	// Custom models/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)
	
	new ent
	
	// Fake Hostage (to force round ending)
	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 defined AMBIENCE_FOG
	ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_fog"))
	if (pev_valid(ent))
	{
		fm_set_kvd(ent, "density", FOG_DENSITY, "env_fog")
		fm_set_kvd(ent, "rendercolor", FOG_COLOR, "env_fog")
	}
	#endif
	
	#if defined AMBIENCE_RAIN
	engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_rain"))
	#endif
	
	#if defined AMBIENCE_SNOW
	engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "env_snow"))
	#endif
	
	// Prevent some entities from spawning
	g_fwSpawn = register_forward(FM_Spawn, "fw_Spawn")
}

public plugin_init()
{
	g_type = register_cvar("amx_bulletdamage","1")
	g_recieved = register_cvar("amx_bulletdamage_recieved","1")   
	register_event("Damage", "on_damage", "b", "2!0", "3=0", "4!0")   
	register_event("HLTV", "on_new_round", "a", "1=0", "2=0")
	g_hudmsg1 = CreateHudSyncObj()   
	g_hudmsg2 = CreateHudSyncObj()
	
	// Register plugin call
	register_plugin("Zombie Fuerzas Especiales Aztecas", PLUGIN_VERSION, "Andreiita")
	
	// Plugin disabled?
	if (!g_pluginenabled) return;
	
	// No zombie classes?
	if (!g_zclass_i) set_fail_state("No zombie classes loaded!")
	
	// Language files
	register_dictionary("zombie_plague.txt")
	
	// Events
	register_event("HLTV", "event_round_start", "a", "1=0", "2=0")
	register_logevent("logevent_round_start",2, "1=Round_Start")
	register_logevent("logevent_round_end", 2, "1=Round_End")
	#if defined AMBIENCE_SOUNDS
	register_event("30", "event_intermission", "a")
	#endif
	register_event("CurWeapon", "event_cur_weapon", "b", "1=1")
	register_event("35", "event_weapon_anim", "b")
	
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_awp", "fw_Awp_PrimaryAttack_Post", 1)
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_sg550", "fw_Sg550_PrimaryAttack_Post", 1)
        RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_mac10", "fw_Mac10_PrimaryAttack_Post", 1)  
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_mp5navy", "fw_Mp5navy_PrimaryAttack_Post", 1)
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_m249", "fw_M249_PrimaryAttack_Post", 1)
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_m3", "fw_M3_PrimaryAttack_Post", 1)
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_scout", "fw_Scout_PrimaryAttack_Post", 1)
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_g3sg1", "fw_G3sg1_PrimaryAttack_Post", 1)
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_ump45", "fw_Ump45_PrimaryAttack_Post", 1)
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_m4a1", "fw_M4a1_PrimaryAttack_Post", 1)
	RegisterHam(Ham_Weapon_PrimaryAttack, "weapon_elite", "fw_Elite_PrimaryAttack_Post", 1)

	// Forwards
	RegisterHam(Ham_Spawn, "player", "fw_PlayerSpawn_Post", 1)
	RegisterHam(Ham_Killed, "player", "fw_PlayerKilled")
	RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage")
	RegisterHam(Ham_TraceAttack, "player", "fw_TraceAttack")
	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_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_AddPlayerItem, "player", "fw_AddPlayerItem")
	register_forward(FM_ClientKill, "fw_ClientKill")
	register_forward(FM_EmitSound, "fw_EmitSound")
	#if !defined HANDLE_MODELS_ON_SEPARATE_ENT
	register_forward(FM_SetClientKeyValue, "fw_SetClientKeyValue")
	register_forward(FM_ClientUserInfoChanged, "fw_ClientUserInfoChanged")
	#endif
	register_forward(FM_GetGameDescription, "fw_GetGameDescription")
	register_forward(FM_CmdStart, "fw_CmdStart")
	register_forward(FM_SetModel, "fw_SetModel")
	RegisterHam(Ham_Think, "grenade", "fw_ThinkGrenade")
	register_forward(FM_PlayerPreThink, "fw_PlayerPreThink")
	register_forward(FM_PlayerPreThink, "fw_PlayerPreThink_Post", 1)
	unregister_forward(FM_Spawn, g_fwSpawn)
	
	// Client commands
	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("chooseteam", "clcmd_changeteam")
	register_clcmd("jointeam", "clcmd_changeteam")
	
	// Menus
	register_menu("Buy Menu 1", KEYSMENU, "menu_buy1")
	register_menu("Buy Menu 2", KEYSMENU, "menu_buy2")
	register_menu("Zombie Class Menu", KEYSMENU, "menu_zclass")
	register_menu("Game Menu", KEYSMENU, "menu_game")
	register_menu("Extra Items", KEYSMENU, "menu_extras")
	register_menu("Mod Info", KEYSMENU, "menu_info")
	register_menu("Admin Menu", KEYSMENU, "menu_admin")
	register_menu("Player List Menu", KEYSMENU, "menu_player_list")
	
	// Admin commands
	register_concmd("zp_zombie", "cmd_zombie", ACCESS_FLAG, "<target> - Turn someone into a Zombie")
	register_concmd("zp_human", "cmd_human", ACCESS_FLAG, "<target> - Turn someone back to Human")
	register_concmd("zp_nemesis", "cmd_nemesis", ACCESS_FLAG, "<target> - Turn someone into a Nemesis")
	register_concmd("zp_survivor", "cmd_survivor", ACCESS_FLAG, "<target> - Turn someone into a Survivor")
	register_concmd("zp_respawn", "cmd_respawn", ACCESS_FLAG, "<target> - Respawn someone")
	register_concmd("zp_swarm", "cmd_swarm", ACCESS_FLAG, " - Start Swarm Mode")
	register_concmd("zp_multi", "cmd_multi", ACCESS_FLAG, " - Start Multi Infection")
	/* Menu asd */
	/* Use menu_display(id, masd, 0) to show the menu to an user. */
	masd = menu_create("asd", "mh_asd")
	mcbasd = menu_makecallback("mcb_asd")
	menu_additem(masd, "asd", "ma_asd", ADMIN_ALL, mcbasd)
	menu_additem(masd, "asd", "ma_asd", ADMIN_ALL, mcbasd)
	/* Menu End */

	register_concmd("zp_plague", "cmd_plague", ACCESS_FLAG, " - Start Plague Mode")
	
	// Message IDs
	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")
	
	// Message hooks
	register_message(g_msgCurWeapon, "message_cur_weapon")
	register_message(get_user_msgid("AmmoX"), "message_ammo_x")
	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 defined HANDLE_MODELS_ON_SEPARATE_ENT
	register_message(get_user_msgid("ClCorpse"), "message_clcorpse")
	#endif
	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")
	
	// CVARS - General Purpose
	cvar_warmup = register_cvar("zp_delay", "12")
	cvar_lighting = register_cvar("zp_lighting", "b")
	cvar_thunder = register_cvar("zp_thunderclap", "90")
	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_deathmatch = register_cvar("zp_deathmatch", "2")
	cvar_spawndelay = register_cvar("zp_spawn_delay", "0")
	cvar_spawnprotection = register_cvar("zp_spawn_protection", "1")
	cvar_respawnonsuicide = register_cvar("zp_respawn_on_suicide", "0")
	cvar_respawnafterlast = register_cvar("zp_respawn_after_last_human", "1")
	cvar_respawnworldspawnkill = register_cvar("zp_respawn_on_worldspawn_kill", "1")
	cvar_randspawn = register_cvar("zp_random_spawn", "1")
	cvar_removedropped = register_cvar("zp_remove_dropped", "0")
	cvar_removemoney = register_cvar("zp_remove_money", "1")
	cvar_buycustom = register_cvar("zp_buy_custom", "1")
	cvar_adminmodelshuman = register_cvar("zp_admin_models_human", "1")
	cvar_adminmodelszombie = register_cvar("zp_admin_models_zombie", "1")
	cvar_zclasses = register_cvar("zp_zombie_classes", "1")
	cvar_statssave = register_cvar("zp_stats_save", "1")
	cvar_preventconsecutive = register_cvar("zp_prevent_consecutive_modes", "1")
	
	// CVARS - Extra Items
	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_extramadness = register_cvar("zp_extra_madness", "1")
	cvar_madnessduration = register_cvar("zp_extra_madness_duration", "3.0")
	cvar_extrainfbomb = register_cvar("zp_extra_infbomb", "1")
	cvar_infbomblimit = register_cvar("zp_extra_infbomb_limit", "5")
	
	// CVARS - Flashlight and Nightvision
	cvar_nvggive = register_cvar("zp_nvg_give", "1")
	cvar_cnvg = 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_cflash = 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")
	
	// CVARS - Leap
	cvar_leapzombies = register_cvar("zp_leap_zombies", "0")
	cvar_leapzombiesforce = register_cvar("zp_leap_zombies_force", "500")
	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", "500")
	cvar_leapnemesisheight = register_cvar("zp_leap_nemesis_height", "300")
	cvar_leapnemesiscooldown = register_cvar("zp_leap_nemesis_cooldown", "0")
	cvar_leapsurvivor = register_cvar("zp_leap_survivor", "1")
	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", "0")
	
	// CVARS - Humans
	cvar_humanhp = register_cvar("zp_human_health", "100")
	cvar_humanlasthp = register_cvar("zp_human_last_extrahp", "0")
	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", "1")
	cvar_ammodamage = register_cvar("zp_human_damage_reward", "500")
	cvar_fragskill = register_cvar("zp_human_frags_for_kill", "3")
	
	// 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", "5000")
	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_flaregrenades = register_cvar("zp_flare_grenades","1")
	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", "2.0")
	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", "1000")
	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", "10")
	cvar_fragsinfect = register_cvar("zp_zombie_frags_for_infect", "1")
	
	// CVARS - Weapon Speed
	cvar_rapides_awp = register_cvar("amx_awp_rapido", "1.4")
        cvar_rapides_mac10 = register_cvar("amx_mac10_rapido", "0.1")
        cvar_rapides_sg550 = register_cvar("amx_sg550_rapido", "0.10")
	cvar_rapides_m4a1 = register_cvar("amx_m4a1_rapido", "0.1")
	cvar_rapides_m3 = register_cvar("amx_m3_rapido", "0.4")
	cvar_rapides_g3sg1 = register_cvar("amx_g3sg1_rapido", "0.80")
	cvar_rapides_elite = register_cvar("amx_elite_rapido", "0")
	cvar_rapides_m249 = register_cvar("amx_m249_rapido", "0.1")
	cvar_rapides_scout = register_cvar("amx_scout_rapido", "0.6")
	cvar_rapides_ump45 = register_cvar("amx_ump45_rapido", "0.1")
	cvar_rapides_mp5navy = register_cvar("amx_mp5navy_rapido", "0.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", "15")
	cvar_nemminplayers = register_cvar("zp_nem_min_players", "0")
	cvar_nemhp = register_cvar("zp_nem_health", "500000")
	cvar_nembasehp = register_cvar("zp_nem_base_health", "0")
	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", "1")	
	cvar_nempainfree = register_cvar("zp_nem_painfree", "0")
	cvar_nemignorefrags = register_cvar("zp_nem_ignore_frags", "0")
	cvar_nemignoreammo = register_cvar("zp_nem_ignore_rewards", "0")
	
	// CVARS - Survivor
	cvar_surv = register_cvar("zp_surv_enabled", "1")
	cvar_survchance = register_cvar("zp_surv_chance", "20")
	cvar_survminplayers = register_cvar("zp_surv_min_players", "0")
	cvar_survhp = register_cvar("zp_surv_health", "3500")
	cvar_survbasehp = register_cvar("zp_surv_base_health", "0")
	cvar_survspd = register_cvar("zp_surv_speed", "240")
	cvar_survgravity = register_cvar("zp_surv_gravity", "1.25")
	cvar_survglow = register_cvar("zp_surv_glow", "1")
	cvar_survaura = register_cvar("zp_surv_aura", "1")
	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_mp5navy")
	
	// CVARS - Swarm Mode
	cvar_swarm = register_cvar("zp_swarm_enabled", "1")
	cvar_swarmchance = register_cvar("zp_swarm_chance", "20")
	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", "5")
	cvar_plaguenemhpmulti = register_cvar("zp_plague_nem_hp_multi", "0.15")
	cvar_plaguesurvnum = register_cvar("zp_plague_surv_number", "3")
	cvar_plaguesurvhpmulti = register_cvar("zp_plague_surv_hp_multi", "0.10")
	
	// 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)
	
	// Custom Forwards
	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)
	g_fwUserInfected_post = CreateMultiForward("zp_user_infected_post", ET_IGNORE, FP_CELL, FP_CELL)
	g_fwUserHumanized_pre = CreateMultiForward("zp_user_humanized_pre", ET_IGNORE, FP_CELL)
	g_fwUserHumanized_post = CreateMultiForward("zp_user_humanized_post", ET_IGNORE, FP_CELL)
	g_fwExtraItemSelected = CreateMultiForward("zp_extra_item_selected", ET_IGNORE, FP_CELL, FP_CELL)
	
	// Collect random spawn points
	load_spawns()
	
	#if !defined DONT_CHANGE_SKY
	// Set a random skybox
	set_cvar_string("sv_skyname", skynames[random_num(0, sizeof skynames - 1)])
	#endif
	
	// Disable sky lighting so it doesn't mess up our custom lighting
	set_cvar_num("sv_skycolor_r", 0)
	set_cvar_num("sv_skycolor_g", 0)
	set_cvar_num("sv_skycolor_b", 0)
	
	// Create the HUD Sync Objects
	g_MsgSync = CreateHudSyncObj()
	g_MsgSync2 = CreateHudSyncObj()
	g_MsgSync3 = CreateHudSyncObj()
	
	// Format mod name
	formatex(g_modname, sizeof g_modname - 1, "Zombie Fuerzas Especiales Aztecas %s", PLUGIN_VERSION)
	
	// Get Max Players
	g_maxplayers = get_maxplayers()
	
	// Reserved saving slots starts on maxplayers+1
	db_slot_i = g_maxplayers+1
	
	// Check if it's a CZ server
	new mymod[6]
	get_modname(mymod, sizeof mymod - 1)
	if (equal(mymod, "czero")) g_czero = 1
	
	// Lighting task
	set_task(5.0, "lighting_effects", TASK_LIGHTING, _, _, "b")
	
	// Call Round Start
	set_task(1.0, "event_round_start")
}

public plugin_cfg()
{
	// Get configs dir
	new cfgdir[32]
	get_configsdir(cfgdir, sizeof cfgdir - 1);
	
	// Execute config file (zombieplague.cfg)
	server_cmd("exec %s/zombieplague.cfg", cfgdir)
}

/*================================================================================
 [Main Events]
=================================================================================*/

// Event Round Start
public event_round_start()
{
	// Remove any tasks bound to custom nades (since they're removed at roundstart)
	remove_task(TASK_NADES)
	
	// Remove doors/lights?
	set_task(0.2, "remove_stuff")
	
	// New round starting
	g_newround = true
	g_endround = false
	g_survround = false
	g_nemround = false
	g_swarmround = false
	g_plagueround = false
	
	// Freezetime begins
	g_freezetime = true
	new data[3]
	get_time("%H", data, 2)
	
	new Tiempo = str_to_num(data)
	
	for(new i=0;i <= sizeof horas - 1;i++)
	{
		if(Tiempo != horas[i]) continue
		g_happytime = true
		server_cmd("zp_human_damage_reward ^"1000^"")
		server_cmd("zp_deathmatch 2")
	}
	
	new data1[3]
	get_time("%H", data1, 2)
	
	new Tiempo2 = str_to_num(data1)
	
	for(new i=0;i <= sizeof horas2 - 1;i++)
	{
		if(Tiempo2 != horas2[i]) continue
		g_happytime = false
		server_cmd("zp_human_damage_reward ^"1900^"")
		server_cmd("zp_deathmatch 2")
	}
	
	// Show welcome message and T-Virus notice
	remove_task(TASK_WELCOMEMSG)
	set_task(2.0, "welcome_msg", TASK_WELCOMEMSG)
	
	// Set a new "Make Zombie Task"
	remove_task(TASK_MAKEZOMBIE)
	set_task(2.0+random_float(get_pcvar_float(cvar_warmup), get_pcvar_float(cvar_warmup)+3.0), "make_zombie_task", TASK_MAKEZOMBIE)
}

// Log Event Round Start
public logevent_round_start()
{
	// Freezetime ends
	g_freezetime = false
}

// Log Event Round End
public logevent_round_end()
{
	// Prevent this from getting called twice when restarting (bugfix)
	static Float:lastendtime
	if (get_gametime() - lastendtime < 0.5) return;
	lastendtime = get_gametime()
	
	// Temporarily save player stats?
	if (get_pcvar_num(cvar_statssave))
	{
		static id, team
		for (id = 1; id <= g_maxplayers; id++)
		{
			// Not connected
			if (!is_user_connected(id))
				continue;
			
			team = fm_get_user_team(id)
			
			// Not playing
			if (team == CS_TEAM_SPECTATOR || team == CS_TEAM_UNASSIGNED)
				continue;
			
			save_stats(id)
		}
	}
	
	// Round ended
	g_endround = true
	
	// Stop old tasks (if any)
	remove_task(TASK_WELCOMEMSG)
	remove_task(TASK_MAKEZOMBIE)
	
	#if defined AMBIENCE_SOUNDS
	// Stop ambience sounds
	remove_task(TASK_AMBIENCESOUNDS)
	ambience_sound_stop()
	#endif
	
	// Balance the teams
	set_task(0.1, "balance_teams")
	
	// Show HUD notice, play win sound, update team scores...
	if (!fnGetZombies())
	{
		// Human team wins
		set_hudmessage(0, 0, 200, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
		ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "WIN_HUMAN")
		
		// Play win sound and increase score
		PlaySound(sound_win_humans[random_num(0, sizeof sound_win_humans -1)])
		g_scorehumans++
		
		// Round end forward
		ExecuteForward(g_fwRoundEnd, g_fwDummyResult, 2);
	}
	else if (!fnGetHumans())
	{
		// Zombie team wins
		set_hudmessage(200, 0, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
		ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "WIN_ZOMBIE")
		
		// Play win sound and increase score
		PlaySound(sound_win_zombies[random_num(0, sizeof sound_win_zombies -1)])
		g_scorezombies++
		
		// Round end forward
		ExecuteForward(g_fwRoundEnd, g_fwDummyResult, 1);
	}
	else
	{
		// No one wins
		set_hudmessage(0, 200, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 3.0, 2.0, 1.0, -1)
		ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "WIN_NO_ONE")
		PlaySound(sound_win_no_one[random_num(0, sizeof sound_win_no_one -1)])
		
		// Round end forward
		ExecuteForward(g_fwRoundEnd, g_fwDummyResult, 0);
	}
}

#if defined AMBIENCE_SOUNDS
// Event Map Ended
public event_intermission()
{
	// Remove ambience sounds task
	remove_task(TASK_AMBIENCESOUNDS)
}
#endif

// Current Weapon Event
public event_cur_weapon(id)
{
	// Not alive
	if (!is_user_alive(id))
		return;
	
	// Zombie not holding an allowed weapon for some reason
	if (g_zombie[id] && !((1<<read_data(2)) & ZOMBIE_ALLOWED_WEAPONS_BITSUM))
	{
		// Switch to knife
		engclient_cmd(id, "weapon_knife")
		
		// Update the HUD and let other plugins know
		emessage_begin(MSG_ONE, g_msgCurWeapon, _, id)
		ewrite_byte(1) // active
		ewrite_byte(CSW_KNIFE) // weapon
		ewrite_byte(MAXCLIP[CSW_KNIFE]) // clip
		emessage_end()
	}
}

// Weapon Animation Event
public event_weapon_anim()
{
	// Because of a weird bug within the AMXX event system, we need to
	// hook this message to prevent some weird behavior when calling
	// engclient_cmd(id, "weapon_knife") in the CurWeapon Event forward.
	// http://forums.alliedmods.net/showthread.php?t=85161&page=2
}

/*================================================================================
 [Main Forwards]
=================================================================================*/

// Client joins the game
public client_putinserver(id)
{
	// Plugin disabled?
	if (!g_pluginenabled) return;
	
	// Initialize player vars
	reset_vars(id, 1)
	
	// Load player stats?
	if (get_pcvar_num(cvar_statssave)) load_stats(id)
	
	// Set some tasks for humans only
	if (!is_user_bot(id))
	{
		// Set the custom HUD display task
		set_task(1.0, "ShowHUD", id+TASK_SHOWHUD, _, _, "b")
		
		// Disable minmodels for clients to see zombies properly
		set_task(5.0, "disable_minmodels", id)
	}
	else
	{
		// CZ bots seem to use a different "classtype" for player entities
		// (or something like that) which needs to be hooked separately
		if (!g_hamczbots && cvar_botquota)
		{
			// Set a task to let the private data initialize
			set_task(0.1, "register_ham_czbots", id)
		}
	}
	set_task(1.0, "sistema_levels", id)
}

// Client disconnect
public client_disconnect(id)
{
	g_damage_done[id] = 0
	g_combo[id] = 0
	
	// Plugin disabled?
	if (!g_pluginenabled) return;
	
	// Check that we still have both humans and zombies to keep the round going
	if (is_user_alive(id)) check_round(id)
	
	// Temporarily save player stats?
	if (get_pcvar_num(cvar_statssave)) save_stats(id)
	
	// Remove previous tasks
	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_NVISION)
	remove_task(id+TASK_SHOWHUD)
	
	#if defined HANDLE_MODELS_ON_SEPARATE_ENT
	// Remove custom model entities
	fm_remove_model_ents(id)
	#endif
	
	// Last Zombie Check
	set_task(0.1, "fnCheckLastZombie")
}

// Entity Spawn Forward
public fw_Spawn(entity)
{
	// Invalid entity
	if (!pev_valid(entity)) return FMRES_IGNORED;
	
	// Get classname
	new classname[32]
	pev(entity, pev_classname, classname, sizeof classname - 1)
	
	// Check whether it needs to be removed
	for (new i = 0; i < sizeof g_objective_ents; i++)
	{
		if (equal(classname, g_objective_ents[i]))
		{
			engfunc(EngFunc_RemoveEntity, entity)
			return FMRES_SUPERCEDE;
		}
	}
	
	return FMRES_IGNORED;
}

// Ham Player Spawn Post Forward
public fw_PlayerSpawn_Post(id)
{
	// Not alive or didn't join a team yet
	if (!is_user_alive(id) || !fm_get_user_team(id))
		return;
	
	// Remove previous tasks
	remove_task(id+TASK_SPAWN)
	remove_task(id+TASK_TEAM)
	remove_task(id+TASK_MODEL)
	remove_task(id+TASK_BLOOD)
	
	// Spawn randomly?
	if (get_pcvar_num(cvar_randspawn)) do_random_spawn(id)
	
	// Hide money?
	if (get_pcvar_num(cvar_removemoney))
		set_task(0.2, "task_hide_money", id+TASK_SPAWN)
	
	// Respawn player if he dies because of a worldspawn kill?
	if (get_pcvar_num(cvar_respawnworldspawnkill))
		set_task(2.0, "respawn_player", id+TASK_SPAWN)
	
	// Spawn as zombie?
	if (g_respawn_as_zombie[id] && !g_newround)
	{
		reset_vars(id, 0) // reset player vars
		zombieme(id, 0, 0, 0) // make him zombie right away
		return;
	}
	
	// Reset player vars
	reset_vars(id, 0)
	
	// Set health and gravity
	fm_set_user_health(id, get_pcvar_num(cvar_humanhp))
	set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))
	
	#if defined HANDLE_MODELS_ON_SEPARATE_ENT
	
	// Set the right model
	if (get_pcvar_num(cvar_adminmodelshuman) && get_user_flags(id) & ACCESS_FLAG3)
		copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_admin[random_num(0, sizeof model_admin -1)])
	else
		copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_human[random_num(0, sizeof model_human -1)])
	
	// Set model on player model entity
	fm_set_playermodel_ent(id)
	
	// Remove glow on player model entity
	fm_set_rendering(g_ent_playermodel[id])
	
	#else
	
	// Set the right model, after checking that we don't already have it
	static currentmodel[32], already_has_model, i, iRand
	already_has_model = false
	
	// Get current model and compare it with current one
	fm_get_user_model(id, currentmodel, sizeof currentmodel - 1)
	
	if (get_pcvar_num(cvar_adminmodelshuman) && get_user_flags(id) & ACCESS_FLAG3)
	{
		for (i = 0; i < sizeof model_admin; i++)
			if (equal(model_admin[i], currentmodel)) already_has_model = true
		
		if (!already_has_model)
		{
			iRand = random_num(0, sizeof model_admin -1)
			copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_admin[iRand])
			#if defined SET_MODELINDEX_OFFSET
			fm_set_user_model_index(id, g_modelindex_admin[iRand])
			#endif
		}
	}
	else
	{
		for (i = 0; i < sizeof model_human; i++)
			if (equal(model_human[i], currentmodel)) already_has_model = true;
		
		if (!already_has_model)
		{
			iRand = random_num(0, sizeof model_human -1)
			copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_human[iRand])
			#if defined SET_MODELINDEX_OFFSET
			fm_set_user_model_index(id, g_modelindex_human[iRand])
			#endif
		}
	}
	
	// Need to change the model?
	if (!already_has_model)
	{
		// 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*MODELCHANGE_DELAY, "fm_user_model_update", id+TASK_MODEL)
		else
			fm_user_model_update(id+TASK_MODEL)
	}
	
	// Remove glow
	fm_set_rendering(id)
	
	#endif
	
	// Bots stuff
	if (is_user_bot(id))
	{
		// Turn off NVG for bots
		fm_set_bot_nvg(id, 0)
		
		// Automatically buy extra items/weapons after first zombie is chosen
		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)
		}
	}
	
	// Show custom buy menu?
	if (get_pcvar_num(cvar_buycustom))
		set_task(0.4, "show_menu_buy1", id+TASK_SPAWN)
	
	// Get spawn protection time
	static Float:sptime
	sptime = get_pcvar_float(cvar_spawnprotection)
	
	// Enable spawn protection for humans spawning mid-round
	if (!g_newround && sptime > 0.0)
	{
		// Dont take any damage
		g_nodamage[id] = true
		
		// Make temporarily invisible
		set_pev(id, pev_effects, pev(id, pev_effects) | EF_NODRAW)
		
		// Set task to remove it
		set_task(sptime, "remove_spawn_protection", id+TASK_SPAWN)
	}
	
	// Last Zombie Check
	set_task(0.1, "fnCheckLastZombie")
}

// Ham Player Killed Forward
public fw_PlayerKilled(victim, attacker, shouldgib)
{
	// Last Zombie Check
	set_task(0.1, "fnCheckLastZombie")
	
	// Enable dead players nightvision
	set_task(0.2, "spec_nvision", victim)
	
	// Get nightvision give setting
	static nvggive
	nvggive = get_pcvar_num(cvar_nvggive)
	
	// Disable nightvision when killed (bugfix)
	if (nvggive == 0 && g_nvision[victim])
	{
		if (g_nvisionenabled[victim] && !get_pcvar_num(cvar_cnvg)) set_user_gnvision(victim, 0)
		g_nvision[victim] = false
		g_nvisionenabled[victim] = false
	}
	
	// Turn off nightvision when killed (bugfix)
	if (nvggive == 2 && g_nvision[victim] && g_nvisionenabled[victim])
	{
		if (!get_pcvar_num(cvar_cnvg)) set_user_gnvision(victim, 0)
		g_nvisionenabled[victim] = false
	}
	
	// Stop bleeding/burning when killed
	if (g_zombie[victim])
		remove_task(victim+TASK_BLOOD)
	
	// Nemesis explodes!
	if (g_nemesis[victim])
		SetHamParamInteger(3, 2)
	
	// Get deathmatch mode status and whether the player killed himself
	static deathmatch, selfkill
	deathmatch = get_pcvar_num(cvar_deathmatch)
	selfkill = (victim == attacker || !is_user_connected(attacker)) ? true : false
	
	// Respawn if deathmatch is enabled
	if (deathmatch)
	{
		// Respawn on suicide?
		if (selfkill && !get_pcvar_num(cvar_respawnonsuicide))
			return;
		
		// Respawn if only the last human is left?
		if (!get_pcvar_num(cvar_respawnafterlast) && fnGetHumans() == 1)
			return;
		
		// Respawn as zombie?
		if (deathmatch == 2 || (deathmatch == 3 && random_num(0, 1)) || (deathmatch == 4 && fnGetZombies() < fnGetAlive()/2))
			g_respawn_as_zombie[victim] = true
		
		// Set the respawn task
		set_task(get_pcvar_float(cvar_spawndelay), "respawn_player", victim+TASK_SPAWN)
	}
	
	// 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_exp[attacker] += get_pcvar_num(cvar_ammoinfect)
	
	// Get frag rewards for humans and zombies
	static fragskill, fragsinfect
	fragskill = get_pcvar_num(cvar_fragskill)
	fragsinfect = get_pcvar_num(cvar_fragsinfect)
	
	// Human killed zombie, add up the extra frags for kill
	if (!g_zombie[attacker] && fragskill > 1)
		UpdateFrags(attacker, victim, fragskill-1, 0, 0)
	
	// Zombie killed human, add up the extra frags for kill
	if (g_zombie[attacker] && fragsinfect > 1)
		UpdateFrags(attacker, victim, fragsinfect-1, 0, 0)
}

// Ham Take Damage Forward (inflictor = weapon)
public fw_TakeDamage(victim, inflictor, attacker, Float:damage, damage_type)
{
	static plrWeapId
	if (is_user_connected(attacker))
		plrWeapId = get_user_weapon(attacker)
	// Non-player damage or self damage
	if (victim == attacker || !is_user_connected(attacker))
		return HAM_IGNORED;
	
	// New round starting or round ended
	if (g_newround || g_endround)
		return HAM_SUPERCEDE;
	
	// Victim shouldn't take damage or victim is frozen
	if (g_nodamage[victim])  
		return HAM_SUPERCEDE;  
	
	// Prevent friendly fire
	if (g_zombie[attacker] == g_zombie[victim])
		return HAM_SUPERCEDE;
	
	// Attacker is human...
	if (!g_zombie[attacker])
	{
		damage *= get_pcvar_float(cvar_zombiearmor)
		switch (plrWeapId)
		{
			case (CSW_MP5NAVY): damage *= 350.0
			case (CSW_FAMAS): damage *= 499.5
			case (CSW_KNIFE): damage *= 50.0	
			case (CSW_AWP): damage *= 800.0
			case (CSW_AUG): damage *= 220.0
			case (CSW_SG552): damage *= 375.0
			case (CSW_AK47): damage *= 720.0
			case (CSW_M4A1): damage *= 934.5
			case (CSW_XM1014): damage *= 860.0
			case (CSW_G3SG1): damage *= 500.0
			case (CSW_SG550): damage *= 600.0
			case (CSW_DEAGLE): damage *= 450.0
			case (CSW_ELITE): damage *= 320.0
			case (CSW_M249): damage *= 450.0
                        case (CSW_MAC10): damage *= 12.5
			case (CSW_UMP45): damage *= 800.0
			case (CSW_GALIL): damage *= 160.0
			case (CSW_M3): damage *= 500.0
			case (CSW_SCOUT): damage *= 300.0
			case (CSW_P90): damage *= 40.5
			case (CSW_P228): damage *=  60.0
			case (CSW_GLOCK18): damage *= 70.0
		}
		SetHamParamFloat(4, damage)
		
		// Armor multiplier for the final damage on normal zombies
		if (!g_nemesis[victim])
		{
			damage *= get_pcvar_float(cvar_zombiearmor)
			SetHamParamFloat(4, damage)
		}
		
		// Reward ammo packs
		if (!g_survivor[attacker] || !get_pcvar_num(cvar_survignoreammo))
		{
			// Store damage dealt
			g_damagedealt[attacker] += floatround(damage)
			
			// Get damage required to get an ammo pack
			static ammodamage
			ammodamage = get_pcvar_num(cvar_ammodamage)
			
			// Reward ammo packs for every [ammo damage] dealt
			while (g_damagedealt[attacker] >= ammodamage)
			{
				if (is_user_admin(attacker))
				{
					if (g_happytime)
					{
						if (Lvl[attacker] < 60)
						{
							g_exp[attacker] += 12
							g_damagedealt[attacker] -= ammodamage
						}
						else
						{
							g_exp[attacker] += 10
							g_damagedealt[attacker] -= ammodamage
						}
					}
					else if (!g_happytime)
					{
						if (Lvl[attacker] < 60)
						{
							g_exp[attacker] += 4
							g_damagedealt[attacker] -= ammodamage
						}
						else
						{
							g_exp[attacker] += 2
							g_damagedealt[attacker] -= ammodamage
						}
					}
				}
				else
				{
					if (g_happytime)
					{
						if (Lvl[attacker] < 60)
						{
							g_exp[attacker] += 4
							g_damagedealt[attacker] -= ammodamage
						}
						else
						{
							g_exp[attacker] += 2
							g_damagedealt[attacker] -= ammodamage
						}
					}
					else if (!g_happytime)
					{
						if (Lvl[attacker] < 60)
						{
							g_exp[attacker] += 2
							g_damagedealt[attacker] -= ammodamage
						}
						else
						{
							g_exp[attacker]++
							g_damagedealt[attacker] -= ammodamage
						}
					}
				}
			}
			return HAM_IGNORED;
		}
	}
	
	// Attacker is zombie...
	
	// Prevent infection by HE grenade (bugfix)
	if (damage_type & DMG_HEGRENADE)
		return HAM_SUPERCEDE;
	
	// Nemesis?
	if (g_nemesis[attacker])
	{
		// Set nemesis damage
		SetHamParamFloat(4, get_pcvar_float(cvar_nemdamage))
		return HAM_IGNORED;
	}
	
	// Last human or swarm round or plague round
	if (g_swarmround || g_plagueround || fnGetHumans() == 1)
		return HAM_IGNORED; // human is killed
	
	// Does human armor need to be reduced before infecting?
	if (get_pcvar_num(cvar_humanarmor))
	{
		// Get victim armor
		static Float:armor
		pev(victim, pev_armorvalue, armor)
		
		// Block the attack if he has some
		if (armor > 0.0)
		{
			engfunc(EngFunc_EmitSound, victim, CHAN_BODY, sound_armorhit, 1.0, ATTN_NORM, 0, PITCH_NORM)
			set_pev(victim, pev_armorvalue, floatmax(0.0, armor - damage))
			return HAM_SUPERCEDE;
		}
	}
	
	// Infection allowed
	SendDeathMsg(attacker, victim) // send death notice
	FixDeadAttrib(victim) // fix the "dead" attrib on scoreboard
	UpdateFrags(attacker, victim, get_pcvar_num(cvar_fragsinfect), 1, 1) // add corresponding frags and deaths
	
	zombieme(victim, attacker, 0, 0) // turn into zombie
	g_exp[attacker] += get_pcvar_num(cvar_ammoinfect) // ammo packs given to zombie for infection
	fm_set_user_health(attacker, pev(attacker, pev_health)+get_pcvar_num(cvar_zombiebonushp)) // attacker gets bonus HP for the infection
	
	return HAM_SUPERCEDE;
}

// Ham Trace Attack Forward
public fw_TraceAttack(victim, attacker, Float:damage, Float:direction[3], tracehandle, damage_type)
{
	// Non-player damage or self damage
	if (victim == attacker || !is_user_connected(attacker))
		return HAM_IGNORED;
	
	// New round starting or round ended
	if (g_newround || g_endround)
		return HAM_SUPERCEDE;
	
	// Victim shouldn't take damage or victim is frozen
	if (g_nodamage[victim])
		return HAM_SUPERCEDE;
	
	// Prevent friendly fire
	if (g_zombie[attacker] == g_zombie[victim])
		return HAM_SUPERCEDE;
	
	// Victim isn't a normal zombie
	if (!g_zombie[victim] || g_nemesis[victim])
		return HAM_IGNORED;
	
	// Get custom hitzones setting
	static hitzones
	hitzones = get_pcvar_num(cvar_hitzones)
	
	// Check if we hit an allowed one
	if (hitzones && !(hitzones & (1<<get_tr2(tracehandle, TR_iHitgroup))))
		return HAM_SUPERCEDE;
	
	// Knockback disabled or not bullet damage
	if (!(damage_type & DMG_BULLET) || !get_pcvar_num(cvar_knockback))
		return HAM_IGNORED;
	
	// Get victim flags and knockback while ducking setting
	static victimflags, Float:knockduck
	victimflags = pev(victim, pev_flags)
	knockduck = get_pcvar_float(cvar_knockbackducking)
	
	// Zombie is ducking on ground
	if (knockduck == 0.0 && (victimflags & FL_DUCKING) && (victimflags & FL_ONGROUND))
		return HAM_IGNORED;
	
	// Get distance between players
	static Float:origin1F[3], Float:origin2F[3]
	pev(victim, pev_origin, origin1F)
	pev(attacker, pev_origin, origin2F)
	
	// Max distance exceeded
	if (get_distance_f(origin1F, origin2F) > get_pcvar_float(cvar_knockbackdist))
		return HAM_IGNORED;
	
	// Get victim's velocity
	static Float:velocity[3]
	pev(victim, pev_velocity, velocity)
	
	// Use damage on knockback calculation
	if (get_pcvar_num(cvar_knockbackdamage))
		xs_vec_mul_scalar(direction, damage, direction)
	
	// Use weapon power on knockback calculation
	if (kb_weapon_power[g_currentweapon[attacker]] > 0.0 && get_pcvar_num(cvar_knockbackpower))
		xs_vec_mul_scalar(direction, kb_weapon_power[g_currentweapon[attacker]], direction)
	
	// Apply ducking knockback multiplier
	if ((victimflags & FL_DUCKING) && (victimflags & FL_ONGROUND))
		xs_vec_mul_scalar(direction, knockduck, direction)
	
	// Apply zombie class knockback multiplier
	xs_vec_mul_scalar(direction, g_zclass_kb[g_zombieclass[victim]], direction)
	
	// Add up the new vector
	xs_vec_add(velocity, direction, direction)
	
	// Should knockback also affect vertical velocity?
	if (!get_pcvar_num(cvar_knockbackzvel))
		direction[2] = velocity[2]
	
	// Set the knockback'd victim's velocity
	set_pev(victim, pev_velocity, direction)
	
	return HAM_IGNORED;
}

// Ham Use Stationary Gun Forward
public fw_UseStationary(entity, caller, activator, use_type)
{
	// Not a player
	if (!is_user_connected(caller))
		return HAM_IGNORED;
	
	// Prevent zombies from using stationary guns
	if (use_type == USE_USING && g_zombie[caller])
		return HAM_SUPERCEDE;
	
	// Someone stopped using a stationary gun
	if (use_type == USE_STOPPED)
		set_task(0.1, "replace_models", caller) // replace weapon models (bugfix)
	
	return HAM_IGNORED;
}

// Ham Use Pushable Forward
public fw_UsePushable()
{
	// Prevent speed bug with pushables?
	if (get_pcvar_num(cvar_blockpushables))
		return HAM_SUPERCEDE;
	
	return HAM_IGNORED;
}

// Ham Weapon Touch Forward
public fw_TouchWeapon(weapon, id)
{
	// Not a player
	if (!is_user_connected(id))
		return HAM_IGNORED;
	
	// Dont pickup weapons if zombie or survivor (+PODBot MM fix)
	if (g_zombie[id] || (g_survivor[id] && !is_user_bot(id)))
		return HAM_SUPERCEDE;
	
	return HAM_IGNORED;
}

// Ham Weapon Pickup Forward
public fw_AddPlayerItem(id, weapon_ent)
{
	// Retrieve our custom extra ammo from the weapon
	static extra_ammo
	extra_ammo = pev(weapon_ent, PEV_ADDITIONAL_AMMO)
	
	// If present, add to player's bpammo (dont exceed max capacity though)
	if (extra_ammo)
	{
		static wname[32], weapon
		pev(weapon_ent, pev_classname, wname, sizeof wname - 1)
		weapon = get_weaponid(wname)
		
		fm_set_user_bpammo(id, weapon, min(fm_get_user_bpammo(id, weapon)+extra_ammo, MAXBPAMMO[weapon]))
		set_pev(weapon_ent, PEV_ADDITIONAL_AMMO, 0)
	}
}

// Client Kill Forward
public fw_ClientKill()
{
	// Prevent players from killing themselves?
	if (get_pcvar_num(cvar_blocksuicide))
		return FMRES_SUPERCEDE;
	
	return FMRES_IGNORED;
}

// Emit Sound Forward
public fw_EmitSound(id, channel, const sample[], Float:volume, Float:attn, flags, pitch)
{
	// Replace these sounds for zombies only
	if (!is_user_connected(id) || !g_zombie[id])
		return FMRES_IGNORED;
	
	// Zombie being hit
	if (equal(sample[7], "bhit", 4))
	{
		if (g_nemesis[id])
			engfunc(EngFunc_EmitSound, id, channel, nemesis_pain[random_num(0, sizeof nemesis_pain - 1)], volume, attn, flags, pitch)
		else
			engfunc(EngFunc_EmitSound, id, channel, zombie_pain[random_num(0, sizeof zombie_pain - 1)], volume, attn, flags, pitch)
		return FMRES_SUPERCEDE;
	}
	
	// Zombie attacks with knife
	if (equal(sample[8], "kni", 3))
	{
		if (equal(sample[14], "sla", 3)) // slash
		{
			engfunc(EngFunc_EmitSound, id, channel, zombie_miss_slash[random_num(0, sizeof zombie_miss_slash - 1)], volume, attn, flags, pitch)
			return FMRES_SUPERCEDE;
		}
		if (equal(sample[14], "hit", 3))
		{
			if (sample[17] == 'w') // wall
			{
				engfunc(EngFunc_EmitSound, id, channel, zombie_miss_wall[random_num(0, sizeof zombie_miss_wall - 1)], volume, attn, flags, pitch)
				return FMRES_SUPERCEDE;
			}
			else // hit
			{
				engfunc(EngFunc_EmitSound, id, channel, zombie_hit_normal[random_num(0, sizeof zombie_hit_normal - 1)], volume, attn, flags, pitch)
				return FMRES_SUPERCEDE;
			}
		}
		if (equal(sample[14], "sta", 3)) // stab
		{
			engfunc(EngFunc_EmitSound, id, channel, zombie_hit_stab[random_num(0, sizeof zombie_hit_stab - 1)], volume, attn, flags, pitch)
			return FMRES_SUPERCEDE;
		}
	}
	
	// Zombie dies
	if (equal(sample[7], "die", 3) || equal(sample[7], "dea", 3))
	{
		engfunc(EngFunc_EmitSound, id, channel, zombie_die[random_num(0, sizeof zombie_die - 1)], volume, attn, flags, pitch)
		return FMRES_SUPERCEDE;
	}
	
	// Zombie falls off
	if (equal(sample[10], "fall", 4))
	{
		engfunc(EngFunc_EmitSound, id, channel, zombie_fall[random_num(0, sizeof zombie_fall - 1)], volume, attn, flags, pitch)
		return FMRES_SUPERCEDE;
	}
	
	return FMRES_IGNORED;
}

#if !defined HANDLE_MODELS_ON_SEPARATE_ENT
// Forward Set ClientKey Value -prevent CS from changing player models-
public fw_SetClientKeyValue(id, const infobuffer[], const key[])
{
	// Block CS model changes
	if (equal(key, "model"))
		return FMRES_SUPERCEDE;
	
	return FMRES_IGNORED;
}

// Forward Client User Info Changed -prevent players from changing models-
public fw_ClientUserInfoChanged(id)
{
	// Get current model
	static currentmodel[32]
	fm_get_user_model(id, currentmodel, sizeof currentmodel - 1)
	
	// If they're different, set model again
	if (!equal(currentmodel, g_playermodel[id]) && !task_exists(id+TASK_MODEL))
		fm_set_user_model(id+TASK_MODEL)
}
#endif

// Forward Get Game Description
public fw_GetGameDescription()
{
	// Return the mod name so it can be easily identified
	forward_return(FMV_STRING, g_modname)
	
	return FMRES_SUPERCEDE;
}

// Forward CmdStart
public fw_CmdStart(id, handle)
{
	// Check if it's a flashlight impulse
	if (get_uc(handle, UC_Impulse) != IMPULSE_FLASHLIGHT)
		return;
	
	// Not alive
	if (!is_user_alive(id))
		return;
	
	// Block it for zombies, survivor (and override it for humans when custom flashlight is on)
	if (g_zombie[id] || g_survivor[id] || (!g_zombie[id] && get_pcvar_num(cvar_cflash)))
	{
		// Human's custom flashlight should be turned on instead
		if (!g_zombie[id] && !g_survivor[id] && get_gametime() - g_lastflashtime[id] > 1.1)
		{
			// Prevent turning the flashlight on/off too quickly (bugfix)
			g_lastflashtime[id] = get_gametime()
			
			// Turn custom flashlight on/off
			g_flashlight[id] = !(g_flashlight[id])
			
			// Set the flashlight charge task
			remove_task(id+TASK_CHARGE)
			set_task(1.0, "flashlight_charge", id+TASK_CHARGE, _, _, "b")
			
			// 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()
			
			// Turn off original flashlight if active
			set_pev(id, pev_effects, pev(id, pev_effects) & ~EF_DIMLIGHT)
			
			// Play flashlight toggle sound
			engfunc(EngFunc_EmitSound, id, CHAN_ITEM, sound_flashlight, 1.0, ATTN_NORM, 0, PITCH_NORM)
			
			// Finally call our custom flashlight task
			remove_task(id+TASK_FLASH)
			set_task(0.1, "set_user_flashlight", id+TASK_FLASH, _, _, "b")
		}
		
		// Block the impulse
		set_uc(handle, UC_Impulse, 0)
	}
}

// Forward Set Model
public fw_SetModel(entity, const model[])
{
	// Get remove dropped weapons setting
	static Float:removeweapons
	removeweapons = get_pcvar_float(cvar_removedropped)
	
	// Remove weapons?
	if (removeweapons > 0.0)
	{
		// Get entity's classname
		static class[10]
		pev(entity, pev_classname, class, sizeof class - 1)
		
		// Check if it's a weapon box
		if (equal(class, "weaponbox"))
		{
			// They get automatically removed when thinking
			set_pev(entity, pev_nextthink, get_gametime() + removeweapons)
			return;
		}
	}
	
	// Get damage time of grenade
	static Float:dmgtime
	pev(entity, pev_dmgtime, dmgtime)
	
	// Grenade not yet thrown
	if (dmgtime == 0.0)
		return;
	
	if (equal(model[7], "w_he", 4))
	{
		if (g_zombie[pev(entity, pev_owner)]) // [ZOMBIE] - Infection Grenade
		{
			// Give it a glow
			fm_set_rendering(entity, kRenderFxGlowShell, 0, 200, 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(0) // r
			write_byte(200) // g
			write_byte(0) // b
			write_byte(200) // brightness
			message_end()
			
			// Set grenade type on the thrown grenade entity
			set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_INFECTION)
		}
		else if (get_pcvar_num(cvar_firegrenades)) // [HUMAN] - Fire Grenade
		{
			// 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 grenade type on the thrown grenade entity
			set_pev(entity, PEV_NADE_TYPE, NADE_TYPE_NAPALM)
		}
	}
	else if (equal(model[7], "w_fl", 4) && get_pcvar_num(cvar_frostgrenades)) // Frost Grenade
	{
		// Give it a glow
		fm_set_rendering(entity, kRenderFxGlowShell, 0, 100, 200, 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(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)
	}
	else if (equal(model[7], "w_sm", 4) && get_pcvar_num(cvar_flaregrenades)) // Flare
	{
		// Make the flare 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)
	}
}

// Ham Grenade Think Forward
public fw_ThinkGrenade(entity)
{
	// Invalid entity
	if (!pev_valid(entity)) return FMRES_IGNORED;
	
	// Get damage time of grenade
	static Float:dmgtime
	pev(entity, pev_dmgtime, dmgtime)
	
	// Check if it's time to go off
	if (dmgtime > get_gametime())
		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)
		}
		case NADE_TYPE_NAPALM: // Napalm Grenade
		{
			fire_explode(entity)
		}
		case NADE_TYPE_FROST: // Frost Grenade
		{
			frost_explode(entity)
		}
		case NADE_TYPE_FLARE: // Flare
		{			
			// Light up when it's stopped on ground
			if ((pev(entity, pev_flags) & FL_ONGROUND) && fm_get_speed(entity) < 10)
			{
				// Flare sound
				engfunc(EngFunc_EmitSound, entity, CHAN_WEAPON, grenade_flare[random_num(0, sizeof grenade_flare - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
				
				// Our task params
				static params[5]
				params[0] = entity // entity id
				params[1] = get_pcvar_num(cvar_flareduration)/5 // duration
				
				// Retrieve flare color from entity
				pev(entity, PEV_FLARE_COLOR, params[2]) // params[2] r - params[3] g - params[4] b
				
				// Call our lighting task
				set_task(0.1, "flare_lighting", TASK_NADES, params, sizeof params)
			}
			else
			{
				// Delay the explosion until we hit ground
				set_pev(entity, pev_dmgtime, get_gametime() + 0.5)
				return HAM_IGNORED;
			}
		}
		default: return HAM_IGNORED;
	}
	
	return HAM_SUPERCEDE;
}

// Forward Player PreThink
public fw_PlayerPreThink(id)
{
	// Not alive
	if (!is_user_alive(id))
		return;
	
	// Silent footsteps for zombies?
	if (g_zombie[id] && !g_nemesis[id] && get_pcvar_num(cvar_zombiesilent))
		set_pev(id, pev_flTimeStepSound, STEPTIME_SILENT)
	
	// Set Player MaxSpeed
	if (g_frozen[id])
	{
		set_pev(id, pev_velocity, Float:{0.0,0.0,0.0}) // stop motion
		set_pev(id, pev_maxspeed, 1.0) // prevent from moving
	}
	else if (!g_freezetime)
	{
		if (g_zombie[id])
		{
			if (g_nemesis[id])
				set_pev(id, pev_maxspeed, get_pcvar_float(cvar_nemspd))
			else
				set_pev(id, pev_maxspeed, float(g_zclass_spd[g_zombieclass[id]]))
		}
		else
		{
			if (g_survivor[id])
				set_pev(id, pev_maxspeed, get_pcvar_float(cvar_survspd))
			else
				set_pev(id, pev_maxspeed, get_pcvar_float(cvar_humanspd))
		}
	}
	
	// Should Leap?
	if (allowed_leap(id))
	{
		// Get force and height cvars
		static force, height, Float:velocity[3]
		force = g_survivor[id] ? get_pcvar_num(cvar_leapsurvivorforce) : g_nemesis[id] ? get_pcvar_num(cvar_leapnemesisforce) : get_pcvar_num(cvar_leapzombiesforce)
		height = g_survivor[id] ? get_pcvar_num(cvar_leapsurvivorheight) : g_nemesis[id] ? get_pcvar_num(cvar_leapnemesisheight) : get_pcvar_num(cvar_leapzombiesheight)
		
		// Make velocity vector
		velocity_by_aim(id, force, velocity)
		
		// Set custom height
		velocity[2] = float(height)
		
		// Apply the new velocity
		set_pev(id, pev_velocity, velocity)
		
		// Set the current leap time
		g_lastleaptime[id] = get_gametime()
	}
	
	// Should be Pain Shock Free?
	if (allowed_painshockfree(id))
	{
		// Remember his velocity
		pev(id, pev_velocity, g_velocity[id])
		g_restorevel[id] = true
	}
}

// Forward Player PreThink Post
public fw_PlayerPreThink_Post(id)
{
	// Pain Shock Free: need to restore velocity?
	if (!g_restorevel[id])
		return FMRES_IGNORED;
	
	g_restorevel[id] = false
	
	// Not alive
	if (!is_user_alive(id))
		return FMRES_IGNORED;
	
	// Driving a vehicle
	if (pev(id, pev_flags) & FL_ONTRAIN)
		return FMRES_IGNORED;
	
	// NOTE: within DLL PlayerPreThink Jump() function is called;
	// there is a conveyor velocity addiction we should care of
	static groundent
	groundent = pev(id, pev_groundentity)
	
	if (pev_valid(groundent) && (pev(groundent, pev_flags) & FL_CONVEYOR))
	{
		// Add pev_basevelocity to our stored velocity
		static Float:tempvel[3]
		pev(id, pev_basevelocity, tempvel)
		xs_vec_add(g_velocity[id], tempvel, g_velocity[id])
	}
	
	// Restore previous velocity
	set_pev(id, pev_velocity, g_velocity[id])
	return FMRES_HANDLED;
}

/*================================================================================
 [Client Commands]
=================================================================================*/

// Say "/zpmenu"
public clcmd_saymenu(id)
{
	show_menu_game(id) // show game menu
}

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

// Nightvision toggle
public clcmd_nightvision(id)
{
	if (g_nvision[id])
	{
		// Enable-disable
		g_nvisionenabled[id] = !(g_nvisionenabled[id])
		
		// Custom nvg?
		if (get_pcvar_num(cvar_cnvg))
		{
			remove_task(id+TASK_NVISION);
			set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
		}
		else
			set_user_gnvision(id, g_nvisionenabled[id])
	}
	
	return PLUGIN_HANDLED;
}

// Weapon Drop
public clcmd_drop(id)
{
	// Survivor should stick with MP5NAVY
	if (g_survivor[id])
		return PLUGIN_HANDLED;
	
	return PLUGIN_CONTINUE;
}

// Buy BP Ammo
public clcmd_buyammo(id)
{
	// Not alive or infinite ammo setting enabled
	if (get_pcvar_num(cvar_infammo) || !is_user_alive(id))
		return PLUGIN_HANDLED;
	
	// Not human
	if (g_zombie[id])
	{
		zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_HUMAN_ONLY")
		return PLUGIN_HANDLED;
	}
	
	// Not enough ammo packs
	if (g_exp[id] < 1)
	{
		zp_colored_print(id, "^x04[ZW]^x01 %L", id, "NOT_ENOUGH_AMMO")
		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]
		
		// Primary and secondary only
		if (MAXBPAMMO[weaponid] > 2)
		{
			// Get current ammo of the weapon
			currentammo = fm_get_user_bpammo(id, weaponid)
			
			// Check if we are close to the BP ammo limit
			if (currentammo < MAXBPAMMO[weaponid]-BUYAMMO[weaponid])
			{
				// Flash ammo in hud
				message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
				write_byte(AMMOID[weaponid]) // ammo id
				write_byte(BUYAMMO[weaponid]) // ammo amount
				message_end()
				
				// Increase BP ammo
				fm_set_user_bpammo(id, weaponid, currentammo + BUYAMMO[weaponid])
				
				refilled = true
			}
			else if (currentammo < MAXBPAMMO[weaponid])
			{
				// Flash ammo in hud
				message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
				write_byte(AMMOID[weaponid]) // ammo id
				write_byte(MAXBPAMMO[weaponid]-currentammo) // ammo amount
				message_end()
				
				// Reached the limit
				fm_set_user_bpammo(id, weaponid, MAXBPAMMO[weaponid])
				
				refilled = true
			}
		}
	}
	
	// Weapons already have full ammo
	if (!refilled) return PLUGIN_HANDLED;
	
	// Deduce ammo packs, play clip purchase sound, and notify the player
	g_exp[id]--
	engfunc(EngFunc_EmitSound, id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
	zp_colored_print(id, "^x04[ZW]^x01 %L", id, "AMMO_BOUGHT")
	
	return PLUGIN_HANDLED;
}

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

/*================================================================================
 [Menus]
=================================================================================*/

// Game Menu
show_menu_game(id)
{
	static menu[250], len
	len = 0
	
	// Title
	len += formatex(menu[len], sizeof menu - 1 - len, "\y%s^n^n", g_modname)
	
	// 1. Buy weapons
	if (get_pcvar_num(cvar_buycustom))
		len += formatex(menu[len], sizeof menu - 1 - len, "\r1.\w %L^n", id, "MENU_BUY")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d1. %L^n", id, "MENU_BUY")
	
	// 2. Extra items
	if (!g_survivor[id] && !g_nemesis[id] && get_pcvar_num(cvar_extraitems) && is_user_alive(id))
		len += formatex(menu[len], sizeof menu - 1 - len, "\r2.\w %L^n", id, "MENU_EXTRABUY")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d2. %L^n", id, "MENU_EXTRABUY")
	
	// 3. Zombie class
	if (get_pcvar_num(cvar_zclasses))
		len += formatex(menu[len], sizeof menu - 1 - len, "\r3.\w %L^n", id,"MENU_ZCLASS")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d3. %L^n", id,"MENU_ZCLASS")
	
	// 4. Unstuck
	if (is_user_alive(id))
		len += formatex(menu[len], sizeof menu - 1 - len, "\r4.\w %L^n", id, "MENU_UNSTUCK")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d4. %L^n", id, "MENU_UNSTUCK")
	
	// 5-6. Help and join spec
	len += formatex(menu[len], sizeof menu - 1 - len, "\r5.\w %L^n^n\r6.\w %L^n^n", id, "MENU_INFO", id, "MENU_SPECTATOR")
	
	// 9. Admin menu
	if (get_user_flags(id) & ACCESS_FLAG)
		len += formatex(menu[len], sizeof menu - 1 - len, "\r9.\w %L", id, "MENU_ADMIN")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d9. %L", id, "MENU_ADMIN")
	
	// 0. Exit
	len += formatex(menu[len], sizeof menu - 1 - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
	
	show_menu(id, KEYSMENU, menu, -1, "Game Menu")
}

// Buy Menu 1
public show_menu_buy1(taskid)
{
	// Get player id
	static id
	(taskid > g_maxplayers) ? (id = ID_SPAWN) : (id = taskid);
	
	// Zombies or survivors get no guns
	if (g_zombie[id] || g_survivor[id] || !is_user_alive(id))
		return;
	
	// Bots pick their weapons randomly
	if (is_user_bot(id))
	{
		buy_primary_weapon(id, random_num(0, sizeof g_primary_items - 1))
		menu_buy2(id, random_num(0, sizeof g_secondary_items - 1))
		return;
	}
	
	// Automatic selection enabled for player and menu called on spawn event
	if (WPN_AUTO_ON && taskid > g_maxplayers)
	{
		buy_primary_weapon(id, WPN_AUTO_PRI)
		menu_buy2(id, WPN_AUTO_SEC)
		return;
	}
	
	static menu[999], len, weap
	len = 0
	
	// Title
	len += formatex(menu[len], sizeof menu - 1 - len, "\w Armas Primarias \w[%d-%d]^n^n", WPN_STARTID+1, min(WPN_STARTID+7, WPN_MAXIDS))
	
	// 1-7. Weapon List
	for (weap = WPN_STARTID; weap < min(WPN_STARTID+7, WPN_MAXIDS); weap++)
		if(Lvl[id] >= lvlarmas[weap])
			len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %s^n", weap-WPN_STARTID+1, WEAPONNAMES[get_weaponid(g_primary_items[weap])])
		else
			len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\d %s\d [\rMin Level: %d\d]^n", weap-WPN_STARTID+1, WEAPONNAMES[get_weaponid(g_primary_items[weap])], lvlarmas[weap])  
		
	
	// 8. Auto Select
	len += formatex(menu[len], sizeof menu - 1 - len, "^n\r8.\w %L \r[%L]", id, "MENU_AUTOSELECT", id, (WPN_AUTO_ON) ? "MOTD_ENABLED" : "MOTD_DISABLED")
	
	// 9. Next/Back - 0. Salir
	len += formatex(menu[len], sizeof menu - 1 - len, "^n^n\r9.\w %L/%L^n^n\r0.\w %L", id, "MENU_NEXT", id, "MENU_BACK", id, "MENU_EXIT")
	
	show_menu(id, KEYSMENU, menu, -1, "Buy Menu 1")
}

// Buy Menu 2
show_menu_buy2(id)
{
	static menu[350], len, weap
	len = 0
	
	// Title
	len += formatex(menu[len], sizeof menu - 1 - len, "\w Armas Secundarias^n")
	
	// 1-6. Weapon List
	for (weap = 0; weap < sizeof g_secondary_items; weap++) 
		if(Lvl[id] >= lvlarmas2[weap]) 
			len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %s^n", weap+1, WEAPONNAMES[get_weaponid(g_secondary_items[weap])], lvlarmas2[weap]) 
		else 
			len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\d %s\r [Min Lvl: %d]^n", weap+1, WEAPONNAMES[get_weaponid(g_secondary_items[weap])], lvlarmas2[weap]) 
		
	
	// 8. Auto Select
	len += formatex(menu[len], sizeof menu - 1 - len, "^n^n\r8.\w %L \r[%L]", id, "MENU_AUTOSELECT", id, (WPN_AUTO_ON) ? "MOTD_ENABLED" : "MOTD_DISABLED")
	
	// 0. Exit
	len += formatex(menu[len], sizeof menu - 1 - len, "^n^n\r0.\w %L", id, "MENU_EXIT")
	
	show_menu(id, KEYSMENU, menu, -1, "Buy Menu 2")
}

// Extra Items Menu
show_menu_extras(id)
{
	static menu[400], len, item
	len = 0
	
	// Title
	len += formatex(menu[len], sizeof menu - 1 - len, "\y%L [%L] \r[%d-%d]^n^n", id, "MENU_EXTRA_TITLE", id, (g_zombie[id]) ? "CLASS_ZOMBIE" : "CLASS_HUMAN", EXTRAS_STARTID+1, min(EXTRAS_STARTID+7, g_extraitem_i))
	
	// 1-7. Item List
	for (item = EXTRAS_STARTID; item < min(EXTRAS_STARTID+7, g_extraitem_i); item++)
	{
		// Unavailable item
		if ((g_zombie[id] && g_extraitem_team[item] == ZP_TEAM_HUMAN) || (!g_zombie[id] && g_extraitem_team[item] == ZP_TEAM_ZOMBIE) || (item == EXTRA_NVISION && !get_pcvar_num(cvar_extranvision)) || (item == EXTRA_ANTIDOTE && !get_pcvar_num(cvar_extraantidote)) || (item == EXTRA_MADNESS && !get_pcvar_num(cvar_extramadness))
		|| (item == EXTRA_INFBOMB && (!get_pcvar_num(cvar_extrainfbomb) || g_infbombcounter >= get_pcvar_num(cvar_infbomblimit))) || (item >= EXTRA_WEAPONS_STARTID && item <= EXTRAS_CUSTOM_STARTID-1 && !get_pcvar_num(cvar_extraweapons)))
		{
			// Check if it's one of the hardcoded items and set the correct caption
			switch (item)
			{
				case EXTRA_NVISION: len += formatex(menu[len], sizeof menu - 1 - len, "\d%d %L", item-EXTRAS_STARTID+1, id, "MENU_EXTRA1")
				case EXTRA_ANTIDOTE: len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. %L", item-EXTRAS_STARTID+1, id, "MENU_EXTRA2")
				case EXTRA_MADNESS: len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. %L", item-EXTRAS_STARTID+1, id, "MENU_EXTRA3")
				case EXTRA_INFBOMB: len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. %L", item-EXTRAS_STARTID+1, id, "MENU_EXTRA4")
				default: len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. %s", item-EXTRAS_STARTID+1, g_extraitem_name[item])
			}
			// Item Cost
			len += formatex(menu[len], sizeof menu - 1 - len, " %d %L^n", g_extraitem_cost[item], id, "AMMO_PACKS2")
		}
		else
		{
			// Check if it's one of the hardcoded items and set the correct caption
			switch (item)
			{
				case EXTRA_NVISION: len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %L", item-EXTRAS_STARTID+1, id, "MENU_EXTRA1")
				case EXTRA_ANTIDOTE: len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %L", item-EXTRAS_STARTID+1, id, "MENU_EXTRA2")
				case EXTRA_MADNESS: len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %L", item-EXTRAS_STARTID+1, id, "MENU_EXTRA3")
				case EXTRA_INFBOMB: len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %L", item-EXTRAS_STARTID+1, id, "MENU_EXTRA4")
				default: len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %s", item-EXTRAS_STARTID+1, g_extraitem_name[item])
			}
			// Item Cost
			len += formatex(menu[len], sizeof menu - 1 - len, " \y%d %L^n", g_extraitem_cost[item], id, "AMMO_PACKS2")
		}
	}
	
	// 8. Back - 9. Next - 0. Exit
	len += formatex(menu[len], sizeof menu - 1 - len, "^n\r8.\w %L^n\r9.\w %L^n^n\r0.\w %L", id, "MENU_BACK", id, "MENU_NEXT", id, "MENU_EXIT")
	
	show_menu(id, KEYSMENU, menu, -1, "Extra Items")
}

// Zombie Class Menu
public show_menu_zclass(id)
{
	// Player disconnected
	if (!is_user_connected(id))
		return;
	
	// Bots pick their zombie class randomly
	if (is_user_bot(id))
	{
		g_zombieclassnext[id] = random_num(0, g_zclass_i - 1)
		return;
	}
	
	static menu[1000], len, class
	len = 0
	
	// Title
	len += formatex(menu[len], sizeof menu - 1 - len, "\y%L \r[%d-%d]^n^n", id, "MENU_ZCLASS_TITLE", ZCLASSES_STARTID+1, min(ZCLASSES_STARTID+7, g_zclass_i))
	
        // 1-7. Class List
        for (class = ZCLASSES_STARTID; class < min(ZCLASSES_STARTID+7, g_zclass_i); class++)
        {
        if (Lvl[id] >= g_zclass_lvl[class])
        {
            if (class == g_zombieclassnext[id])
                len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. %s %s^n", class-ZCLASSES_STARTID+1, g_zclass_name[class], g_zclass_info[class])
            else
                len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %s\y %s^n", class-ZCLASSES_STARTID+1, g_zclass_name[class], g_zclass_info[class])
        }
        else
            len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\d %s %s\r [Nivel Requerido: %d]^n", class-ZCLASSES_STARTID+1, g_zclass_name[class], g_zclass_info[class], g_zclass_lvl[class])
        }  
	// 8. Back - 9. Next - 0. Exit
	len += formatex(menu[len], sizeof menu - 1 - len, "^n\r8.\w %L^n\r9.\w %L^n^n\r0.\w %L", id, "MENU_BACK", id, "MENU_NEXT", id, "MENU_EXIT")
	
	show_menu(id, KEYSMENU, menu, -1, "Zombie Class Menu")
}

// Help Menu
public show_menu_info(id)
{
	// Player disconnected
	if (!is_user_connected(id))
		return;
	
	static menu[150]
	
	formatex(menu, sizeof menu - 1, "\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")
	show_menu(id, KEYSMENU, menu, -1, "Mod Info")
}

// Admin Menu
show_menu_admin(id)
{
	static menu[250], len
	len = 0
	
	// Title
	len += formatex(menu[len], sizeof menu - 1 - len, "\y%L^n^n", id, "MENU_ADMIN_TITLE")
	
	// 1. Zombiefy/Humanize command
	if (!g_endround && !g_swarmround && !g_nemround && !g_survround && !g_plagueround && !task_exists(TASK_WELCOMEMSG))
		len += formatex(menu[len], sizeof menu - 1 - len, "\r1.\w %L^n", id, "MENU_ADMIN1")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d1. %L^n", id, "MENU_ADMIN1")
	
	// 2. Nemesis command
	if (g_newround && !g_endround && get_pcvar_num(cvar_nem) && !task_exists(TASK_WELCOMEMSG))
		len += formatex(menu[len], sizeof menu - 1 - len, "\r2.\w %L^n", id, "MENU_ADMIN2")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d2. %L^n", id, "MENU_ADMIN2")
	
	// 3. Survivor command
	if (g_newround && !g_endround && get_pcvar_num(cvar_surv) && !task_exists(TASK_WELCOMEMSG))
		len += formatex(menu[len], sizeof menu - 1 - len, "\r3.\w %L^n", id, "MENU_ADMIN3")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d3. %L^n", id, "MENU_ADMIN3")
	
	// 4. Respawn command
	if (!g_endround && !g_survround && !g_swarmround && !g_nemround && !g_plagueround)
		len += formatex(menu[len], sizeof menu - 1 - len, "\r4.\w %L^n", id, "MENU_ADMIN4")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d4. %L^n", id, "MENU_ADMIN4")
	
	// 5. Swarm mode command
	if (allowed_swarm())
		len += formatex(menu[len], sizeof menu - 1 - len, "\r5.\w %L^n", id, "MENU_ADMIN5")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d5. %L^n", id, "MENU_ADMIN5")
	
	// 6. Multi infection command
	if (allowed_multi())
		len += formatex(menu[len], sizeof menu - 1 - len, "\r6.\w %L^n", id, "MENU_ADMIN6")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d6. %L^n", id, "MENU_ADMIN6")
	
	// 7. Plague mode command
	if (allowed_plague())
		len += formatex(menu[len], sizeof menu - 1 - len, "\r7.\w %L^n", id, "MENU_ADMIN7")
	else
		len += formatex(menu[len], sizeof menu - 1 - len, "\d7. %L^n", id, "MENU_ADMIN7")
	
	// 0. Exit
	len += formatex(menu[len], sizeof menu - 1 - len, "^n\r0.\w %L", id, "MENU_EXIT")
	
	show_menu(id, KEYSMENU, menu, -1, "Admin Menu")
}

// Player List Menu
show_menu_player_list(id)
{
	static menu[400], len, player, name[32]
	len = 0
	
	// Title
	switch (PL_ACTION)
	{
		case 0: len += formatex(menu[len], sizeof menu - 1 - len, "\y%L ", id, "MENU_ADMIN1")
		case 1: len += formatex(menu[len], sizeof menu - 1 - len, "\y%L ", id, "MENU_ADMIN2")
		case 2: len += formatex(menu[len], sizeof menu - 1 - len, "\y%L ", id, "MENU_ADMIN3")
		case 3: len += formatex(menu[len], sizeof menu - 1 - len, "\y%L ", id, "MENU_ADMIN4")
	}
	len += formatex(menu[len], sizeof menu - 1 - len, "\r[%d-%d]^n^n", PL_STARTID+1, min(PL_STARTID+7, g_maxplayers))
	
	// 1-7. player list
	for (player = PL_STARTID+1; player <= min(PL_STARTID+7, g_maxplayers); player++)
	{
		if (is_user_connected(player)) // check if it's connected
		{
			// Get player's name
			get_user_name(player, name, sizeof name - 1)
			
			// Format text depending on the action to take
			switch (PL_ACTION)
			{
				case 0:
				{
					if (g_zombie[player])
					{
						if (allowed_human(player))
							len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %s \r[%L]^n", player-PL_STARTID, name, id, "CLASS_ZOMBIE")
						else
							len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. %s [%L]^n", player-PL_STARTID, name, id, "CLASS_ZOMBIE")
					}
					else
					{
						if (allowed_zombie(player))
							len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %s \y[%L]^n", player-PL_STARTID, name, id, "CLASS_HUMAN")
						else
							len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. %s [%L]^n", player-PL_STARTID, name, id, "CLASS_HUMAN")
					}
				}
				case 1:
				{
					if (allowed_nemesis(player))
						len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %s^n", player-PL_STARTID, name)
					else
						len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. %s^n", player-PL_STARTID, name)
				}
				case 2:
				{
					if (allowed_survivor(player))
						len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %s^n", player-PL_STARTID, name)
					else
						len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. %s^n", player-PL_STARTID, name)
				}
				case 3:
				{
					if (allowed_respawn(player))
						len += formatex(menu[len], sizeof menu - 1 - len, "\r%d.\w %s^n", player-PL_STARTID, name)
					else
						len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. %s^n", player-PL_STARTID, name)
				}
			}
		}
		else
		{
			len += formatex(menu[len], sizeof menu - 1 - len, "\d%d. -----^n", player-PL_STARTID)
		}
	}
	
	// 8. Back - 9. Next - 0. Exit
	len += formatex(menu[len], sizeof menu - 1 - len, "^n\r8.\w %L^n\r9.\w %L^n^n\r0.\w %L", id, "MENU_BACK", id, "MENU_NEXT", id, "MENU_EXIT")
	
	show_menu(id, KEYSMENU, menu, -1, "Player List Menu")
}

/*================================================================================
 [Menu Handlers]
=================================================================================*/

// Game Menu
public menu_game(id, key)
{
	switch (key)
	{
		case 0: // Buy Weapons
		{
			// Custom buy menus enabled?
			if (get_pcvar_num(cvar_buycustom))
			{
				// Disable the remember selection setting
				WPN_AUTO_ON = 0
				zp_colored_print(id, "^x04[ZW]^x01 %L", id ,"BUY_ENABLED")
				
				// Show menu if player hasn't yet bought anything
				if (g_canbuy[id]) show_menu_buy1(id)
			}
			else
				zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
		}
		case 1: // Extra Items
		{
			// Extra items enabled?
			if (get_pcvar_num(cvar_extraitems))
			{
				// Check whether the player is able to buy anything
				if (is_user_alive(id) && !g_survivor[id] && !g_nemesis[id])
					show_menu_extras(id)
				else
					zp_colored_print(id, "^x04[ZW]^x01 %L", id ,"CMD_NOT")
			}
			else
				zp_colored_print(id, "^x04[ZW]^x01 %L", id ,"CMD_NOT_EXTRAS")
		}
		case 2: // Zombie Classes
		{
			// Zombie classes enabled?
			if (get_pcvar_num(cvar_zclasses))
				show_menu_zclass(id)
			else
				zp_colored_print(id, "^x04[ZW]^x01 %L", id ,"CMD_NOT_ZCLASSES")
		}
		case 3: // Unstuck
		{
			// Check if player is stuck
			if (is_user_alive(id) && is_player_stuck(id))
			{
				// Spawn randomly / get back to base
				if (get_pcvar_num(cvar_randspawn))
					do_random_spawn(id)
				else
					dllfunc(DLLFunc_Spawn, id)
			}
			else
				zp_colored_print(id, "^x04[ZW]^x01 %L", id ,"CMD_NOT_STUCK")
		}
		case 4: // Help Menu
		{
			show_menu_info(id)
		}
		case 5: // Join Spectator
		{
			// If alive
			if (is_user_alive(id))
			{
				// Check that we still have both humans and zombies to keep the round going
				check_round(id)
				
				// Kill him before he switches team
				dllfunc(DLLFunc_ClientKill, id)
			}
			
			// Temporarily save player stats?
			if (get_pcvar_num(cvar_statssave)) save_stats(id)
			
			// Remove previous tasks
			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)
			
			// Then move him to the spectator team
			fm_set_user_team(id, CS_TEAM_SPECTATOR)
			fm_user_team_update(id)
		}
		case 8: // Admin Menu
		{
			// Check if player has the required access
			if (get_user_flags(id) & ACCESS_FLAG)
				show_menu_admin(id)
			else
				zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT_ACCESS")
		}
	}
	
	return PLUGIN_HANDLED;
}

// Buy Menu 1
public menu_buy1(id, key)
{
	// Zombies or survivors get no guns
	if (g_zombie[id] || g_survivor[id] || !is_user_alive(id))
		return PLUGIN_HANDLED;
	
	// Special keys / weapon list exceeded
	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 buy menu again
		show_menu_buy1(id)
		return PLUGIN_HANDLED;
	}
	
	// Store selected weapon id
	WPN_AUTO_PRI = WPN_SELECTION
	
	// Buy primary weapon
	buy_primary_weapon(id, WPN_AUTO_PRI)
	
	// Show pistols menu
	show_menu_buy2(id)
	
	return PLUGIN_HANDLED;
}

// Buy Primary Weapon
buy_primary_weapon(id, selection)
{
	// Get weapon index 
	static weaponid 
	weaponid = get_weaponid(g_primary_items[selection]) 
	
	static lvl 
	lvl = lvlarmas[selection] 
	
	if(Lvl[id] >= lvl) 
	{ 
		
		// 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")
		
		// Give the new weapon
		fm_give_item(id, g_primary_items[selection])
		fm_set_user_bpammo(id, weaponid, MAXBPAMMO[weaponid])
	
		// Pistol Menu
		show_menu_buy2(id)
		g_canbuy[id] = false
		//static i
		//for (i = 0; i < sizeof g_additional_items; i++)
			//fm_give_item(id, g_additional_items[i])
	}
	else
	{
		show_menu_buy1(id)
	}
	return PLUGIN_CONTINUE
}
// Buy Menu 2 
public menu_buy2(id, selection) 
{    
	new lvl = lvlarmas2[selection] 
	
	if(Lvl[id] >= lvl) 
	{ 
		
		// Zombies or survivors get no guns 
		if (g_zombie[id] || g_survivor[id] || !is_user_alive(id)) 
			return PLUGIN_HANDLED; 
		
		// Special keys / weapon list exceeded 
		if (selection >= sizeof g_secondary_items) 
		{ 
			// Toggle autoselect 
			if (selection == MENU_KEY_AUTOSELECT) 
				WPN_AUTO_ON = 1 - WPN_AUTO_ON 
			
			// Reshow menu unless user exited 
			if (selection != MENU_KEY_EXIT) 
				show_menu_buy2(id) 
			
			return PLUGIN_HANDLED; 
		} 
		
		// Store selected weapon 
		WPN_AUTO_SEC = selection 
		
		// Drop secondary gun again, in case we picked another (bugfix) 
		drop_weapons(id, 2) 
		
		// Get weapon index 
		static weaponid 
		weaponid = get_weaponid(g_secondary_items[selection]) 
		
		// Give the new weapon with full ammo 
		fm_give_item(id, g_secondary_items[selection]) 
		fm_set_user_bpammo(id, weaponid, MAXBPAMMO[weaponid]) 
		
		// Menu de bombas
		show_menu_granades(id)
	}
	else
	{
		show_menu_buy2(id)
	}
	return PLUGIN_HANDLED
}

// Extra Items Menu
public menu_extras(id, key)
{
	// Nemesis or Survivor shouldnt get extra items
	if (g_survivor[id] || g_nemesis[id] || !is_user_alive(id))
	{
		zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	// Special keys / items list exceeded
	if (key >= MENU_KEY_BACK || EXTRAS_SELECTION >= g_extraitem_i)
	{
		switch (key)
		{
			case MENU_KEY_BACK: // back
			{
				if (EXTRAS_STARTID-7 >= 0) EXTRAS_STARTID -= 7
			}
			case MENU_KEY_NEXT: // next
			{
				if (EXTRAS_STARTID+7 < g_extraitem_i) EXTRAS_STARTID += 7
			}
			case MENU_KEY_EXIT: // exit
			{
				return PLUGIN_HANDLED;
			}
		}
		
		// Show extra items menu again
		show_menu_extras(id)
		return PLUGIN_HANDLED;
	}
	
	// Try to buy the item
	buy_extra_item(id, EXTRAS_SELECTION);
	
	return PLUGIN_HANDLED;
}

// Buy Extra Item
buy_extra_item(id, itemid)
{
	// Check for human only items
	if (g_zombie[id] && g_extraitem_team[itemid] == ZP_TEAM_HUMAN)
	{
		zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_HUMAN_ONLY")
		return;
	}
	
	// Check for zombie only items
	if (!g_zombie[id] && g_extraitem_team[itemid] == ZP_TEAM_ZOMBIE)
	{
		zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_ZOMBIE_ONLY")
		return;
	}
	
	// Check for unavailable items
	if ((itemid == EXTRA_NVISION && !get_pcvar_num(cvar_extranvision)) || (itemid == EXTRA_ANTIDOTE && !get_pcvar_num(cvar_extraantidote)) || (itemid == EXTRA_MADNESS && !get_pcvar_num(cvar_extramadness)) || (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[ZW]^x01 %L", id, "CMD_NOT")
		return;
	}
	
	// Check for hard coded items with special conditions
	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[ZW]^x01 %L", id, "CMD_NOT_CANTUSE")
		return;
	}
	
	// Check that we have enough ammo packs
	if (g_exp[id] < g_extraitem_cost[itemid])
	{
		zp_colored_print(id, "^x04[ZW]^x01 %L", id, "NOT_ENOUGH_AMMO")
		return;
	}
	
	// Deduce item cost
	g_exp[id] -= g_extraitem_cost[itemid]
	
	// Check which kind of item we're buying
	switch (itemid)
	{
		case EXTRA_NVISION: // Night Vision
		{
			if (!is_user_bot(id))
			{
				g_nvision[id] = true
				g_nvisionenabled[id] = true
				
				// Custom nvg?
				if (get_pcvar_num(cvar_cnvg))
				{
					remove_task(id+TASK_NVISION)
					set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
				}
				else
					set_user_gnvision(id, 1)
			}
			else
				fm_set_bot_nvg(id, 1)
		}
		case EXTRA_ANTIDOTE: // Antidote
		{
			humanme(id, 0)
		}
		case EXTRA_MADNESS: // Zombie Madness
		{
			g_nodamage[id] = true
			zombie_aura(id+TASK_BLOOD)
			engfunc(EngFunc_EmitSound, id, CHAN_VOICE, zombie_madness[random_num(0, sizeof zombie_madness - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
			set_task(get_pcvar_float(cvar_madnessduration), "madness_over", id+TASK_BLOOD)
		}
		case EXTRA_INFBOMB: // Infection Bomb
		{
			// Increase infection bomb purchase count for this round
			g_infbombcounter++
			
			// Already own one
			if (user_has_weapon(id, CSW_HEGRENADE))
			{
				// Increase BP ammo on it instead
				fm_set_user_bpammo(id, CSW_HEGRENADE, fm_get_user_bpammo(id, CSW_HEGRENADE) + 1)
				
				// Flash ammo in hud
				message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
				write_byte(AMMOID[CSW_HEGRENADE]) // ammo id
				write_byte(1) // ammo amount
				message_end()
				
				// Play clip purchase sound
				engfunc(EngFunc_EmitSound, id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
				
				return; // stop here
			}
			
			// Give weapon to the player
			fm_give_item(id, "weapon_hegrenade")
		}
		case EXTRA_WEAPONS_STARTID .. EXTRAS_CUSTOM_STARTID-1: // Weapons
		{
			// Get weapon index
			static weaponid
			weaponid = get_weaponid(g_extra_items[itemid-4])
			
			// If we are giving a primary/secondary weapon
			if (MAXBPAMMO[weaponid] > 2)
			{
				// Make user drop the previous one
				if ((1<<weaponid) & PRIMARY_WEAPONS_BIT_SUM)
					drop_weapons(id, 1)
				else
					drop_weapons(id, 2)
				
				// Give full BP ammo for the new one
				fm_set_user_bpammo(id, weaponid, MAXBPAMMO[weaponid])
			}
			// If we are giving a grenade which the user already owns
			else if (user_has_weapon(id, weaponid))
			{
				// Increase BP ammo on it instead
				fm_set_user_bpammo(id, weaponid, fm_get_user_bpammo(id, weaponid) + 1)
				
				// Flash ammo in hud
				message_begin(MSG_ONE_UNRELIABLE, g_msgAmmoPickup, _, id)
				write_byte(AMMOID[weaponid]) // ammo id
				write_byte(1) // ammo amount
				message_end()
				
				// Play clip purchase sound
				engfunc(EngFunc_EmitSound, id, CHAN_ITEM, sound_buyammo, 1.0, ATTN_NORM, 0, PITCH_NORM)
				
				return; // stop here
			}
			
			// Give weapon to the player
			fm_give_item(id, g_extra_items[itemid-4])
		}
		default: // Custom additions
		{
			// Item selected forward
			ExecuteForward(g_fwExtraItemSelected, g_fwDummyResult, id, itemid);
		}
	}
}

// Zombie Class Menu
public menu_zclass(id, key)
{
	// Special keys / items list exceeded
	if (key >= MENU_KEY_BACK || ZCLASSES_SELECTION >= g_zclass_i)
	{
		switch (key)
		{
			case MENU_KEY_BACK: // back
			{
				if (ZCLASSES_STARTID-7 >= 0) ZCLASSES_STARTID -= 7
			}
			case MENU_KEY_NEXT: // next
			{
				if (ZCLASSES_STARTID+7 < g_zclass_i) ZCLASSES_STARTID += 7
			}
			case MENU_KEY_EXIT: // exit
			{
				return PLUGIN_HANDLED;
			}
		}
		
		// Show extra items menu again
		show_menu_zclass(id)
		return PLUGIN_HANDLED;
	}
	
        if (Lvl[id] >= g_zclass_lvl[ZCLASSES_SELECTION])
        {
        // Store selection for the next infection
        g_zombieclassnext[id] = ZCLASSES_SELECTION;
        
        // Show selected zombie class info and stats
    zp_colored_print(id, "^x04[ZW]^x01 %L: %s", id, "ZOMBIE_SELECT", g_zclass_name[g_zombieclassnext[id]])
    zp_colored_print(id, "^x04[ZW]^x01 %L: %d %L: %d %L: %d %L: %d%%", id, "ZOMBIE_ATTRIB1", g_zclass_hp[g_zombieclassnext[id]], id, "ZOMBIE_ATTRIB2", g_zclass_spd[g_zombieclassnext[id]],
    id, "ZOMBIE_ATTRIB3", floatround(g_zclass_grav[g_zombieclassnext[id]]*800), id, "ZOMBIE_ATTRIB4", floatround(g_zclass_kb[g_zombieclassnext[id]]*100))
    }
    else
    {
        zp_colored_print(id, "^x04[ZW]^x01 No Tienes Nivel Suficiente Para Elegir Esta Clase de Zombie. [Nivel Requerido: %d]", g_zclass_lvl[ZCLASSES_SELECTION])
        return PLUGIN_HANDLED;
    }
    
    return PLUGIN_HANDLED;
}

// Info Menu
public menu_info(id, key)
{
	static motd[1000], len
	len = 0
	
	switch (key)
	{
		case 0: // General
		{
			static weather, lights[2]
			weather = 0
			
			// Get light style
			get_pcvar_string(cvar_lighting, lights, sizeof lights - 1)
			strtolower(lights)
			
			len += formatex(motd[len], sizeof motd - 1 - len, "%L ", id, "MOTD_INFO11", "Zombie Fuerzas Especiales Aztecas", PLUGIN_VERSION, "Andreiita")
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO12")
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO1_A")
			
			#if defined AMBIENCE_FOG
			len += formatex(motd[len], sizeof motd - 1 - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_FOG")
			weather++
			#endif
			#if defined AMBIENCE_RAIN
			len += formatex(motd[len], sizeof motd - 1 - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_RAIN")
			weather++
			#endif
			#if defined AMBIENCE_SNOW
			len += formatex(motd[len], sizeof motd - 1 - len, (weather < 1) ? " %L" : ". %L", id, "MOTD_SNOW")
			weather++
			#endif
			if (weather < 1) len += formatex(motd[len], sizeof motd - 1 - len, " %L", id, "MOTD_DISABLED")
			
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO1_B", lights)
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO1_C", id, get_pcvar_num(cvar_triggered) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			if (lights[0] == 'a' && get_pcvar_num(cvar_thunder)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO1_D", get_pcvar_num(cvar_thunder))
			len += formatex(motd[len], sizeof motd - 1 - 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], sizeof motd - 1 - 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], sizeof motd - 1 - len, "%L", id, "MOTD_INFO1_G", get_pcvar_num(cvar_spawnprotection))
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO1_H", id, get_pcvar_num(cvar_randspawn) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO1_I", id, get_pcvar_num(cvar_extraitems) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO1_J", id, get_pcvar_num(cvar_zclasses) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO1_K", id, get_pcvar_num(cvar_cnvg) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO1_L", id, get_pcvar_num(cvar_cflash) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			
			show_motd(id, motd)
		}
		case 1: // Humans
		{
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO2")
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO2_A", get_pcvar_num(cvar_humanhp))
			if (get_pcvar_num(cvar_humanlasthp) > 0) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO2_B", get_pcvar_num(cvar_humanlasthp))
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO2_C", get_pcvar_num(cvar_humanspd))
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO2_D", floatround(get_pcvar_float(cvar_humangravity)*800))
			len += formatex(motd[len], sizeof motd - 1 - 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], sizeof motd - 1 - len, "%L", id, "MOTD_INFO2_F", get_pcvar_num(cvar_ammodamage))
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO2_G", id, get_pcvar_num(cvar_firegrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO2_H", id, get_pcvar_num(cvar_frostgrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO2_I", id, get_pcvar_num(cvar_flaregrenades) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], sizeof motd - 1 - 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], sizeof motd - 1 - len, "%L", id, "MOTD_INFO3")
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO3_A", g_zclass_hp[0])
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO3_B", floatround(g_zclass_hp[0]*get_pcvar_float(cvar_zombiefirsthp)))
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO3_C", floatround(get_pcvar_float(cvar_zombiearmor)*100))
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO3_D", g_zclass_spd[0])
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO3_E", floatround(g_zclass_grav[0]*800))
			if (get_pcvar_num(cvar_zombiebonushp)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO3_F", get_pcvar_num(cvar_zombiebonushp))
			len += formatex(motd[len], sizeof motd - 1 - 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], sizeof motd - 1 - len, "%L", id, "MOTD_INFO3_H", id, get_pcvar_num(cvar_zombiebleeding) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], sizeof motd - 1 - 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, sizeof nemhp - 1)
			num_to_str(get_pcvar_num(cvar_survhp), survhp, sizeof survhp - 1)
			
			len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4")
			len += formatex(motd[len], sizeof motd - 1 - 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], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_B", get_pcvar_num(cvar_nemchance))
			if (get_pcvar_num(cvar_nem)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_C", get_pcvar_num(cvar_nemhp) > 0 ? nemhp : "[Auto]")
			if (get_pcvar_num(cvar_nem)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_D", get_pcvar_num(cvar_nemspd))
			if (get_pcvar_num(cvar_nem)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_E", floatround(get_pcvar_float(cvar_nemgravity)*800))
			if (get_pcvar_num(cvar_nem)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_F", id, get_pcvar_num(cvar_leapnemesis) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			if (get_pcvar_num(cvar_nem)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_G", id, get_pcvar_num(cvar_nempainfree) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], sizeof motd - 1 - 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], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_I", get_pcvar_num(cvar_survchance))
			if (get_pcvar_num(cvar_surv)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_J", get_pcvar_num(cvar_survhp) > 0 ? survhp : "[Auto]")
			if (get_pcvar_num(cvar_surv)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_K", get_pcvar_num(cvar_survspd))
			if (get_pcvar_num(cvar_surv)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_L", floatround(get_pcvar_float(cvar_survgravity)*800))
			if (get_pcvar_num(cvar_surv)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_M", id, get_pcvar_num(cvar_leapsurvivor) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			if (get_pcvar_num(cvar_surv)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_N", id, get_pcvar_num(cvar_survpainfree) ? "MOTD_ENABLED" : "MOTD_DISABLED")
			len += formatex(motd[len], sizeof motd - 1 - 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], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_P", get_pcvar_num(cvar_swarmchance))
			len += formatex(motd[len], sizeof motd - 1 - 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], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_R", get_pcvar_num(cvar_multichance))
			if (get_pcvar_num(cvar_multi)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_S", floatround(get_pcvar_float(cvar_multiratio)*100))
			len += formatex(motd[len], sizeof motd - 1 - 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], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_U", get_pcvar_num(cvar_plaguechance))
			if (get_pcvar_num(cvar_plague)) len += formatex(motd[len], sizeof motd - 1 - len, "%L", id, "MOTD_INFO4_V", floatround(get_pcvar_float(cvar_plagueratio)*100))
			
			show_motd(id, motd)
		}
		default: return PLUGIN_HANDLED;
	}
	
	// Show help menu again if user wishes to read another topic
	set_task(0.2, "show_menu_info", id);
	
	return PLUGIN_HANDLED;
}

// Admin Menu
public menu_admin(id, key)
{
	switch (key)
	{
		case 0: // Zombiefy/Humanize command
		{
			if (g_endround || g_swarmround || g_nemround || g_survround || g_plagueround || task_exists(TASK_WELCOMEMSG))
			{
				// Not available
				zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
				show_menu_admin(id)
			}
			else
			{
				// Show player list for admin to pick a target
				PL_ACTION = key
				show_menu_player_list(id)
			}
		}
		case 1: // Nemesis command
		{
			if (g_endround || !g_newround || !get_pcvar_num(cvar_nem) || task_exists(TASK_WELCOMEMSG))
			{
				// Not available
				zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
				show_menu_admin(id)
			}
			else
			{
				// Show player list for admin to pick a target
				PL_ACTION = key
				show_menu_player_list(id)
			}
		}
		case 2: // Survivor command
		{
			if (g_endround || !g_newround || !get_pcvar_num(cvar_surv) || task_exists(TASK_WELCOMEMSG))
			{
				// Not available
				zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
				show_menu_admin(id)
			}
			else
			{
				// Show player list for admin to pick a target
				PL_ACTION = key
				show_menu_player_list(id)
			}
		}
		case 3: // Respawn command
		{
			if (g_endround || g_survround || g_swarmround || g_nemround || g_plagueround)
			{
				// Not available
				zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
				show_menu_admin(id)
			}
			else
			{
				// Show player list for admin to pick a target
				PL_ACTION = key
				show_menu_player_list(id)
			}
		}
		case 4: // Swarm Mode command
		{
			if (allowed_swarm())
				command_swarm(id)
			else
				zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
			
			show_menu_admin(id)
		}
		case 5: // Multiple Infection command
		{
			if (allowed_multi())
				command_multi(id)
			else
				zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
			
			show_menu_admin(id)
		}
		case 6: // Plague Mode command
		{
			if (allowed_plague())
				command_plague(id)
			else
				zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
			
			show_menu_admin(id)
		}
	}
	
	return PLUGIN_HANDLED;
}

// Player List Menu
public menu_player_list(id, key)
{
	switch (key)
	{
		case MENU_KEY_BACK: // back
		{
			if (PL_STARTID-7 >= 0) PL_STARTID -= 7
		}
		case MENU_KEY_NEXT: // next
		{
			if (PL_STARTID+7 < g_maxplayers) PL_STARTID += 7
		}
		case MENU_KEY_EXIT: // go back to admin menu
		{
			show_menu_admin(id);
			return PLUGIN_HANDLED
		}
		default: // perform action on player
		{
			// Make sure it's connected
			if (is_user_connected(PL_SELECTION))
			{
				// Perform the right action if allowed
				switch (PL_ACTION)
				{
					case 0:
					{
						if (g_zombie[PL_SELECTION])
						{
							if (allowed_human(PL_SELECTION))
								command_human(id, PL_SELECTION)
							else
								zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
						}
						else
						{
							if (allowed_zombie(PL_SELECTION))
								command_zombie(id, PL_SELECTION)
							else
								zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
						}
					}
					case 1:
					{
						if (allowed_nemesis(PL_SELECTION))
							command_nemesis(id, PL_SELECTION)
						else
							zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
					}
					case 2:
					{
						if (allowed_survivor(PL_SELECTION))
							command_survivor(id, PL_SELECTION)
						else
							zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
					}
					case 3:
					{
						if (allowed_respawn(PL_SELECTION))
							command_respawn(id, PL_SELECTION)
						else
							zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
					}		
				}
			}
			else
			{
				zp_colored_print(id, "^x04[ZW]^x01 %L", id, "CMD_NOT")
			}
		}
	}
	
	show_menu_player_list(id)
	return PLUGIN_HANDLED;
}

/*================================================================================
 [Admin Commands]
=================================================================================*/

// zp_toggle [1/0]
public cmd_toggle(id, level, cid)
{
	// Check for access flag
	if (!cmd_access(id, level, cid, 2))
		return PLUGIN_HANDLED;
	
	// Retrieve arguments
	new arg[2]
	read_argv(1, arg, sizeof arg - 1)
	
	// Mod already enabled/disabled
	if (str_to_num(arg) == g_pluginenabled)
		return PLUGIN_HANDLED;
	
	// Set the toggle cvar
	set_pcvar_num(cvar_toggle, str_to_num(arg))
	
	// Retrieve map name
	new mapname[32]
	get_mapname(mapname, sizeof mapname - 1)
	
	// Restart current map	
	server_cmd("changelevel %s", mapname)
	
	return PLUGIN_HANDLED;
}

// zp_zombie [target]
public cmd_zombie(id, level, cid)
{
	// Check for access flag
	if (!cmd_access(id, level, cid, 2))
		return PLUGIN_HANDLED;
	
	// Retrieve arguments
	static arg[32], player
	read_argv(1, arg, sizeof arg - 1)
	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, "[ZW] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED
	}
	
	command_zombie(id, player)
	
	return PLUGIN_HANDLED;
}

// zp_human [target]
public cmd_human(id, level, cid)
{
	// Check for access flag
	if (!cmd_access(id, level, cid, 2))
		return PLUGIN_HANDLED;
	
	// Retrieve arguments
	static arg[32], player
	read_argv(1, arg, sizeof arg - 1)
	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, "[ZW] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_human(id, player)
	
	return PLUGIN_HANDLED;
}

// zp_survivor [target]
public cmd_survivor(id, level, cid)
{
	// Check for access flag
	if (!cmd_access(id, level, cid, 2))
		return PLUGIN_HANDLED;
	
	// Retrieve arguments
	static arg[32], player
	read_argv(1, arg, sizeof arg - 1)
	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, "[ZW] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_survivor(id, player)
	
	return PLUGIN_HANDLED;
}

// zp_nemesis [target]
public cmd_nemesis(id, level, cid)
{
	// Check for access flag
	if (!cmd_access(id, level, cid, 2))
		return PLUGIN_HANDLED;
	
	// Retrieve arguments
	static arg[32], player
	read_argv(1, arg, sizeof arg - 1)
	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, "[ZW] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_nemesis(id, player)
	
	return PLUGIN_HANDLED;
}

// zp_respawn [target]
public cmd_respawn(id, level, cid)
{
	// Check for access flag
	if (!cmd_access(id, level, cid, 2))
		return PLUGIN_HANDLED;
	
	// Retrieve arguments
	static arg[32], player
	read_argv(1, arg, sizeof arg - 1)
	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, "[ZW] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_respawn(id, player)
	
	return PLUGIN_HANDLED;
}

// zp_swarm
public cmd_swarm(id, level, cid)
{
	// Check for access flag
	if (!cmd_access(id, level, cid, 1))
		return PLUGIN_HANDLED;
	
	// Swarm mode not allowed
	if (!allowed_swarm())
	{
		client_print(id, print_console, "[ZW] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_swarm(id)
	
	return PLUGIN_HANDLED;
}

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

// zp_plague
public cmd_plague(id, level, cid)
{
	// Check for access flag
	if (!cmd_access(id, level, cid, 1))
		return PLUGIN_HANDLED;
	
	// Plague mode not allowed
	if (!allowed_plague())
	{
		client_print(id, print_console, "[ZW] %L", id, "CMD_NOT")
		return PLUGIN_HANDLED;
	}
	
	command_plague(id)
	
	return PLUGIN_HANDLED;
}

/*================================================================================
 [Message Hooks]
=================================================================================*/

// Current Weapon info
public message_cur_weapon(msg_id, msg_dest, msg_entity)
{
	// Player not alive or not an active weapon
	if (!is_user_alive(msg_entity) || get_msg_arg_int(1) != 1)
		return;
	
	// Get weapon id
	static weapon
	weapon = get_msg_arg_int(2)
	
	// Store weapon id for reference
	g_currentweapon[msg_entity] = weapon
	
	// Replace weapon models with custom ones
	replace_models(msg_entity)
	
	// Unlimited Clip Ammo?
	if (MAXBPAMMO[weapon] > 2 && (g_survivor[msg_entity] || get_pcvar_num(cvar_infammo) > 1))
	{
		// Refill when it's running out
		if (get_msg_arg_int(3) < 7)
		{
			// Get weapon entity
			static wname[32], weapon_ent
			get_weaponname(weapon, wname, sizeof wname - 1)
			weapon_ent = fm_find_ent_by_owner(-1, wname, msg_entity)
			
			// Max out clip ammo
			fm_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])
	}
}

// BP Ammo update
public message_ammo_x(msg_id, msg_dest, msg_entity)
{
	// Get ammo type
	static type
	type = get_msg_arg_int(1)
	
	// Unknown ammo type
	if (type >= sizeof AMMOWEAPON) return;
	
	// Get weapon id
	static weapon
	weapon = AMMOWEAPON[type]
	
	// Primary and secondary only
	if (MAXBPAMMO[weapon] > 2)
	{
		// Get ammo amount
		static amount
		amount = get_msg_arg_int(2)
		
		// Unlimited BP Ammo?
		if (g_survivor[msg_entity] || get_pcvar_num(cvar_infammo))
		{
			if (amount < MAXBPAMMO[weapon])
			{
				fm_set_user_bpammo(msg_entity, weapon, MAXBPAMMO[weapon])
				set_msg_arg_int(2, get_msg_argtype(2), MAXBPAMMO[weapon])
			}
		}
		// Bots automatically buy ammo when needed
		else if (!g_zombie[msg_entity] && !g_survivor[msg_entity] && g_exp[msg_entity] > 0 && amount <= BUYAMMO[weapon] && is_user_bot(msg_entity))
			clcmd_buyammo(msg_entity);
	}
}

// Take off player's money
public message_money(msg_id, msg_dest, msg_entity)
{
	// Remove money setting enabled?
	if (!get_pcvar_num(cvar_removemoney))
		return PLUGIN_CONTINUE;
	
	set_pdata_int(msg_entity, OFFSET_CSMONEY, 0, OFFSET_LINUX)
	return PLUGIN_HANDLED;
}

// Fix for the HL engine bug when HP is multiples of 256
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)
}

// Block flashlight battery messages when it's not available, or if custom flashlight is enabled instead
public message_flashbat(msg_id, msg_dest, msg_entity)
{
	if (g_zombie[msg_entity] || g_survivor[msg_entity] || get_pcvar_num(cvar_cflash) || !is_user_alive(msg_entity))
		return PLUGIN_HANDLED;
	
	return PLUGIN_CONTINUE;
}

// Flashbangs should only affect zombies
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;
}

// Prevent spectators' nightvision from being turned off when switching targets, etc.
public message_nvgtoggle(msg_id, msg_dest, msg_entity)
{
	return PLUGIN_HANDLED;
}

#if defined HANDLE_MODELS_ON_SEPARATE_ENT
// Set correct model on player corpses
public message_clcorpse()
{
	set_msg_arg_string(1, g_playermodel[get_msg_arg_int(12)])
}
#endif

// Prevent zombies from seeing any weapon pickup icon
public message_weappickup(msg_id, msg_dest, msg_entity)
{
	if (g_zombie[msg_entity])
		return PLUGIN_HANDLED;
	
	return PLUGIN_CONTINUE;
}

// Prevent zombies from seeing any ammo pickup icon
public message_ammopickup(msg_id, msg_dest, msg_entity)
{
	if (g_zombie[msg_entity])
		return PLUGIN_HANDLED;

	return PLUGIN_CONTINUE;
}

// Block hostage HUD display
public message_scenario()
{
	if (get_msg_args() > 1)
	{
		static sprite[8]
		get_msg_arg_string(2, sprite, sizeof sprite - 1)
		
		if (equal(sprite, "hostage"))
			return PLUGIN_HANDLED;
	}
	
	return PLUGIN_CONTINUE;
}

// Block hostages from appearing on radar
public message_hostagepos()
{
	return PLUGIN_HANDLED;
}

// Block some text messages
public message_textmsg()
{
	static textmsg[22]
	get_msg_arg_string(2, textmsg, sizeof textmsg - 1);
	
	// 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()
	}
	// Block round end related messages
	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;
}

// Block CS round win audio messages, since we're playing our own instead
public message_sendaudio()
{
	static audio[17]
	get_msg_arg_string(2, audio, sizeof audio - 1)
	
	if(equal(audio[7], "terwin") || equal(audio[7], "ctwin") || equal(audio[7], "rounddraw"))
		return PLUGIN_HANDLED;
	
	return PLUGIN_CONTINUE;
}

// Send actual team scores (T = zombies // CT = humans)
public message_teamscore()
{
	static team[2]
	get_msg_arg_string(1, team, sizeof team - 1)
	
	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)
	}
}

// Team Switch (or player joining a team for first time)
public message_teaminfo(msg_id, msg_dest)
{
	// Only hook global messages
	if (msg_dest != MSG_ALL && msg_dest != MSG_BROADCAST) return;
	
	// Get player id
	static id
	id = get_msg_arg_int(1)
	
	// Don't pick up our own TeamInfo messages for this player (bugfix)
	if (g_switchingteam[id]) return;
	
	// Enable spectators' nightvision if not spawning right away
	set_task(0.2, "spec_nvision", id)
	
	// Round didn't start yet, nothing to worry about
	if (g_newround) return;
	
	// Get his new team
	static team[2]
	get_msg_arg_string(2, team, sizeof team - 1)
	
	switch (team[0])
	{
		case 'C': // CT
		{
			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_set_user_team(id, 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_set_user_team(id, 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_set_user_team(id, CS_TEAM_CT)
				set_msg_arg_string(2, "CT")
			}
		}
	}
}

/*================================================================================
 [Main Functions]
=================================================================================*/

// Make Zombie Task
public make_zombie_task()
{
	// Call make a zombie with no specific mode
	make_a_zombie(MODE_NONE, 0)
}

// Make a Zombie Function
make_a_zombie(mode, id)
{
	// Get alive players count
	static iPlayersnum
	iPlayersnum = fnGetAlive()
	
	// Not enough players, come back later!
	if (iPlayersnum < 1)
	{
		set_task(10.0, "make_zombie_task", TASK_MAKEZOMBIE)
		return;
	}
	
	#if defined AMBIENCE_SOUNDS
	// Start ambience sounds after a mode begins
	remove_task(TASK_AMBIENCESOUNDS)
	set_task(2.0, "ambience_sound_effects", TASK_AMBIENCESOUNDS)
	#endif
	
	// Get prevent consecutive modes setting
	static preventconsecutive
	preventconsecutive = get_pcvar_num(cvar_preventconsecutive)
	
	// Round starting
	g_newround = false
	g_survround = false
	g_nemround = false
	g_swarmround = false
	g_plagueround = false
	
	// Set up some common vars
	static forward_id, name[32], iZombies, iMaxZombies
	
	if ((mode == MODE_NONE && (!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)
	{
		// Survivor Mode
		g_survround = true
		g_lastmode = MODE_SURVIVOR
		
		// Choose player randomly?
		if (mode == MODE_NONE)
			id = fnGetRandomAlive(random_num(1, iPlayersnum))		
		
		// Remember id for calling our forward later
		forward_id = id
		
		// Turn player into a survivor
		humanme(id, 1)
		
		// Turn the remaining players into zombies
		for (id = 1; id <= g_maxplayers; id++)
		{
			// Not alive
			if (!is_user_alive(id))
				continue;
			
			// Survivor or already a zombie
			if (g_survivor[id] || g_zombie[id])
				continue;
			
			// Turn into a zombie
			zombieme(id, 0, 0, 1)
		}
		
		// Play survivor sound
		PlaySound(sound_survivor[random_num(0, sizeof sound_survivor -1)]);
		
		// Get player's name
		get_user_name(forward_id, name, sizeof name - 1)
		
		// Show Survivor HUD notice
		set_hudmessage(20, 20, 255, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
		ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_SURVIVOR", name)
		
		// Round start forward
		ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_SURVIVOR, forward_id);
	}
	else if ((mode == MODE_NONE && (!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)
	{		
		// Swarm Mode
		g_swarmround = true
		g_lastmode = MODE_SWARM
		
		// Turn every T into a zombie
		for (id = 1; id <= g_maxplayers; id++)
		{
			// Not alive
			if (!is_user_alive(id))
				continue;
			
			// Not a Terrorist
			if (fm_get_user_team(id) != CS_TEAM_T)
				continue;
			
			// Turn into a zombie
			zombieme(id, 0, 0, 1)
		}
		
		// Play swarm sound
		PlaySound(sound_swarm[random_num(0, sizeof sound_swarm -1)]);
		
		// Show Swarm HUD notice
		set_hudmessage(20, 255, 20, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
		ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_SWARM")
		
		// Round start forward
		ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_SWARM, 0);
	}
	else if ((mode == MODE_NONE && (!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)
	{
		// Multi Infection Mode
		g_lastmode = MODE_MULTI
		
		// iMaxZombies is rounded up, in case there aren't enough players
		iMaxZombies = floatround(iPlayersnum*get_pcvar_float(cvar_multiratio), floatround_ceil)
		iZombies = 0
		
		// Randomly turn iMaxZombies players into zombies
		while (iZombies < iMaxZombies)
		{
			// Keep looping through all players
			if (++id > g_maxplayers) id = 1
			
			// Dead or already a zombie
			if (!is_user_alive(id) || g_zombie[id])
				continue;
			
			// Random chance
			if (random_num(0, 1))
			{
				// Turn into a zombie
				zombieme(id, 0, 0, 1)
				iZombies++
			}
		}
		
		// Turn the remaining players into humans
		for (id = 1; id <= g_maxplayers; id++)
		{
			// Only those of them who aren't zombies
			if (!is_user_alive(id) || g_zombie[id])
				continue
			
			// Remove previous tasks
			remove_task(id+TASK_TEAM)
			
			// Switch to CT
			if (fm_get_user_team(id) != CS_TEAM_CT) // need to change team?
			{
				fm_set_user_team(id, CS_TEAM_CT)
				fm_user_team_update(id)
			}
		}
		
		// Play multi infection sound
		PlaySound(sound_multi[random_num(0, sizeof sound_multi -1)]);
		
		// Show Multi Infection HUD notice
		set_hudmessage(200, 50, 0, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
		ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_MULTI")
		
		// Round start forward
		ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_MULTI, 0);
	}
	else if ((mode == MODE_NONE && (!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)
	{
		// Plague Mode
		g_plagueround = true
		g_lastmode = MODE_PLAGUE
		
		// Turn specified amount of players into Survivors
		static iSurvivors, iMaxSurvivors
		iMaxSurvivors = get_pcvar_num(cvar_plaguesurvnum)
		iSurvivors = 0
		
		while (iSurvivors < iMaxSurvivors)
		{
			// Choose random guy
			id = fnGetRandomAlive(random_num(1, iPlayersnum))
			
			// Already a survivor?
			if (g_survivor[id])
				continue;
			
			// If not, turn him into one
			humanme(id, 1)
			iSurvivors++
			
			// Apply survivor health multiplier
			fm_set_user_health(id, floatround(pev(id, pev_health)*get_pcvar_float(cvar_plaguesurvhpmulti)))
		}
		
		// Turn specified amount of players into Nemesis
		static iNemesis, iMaxNemesis
		iMaxNemesis = get_pcvar_num(cvar_plaguenemnum)
		iNemesis = 0
		
		while (iNemesis < iMaxNemesis)
		{
			// Choose random guy
			id = fnGetRandomAlive(random_num(1, iPlayersnum))
			
			// Already a survivor or nemesis?
			if (g_survivor[id] || g_nemesis[id])
				continue;
			
			// If not, turn him into one
			zombieme(id, 0, 1, 0)
			iNemesis++
			
			// Apply nemesis health multiplier
			fm_set_user_health(id, floatround(pev(id, pev_health)*get_pcvar_float(cvar_plaguenemhpmulti)))
		}
		
		// iMaxZombies is rounded up, in case there aren't enough players
		iMaxZombies = floatround((iPlayersnum-(get_pcvar_num(cvar_plaguenemnum)+get_pcvar_num(cvar_plaguesurvnum)))*get_pcvar_float(cvar_plagueratio), floatround_ceil)
		iZombies = 0
		
		// Randomly turn iMaxZombies players into zombies
		while (iZombies < iMaxZombies)
		{
			// Keep looping through all players
			if (++id > g_maxplayers) id = 1
			
			// Dead or already a zombie or survivor
			if (!is_user_alive(id) || g_zombie[id] || g_survivor[id])
				continue;
			
			// Random chance
			if (random_num(0, 1))
			{
				// Turn into a zombie
				zombieme(id, 0, 0, 1)
				iZombies++
			}
		}
		
		// Turn the remaining players into humans
		for (id = 1; id <= g_maxplayers; id++)
		{
			// Only those of them who arent zombies or survivor
			if (!is_user_alive(id) || g_zombie[id] || g_survivor[id])
				continue;
			
			// Remove previous tasks
			remove_task(id+TASK_TEAM)
			
			// Switch to CT
			if (fm_get_user_team(id) != CS_TEAM_CT) // need to change team?
			{
				fm_set_user_team(id, CS_TEAM_CT)
				fm_user_team_update(id)
			}
		}
		
		// Play plague sound
		PlaySound(sound_plague[random_num(0, sizeof sound_plague -1)]);
		
		// Show Plague HUD notice
		set_hudmessage(0, 50, 200, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
		ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_PLAGUE")
		
		// Round start forward
		ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_PLAGUE, 0);
	}
	else
	{
		// Single Infection Mode or Nemesis Mode
		
		// Choose player randomly?
		if (mode == MODE_NONE)
			id = fnGetRandomAlive(random_num(1, iPlayersnum))
		
		// Remember id for calling our forward later
		forward_id = id
		
		if ((mode == MODE_NONE && (!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)
		{
			// Nemesis Mode
			g_nemround = true
			g_lastmode = MODE_NEMESIS
                            
                        // Get player's name
                         get_user_name(forward_id, name, sizeof name - 1)  

			
			// Turn player into nemesis
			zombieme(id, 0, 1, 0)
		}
		else
		{
			// Single Infection Mode
			g_lastmode = MODE_INFECTION
			
			// Turn player into the first zombie
			zombieme(id, 0, 0, 0)
		}
		
		// Remaining players should be humans (CTs)
		for (id = 1; id <= g_maxplayers; id++)
		{
			// Not alive
			if (!is_user_alive(id))
				continue;
			
			// First zombie/nemesis
			if (g_zombie[id])
				continue;
			
			// Remove previous tasks
			remove_task(id+TASK_TEAM)
			
			// Switch to CT
			if (fm_get_user_team(id) != CS_TEAM_CT) // need to change team?
			{
				fm_set_user_team(id, CS_TEAM_CT)
				fm_user_team_update(id)
			}
		}
		
		if (g_nemround)
		{
			// Play Nemesis sound
			PlaySound(sound_nemesis[random_num(0, sizeof sound_nemesis -1)]);
			
			// Get player's name
			get_user_name(forward_id, name, sizeof name - 1)
			
			// Show Nemesis HUD notice
			set_hudmessage(255, 20, 20, HUD_EVENT_X, HUD_EVENT_Y, 1, 0.0, 5.0, 1.0, 1.0, -1)
			ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_NEMESIS", name)
			
			// Round start forward
			ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_NEMESIS, forward_id);
		}
		else
		{
			// Get player's name
			get_user_name(forward_id, name, sizeof name - 1)
			
			// Show First Zombie HUD notice
			set_hudmessage(255, 0, 0, HUD_EVENT_X, HUD_EVENT_Y, 0, 0.0, 5.0, 1.0, 1.0, -1)
			ShowSyncHudMsg(0, g_MsgSync, "%L",LANG_PLAYER, "NOTICE_FIRST", name)
			
			// Round start forward
			ExecuteForward(g_fwRoundStart, g_fwDummyResult, MODE_INFECTION, forward_id);
		}
	}
	
	// Last Zombie Check
	set_task(0.1, "fnCheckLastZombie")
}

// Zombie Me Function (player id, infector, turn into a nemesis, special mode)
zombieme(id, infector, nemesis, specialmode)
{
	// Pre user infect forward
	ExecuteForward(g_fwUserInfected_pre, g_fwDummyResult, id, infector)
	
	// Show zombie class menu if they haven't chosen any (e.g. just connected)
	if (g_zombieclassnext[id] == ZCLASS_NONE && get_pcvar_num(cvar_zclasses))
		set_task(2.0, "show_menu_zclass", id)
	
	// Set selected zombie class
	g_zombieclass[id] = g_zombieclassnext[id]
	// If no class selected yet, use the first (default) one
	if (g_zombieclass[id] == ZCLASS_NONE) g_zombieclass[id] = 0
	
	// Way to go...
	g_zombie[id] = true
	g_survivor[id] = false
	
	// Set zombie attributes based on the mode
	if (!specialmode)
	{
		if (nemesis)
		{
			// Nemesis
			g_nemesis[id] = true
			
			// Get nemesis health setting
			static nemhealth, nembasehealth
			nemhealth = get_pcvar_num(cvar_nemhp)
			nembasehealth = get_pcvar_num(cvar_nembasehp)
			
			// Set health [0 = auto]
			if (nemhealth == 0)
			{
				if (nembasehealth == 0)
					fm_set_user_health(id, g_zclass_hp[0]*fnGetAlive())
				else
					fm_set_user_health(id, nembasehealth*fnGetAlive())
			}
			else
				fm_set_user_health(id, nemhealth)
			
			// Set gravity
			set_pev(id, pev_gravity, get_pcvar_float(cvar_nemgravity))
		}
		else if (fnGetZombies() == 1)
		{
			// First zombie
			g_firstzombie[id] = true
			
			// Set health and gravity
			fm_set_user_health(id, floatround(g_zclass_hp[g_zombieclass[id]]*get_pcvar_float(cvar_zombiefirsthp)))
			set_pev(id, pev_gravity, g_zclass_grav[g_zombieclass[id]])
			
			// Infection sound
			engfunc(EngFunc_EmitSound, id, CHAN_VOICE, zombie_infect[random_num(0, sizeof zombie_infect - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
		}
		else
		{
			// Infected by someone
			
			// Set health and gravity
			fm_set_user_health(id, g_zclass_hp[g_zombieclass[id]])
			set_pev(id, pev_gravity, g_zclass_grav[g_zombieclass[id]])
			
			// Infection sound
			engfunc(EngFunc_EmitSound, id, CHAN_VOICE, zombie_infect[random_num(0, sizeof zombie_infect - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
			
			// Get player's name
			static name[32]
			get_user_name(id, name, sizeof name - 1)
			
			// Show Infection HUD notice
			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?
			{
				static name2[32]
				get_user_name(infector, name2, sizeof name2 - 1)
				ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_INFECT2", name, name2)
			}
			else ShowSyncHudMsg(0, g_MsgSync, "%L", LANG_PLAYER, "NOTICE_INFECT", name)
		}
	}
	else
	{
		// Survivor/multi infection/swarm/plague/infection grenade
		
		// Set health and gravity
		fm_set_user_health(id, g_zclass_hp[g_zombieclass[id]])
		set_pev(id, pev_gravity, g_zclass_grav[g_zombieclass[id]])
	}
	
	// Remove previous tasks
	remove_task(id+TASK_TEAM)
	remove_task(id+TASK_MODEL)
	remove_task(id+TASK_BLOOD)
	
	// Switch to T
	if (fm_get_user_team(id) != CS_TEAM_T) // need to change team?
	{
		fm_set_user_team(id, CS_TEAM_T)
		fm_user_team_update(id)
	}
	
	#if defined HANDLE_MODELS_ON_SEPARATE_ENT
	
	// Set the right model
	if (g_nemesis[id])
		copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_nemesis[random_num(0, sizeof model_nemesis -1)])
	else
	{
		if (get_pcvar_num(cvar_adminmodelszombie) && get_user_flags(id) & ACCESS_FLAG3)
			copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_admin_zombie[random_num(0, sizeof model_admin_zombie -1)])
		else
			copy(g_playermodel[id], sizeof g_playermodel[] - 1, g_zclass_model[g_zombieclass[id]])
	}
	
	// Set model on player model entity
	fm_set_playermodel_ent(id)
	
	// Nemesis 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
		fm_set_rendering(g_ent_playermodel[id])
	
	#else
	
	// Set the right model, after checking that we don't already have it
	static currentmodel[32], already_has_model, i, iRand
	already_has_model = false
	
	// Get current model and compare it with current one
	fm_get_user_model(id, currentmodel, sizeof currentmodel - 1)
	
	if (g_nemesis[id])
	{
		for (i = 0; i < sizeof model_nemesis; i++)
			if (equal(model_nemesis[i], currentmodel)) already_has_model = true;
		
		if (!already_has_model)
		{
			iRand = random_num(0, sizeof model_nemesis -1)
			copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_nemesis[iRand])
			#if defined SET_MODELINDEX_OFFSET
			fm_set_user_model_index(id, g_modelindex_nemesis[iRand])
			#endif
		}
	}
	else
	{
		if (get_pcvar_num(cvar_adminmodelszombie) && get_user_flags(id) & ACCESS_FLAG3)
		{
			for (i = 0; i < sizeof model_admin_zombie; i++)
				if (equal(model_admin_zombie[i], currentmodel)) already_has_model = true;
			
			if (!already_has_model)
			{
				iRand = random_num(0, sizeof model_admin_zombie -1)
				copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_admin_zombie[iRand])
				#if defined SET_MODELINDEX_OFFSET
				fm_set_user_model_index(id, g_modelindex_admin_zombie[iRand])
				#endif
			}
		}
		else
		{
			if (equal(g_zclass_model[g_zombieclass[id]], currentmodel)) already_has_model = true;		
			
			if (!already_has_model)
			{
				copy(g_playermodel[id], sizeof g_playermodel[] - 1, g_zclass_model[g_zombieclass[id]])
				#if defined SET_MODELINDEX_OFFSET
				fm_set_user_model_index(id, g_zclass_modelindex[g_zombieclass[id]])
				#endif
			}
		}
	}
	
	// Need to change the model?
	if (!already_has_model)
	{
		// 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*MODELCHANGE_DELAY, "fm_user_model_update", id+TASK_MODEL)
		else
			fm_user_model_update(id+TASK_MODEL)
	}
	
	// Nemesis glow / remove glow
	if (g_nemesis[id] && get_pcvar_num(cvar_nemglow))
		fm_set_rendering(id, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 25)
	else
		fm_set_rendering(id)
	
	#endif
	
	// Remove any zoom (bugfix)
	fm_remove_user_zoom(id)
	
	// Remove armor
	set_pev(id, pev_armorvalue, 0.0)
	
	// Drop weapons when infected
	drop_weapons(id, 1)
	drop_weapons(id, 2)
	
	// Strip zombies from guns and give them a knife
	fm_strip_user_weapons(id)
	fm_give_item(id, "weapon_knife")
	
	// Fancy effects
	infection_effects(id)
	
	// Nemesis aura task
	if (g_nemesis[id] && get_pcvar_num(cvar_nemaura))
		zombie_aura(id+TASK_BLOOD)
	
	// Get nightvision give setting
	static nvggive
	nvggive = get_pcvar_num(cvar_nvggive)
	
	// Give Zombies Night Vision?
	if (nvggive)
	{
		if (!is_user_bot(id))
		{
			g_nvision[id] = true
			
			// Turn on Night Vision automatically?
			if (nvggive == 1)
			{
				g_nvisionenabled[id] = true
				
				// Custom nvg?
				if (get_pcvar_num(cvar_cnvg))
				{
					remove_task(id+TASK_NVISION)
					set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
				}
				else
					set_user_gnvision(id, 1)
			}
			// Turn off nightvision when infected (bugfix)
			else if (g_nvisionenabled[id])
			{
				if (!get_pcvar_num(cvar_cnvg)) set_user_gnvision(id, 0)
				g_nvisionenabled[id] = false
			}
		}
		else
			fm_set_bot_nvg(id, 1); // turn on NVG for bots
	}
	// Disable nightvision when infected (bugfix)
	else if (g_nvision[id])
	{
		if (g_nvisionenabled[id] && !get_pcvar_num(cvar_cnvg)) set_user_gnvision(id, 0)
		g_nvision[id] = false
		g_nvisionenabled[id] = false
	}
	
	// Get FOV setting
	static fov
	fov = get_pcvar_num(cvar_zombiefov)
	
	// Set custom FOV?
	if (fov != 90 && fov != 0)
	{
		message_begin(MSG_ONE, g_msgSetFOV, _, id)
		write_byte(fov) // angle
		message_end()
	}
	
	// Call the bloody task
	if (!g_nemesis[id] && get_pcvar_num(cvar_zombiebleeding))
		set_task(0.7, "make_blood", id+TASK_BLOOD, _, _, "b")
	
	// Idle sounds task
	if (!g_nemesis[id])
		set_task(random_float(50.0, 70.0), "zombie_play_idle", id+TASK_BLOOD, _, _, "b")
	
	// Turn off zombie's flashlight
	turn_off_flashlight(id)
	
	// Remove survivor's aura (bugfix)
	set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_BRIGHTLIGHT)
	
	// Remove spawn protection (bugfix)
	g_nodamage[id] = false
	set_pev(id, pev_effects, pev(id, pev_effects) &~ EF_NODRAW)
	
	// Post user infect forward
	ExecuteForward(g_fwUserInfected_post, g_fwDummyResult, id, infector)
	
	// Last Zombie Check
	set_task(0.1, "fnCheckLastZombie")
}

// Function Human Me (player id, turn into a survivor)
humanme(id, survivor)
{
	// Pre user humanize forward
	ExecuteForward(g_fwUserHumanized_pre, g_fwDummyResult, id)
	
	// Reset some vars
	g_zombie[id] = false
	g_nemesis[id] = false
	g_firstzombie[id] = false
	g_nodamage[id] = false
	g_canbuy[id] = true
	g_nvision[id] = false
	g_nvisionenabled[id] = false
	
	// Set human attributes based on the mode
	if (survivor)
	{
		// Survivor
		g_survivor[id] = true
		
		// Get survivor health setting
		static survhealth, survbasehealth
		survhealth = get_pcvar_num(cvar_survhp)
		survbasehealth = get_pcvar_num(cvar_survbasehp)
		
		// Set Health [0 = auto]
		if (survhealth == 0)
		{
			if (survbasehealth == 0)
				fm_set_user_health(id, get_pcvar_num(cvar_humanhp)*fnGetAlive())
			else
				fm_set_user_health(id, survbasehealth*fnGetAlive())
		}
		else
			fm_set_user_health(id, survhealth)
		
		// Set Gravity
		set_pev(id, pev_gravity, get_pcvar_float(cvar_survgravity))
		
		// Get survivor's weapon setting
		static survweapon[32]
		get_pcvar_string(cvar_survweapon, survweapon, sizeof survweapon - 1)
		
		// Strip survivor from weapons and give him his own
		fm_strip_user_weapons(id)
		fm_give_item(id, "weapon_knife")
		fm_give_item(id, survweapon)
		
		// Turn off his flashlight
		turn_off_flashlight(id)
		
		// Give the survivor a bright light
		infectionFX2(id)   
		
		// Survivor bots will also need nightvision to see in the dark
		if (is_user_bot(id)) fm_set_bot_nvg(id, 1);
	}
	else
	{
		// Human taking an antidote
		
		// Set health
		fm_set_user_health(id, get_pcvar_num(cvar_humanhp))
		
		// Set gravity, unless frozen
		if (!g_frozen[id]) set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))	
		
		// Strip off from weapons
		fm_strip_user_weapons(id)
		fm_give_item(id, "weapon_knife")
		
		// Show custom buy menu?
		if (get_pcvar_num(cvar_buycustom))
			set_task(0.4, "show_menu_buy1", id+TASK_SPAWN)
		
		// Antidote sound
		engfunc(EngFunc_EmitSound, id, CHAN_ITEM, sound_antidote[random_num(0, sizeof sound_antidote - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
		
		// Get player's name
		static name[32]
		get_user_name(id, name, sizeof name - 1)
		
		// Show Antidote HUD notice
		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", name)
	}	
	
	// Remove previous tasks
	remove_task(id+TASK_TEAM)
	remove_task(id+TASK_MODEL)
	remove_task(id+TASK_BLOOD)
	
	// Switch to CT
	if (fm_get_user_team(id) != CS_TEAM_CT) // need to change team?
	{
		fm_set_user_team(id, CS_TEAM_CT)
		fm_user_team_update(id)
	}
	
	#if defined HANDLE_MODELS_ON_SEPARATE_ENT
	
	// Set the right model
	if (g_survivor[id])
		copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_survivor[random_num(0, sizeof model_survivor -1)])
	else
	{
		if (get_pcvar_num(cvar_adminmodelshuman) && get_user_flags(id) & ACCESS_FLAG3)
			copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_admin[random_num(0, sizeof model_admin -1)])
		else
			copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_human[random_num(0, sizeof model_human -1)])
	}
	
	// Set model on player model entity
	fm_set_playermodel_ent(id)
	
	// Set survivor glow / remove glow, unless frozen
	if (g_survivor[id] && get_pcvar_num(cvar_survglow))
		fm_set_rendering(g_ent_playermodel[id], kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
	else if (!g_frozen[id])
		fm_set_rendering(g_ent_playermodel[id])
	
	#else
	
	// Set the right model, after checking that we don't already have it
	static currentmodel[32], already_has_model, i, iRand
	already_has_model = false;
	
	// Get current model and compare it with current one
	fm_get_user_model(id, currentmodel, sizeof currentmodel - 1);
	
	if (g_survivor[id])
	{
		for (i = 0; i < sizeof model_survivor; i++)
			if (equal(model_survivor[i], currentmodel)) already_has_model = true;
		
		if (!already_has_model)
		{
			iRand = random_num(0, sizeof model_survivor -1)
			copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_survivor[iRand])
			#if defined SET_MODELINDEX_OFFSET
			fm_set_user_model_index(id, g_modelindex_survivor[iRand])
			#endif
		}
	}
	else
	{
		if (get_pcvar_num(cvar_adminmodelshuman) && get_user_flags(id) & ACCESS_FLAG3)
		{
			for (i = 0; i < sizeof model_admin; i++)
				if (equal(model_admin[i], currentmodel)) already_has_model = true;
			
			if (!already_has_model)
			{
				iRand = random_num(0, sizeof model_admin -1)
				copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_admin[iRand])
				#if defined SET_MODELINDEX_OFFSET
				fm_set_user_model_index(id, g_modelindex_admin[iRand])
				#endif
			}
		}
		else
		{
			for (i = 0; i < sizeof model_human; i++)
				if (equal(model_human[i], currentmodel)) already_has_model = true;
			
			if (!already_has_model)
			{
				iRand = random_num(0, sizeof model_human -1)
				copy(g_playermodel[id], sizeof g_playermodel[] - 1, model_human[iRand])
				#if defined SET_MODELINDEX_OFFSET
				fm_set_user_model_index(id, g_modelindex_human[iRand])
				#endif
			}
		}
	}
	
	// Need to change the model?
	if (!already_has_model)
	{
		// 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*MODELCHANGE_DELAY, "fm_user_model_update", id+TASK_MODEL)
		else
			fm_user_model_update(id+TASK_MODEL)
	}
	
	// Set survivor glow / remove glow, unless frozen
	if (g_survivor[id] && get_pcvar_num(cvar_survglow))
		fm_set_rendering(id, kRenderFxGlowShell, 0, 0, 255, kRenderNormal, 25)
	else if (!g_frozen[id])
		fm_set_rendering(id)
	
	#endif
	
	// Get FOV setting
	static fov
	fov = get_pcvar_num(cvar_zombiefov)
	
	// Restore FOV?
	if (fov != 90 && fov != 0)
	{
		message_begin(MSG_ONE, g_msgSetFOV, _, id)
		write_byte(90) // angle
		message_end()
	}
	
	// Disable nightvision
	if (is_user_bot(id)) fm_set_bot_nvg(id, 0)
	else if (!get_pcvar_num(cvar_cnvg)) set_user_gnvision(id, 0)
	
	// Post user humanize forward
	ExecuteForward(g_fwUserHumanized_post, g_fwDummyResult, id)
	
	// Last Zombie Check
	set_task(0.1, "fnCheckLastZombie")
}

/*================================================================================
 [Other Functions and Tasks]
=================================================================================*/

// Register Ham Forwards for CZ bots
public register_ham_czbots(id)
{
	// Make sure it's a CZ bot and it's still connected
	if (g_hamczbots || !get_pcvar_num(cvar_botquota) || !is_user_connected(id) || !is_user_bot(id))
		return;
	
	RegisterHamFromEntity(Ham_Spawn, id, "fw_PlayerSpawn_Post", 1)
	RegisterHamFromEntity(Ham_Killed, id, "fw_PlayerKilled")
	RegisterHamFromEntity(Ham_TakeDamage, id, "fw_TakeDamage")
	RegisterHamFromEntity(Ham_TraceAttack, id, "fw_TraceAttack")
	
	// 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)
}

// Disable minmodels task
public disable_minmodels(id)
{
	if (!is_user_connected(id)) return;
	client_cmd(id, "cl_minmodels 0")
}

// Bots automatically buy extra items
public bot_buy_extras(taskid)
{
	// Nemesis or Survivor shouldnt get extra items
	if (g_survivor[ID_SPAWN] || g_nemesis[ID_SPAWN] || !is_user_alive(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)
	}
}

// Balance Teams Task
public balance_teams()
{
	// Get users playing
	static iPlayersnum
	iPlayersnum = fnGetPlaying()
	
	// No players, don't bother
	if (iPlayersnum < 1) return;
	
	// Split players evenly
	static g_team[33], id, iTerrors, iMaxTerrors, team
	iMaxTerrors = iPlayersnum/2
	iTerrors = 0
	
	// First, mark everyone as CT
	for (id = 1; id <= g_maxplayers; id++)
		g_team[id] = CS_TEAM_CT
	
	// Then randomly mark half of the players as Terrorists
	while (iTerrors < iMaxTerrors)
	{
		// Keep looping through all players
		if (++id > g_maxplayers) id = 1
		
		// Skip if not connected
		if (!is_user_connected(id))
			continue;
		
		team = fm_get_user_team(id)
		
		// Skip if not playing
		if (team == CS_TEAM_SPECTATOR || team == CS_TEAM_UNASSIGNED)
			continue;
		
		// Already a Terrorist
		if (g_team[id] == CS_TEAM_T)
			continue;
		
		// Random chance
		if (random_num(0, 1))
		{
			g_team[id] = CS_TEAM_T
			iTerrors++
		}
	}
	
	// Set everyone's team for real
	for (id = 1; id <= g_maxplayers; id++)
	{
		// Skip if not connected
		if (!is_user_connected(id))
			continue;
		
		team = fm_get_user_team(id)
		
		// Skip if not playing
		if (team == CS_TEAM_SPECTATOR || team == CS_TEAM_UNASSIGNED)
			continue;
		
		// Set team
		remove_task(id+TASK_TEAM)
		fm_set_user_team(id, g_team[id])
	}
}

// Welcome Message Task
public welcome_msg()
{
	// Show mod info
	zp_colored_print(0, "^x01**** ^x04%s^x01 ****", g_modname)
	zp_colored_print(0, "^x04[ZW]^x01 %L", LANG_PLAYER, "NOTICE_INFO1")
	if (!get_pcvar_num(cvar_infammo)) zp_colored_print(0, "^x04[ZW]^x01 %L", LANG_PLAYER, "NOTICE_INFO2")
	
	// Show T-virus HUD notice
	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")
}

// Respawn Player Task
public respawn_player(taskid)
{
	// Get player's team
	static team
	team = fm_get_user_team(ID_SPAWN)
	
	// Respawn on infection rounds only
	if (!g_endround && !g_survround && !g_swarmround && !g_nemround && !g_plagueround && team != CS_TEAM_SPECTATOR && team != CS_TEAM_UNASSIGNED && !is_user_alive(ID_SPAWN))
	{
		// Set proper team before respawning, so that the TeamInfo message that's sent doesn't confuse PODBots
		if (g_respawn_as_zombie[ID_SPAWN])
			fm_set_user_team(ID_SPAWN, CS_TEAM_T)
		else
			fm_set_user_team(ID_SPAWN, CS_TEAM_CT)
		
		// Respawning a player has never been so easy
		ExecuteHamB(Ham_CS_RoundRespawn, ID_SPAWN)
	}
}

// Check Round Task -check that we still have both zombies & humans on a round-
check_round(leaving_player)
{
	// Round ended or make_a_zombie task still active
	if (g_endround || task_exists(TASK_MAKEZOMBIE))
		return;
	
	// Get alive players count
	static iPlayersnum
	iPlayersnum = fnGetAlive()
	
	// Last alive player, don't bother
	if (iPlayersnum < 2)
		return;
	
	// Set up some common vars
	static id, name[32]
	
	// Last zombie disconnecting
	if (g_zombie[leaving_player] && fnGetZombies() == 1)
	{
		// Only one CT left, don't bother
		if (fnGetHumans() == 1 && fnGetCTs() == 1)
			return;
		
		// Pick a random one to take his place
		while ((id = fnGetRandomAlive(random_num(1, iPlayersnum))) == leaving_player ) {}
		
		// Show last zombie left notice
		get_user_name(id, name, sizeof name - 1)
		zp_colored_print(0, "^x04[ZW]^x01 %L", LANG_PLAYER, "LAST_ZOMBIE_LEFT", name)
		
		// Turn into a Nemesis or just a zombie?
		if (g_nemesis[leaving_player] && !g_plagueround)
			make_a_zombie(MODE_NEMESIS, id)
		else
			zombieme(id, 0, 0, 0)
	}
	
	// Last human disconnecting
	else if (!g_zombie[leaving_player] && fnGetHumans() == 1)
	{
		// Only one T left, don't bother
		if (fnGetZombies() == 1 && fnGetTs() == 1)
			return;
		
		// Pick a random one to take his place
		while ((id = fnGetRandomAlive(random_num(1, iPlayersnum))) == leaving_player ) {}
		
		// Show last human left notice
		get_user_name(id, name, sizeof name - 1)
		zp_colored_print(0, "^x04[ZW]^x01 %L", LANG_PLAYER, "LAST_HUMAN_LEFT", name)
		
		// Turn into a Survivor or just a human?
		if (g_survivor[leaving_player] && !g_plagueround)
			make_a_zombie(MODE_SURVIVOR, id)
		else
			humanme(id, 0)
	}
}

// Lighting Effects Task
public lighting_effects()
{
	// Lighting style ["a"-"z"]
	static lights[2]
	get_pcvar_string(cvar_lighting, lights, sizeof lights - 1)
	strtolower(lights)
	
	// Lighting disabled? ["0"]
	if (lights[0] == '0')
	{
		// Task not needed anymore
		remove_task(TASK_LIGHTING)
		return;
	}
	
	// Darkest light settings?
	if (lights[0] >= 'a' && lights[0] <= 'd')
	{
		// Get thunderclaps setting
		static Float:thunderclap
		thunderclap = get_pcvar_float(cvar_thunder)
		
		// Set thunderclap tasks if neccesary
		if (thunderclap > 0.0 && !task_exists(TASK_THUNDER_PRE) && !task_exists(TASK_THUNDER))
		{
			g_lights_i = 0
			switch (random_num(0, 2))
			{
				case 0: set_task(thunderclap, "thunderclap1", TASK_THUNDER_PRE)
				case 1: set_task(thunderclap, "thunderclap2", TASK_THUNDER_PRE)
				case 2: set_task(thunderclap, "thunderclap3", TASK_THUNDER_PRE)
			}
		}
		
		// Set lighting only when no thunderclaps are going on
		if (!task_exists(TASK_THUNDER)) engfunc(EngFunc_LightStyle, 0, lights)
	}
	else
	{
		// Remove thunderclap tasks
		remove_task(TASK_THUNDER_PRE)
		remove_task(TASK_THUNDER)
		
		// Set lighting
		engfunc(EngFunc_LightStyle, 0, lights)
	}
}

// Thunderclap 1
public thunderclap1()
{
	// Play thunder sound
	if (!g_lights_i) PlaySound(sound_thunder[random_num(0, sizeof sound_thunder - 1)])
	
	// Set lighting
	engfunc(EngFunc_LightStyle, 0, lights_thunder1[g_lights_i])
	g_lights_i++
	
	// Loop the task until we reach the end of the cycle
	if (g_lights_i >= sizeof lights_thunder1)
	{
		remove_task(TASK_THUNDER)
		lighting_effects()
	}
	else if (!task_exists(TASK_THUNDER))
		set_task(0.1, "thunderclap1", TASK_THUNDER, _, _, "b")
}

// Thunderclap 2
public thunderclap2()
{
	// Play thunder sound
	if (!g_lights_i) PlaySound(sound_thunder[random_num(0, sizeof sound_thunder - 1)])
	
	// Set lighting
	engfunc(EngFunc_LightStyle, 0, lights_thunder2[g_lights_i])
	g_lights_i++
	
	// Loop the task until we reach the end of the cycle
	if (g_lights_i >= sizeof lights_thunder2)
	{
		remove_task(TASK_THUNDER)
		lighting_effects()
	}
	else if (!task_exists(TASK_THUNDER))
		set_task(0.1, "thunderclap2", TASK_THUNDER, _, _, "b")
}

// Thunderclap 3
public thunderclap3()
{
	// Play thunder sound
	if (!g_lights_i) PlaySound(sound_thunder[random_num(0, sizeof sound_thunder - 1)])
	
	// Set lighting
	engfunc(EngFunc_LightStyle, 0, lights_thunder3[g_lights_i])
	g_lights_i++
	
	// Loop the task until we reach the end of the cycle
	if (g_lights_i >= sizeof lights_thunder3)
	{
		remove_task(TASK_THUNDER)
		lighting_effects()
	}
	else if (!task_exists(TASK_THUNDER))
		set_task(0.1, "thunderclap3", TASK_THUNDER, _, _, "b")
}

#if defined AMBIENCE_SOUNDS
// Ambience Sound Effects Task
public ambience_sound_effects(taskid)
{
	// Play a random sound depending on the round
	static amb_sound[64], isound, Float:duration
	
	if (g_nemround) // Nemesis Mode
	{
		isound = random_num(0, sizeof sound_ambience2 - 1)
		copy(amb_sound, sizeof amb_sound -1, sound_ambience2[isound])
		duration = sound_ambience2_duration[isound]
	}
	else if (g_survround) // Survivor Mode
	{
		isound = random_num(0, sizeof sound_ambience3 - 1)
		copy(amb_sound, sizeof amb_sound -1, sound_ambience3[isound])
		duration = sound_ambience3_duration[isound]
	}
	else if (g_swarmround) // Swarm Mode
	{
		isound = random_num(0, sizeof sound_ambience4 - 1)
		copy(amb_sound, sizeof amb_sound -1, sound_ambience4[isound])
		duration = sound_ambience4_duration[isound]
	}
	else if (g_plagueround) // Plague Mode
	{
		isound = random_num(0, sizeof sound_ambience5 - 1)
		copy(amb_sound, sizeof amb_sound -1, sound_ambience5[isound])
		duration = sound_ambience5_duration[isound]
	}
	else // Infection Mode
	{
		isound = random_num(0, sizeof sound_ambience1 - 1)
		copy(amb_sound, sizeof amb_sound -1, sound_ambience1[isound])
		duration = sound_ambience1_duration[isound]
	}
	
	// Check whether it's a wav or mp3 and play it on clients
	if (equal(amb_sound[strlen(amb_sound)-4], ".mp3"))
		client_cmd(0, "mp3 play ^"sound/%s^"", amb_sound)
	else
		PlaySound(amb_sound)
	
	// The task should be called again after the sound is done playing
	set_task(duration, "ambience_sound_effects", TASK_AMBIENCESOUNDS)
}

// Ambience Sounds Stop Task
public ambience_sound_stop()
{
	client_cmd(0, "mp3 stop; stopsound")
}
#endif

// Flashlight Charge Task
public flashlight_charge(taskid)
{
	// Custom flashlight disabled or flashlight not available for player
	if (g_zombie[ID_CHARGE] || g_survivor[ID_CHARGE] || !get_pcvar_num(cvar_cflash) || !is_user_alive(ID_CHARGE))
	{
		// Task not needed anymore
		remove_task(taskid);
		return;
	}
	
	// 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(g_flashbattery[ID_CHARGE]) // 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;
		
		// Update flashlight status on HUD
		message_begin(MSG_ONE, g_msgFlashlight, _, ID_CHARGE)
		write_byte(g_flashlight[ID_CHARGE]) // toggle
		write_byte(g_flashbattery[ID_CHARGE]) // battery
		message_end()
	}
	else
	{
		// Update flashlight battery on HUD
		message_begin(MSG_ONE_UNRELIABLE, g_msgFlashBat, _, ID_CHARGE)
		write_byte(g_flashbattery[ID_CHARGE]) // battery
		message_end()
	}
}

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

// Task Hide Player's Money
public task_hide_money(taskid)
{
	// Not alive
	if (!is_user_alive(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()
}

// Turn Off Game Flashlight
turn_off_flashlight(id)
{
	// Check if flashlight is on
	if (pev(id, pev_effects) & EF_DIMLIGHT)
	{
		// Turn it off
		set_pev(id, pev_effects, pev(id, pev_effects) & ~EF_DIMLIGHT)
		
		// Update HUD
		message_begin(MSG_ONE, g_msgFlashlight, _, id)
		write_byte(0) // toggle
		write_byte(100) // battery
		message_end()
	}
	
	// Clear any stored flashlight impulse (bugfix)
	set_pev(id, pev_impulse, 0)
}

// Infection Grenade Explosion
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
	engfunc(EngFunc_EmitSound, ent, CHAN_WEAPON, grenade_infect[random_num(0, sizeof grenade_infect - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
	
	// Get attacker
	static attacker
	attacker = pev(ent, pev_owner)
	
	// 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_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
		engfunc(EngFunc_EmitSound, victim, CHAN_VOICE, grenade_infect_player[random_num(0, sizeof grenade_infect_player - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
		
		SendDeathMsg(attacker, victim) // send death notice
		FixDeadAttrib(victim) // fix the "dead" attrib on scoreboard
		UpdateFrags(attacker, victim, get_pcvar_num(cvar_fragsinfect), 1, 1) // add corresponding frags & deaths		
		
		zombieme(victim, attacker, 0, 1) // turn into zombie
		g_exp[attacker] += get_pcvar_num(cvar_ammoinfect) // ammo packs given to zombie for infection
		fm_set_user_health(attacker, pev(attacker, pev_health)+get_pcvar_num(cvar_zombiebonushp)) // infection HP bonus
	}
	
	// Get rid of the grenade
	engfunc(EngFunc_RemoveEntity, ent)
}

// Fire Grenade Explosion
fire_explode(ent)
{
	// Get origin
	static Float:originF[3]
	pev(ent, pev_origin, originF)
	
	// Make the explosion
	create_blast2(originF)
	
	// Fire nade explode sound
	engfunc(EngFunc_EmitSound, ent, CHAN_WEAPON, grenade_fire[random_num(0, sizeof grenade_fire - 1)], 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_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()
		}
		
		// Our task params
		static params[1]
		
		if (g_nemesis[victim]) // fire duration (nemesis takes less)
			params[0] = get_pcvar_num(cvar_fireduration)
		else
			params[0] = get_pcvar_num(cvar_fireduration)*5
		
		// Set burning task on victim
		set_task(0.1, "burning_flame", victim+TASK_BLOOD, params, sizeof params)
	}
	
	// Get rid of the grenade
	engfunc(EngFunc_RemoveEntity, ent)
}

// Frost Grenade Explosion
frost_explode(ent)
{
	// Get origin
	static Float:originF[3]
	pev(ent, pev_origin, originF)
	
	// Make the explosion
	create_blast3(originF)
	
	// Frost nade explode sound
	engfunc(EngFunc_EmitSound, ent, CHAN_WEAPON, grenade_frost[random_num(0, sizeof grenade_frost - 1)], 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_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 Float:origin2F[3]
			pev(victim, pev_origin, origin2F)
			
			// Broken glass sound
			engfunc(EngFunc_EmitSound, victim, CHAN_BODY, grenade_frost_break[random_num(0, sizeof grenade_frost_break - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
			
			// Glass shatter
			engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, origin2F, 0)
			write_byte(TE_BREAKMODEL) // TE id
			engfunc(EngFunc_WriteCoord, origin2F[0]) // x
			engfunc(EngFunc_WriteCoord, origin2F[1]) // y
			engfunc(EngFunc_WriteCoord, origin2F[2]+24.0) // 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 defined 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)
		#endif
		
		// Freeze sound
		engfunc(EngFunc_EmitSound, victim, CHAN_BODY, grenade_frost_player[random_num(0, sizeof grenade_frost_player - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
		
		// Get freeze duration setting
		static Float:freezeduration
		freezeduration = get_pcvar_float(cvar_freezeduration)
		
		// Add a blue tint to their screen
		message_begin(MSG_ONE_UNRELIABLE, g_msgScreenFade, _, victim)
		write_short(UNIT_SECOND*1) // duration
		write_short(floatround(UNIT_SECOND*freezeduration)) // 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()
		
		// 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
		
		// Set a task to remove the freeze
		g_frozen[victim] = true;
		set_task(freezeduration, "remove_freeze", victim)
	}
	
	// Get rid of the grenade
	engfunc(EngFunc_RemoveEntity, ent)
}

// Remove freeze task
public remove_freeze(id)
{
	// Not alive or not frozen anymore
	if (!g_frozen[id] || !is_user_alive(id))
		return;
	
	// Unfreeze
	g_frozen[id] = false;
	
	// Restore normal gravity
	if (g_zombie[id])
		set_pev(id, pev_gravity, g_zclass_grav[g_zombieclass[id]])
	else
		set_pev(id, pev_gravity, get_pcvar_float(cvar_humangravity))
	
	// Broken glass sound
	engfunc(EngFunc_EmitSound, id, CHAN_BODY, grenade_frost_break[random_num(0, sizeof grenade_frost_break - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
	
	// Remove glow
	#if defined HANDLE_MODELS_ON_SEPARATE_ENT
	fm_set_rendering(g_ent_playermodel[id])
	#else
	fm_set_rendering(id)
	#endif
	
	// Get player's origin
	static Float:origin2F[3]
	pev(id, pev_origin, origin2F)
	
	// Glass shatter
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, origin2F, 0)
	write_byte(TE_BREAKMODEL) // TE id
	engfunc(EngFunc_WriteCoord, origin2F[0]) // x
	engfunc(EngFunc_WriteCoord, origin2F[1]) // y
	engfunc(EngFunc_WriteCoord, origin2F[2]+24.0) // 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()
}

// Remove Stuff Task
public remove_stuff()
{
	static ent, removedoors
	removedoors = get_pcvar_num(cvar_removedoors)
	
	// Remove rotating doors
	if (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})
	}
	
	// Remove all doors
	if (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})
	}
	
	// Triggered lights
	if (!get_pcvar_num(cvar_triggered))
	{
		ent = -1
		while ((ent = engfunc(EngFunc_FindEntityByString, ent, "classname", "light")) != 0)
		{
			dllfunc(DLLFunc_Use, ent, 0); // turn off the light
			set_pev(ent, pev_targetname, 0) // prevent it from being triggered
		}
	}
}

// Set Custom Weapon Models
public replace_models(id)
{
	// Not alive
	if (!is_user_alive(id))
		return;
	
	switch (g_currentweapon[id])
	{
		case CSW_KNIFE: // Custom knife models
		{
			if (g_zombie[id] && !g_newround && !g_endround)
			{
				if (g_nemesis[id]) // Nemesis
				{
					set_pev(id, pev_viewmodel2, model_vknife_nemesis)
					set_pev(id, pev_weaponmodel2, "")
				}
				else // Zombies
				{
					static mdl[100]
					formatex(mdl, sizeof mdl - 1, "models/Zombie_Warface/%s", g_zclass_clawmodel[g_zombieclass[id]])					
					set_pev(id, pev_viewmodel2, mdl)
					set_pev(id, pev_weaponmodel2, "")
				}
			}
			else // Humans
			{
				set_pev(id, pev_viewmodel2, model_vknife_human)
				set_pev(id, pev_weaponmodel2, "models/p_knife.mdl")
			}
		}
		case CSW_MP5NAVY: // Survivor's MP5NAVY
		{
			if (g_survivor[id])
				set_pev(id, pev_viewmodel2, model_vmp5navy_survivor)
		}
        case CSW_HEGRENADE: // Infection bomb or fire grenade
        {
            if (g_zombie[id] && !g_newround && !g_endround)
                set_pev(id, pev_viewmodel2, model_grenade_infect)
            else
                set_pev(id, pev_viewmodel2, model_grenade_fire)
        }
        case CSW_FLASHBANG: // Frost grenade
        {
            set_pev(id, pev_viewmodel2, model_grenade_frost)
        }
        case CSW_SMOKEGRENADE: // Flare grenade
        {
            set_pev(id, pev_viewmodel2, model_grenade_flare)
        }
        case CSW_M4A1: // Weapon Thunder Carabina
        {
            set_pev(id, pev_viewmodel2, model_weapon_m4a1)
        }
        case CSW_AK47: // Weapon AK 47 L&C
        {
            set_pev(id, pev_viewmodel2, model_weapon_ak47)
        }
        case CSW_AWP: // Weapon Awp Aniquiladora
        {
            set_pev(id, pev_viewmodel2, model_weapon_awp)
        }
        case CSW_GLOCK18: // Weapon Glock
        {
            set_pev(id, pev_viewmodel2, model_weapon_glock18)
        }
        case CSW_ELITE: // Weapon Dual Akimbo
        {
            set_pev(id, pev_viewmodel2, model_weapon_elite)
        }
        case CSW_DEAGLE: // Weapon Deagle anaconda
        {
            set_pev(id, pev_viewmodel2, model_weapon_deagle)
        }
        case CSW_P228: // Weapon P228 
        {
            set_pev(id, pev_viewmodel2, model_weapon_p228)
        }
        case CSW_FIVESEVEN: // Weapon Fiveseven
        {
            set_pev(id, pev_viewmodel2, model_weapon_fiveseven)
        }
        case CSW_USP: // Weapon Usp
        {
            set_pev(id, pev_viewmodel2, model_weapon_usp)
        }
        case CSW_SG552: // Weapon Sg552 Recortada
        {
            set_pev(id, pev_viewmodel2, model_weapon_sg552)
        }
        case CSW_AUG: // Weapon Aug
        {
            set_pev(id, pev_viewmodel2, model_weapon_aug)
        }
        case CSW_SG550: // Weapon Rifle Experimental
        {
            set_pev(id, pev_viewmodel2, model_weapon_sg550)
        }
        case CSW_G3SG1: // Weapon Rifle De Presicion
        {
            set_pev(id, pev_viewmodel2, model_weapon_g3sg1)
        }
        case CSW_M249: // Weapon Vulcanus Minigun
        {
            set_pev(id, pev_viewmodel2, model_weapon_m249)
        }
        case CSW_GALIL: // Weapon Galil F1
        {
            set_pev(id, pev_viewmodel2, model_weapon_galil)
        }
        case CSW_FAMAS: // Weapon Enfield
        {
            set_pev(id, pev_viewmodel2, model_weapon_famas)
        }
        case CSW_MAC10: // Weapon Mac H&F
        {
            set_pev(id, pev_viewmodel2, model_weapon_mac10)
        }
        case CSW_P90: // Weapon Dual P90 Kriss
        {
            set_pev(id, pev_viewmodel2, model_weapon_p90)
        }
        case CSW_UMP45: // Weapon Ump Core
        {
            set_pev(id, pev_viewmodel2, model_weapon_ump45)
        }
        case CSW_M3: // Weapon Spass 100% DMG
        {
            set_pev(id, pev_viewmodel2, model_weapon_m3)
        }
        case CSW_SCOUT: // Weapon Stalker Vss
        {
            set_pev(id, pev_viewmodel2, model_weapon_scout)
        }
        case CSW_XM1014: // Weapon Super Serbu
        {
            set_pev(id, pev_viewmodel2, model_weapon_xm1014)
        }
    }  
	
	#if defined HANDLE_MODELS_ON_SEPARATE_ENT
	fm_set_weaponmodel_ent(id)
	#endif
}

// Reset Player Vars
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
	
	if (resetall)
	{
		g_exp[id] = 5
		g_zombieclass[id] = ZCLASS_NONE
		g_zombieclassnext[id] = ZCLASS_NONE
		g_damagedealt[id] = 0
		WPN_AUTO_ON = 0
	}
}

// Set spectators nightvision
public spec_nvision(id)
{
	// Not connected, playing, or bot
	if (!is_user_connected(id) || is_user_alive(id) || is_user_bot(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_cnvg))
			{
				remove_task(id+TASK_NVISION)
				set_task(0.1, "set_user_nvision", id+TASK_NVISION, _, _, "b")
			}
			else
				set_user_gnvision(id, 1)
		}
	}
}

// Show HUD Task
public ShowHUD(taskid)
{
	static id
	id = ID_SHOWHUD;
	
	// Player died?
	if (!is_user_alive(id))
	{
		// Get spectating target
		id = pev(id, PEV_SPEC_TARGET)
		
		// Target not alive
		if (!is_user_alive(id)) return;
	}
	
	// Format the classname
	static class[32], red, green, blue
	
	if (g_zombie[id]) // zombies
	{
		red = 0
		green = 250
		blue = 0
		
		if (g_nemesis[id])
			formatex(class, sizeof class - 1, "%L", ID_SHOWHUD,"CLASS_NEMESIS")
		else
			copy(class, sizeof class - 1, g_zclass_name[g_zombieclass[id]])
	}
	else // humans
	{
		red = 0
		green = 0
		blue = 255
		
		if (g_survivor[id])
			formatex(class, sizeof class - 1, "%L", ID_SHOWHUD,"CLASS_SURVIVOR")
		else
			formatex(class, sizeof class - 1, "%L", ID_SHOWHUD,"CLASS_HUMAN")
	}
	
	// Spectating someone else?
	if (id != ID_SHOWHUD)
	{
		static name[32]
		get_user_name(id, name, sizeof name - 1)
		
		// Show name, health, class, and ammo packs
		set_hudmessage(255, 255, 255, HUD_SPECT_X, HUD_SPECT_Y, 0, 6.0, 1.1, 0.0, 0.0, -1)
		ShowSyncHudMsg(ID_SHOWHUD, g_MsgSync2, " - %L %s^n - HP: %d^n - %L %s^n - %L %d^n - Nivel %d^n", ID_SHOWHUD, "SPECTATING", name, pev(id, pev_health), ID_SHOWHUD, "CLASS_CLASS", class, ID_SHOWHUD, "EXP", g_exp[id], Lvl[id])
	}
	else
	{
		// Show health, class and ammo packs
		set_hudmessage(red, green, blue, HUD_STATS_X, HUD_STATS_Y, 0, 6.0, 1.1, 0.0, 0.0, -1)
		ShowSyncHudMsg(ID_SHOWHUD, g_MsgSync2, " - %L: %d^n - Chaleco: %d^n - %L %s^n - %L %d^n - Nivel: %d^n - Exp Requerida: %d^n", id, "ZOMBIE_ATTRIB1", pev(ID_SHOWHUD, pev_health), get_user_armor(id), ID_SHOWHUD, "CLASS_CLASS", class, ID_SHOWHUD, "EXP", g_exp[ID_SHOWHUD], Lvl[ID_SHOWHUD], Levels[Lvl[ID_SHOWHUD]] - g_exp[ID_SHOWHUD])
	}
}

// Play idle zombie sounds
public zombie_play_idle(taskid)
{
	// Round ended/new one starting
	if (g_endround || g_newround)
		return;
	
	// Last zombie?
	if (g_lastzombie[ID_BLOOD])
		engfunc(EngFunc_EmitSound, ID_BLOOD, CHAN_VOICE, zombie_idle_last[random_num(0, sizeof zombie_idle_last - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
	else
		engfunc(EngFunc_EmitSound, ID_BLOOD, CHAN_VOICE, zombie_idle[random_num(0, sizeof zombie_idle - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
}

// Madness Over Task
public madness_over(taskid)
{
	g_nodamage[ID_BLOOD] = false
}

// Place user at a random spawn
do_random_spawn(id)
{
	// No spawns?
	if (!g_spawnCount)
		return;
	
	// Get whether the player is crouching
	static hull
	hull = (pev(id, pev_flags) & FL_DUCKING) ? HULL_HEAD : HULL_HUMAN
	
	// Choose random spawn to start looping at
	static sp_index, i
	sp_index = random_num(0, g_spawnCount - 1)
	
	// Try to find a clear spawn
	for (i = sp_index + 1; i != 999; 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;
	}
}

// Get Zombies -returns alive zombies number-
fnGetZombies()
{
	static iZombies, id
	iZombies = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (is_user_alive(id) && g_zombie[id])
			iZombies++
	}
	
	return iZombies;
}

// Get Humans -returns alive humans number-
fnGetHumans()
{
	static iHumans, id
	iHumans = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (is_user_alive(id) && !g_zombie[id])
			iHumans++
	}
	
	return iHumans;
}

// Get Alive -returns alive players number-
fnGetAlive()
{
	static iAlive, id
	iAlive = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (is_user_alive(id))
			iAlive++
	}
	
	return iAlive;
}

// Get Random Alive -returns index of alive player number n -
fnGetRandomAlive(n)
{
	static iAlive, id
	iAlive = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (is_user_alive(id))
			iAlive++
		
		if (iAlive == n)
			return id;
	}
	
	return -1;
}

// Get Playing -returns number of users playing-
fnGetPlaying()
{
	static iPlaying, id, team
	iPlaying = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (is_user_connected(id))
		{
			team = fm_get_user_team(id)
			
			if (team != CS_TEAM_SPECTATOR && team != CS_TEAM_UNASSIGNED)
				iPlaying++
		}
	}
	
	return iPlaying;
}

// Get CTs -returns number of CTs connected-
fnGetCTs()
{
	static iCTs, id
	iCTs = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (is_user_connected(id))
		{			
			if (fm_get_user_team(id) == CS_TEAM_CT)
				iCTs++
		}
	}
	
	return iCTs;
}

// Get Ts -returns number of Ts connected-
fnGetTs()
{
	static iTs, id
	iTs = 0
	
	for (id = 1; id <= g_maxplayers; id++)
	{
		if (is_user_connected(id))
		{			
			if (fm_get_user_team(id) == CS_TEAM_T)
				iTs++
		}
	}
	
	return iTs;
}

// Last Zombie Check -check for last zombie and set its flag-
public fnCheckLastZombie()
{
	static id
	for (id = 1; id <= g_maxplayers; id++)
	{
		// Last zombie
		if (g_zombie[id] && is_user_alive(id) && fnGetZombies() == 1)
			g_lastzombie[id] = true
		else
			g_lastzombie[id] = false
		
		// Last human
		if (!g_zombie[id] && !g_survivor[id] && is_user_alive(id) && fnGetHumans() == 1)
		{
			// Reward extra hp for last human?
			if (!g_lasthuman[id]) fm_set_user_health(id, pev(id, pev_health)+get_pcvar_num(cvar_humanlasthp))
			g_lasthuman[id] = true
		}
		else
			g_lasthuman[id] = false
	}
}

// Save player's stats into the database
save_stats(id)
{
	// Get user name
	static name[32]
	get_user_name(id, name, sizeof name - 1)
	
	// Check whether there is another record already in that slot
	if (db_name[id][0] && !equal(name, 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], sizeof db_name[] - 1, 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], sizeof db_name[] - 1, name) // name
	db_ammopacks[id] = g_exp[id]  // ammo packs
	db_zombieclass[id] = g_zombieclassnext[id] // zombie class
}

// Load player's stats from the database (if a record is found)
load_stats(id)
{
	// Get user name
	static name[32], i
	get_user_name(id, name, sizeof name - 1)
	
	// Look for a matching record in the DB
	for (i = 0; i < sizeof db_name; i++)
	{
		if (equal(name, db_name[i]))
		{
			// Bingo!
			g_exp[id] = db_ammopacks[i]
			g_zombieclass[id] = db_zombieclass[i]
			g_zombieclassnext[id] = db_zombieclass[i]
			return;
		}
	}
}

// Checks if a player should leap
allowed_leap(id)
{
	// Leap available for zombies/nemesis/survivor only
	if ((!g_zombie[id] && !g_survivor[id]) || g_frozen[id])
		return false;
	
	// Nemesis cvar not enabled
	if (g_nemesis[id] && !get_pcvar_num(cvar_leapnemesis))
		return false;
	
	// Survivor cvar not enabled
	if (g_survivor[id] && !get_pcvar_num(cvar_leapsurvivor))
		return false;
	
	// Get zombie cvar
	static leapzombies
	leapzombies = get_pcvar_num(cvar_leapzombies)
	
	// Zombie cvar not enabled
	if (leapzombies == 0 && !g_nemesis[id] && !g_survivor[id])
		return false;
	
	// Not the first zombie
	if (leapzombies == 2 && !g_nemesis[id] && !g_survivor[id] && !g_firstzombie[id])
		return false;
	
	// Not the last zombie
	if (leapzombies == 3 && !g_nemesis[id] && !g_survivor[id] && !g_lastzombie[id])
		return false;
	
	// Get currently pressed buttons
	static buttons
	buttons = pev(id, pev_button)
	
	// Not doing a longjump (added bot support)
	if ((!(buttons & IN_JUMP) || !(buttons & IN_DUCK)) && !is_user_bot(id))
		return false;
	
	// Get cooldown cvar
	static Float:cooldown
	cooldown = g_survivor[id] ? get_pcvar_float(cvar_leapsurvivorcooldown) : g_nemesis[id] ? get_pcvar_float(cvar_leapnemesiscooldown) : get_pcvar_float(cvar_leapzombiescooldown)
	
	// Cooldown not over yet
	if (get_gametime() - g_lastleaptime[id] < cooldown)
		return false;
	
	// Not on ground or not enough speed
	if (!(pev(id, pev_flags) & FL_ONGROUND) || fm_get_speed(id) < 80)
		return false;
	
	return true;
}

// Checks if a player should be Pain Shock Free
allowed_painshockfree(id)
{
	// Pain shock free available for zombies/nemesis/survivor only
	if (!g_zombie[id] && !g_survivor[id])
		return false;
	
	// Nemesis cvar not enabled
	if (g_nemesis[id] && !get_pcvar_num(cvar_nempainfree))
		return false;
	
	// Survivor cvar not enabled
	if (g_survivor[id] && !get_pcvar_num(cvar_survpainfree))
		return false;
	
	// Get zombie cvar
	static zombiepainfree
	zombiepainfree = get_pcvar_num(cvar_zombiepainfree)
	
	// Zombie cvar not enabled
	if (zombiepainfree == 0 && !g_survivor[id] && !g_nemesis[id])
		return false;
	
	// Not the last zombie
	if (zombiepainfree == 2 && !g_survivor[id] && !g_nemesis[id] && !g_lastzombie[id])
		return false;
	
	// Not on ground
	if (!(pev(id, pev_flags) & FL_ONGROUND))
		return false;
	
	return true;
}

// Checks if a player is allowed to be zombie
allowed_zombie(id)
{
	if (g_zombie[id] || g_swarmround || g_nemround || g_survround || g_plagueround || g_endround || !is_user_alive(id) || task_exists(TASK_WELCOMEMSG) || (!g_zombie[id] && fnGetHumans() == 1))
		return false;
	
	return true;
}

// Checks if a player is allowed to be human
allowed_human(id)
{
	if (!g_zombie[id] || g_swarmround || g_nemround || g_survround || g_plagueround || g_endround || !is_user_alive(id) || task_exists(TASK_WELCOMEMSG) || (g_zombie[id] && fnGetZombies() == 1))
		return false;
	
	return true;
}

// Checks if a player is allowed to be survivor
allowed_survivor(id)
{
	if (g_endround || !g_newround || !is_user_alive(id) || !get_pcvar_num(cvar_surv) || task_exists(TASK_WELCOMEMSG) || fnGetAlive() < get_pcvar_num(cvar_survminplayers))
		return false;
	
	return true;
}

// Checks if a player is allowed to be nemesis
allowed_nemesis(id)
{
	if (g_endround || !g_newround || !is_user_alive(id) || !get_pcvar_num(cvar_nem) || task_exists(TASK_WELCOMEMSG) || fnGetAlive() < get_pcvar_num(cvar_nemminplayers))
		return false;
	
	return true;
}

// Checks if a player is allowed to respawn
allowed_respawn(id)
{
	static team
	team = fm_get_user_team(id)
	
	if (g_endround || g_survround || g_swarmround || g_nemround || g_plagueround || team == CS_TEAM_SPECTATOR || team == CS_TEAM_UNASSIGNED || !is_user_connected(id) || is_user_alive(id))
		return false;
	
	return true;
}

// Checks if swarm mode is allowed
allowed_swarm()
{
	if (g_endround || !g_newround || !get_pcvar_num(cvar_swarm) || task_exists(TASK_WELCOMEMSG) || fnGetAlive() < get_pcvar_num(cvar_swarmminplayers))
		return false;
	
	return true;
}

// Checks if multi infection mode is allowed
allowed_multi()
{
	if (g_endround || !g_newround || !get_pcvar_num(cvar_multi) || task_exists(TASK_WELCOMEMSG) || floatround(fnGetAlive()*get_pcvar_float(cvar_multiratio), floatround_ceil) < 2 || floatround(fnGetAlive()*get_pcvar_float(cvar_multiratio), floatround_ceil) >= fnGetAlive() || fnGetAlive() < get_pcvar_num(cvar_multiminplayers))
		return false;
	
	return true;
}

// Checks if plague mode is allowed
allowed_plague()
{
	if (g_endround || !g_newround || !get_pcvar_num(cvar_plague) || 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 || fnGetAlive() < get_pcvar_num(cvar_plagueminplayers))
		return false;
	
	return true;
}

// Admin Command. zp_zombie
command_zombie(id, player)
{
	static name1[32], name2[32]
	get_user_name(id, name1, sizeof name1 - 1)
	get_user_name(player, name2, sizeof name2 - 1)
	
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %s %L", name2, LANG_PLAYER, "CMD_INFECT")
		case 2: client_print(0, print_chat, "ADMIN %s - %s %L", name1, name2, 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, sizeof authid - 1)
		get_user_ip(id, ip, sizeof ip - 1, 1)
		formatex(logdata, sizeof logdata - 1, "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", name1, authid, ip, name2, 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)
	}
}

// Admin Command. zp_human
command_human(id, player)
{
	static name1[32], name2[32]
	get_user_name(id, name1, sizeof name1 - 1)
	get_user_name(player, name2, sizeof name2 - 1)
	
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %s %L", name2, LANG_PLAYER, "CMD_DISINFECT")
		case 2: client_print(0, print_chat, "ADMIN %s - %s %L", name1, name2, 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, sizeof authid - 1)
		get_user_ip(id, ip, sizeof ip - 1, 1)
		formatex(logdata, sizeof logdata - 1, "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", name1, authid, ip, name2, LANG_SERVER,"CMD_DISINFECT", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	// Turn to human
	humanme(player, 0)
}

// Admin Command. zp_survivor
command_survivor(id, player)
{
	static name1[32], name2[32]
	get_user_name(id, name1, sizeof name1 - 1)
	get_user_name(player, name2, sizeof name2 - 1)
	
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %s %L", name2, LANG_PLAYER, "CMD_SURVIVAL")
		case 2: client_print(0, print_chat, "ADMIN %s - %s %L", name1, name2, LANG_PLAYER, "CMD_SURVIVAL")
	}
	
	 // Log to Zombie Plague log file?
	if (get_pcvar_num(cvar_logcommands))
	{
		static logdata[100], authid[32], ip[16]
		get_user_authid(id, authid, sizeof authid - 1)
		get_user_ip(id, ip, sizeof ip - 1, 1)
		formatex(logdata, sizeof logdata - 1, "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", name1, authid, ip, name2, LANG_SERVER,"CMD_SURVIVAL", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	// Turn into a Survivor
	remove_task(TASK_MAKEZOMBIE)
	make_a_zombie(MODE_SURVIVOR, player)
}

// Admin Command. zp_nemesis
command_nemesis(id, player)
{
	static name1[32], name2[32]
	get_user_name(id, name1, sizeof name1 - 1)
	get_user_name(player, name2, sizeof name2 - 1)
	
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %s %L", name2, LANG_PLAYER, "CMD_NEMESIS")
		case 2: client_print(0, print_chat, "ADMIN %s - %s %L", name1, name2, LANG_PLAYER, "CMD_NEMESIS")
	}
	
	// Log to Zombie Plague log file?
	if (get_pcvar_num(cvar_logcommands))
	{
		static logdata[100], authid[32], ip[16]
		get_user_authid(id, authid, sizeof authid - 1)
		get_user_ip(id, ip, sizeof ip - 1, 1)
		formatex(logdata, sizeof logdata - 1, "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", name1, authid, ip, name2, LANG_SERVER,"CMD_NEMESIS", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	// Turn into a Nemesis
	remove_task(TASK_MAKEZOMBIE)
	make_a_zombie(MODE_NEMESIS, player)
}

// Admin Command. zp_respawn
command_respawn(id, player)
{
	static name1[32], name2[32]
	get_user_name(id, name1, sizeof name1 - 1)
	get_user_name(player, name2, sizeof name2 - 1)
	
	// Show activity?
	switch (get_pcvar_num(cvar_showactivity))
	{
		case 1: client_print(0, print_chat, "ADMIN - %s %L", name2, LANG_PLAYER, "CMD_RESPAWN")
		case 2: client_print(0, print_chat, "ADMIN %s - %s %L", name1, name2, 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, sizeof authid - 1)
		get_user_ip(id, ip, sizeof ip - 1, 1)
		formatex(logdata, sizeof logdata - 1, "ADMIN %s <%s><%s> - %s %L (Players: %d/%d)", name1, authid, ip, name2, LANG_SERVER, "CMD_RESPAWN", fnGetPlaying(), g_maxplayers)
		log_to_file("zombieplague.log", logdata)
	}
	
	// Get deathmatch mode status
	static deathmatch
	deathmatch = get_pcvar_num(cvar_deathmatch)
	
	// Respawn as zombie?
	if (deathmatch == 2 || (deathmatch == 3 && random_num(0, 1)) || (deathmatch == 4 && fnGetZombies() < fnGetAlive()/2))
		g_respawn_as_zombie[player] = true
	
	respawn_player(player+TASK_SPAWN);
}

// Admin Command. zp_swarm
command_swarm(id)
{
	static name1[32]
	get_user_name(id, name1, sizeof name1 - 1)
	
	// 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", name1, 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, sizeof authid - 1)
		get_user_ip(id, ip, sizeof ip - 1, 1)
		formatex(logdata, sizeof logdata - 1, "ADMIN %s <%s><%s> - %L (Players: %d/%d)", name1, 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)
}

// Admin Command. zp_multi
command_multi(id)
{
	static name1[32]
	get_user_name(id, name1, sizeof name1 - 1)
	
	// 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", name1, 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, sizeof authid - 1)
		get_user_ip(id, ip, sizeof ip - 1, 1)
		formatex(logdata, sizeof logdata - 1, "ADMIN %s <%s><%s> - %L (Players: %d/%d)", name1, 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)
}

// Admin Command. zp_plague
command_plague(id)
{
	static name1[32]
	get_user_name(id, name1, sizeof name1 - 1)
	
	// 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", name1, 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, sizeof authid - 1)
		get_user_ip(id, ip, sizeof ip - 1, 1)
		formatex(logdata, sizeof logdata - 1, "ADMIN %s <%s><%s> - %L (Players: %d/%d)", name1, 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)
}

/*================================================================================
 [Custom Natives]
=================================================================================*/

// Native: zp_get_user_zombie
public native_get_user_zombie(id)
{
	return g_zombie[id];
}

// Native: zp_get_user_nemesis
public native_get_user_nemesis(id)
{
	return g_nemesis[id];
}

// Native: zp_get_user_survivor
public native_get_user_survivor(id)
{
	return g_survivor[id];
}

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

// Native: zp_get_user_last_zombie
public native_get_user_last_zombie(id)
{
	return g_lastzombie[id];
}

// Native: zp_get_user_last_human
public native_get_user_last_human(id)
{
	return g_lasthuman[id];
}

// Native: zp_get_user_zombie_class
public native_get_user_zombie_class(id)
{
	return g_zombieclass[id];
}

// Native: zp_set_user_zombie_class
public native_set_user_zombie_class(id, classid)
{
	g_zombieclassnext[id] = classid
}

// Native: zp_get_user_ammo_packs
public native_get_user_ammo_packs(id)
{
	return g_exp[id];
}

// Native: zp_set_user_ammo_packs
public native_set_user_ammo_packs(id, amount)
{
	g_exp[id] = amount;
}
public native_mostrar_menu(id)
{
    show_menu_game(id)
}

// Native: zp_get_zombie_maxhealth
public native_get_zombie_maxhealth(id)
{
	if (g_zombie[id] && !g_nemesis[id])
	{
		if (g_firstzombie[id])
			return floatround(g_zclass_hp[g_zombieclass[id]]*get_pcvar_float(cvar_zombiefirsthp));
		else
			return g_zclass_hp[g_zombieclass[id]];
	}
	return -1;
}

// Native: zp_get_user_batteries
public native_get_user_batteries(id)
{
	return g_flashbattery[id];
}

// Native: zp_set_user_batteries
public native_set_user_batteries(id, value)
{
	g_flashbattery[id] = value;
}

// Native: zp_infect_user
public native_infect_user(id, infector)
{
	// Not allowed to be zombie or round not started yet
	if (!allowed_zombie(id) || g_newround)
		return 0;
	
	// Infect
	zombieme(id, infector, 0, 0)
	return 1;
}

// Native: zp_disinfect_user
public native_disinfect_user(id)
{
	// Not allowed to be human
	if (!allowed_human(id))
		return 0;
	
	// Turn to human
	humanme(id, 0)
	return 1;
}

// Native: zp_respawn_user
public native_respawn_user(id, team)
{
	// 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(id+TASK_SPAWN)
	return 1;
}

// Native: zp_has_round_started
public native_has_round_started()
{
	return !g_newround;
}

// Native: zp_is_nemesis_round
public native_is_nemesis_round()
{
	return g_nemround;
}

// Native: zp_is_survivor_round
public native_is_survivor_round()
{
	return g_survround;
}

// Native: zp_is_swarm_round
public native_is_swarm_round()
{
	return g_swarmround;
}

// Native: zp_is_plague_round
public native_is_plague_round()
{
	return g_plagueround;
}

// Native: zp_register_extra_item
public native_register_extra_item(const name[], cost, team)
{
	// Reached extra items limit
	if (g_extraitem_i >= sizeof g_extraitem_name)
		return -1;
	
	// Strings passed byref
	param_convert(1)
	
	// Add the item
	copy(g_extraitem_name[g_extraitem_i], sizeof g_extraitem_name[] - 1, name)
	g_extraitem_cost[g_extraitem_i] = cost
	g_extraitem_team[g_extraitem_i] = team
	
	// Increase registered items counter
	g_extraitem_i++
	
	// Return id under which we registered the item
	return g_extraitem_i-1;
}

// Function: zp_register_extra_item (to be used within this plugin only)
native_register_extra_item2(const name[], cost, team)
{
	// Reached extra items limit
	if (g_extraitem_i >= sizeof g_extraitem_name)
		return;
	
	// Add the item
	copy(g_extraitem_name[g_extraitem_i], sizeof g_extraitem_name[] - 1, name)
	g_extraitem_cost[g_extraitem_i] = cost
	g_extraitem_team[g_extraitem_i] = team
	
	// Increase registered items counter
	g_extraitem_i++
}

// Native: zp_register_zombie_class
public native_register_zombie_class(const name[], const info[], const model[], const clawmodel[], hp, speed, Float:gravity, Float:knockback, level)
{
	// Reached zombie classes limit
	if (g_zclass_i >= sizeof g_zclass_name)
		return -1;
	
	// Strings passed byref
	param_convert(1)
	param_convert(2)
	param_convert(3)
	param_convert(4)
	
	// Add the class
	copy(g_zclass_name[g_zclass_i], sizeof g_zclass_name[] - 1, name)
	copy(g_zclass_info[g_zclass_i], sizeof g_zclass_info[] - 1, info)
	copy(g_zclass_model[g_zclass_i], sizeof g_zclass_model[] - 1, model)
	copy(g_zclass_clawmodel[g_zclass_i], sizeof g_zclass_clawmodel[] - 1, clawmodel)
	g_zclass_hp[g_zclass_i] = hp
	g_zclass_spd[g_zclass_i] = speed
	g_zclass_grav[g_zclass_i] = gravity
	g_zclass_kb[g_zclass_i] = knockback
        g_zclass_lvl[g_zclass_i] = level
	
	// Precache custom models and retrieve the modelindex
	new prec_mdl[100]
	formatex(prec_mdl, sizeof prec_mdl - 1, "models/player/%s/%s.mdl", model, model)
	g_zclass_modelindex[g_zclass_i] = engfunc(EngFunc_PrecacheModel, prec_mdl)
	formatex(prec_mdl, sizeof prec_mdl - 1, "models/Zombie_Warface/%s", clawmodel)
	engfunc(EngFunc_PrecacheModel, prec_mdl)
	
	// Increase registered classes counter
	g_zclass_i++
	
	// Return id under which we registered the class
	return g_zclass_i-1;
}

/*================================================================================
 [Custom Messages]
=================================================================================*/

// Custom Night Vision
public set_user_nvision(taskid)
{
	// Not meant to have nvision or not enabled
	if (!g_nvision[ID_NVISION] || !g_nvisionenabled[ID_NVISION])
	{
		// Task not needed anymore
		remove_task(taskid);
		return;
	}
	
	// Get player origin and alive status
	static Float:originF[3], alive
	pev(ID_NVISION, pev_origin, originF)
	alive = is_user_alive(ID_NVISION)
	
	// Nightvision message
	message_begin(MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, _, ID_NVISION)
	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_nvgsize)) // radius
	
	// Nemesis / Madness / Spectator in nemesis round
	if (g_nemesis[ID_NVISION] || (g_zombie[ID_NVISION] && g_nodamage[ID_NVISION]) || (!alive && 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] || !alive)
	{
		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()
}

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

// Custom Flashlight
public set_user_flashlight(taskid)
{
	// Not meant to have flashlight / not enabled / depleted
	if (!g_flashlight[ID_FLASH] || g_flashbattery[ID_FLASH] <= 0 || !get_pcvar_num(cvar_cflash))
	{
		// Task not needed anymore
		remove_task(taskid);
		return;
	}
	
	// Disable flashlight if it shouldn't be available
	if (g_zombie[ID_FLASH] || g_survivor[ID_FLASH] || !is_user_alive(ID_FLASH))
	{
		// Turn it off
		g_flashlight[ID_FLASH] = false;
		
		// Update flashlight HUD
		message_begin(MSG_ONE, g_msgFlashlight, _, ID_FLASH)
		write_byte(0) // toggle
		write_byte(100) // battery
		message_end()
		
		// Task not needed anymore
		remove_task(taskid);
		return;
	}
	
	// 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)
	
	// Make sure it's within the max distance
	if (get_distance_f(originF, destoriginF) > get_pcvar_float(cvar_flashdist))
		return;
	
	// Send to every player?
	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 special effects
infection_effects(id)
{
	// Screen fade?
	if (get_pcvar_num(cvar_infectionscreenfade))
	{
		message_begin(MSG_ONE_UNRELIABLE, g_msgScreenFade, _, id)
		write_short(UNIT_SECOND*1) // duration
		write_short(UNIT_SECOND*0) // hold time
		write_short(FFADE_IN) // fade type
		write_byte((g_nemesis[id]) ? get_pcvar_num(cvar_nemnvgcolor[0]) : get_pcvar_num(cvar_nvgcolor[0])) // r
		write_byte((g_nemesis[id]) ? get_pcvar_num(cvar_nemnvgcolor[1]) : get_pcvar_num(cvar_nvgcolor[1])) // g
		write_byte((g_nemesis[id]) ? get_pcvar_num(cvar_nemnvgcolor[2]) : 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 origin
	static Float:originF[3]
	pev(id, pev_origin, originF)
	
	// Tracers?
	if (get_pcvar_num(cvar_infectiontracers))
	{
		engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
		write_byte(TE_IMPLOSION) // TE id
		engfunc(EngFunc_WriteCoord, originF[0]) // x
		engfunc(EngFunc_WriteCoord, originF[1]) // y
		engfunc(EngFunc_WriteCoord, originF[2]) // z
		write_byte(128) // radius
		write_byte(20) // count
		write_byte(3) // duration
		message_end()
	}
	
	// Particle burst?
	if (get_pcvar_num(cvar_infectionparticles))
	{
		engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
		write_byte(TE_PARTICLEBURST) // TE id
		engfunc(EngFunc_WriteCoord, originF[0]) // x
		engfunc(EngFunc_WriteCoord, originF[1]) // y
		engfunc(EngFunc_WriteCoord, originF[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))
	{
		engfunc(EngFunc_MessageBegin, MSG_PVS, 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(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()
	}
}

// Nemesis/madness aura task
public zombie_aura(taskid)
{
	// Not nemesis, not in zombie madness
	if (!g_nemesis[ID_BLOOD] && !g_nodamage[ID_BLOOD])
		return;
	
	// Get player origin
	static Float:originF[3]
	pev(ID_BLOOD, pev_origin, originF)
	
	// Colored Aura
	engfunc(EngFunc_MessageBegin, MSG_PVS, 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(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()
	
	// Keep sending aura messages
	set_task(0.1, "zombie_aura", taskid)
}

// Make zombies leave footsteps and bloodstains on the floor
public make_blood(taskid)
{
	// Only bleed when moving on ground
	if (fm_get_speed(ID_BLOOD) < 80 || !(pev(ID_BLOOD, pev_flags) & FL_ONGROUND))
		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
	
	// Send the decal message
	engfunc(EngFunc_MessageBegin, MSG_PAS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_WORLDDECAL) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]) // x
	engfunc(EngFunc_WriteCoord, originF[1]) // y
	engfunc(EngFunc_WriteCoord, originF[2]) // z
	write_byte(zombie_decals[random_num(0, sizeof zombie_decals - 1)] + (g_czero*12)) // random decal number (offsets +12 for CZ)
	message_end()
}

// Flare Lighting
public flare_lighting(args[5])
{
	// Unexistant flare entity?
	if (!pev_valid(FLARE_ENTITY))
		return;
	
	// Flare depleted -clean up the mess-
	if (FLARE_DURATION <= 0)
	{
		engfunc(EngFunc_RemoveEntity, FLARE_ENTITY)
		return;
	}
	
	// Get origin
	static Float:originF[3]
	pev(FLARE_ENTITY, pev_origin, originF)
	
	// 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(FLARE_R) // r
	write_byte(FLARE_G) // g
	write_byte(FLARE_B) // b
	write_byte(51) //life
	write_byte((FLARE_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()
	
	// Decrease task cycle counter
	FLARE_DURATION -= 1;
	
	// Keep sending flare messaegs
	set_task(5.0, "flare_lighting", TASK_NADES, args, sizeof args)
}

// Burning Flames
public burning_flame(args[1], taskid)
{
	// Get player origin and flags
	static Float:originF[3], flags
	pev(ID_BLOOD, pev_origin, originF)
	flags = pev(ID_BLOOD, pev_flags)
	
	// Madness mode - in water - burning stopped
	if (g_nodamage[ID_BLOOD] || (flags & FL_INWATER) || FLAME_DURATION < 1)
	{
		// Smoke sprite
		engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
		write_byte(TE_SMOKE) // TE id
		engfunc(EngFunc_WriteCoord, originF[0]) // x
		engfunc(EngFunc_WriteCoord, originF[1]) // y
		engfunc(EngFunc_WriteCoord, originF[2]-50.0) // z
		write_short(g_smokeSpr) // sprite
		write_byte(random_num(15, 20)) // scale
		write_byte(random_num(10, 20)) // framerate
		message_end()
		
		return;
	}
	
	// Randomly play burning zombie scream sounds (not for nemesis)
	if (!random_num(0, 20) && !g_nemesis[ID_BLOOD])
		engfunc(EngFunc_EmitSound, ID_BLOOD, CHAN_VOICE, grenade_fire_player[random_num(0, sizeof grenade_fire_player - 1)], 1.0, ATTN_NORM, 0, PITCH_NORM)
	
	// Get fire slow down setting
	static Float:slowdown
	slowdown = get_pcvar_float(cvar_fireslowdown)
	
	// Fire slow down, unless nemesis
	if (slowdown > 0.0 && !g_nemesis[ID_BLOOD] && (flags & FL_ONGROUND))
	{
		static Float:velocity[3]
		pev(ID_BLOOD, pev_velocity, velocity)
		xs_vec_mul_scalar(velocity, slowdown, velocity)
		set_pev(ID_BLOOD, pev_velocity, velocity)
	}
	
	// Get health and fire damage setting
	static health, firedamage
	health = pev(ID_BLOOD, pev_health)
	firedamage = get_pcvar_num(cvar_firedamage)
	
	// Take damage from the fire
	if (health > firedamage)
		fm_set_user_health(ID_BLOOD, health - firedamage)
	
	// Flame sprite
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0)
	write_byte(TE_SPRITE) // TE id
	engfunc(EngFunc_WriteCoord, originF[0]+random_float(-5.0, 5.0)) // x
	engfunc(EngFunc_WriteCoord, originF[1]+random_float(-5.0, 5.0)) // y
	engfunc(EngFunc_WriteCoord, originF[2]+random_float(-10.0, 10.0)) // z
	write_short(g_flameSpr) // sprite
	write_byte(random_num(5, 10)) // scale
	write_byte(200) // brightness
	message_end()
	
	// Decrease task cycle counter
	FLAME_DURATION -= 1;
	
	// Keep sending flame messaegs
	set_task(0.2, "burning_flame", taskid, args, sizeof args)
}

// Infection Grenade: Green Blast
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()
}

// Fire Grenade: Fire Blast
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()
}

// Frost Grenade: Freeze Blast
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()
}

// Fix Dead Attrib on scoreboard
FixDeadAttrib(id)
{
	message_begin(MSG_BROADCAST, g_msgScoreAttrib)
	write_byte(id) // id
	write_byte(0) // attrib
	message_end()
}

// Send Death Message for infections
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()
}

// Update Player Frags and Deaths
UpdateFrags(attacker, victim, frags, deaths, scoreboard)
{
	// Set attacker frags
	set_pev(attacker, pev_frags, float(pev(attacker, pev_frags) + frags))
	
	// Set victim deaths
	fm_set_user_deaths(victim, fm_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(fm_get_user_deaths(attacker)) // deaths
		write_short(0) // class?
		write_short(fm_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(fm_get_user_deaths(victim)) // deaths
		write_short(0) // class?
		write_short(fm_get_user_team(victim)) // team
		message_end()
	}
}

// Remove Player Frags (when Nemesis/Survivor ignore_frags cvar is enabled)
RemoveFrags(attacker, victim)
{
	// Remove attacker frags
	set_pev(attacker, pev_frags, float(pev(attacker, pev_frags) - 1))
	
	// Remove victim deaths
	fm_set_user_deaths(victim, fm_get_user_deaths(victim) - 1)
}


// Plays a sound on clients
PlaySound(const sound[])
{
	client_cmd(0, "spk ^"%s^"", sound)
}

// Prints a colored message to target (use 0 for everyone), supports ML formatting.
// Note: I still need to make something like gungame's LANG_PLAYER_C to avoid unintended
// argument replacement when a function passes -1 (it will be considered a LANG_PLAYER)
zp_colored_print(target, const message[], any:...)
{
	static buffer[512], i, argscount
	argscount = numargs()
	
	// Send to everyone
	if (!target)
	{
		static player
		for (player = 1; player <= g_maxplayers; player++)
		{
			// Not connected
			if (!is_user_connected(player))
				continue;
			
			// Remember changed arguments
			static changed[5], changedcount // [5] = max LANG_PLAYER occurencies
			changedcount = 0
			
			// Replace LANG_PLAYER with player id
			for (i = 2; i < argscount; i++)
			{
				if (getarg(i) == LANG_PLAYER)
				{
					setarg(i, 0, player)
					changed[changedcount] = i
					changedcount++
				}
			}
			
			// Format message for player
			vformat(buffer, sizeof buffer - 1, message, 3)
			
			// Send it
			message_begin(MSG_ONE, g_msgSayText, _, player)
			write_byte(player)
			write_string(buffer)
			message_end()
			
			// Replace back player id's with LANG_PLAYER
			for (i = 0; i < changedcount; i++)
				setarg(changed[i], 0, LANG_PLAYER)
		}
	}
	
	// Send to specific target
	else
	{
		/*
		// Replace LANG_PLAYER with player id
		for (i = 2; i < argscount; i++)
		{
			if (getarg(i) == LANG_PLAYER)
				setarg(i, 0, target)
		}
		*/
		
		// Format message for player
		vformat(buffer, sizeof buffer - 1, message, 3)
		
		// Send it
		message_begin(MSG_ONE, g_msgSayText, _, target)
		write_byte(target)
		write_string(buffer)
		message_end()
	}
}

/*================================================================================
 [Stocks]
=================================================================================*/

// Set an entity's key value (from fakemeta_util)
stock fm_set_kvd(entity, const key[], const value[], const classname[])
{
	set_kvd(0, KV_ClassName, classname)
	set_kvd(0, KV_KeyName, key)
	set_kvd(0, KV_Value, value)
	set_kvd(0, KV_fHandled, 0)

	dllfunc(DLLFunc_KeyValue, entity, 0)
}

// Set entity's rendering type (from fakemeta_util)
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))
}

// Get entity's speed (from fakemeta_util)
stock fm_get_speed(entity)
{
	static Float:velocity[3]
	pev(entity, pev_velocity, velocity)
	
	return floatround(vector_length(velocity));
}

// Get entity's aim origins (from fakemeta_util)
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)
}

// Find entity by its owner (from fakemeta_util)
stock fm_find_ent_by_owner(entity, const classname[], owner)
{
	while ((entity = engfunc(EngFunc_FindEntityByString, entity, "classname", classname)) && pev(entity, pev_owner) != owner) {}
	
	return entity;
}

// Set player's health (from fakemeta_util)
stock fm_set_user_health(id, health)
{
	(health > 0) ? set_pev(id, pev_health, float(health)) : dllfunc(DLLFunc_ClientKill, id);
}

// Give an item to a player (from fakemeta_util)
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)
}

// Strip user weapons (from fakemeta_util)
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)
}

// Collect random spawn points
stock load_spawns()
{
	// Check for CSDM spawns of the current map
	new cfgdir[32], mapname[32], filepath[100], linedata[64]
	get_configsdir(cfgdir, sizeof cfgdir - 1)
	get_mapname(mapname, sizeof mapname - 1)
	formatex(filepath, sizeof filepath - 1, "%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, sizeof linedata - 1)
			
			// 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
	{
		// if not, collect regular spawns
		collect_spawns_ent("info_player_start")
		collect_spawns_ent("info_player_deathmatch")
	}
}

// Collect spawn points from entity origins
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;
	}
}

// Drop primary/secondary weapons
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 the weapon entity
			static wname[32], weapon_ent
			get_weaponname(weaponid, wname, sizeof wname - 1)
			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, fm_get_user_bpammo(id, weaponid))
			
			// Player drops the weapon and looses his bpammo
			engclient_cmd(id, "drop", wname)
			fm_set_user_bpammo(id, weaponid, 0)
		}
	}
}

// Stock by (probably) Twilight Suzuka -counts number of chars in a string
stock str_count(const str[], searchchar)
{
	new count, i
	//count = 0
	
	for (i = 0; i <= strlen(str); i++)
	{
		if(str[i] == searchchar)
			count++
	}
	
	return count;
}

// Checks if a space is vacant (credits to VEN)
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;
}

// Check if a player is stuck (credits to VEN)
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;
}

// Get User BP Ammo
stock fm_get_user_bpammo(id, weapon)
{
	return get_pdata_int(id, AMMOOFFSET[weapon], OFFSET_LINUX);
}

// Set User BP Ammo
stock fm_set_user_bpammo(id, weapon, amount)
{
	set_pdata_int(id, AMMOOFFSET[weapon], amount, OFFSET_LINUX)
}

// Set Weapon Clip Ammo
stock fm_set_weapon_ammo(entity, amount)
{
	set_pdata_int(entity, OFFSET_CLIPAMMO, amount, OFFSET_LINUX_WEAPONS)
}

// Get Weapon Clip Ammo
stock fm_get_weapon_ammo(entity)
{
	return get_pdata_int(entity, OFFSET_CLIPAMMO, OFFSET_LINUX_WEAPONS);
}

// Set User Zoom
stock fm_remove_user_zoom(id)
{
	set_pdata_int(id, OFFSET_ZOOMTYPE, CS_NO_ZOOM, OFFSET_LINUX)
}

// Get User Deaths
stock fm_get_user_deaths(id)
{
	return get_pdata_int(id, OFFSET_CSDEATHS, OFFSET_LINUX);
}

// Set User Deaths
stock fm_set_user_deaths(id, value)
{
	set_pdata_int(id, OFFSET_CSDEATHS, value, OFFSET_LINUX)
}

// Set User NVG for Bots
stock fm_set_bot_nvg(id, toggle)
{
	if (toggle)
	{
		g_nvision[id] = true
		set_pdata_int(id, OFFSET_NVGOGGLES, get_pdata_int(id, OFFSET_NVGOGGLES, OFFSET_LINUX) | HAS_NVGOGGLES, OFFSET_LINUX)
	}
	else
	{
		g_nvision[id] = false
		set_pdata_int(id, OFFSET_NVGOGGLES, get_pdata_int(id, OFFSET_NVGOGGLES, OFFSET_LINUX) &~ HAS_NVGOGGLES, OFFSET_LINUX)
	}
}

// Get User Team
stock fm_get_user_team(id)
{
	return get_pdata_int(id, OFFSET_CSTEAMS, OFFSET_LINUX);
}

// Set a Player's Team
stock fm_set_user_team(id, team)
{
	set_pdata_int(id, OFFSET_CSTEAMS, team, OFFSET_LINUX)
}

// Update Player's Team on all clients (adding needed delays)
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_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_set_user_team_msg", id+TASK_TEAM)
		g_teams_targettime = g_teams_targettime + 0.1
	}
}

// Send User Team Message
public fm_set_user_team_msg(taskid)
{
	// Beware: this message can now be picked up by other metamod
	// plugins (yeah, that includes AMXX plugins as well)
	
	// Set the switching team flag
	g_switchingteam[ID_TEAM] = true
	
	// Tell everyone my new team
	emessage_begin(MSG_ALL, g_msgTeamInfo)
	ewrite_byte(ID_TEAM) // player
	ewrite_string(TEAMNAMES[fm_get_user_team(ID_TEAM)]) // team
	emessage_end()
	
	// Done switching team
	g_switchingteam[ID_TEAM] = false
}

#if defined SET_MODELINDEX_OFFSET
// Set the precached model index (updates hitboxes server side)
stock fm_set_user_model_index(id, value)
{
	set_pdata_int(id, OFFSET_MODELINDEX, value, OFFSET_LINUX)
}
#endif

#if defined HANDLE_MODELS_ON_SEPARATE_ENT
// Set Player Model on Entity
stock fm_set_playermodel_ent(id)
{
	// Make original player entity invisible
	// but without hiding shadows or firing effects
	fm_set_rendering(id, kRenderFxNone, 255, 255, 255, kRenderTransTexture, 1)
	
	// Format model string
	static model[100]
	formatex(model, sizeof model - 1, "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)
	}
	
	engfunc(EngFunc_SetModel, g_ent_playermodel[id], model)
}

// Set Weapon Model on Entity
stock fm_set_weaponmodel_ent(id)
{
	// Get player's p_ weapon model
	static model[100]
	pev(id, pev_weaponmodel2, model, sizeof model - 1)
	
	// 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)
}

// Remove Custom Model Entities
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
	}
}
#else
// Set User Model
public fm_set_user_model(taskid)
{
	set_user_info(ID_MODEL, "model", g_playermodel[ID_MODEL])
}

// Get User Model -model passed byref-
stock fm_get_user_model(player, model[], len)
{
	get_user_info(player, "model", model, len)
}
// Update Player's Model on all clients (adding needed delays)
public fm_user_model_update(taskid)
{
	static Float:current_time
	current_time = get_gametime()
	
	if (current_time - g_models_targettime >= MODELCHANGE_DELAY)
	{
		fm_set_user_model(taskid)
		g_models_targettime = current_time
	}
	else
	{
		set_task(((g_models_targettime + MODELCHANGE_DELAY) - current_time), "fm_set_user_model", taskid)
		g_models_targettime = g_models_targettime + MODELCHANGE_DELAY
	}
}
#endif

public sistema_levels(id)
{
	while(g_exp[id] >= Levels[Lvl[id]])
	{
		Lvl[id]++
	}
	set_task(1.0, "sistema_levels", id)
}  

public show_menu_granades(id)
{ 
	new menu = menu_create("\rMenu de Bombas", "menu_handler") 
	
	if(g_exp[id] <= 0) 
	{ 
		menu_additem(menu, "\r ^n\d|1 Fuego ^n\d|1 Hielo ^n\d|1 Bengala|| \r[Min Lvl: 0]", "1", 0) 
	} 
	else if (g_exp[id] >= 0) 
	{ 
		menu_additem(menu, "\r ^n\w|1 Fuego ^n\w|1 Hielo ^n\w|1 Bengala||", "1", 0) 
	} 
	if(g_exp[id] <= 10200) 
	{ 
		menu_additem(menu, "\r ^n\d|1 Molotov ^n\d|2 Hielo ^n\d|1 Bengala|| \r[Min Lvl: 25]", "2", 0) 
	} 
	else if (g_exp[id] >= 10200)  
	{ 
		menu_additem(menu, "\r ^n\w|1 Fuego ^n\w|2 Hielo ^n\w|1 Bengala||", "2", 0) 
	} 
	if(g_exp[id] <= 32400) 
	{ 
		menu_additem(menu, "\r ^n\d|1 Fuego ^n\d|1 Hielo ^n\d|1 Bubble|| \r[Min Lvl: 50]", "3", 0) 
	} 
	if(g_exp[id] >= 32400) 
	{ 
		menu_additem(menu, "\r ^n\w|1 Fuego ^n\w|1 Hielo ^n\w|1 Bubble||", "3", 0) 
	} 
	if(g_exp[id] <= 93000) 
	{ 
		menu_additem(menu, "\r ^n\d|2 Molotov ^n\d|2 Hielo ^n\d|2 Bubble|| \r[Min Lvl: 110]", "4", 0) 
	} 
	else if (g_exp[id] >= 93000) 
	{ 
		menu_additem(menu, "\r ^n\w|2 Molotov ^n\w|2 Hielo ^n\w|2 Bubble||", "4", 0) 
	} 
	
	menu_display(id, menu, 0) 
} 

public menu_handler(id, menu, item) 
{ 
	if (item == MENU_EXIT) 
	{ 
		menu_destroy(menu) 
		return PLUGIN_HANDLED 
	} 
	
	if(g_zombie[id]) 
	{ 
		menu_destroy(menu) 
		return PLUGIN_HANDLED 
	} 
	
	new data[6], iName[64] 
	new access, callback 
	menu_item_getinfo(menu, item, access, data,5, iName, 63, callback) 
	new key = str_to_num(data) 
	
	new costo =  g_costgrenade[item] 
	
	if(g_exp[id] >= costo) 
	{ 
		switch(key) 
		{     
			case 1: 
			{ 
				if (g_exp[id] >= 0) 
				{ 
					fm_give_item(id, "weapon_hegrenade") 
					fm_give_item(id, "weapon_smokegrenade") 
					
				} 
			} 
			case 2: 
			{ 
				if (g_exp[id] >= 10200) 
				{ 
					fm_give_item(id, "weapon_hegrenade") 
					fm_give_item(id, "weapon_hegrenade") 
					fm_give_item(id, "weapon_smokegrenade")
					fm_give_item(id, "weapon_smokegrenade") 
					fm_set_user_bpammo(id, CSW_HEGRENADE, 2) 
					fm_set_user_bpammo(id, CSW_SMOKEGRENADE, 2) 
				
				} 
			} 
			case 3: 
			{ 
				if (g_exp[id] >= 32400) 
				{ 
					fm_give_item(id, "weapon_hegrenade") 
					fm_give_item(id, "weapon_hegrenade") 
					fm_give_item(id, "weapon_flashbang") 
					fm_give_item(id, "weapon_flashbang") 
					fm_give_item(id, "weapon_smokegrenade") 
					fm_give_item(id, "weapon_smokegrenade") 
					fm_give_item(id, "weapon_smokegrenade") 
					fm_set_user_bpammo(id, CSW_HEGRENADE, 2) 
					fm_set_user_bpammo(id, CSW_SMOKEGRENADE, 3) 
					
				} 
			} 
			case 4: 
			{ 
				if (g_exp[id] >= 93000) 
				{ 
					fm_give_item(id, "weapon_hegrenade") 
					fm_give_item(id, "weapon_hegrenade") 
					fm_give_item(id, "weapon_hegrenade") 
					fm_give_item(id, "weapon_flashbang") 
					fm_give_item(id, "weapon_flashbang") 
					fm_give_item(id, "weapon_flashbang") 
					fm_give_item(id, "weapon_smokegrenade") 
					fm_give_item(id, "weapon_smokegrenade")
					fm_give_item(id, "weapon_smokegrenade") 
					fm_set_user_bpammo(id, CSW_HEGRENADE, 3) 
					fm_set_user_bpammo(id, CSW_FLASHBANG, 3) 
					fm_set_user_bpammo(id, CSW_SMOKEGRENADE, 3)
				} 
			} 
		} 
	} 
	return PLUGIN_HANDLED 
}

public infectionFX2(id) 
{ 
	// Not alive 
	if (!is_user_alive(id)) 
		return; 
	
	// Get player origin 
	static Float:originF[3] 
	pev(id, pev_origin, originF) 
	
	if (!g_survivor[id]) 
	{ 
		// Nemesis aura 
		engfunc(EngFunc_MessageBegin, MSG_PVS, 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(20) // radius asdasdasd 
		write_byte((g_nemesis[id] || g_nodamage[id]) ? get_pcvar_num(cvar_nemnvgcolor[0]) : get_pcvar_num(cvar_nvgcolor[0])) // r 
		write_byte((g_nemesis[id] || g_nodamage[id]) ? get_pcvar_num(cvar_nemnvgcolor[1]) : get_pcvar_num(cvar_nvgcolor[1])) // g 
		write_byte((g_nemesis[id] || g_nodamage[id]) ? get_pcvar_num(cvar_nemnvgcolor[2]) : get_pcvar_num(cvar_nvgcolor[2]))  // b 
		write_byte(2) // life 
		write_byte(0) // decay rate 
		message_end() 
	} 
	else 
	{ 
		// Survivor aura 
		engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0) // Doesent matter this 
		write_byte(TE_DLIGHT) // Doesent matter this 
		engfunc(EngFunc_WriteCoord, originF[0]) // Doesent matter this 
		engfunc(EngFunc_WriteCoord, originF[1]) // Doesent matter this 
		engfunc(EngFunc_WriteCoord, originF[2]) // Doesent matter this 
		write_byte(45) // Here is the radius. I think 25 is ok, but is your choice 
		write_byte(0) // The red amount 
		write_byte(0) // The green amount 
		write_byte(255) // The blue amount 
		write_byte(2) // // Doesent matter this 
		write_byte(0) // Doesent matter this 
		message_end() 
	} 
	// Keep calling back the task for nemesis/zombie madness aura 
	if (g_nodamage[id] || (g_nemesis[id] && get_pcvar_num(cvar_nemaura)) || (g_survivor[id] && get_pcvar_num(cvar_survaura))) 
	{ 
		set_task(0.1, "infectionFX2", id) 
		return; 
	} 
	
	// Tracers 
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0) 
	write_byte(TE_IMPLOSION) // TE id 
	engfunc(EngFunc_WriteCoord, originF[0]) // x 
	engfunc(EngFunc_WriteCoord, originF[1]) // y 
	engfunc(EngFunc_WriteCoord, originF[2]) // z 
	write_byte(128) // radius 
	write_byte(20) // count 
	write_byte(3) // duration 
	message_end() 
	
	// Particle Burst 
	engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, originF, 0) 
	write_byte(TE_PARTICLEBURST) // TE id 
	engfunc(EngFunc_WriteCoord, originF[0]) // x 
	engfunc(EngFunc_WriteCoord, originF[1]) // y 
	engfunc(EngFunc_WriteCoord, originF[2]) // z 
	write_short(50) // radius 
	write_byte(70) // color 
	write_byte(3) // duration (will be randomized a bit) 
	message_end() 
} 

public fw_Awp_PrimaryAttack_Post(awp)
{
	new id = get_pdata_cbase(awp, 41, 4)
	
	if(!is_user_alive(id))
		return HAM_IGNORED
	
	if(is_user_connected(id))
	{
		static Float:flRate
		flRate = get_pcvar_float(cvar_rapides_awp)
		
		set_pdata_float(awp, 46, flRate, 4)
		set_pdata_float(awp, 47, flRate, 4)
		set_pdata_float(awp, 48, flRate, 4)
	}
	return HAM_IGNORED
}

public fw_Sg550_PrimaryAttack_Post(sg550)
{
	new id = get_pdata_cbase(sg550, 41, 4)
	
	if(!is_user_alive(id))
		return HAM_IGNORED
	
	if(is_user_connected(id))
	{
		static Float:flRate
		flRate = get_pcvar_float(cvar_rapides_sg550)
		
		set_pdata_float(sg550, 46, flRate, 4)
		set_pdata_float(sg550, 47, flRate, 4)
		set_pdata_float(sg550, 48, flRate, 4)
	}

	return HAM_IGNORED
 }

     public fw_Mac10_PrimaryAttack_Post(mac10)
     {
    new id = get_pdata_cbase(mac10, 41, 4)
    
    if(!is_user_alive(id))
        return HAM_IGNORED
    
    if(is_user_connected(id))
    {
        static Float:flRate
        flRate = get_pcvar_float(cvar_rapides_mac10)
        
        set_pdata_float(mac10, 46, flRate, 4)
        set_pdata_float(mac10, 47, flRate, 4)
        set_pdata_float(mac10, 48, flRate, 4)
    }
    return HAM_IGNORED
}  
     public fw_G3sg1_PrimaryAttack_Post(g3sg1)
     {
    new id = get_pdata_cbase(g3sg1, 41, 4)
    
    if(!is_user_alive(id))
        return HAM_IGNORED
    
    if(is_user_connected(id))
    {
        static Float:flRate
        flRate = get_pcvar_float(cvar_rapides_g3sg1)
        
        set_pdata_float(g3sg1, 46, flRate, 4)
        set_pdata_float(g3sg1, 47, flRate, 4)
        set_pdata_float(g3sg1, 48, flRate, 4)
    }
    return HAM_IGNORED
}  
     public fw_M4a1_PrimaryAttack_Post(m4a1)
     {
    new id = get_pdata_cbase(m4a1, 41, 4)
    
    if(!is_user_alive(id))
        return HAM_IGNORED
    
    if(is_user_connected(id))
    {
        static Float:flRate
        flRate = get_pcvar_float(cvar_rapides_m4a1)
        
        set_pdata_float(m4a1, 46, flRate, 4)
        set_pdata_float(m4a1, 47, flRate, 4)
        set_pdata_float(m4a1, 48, flRate, 4)
    }
    return HAM_IGNORED
}  
     public fw_Ump45_PrimaryAttack_Post(ump45)
     {
    new id = get_pdata_cbase(ump45, 41, 4)
    
    if(!is_user_alive(id))
        return HAM_IGNORED
    
    if(is_user_connected(id))
    {
        static Float:flRate
        flRate = get_pcvar_float(cvar_rapides_ump45)
        
        set_pdata_float(ump45, 46, flRate, 4)
        set_pdata_float(ump45, 47, flRate, 4)
        set_pdata_float(ump45, 48, flRate, 4)
    }
    return HAM_IGNORED
}  
     public fw_Scout_PrimaryAttack_Post(scout)
     {
    new id = get_pdata_cbase(scout, 41, 4)
    
    if(!is_user_alive(id))
        return HAM_IGNORED
    
    if(is_user_connected(id))
    {
        static Float:flRate
        flRate = get_pcvar_float(cvar_rapides_scout)
        
        set_pdata_float(scout, 46, flRate, 4)
        set_pdata_float(scout, 47, flRate, 4)
        set_pdata_float(scout, 48, flRate, 4)
    }
    return HAM_IGNORED
}  
     public fw_M249_PrimaryAttack_Post(m249)
     {
    new id = get_pdata_cbase(m249, 41, 4)
    
    if(!is_user_alive(id))
        return HAM_IGNORED
    
    if(is_user_connected(id))
    {
        static Float:flRate
        flRate = get_pcvar_float(cvar_rapides_m249)
        
        set_pdata_float(m249, 46, flRate, 4)
        set_pdata_float(m249, 47, flRate, 4)
        set_pdata_float(m249, 48, flRate, 4)
    }
    return HAM_IGNORED
}  
     public fw_Elite_PrimaryAttack_Post(elite)
     {
    new id = get_pdata_cbase(elite, 41, 4)
    
    if(!is_user_alive(id))
        return HAM_IGNORED
    
    if(is_user_connected(id))
    {
        static Float:flRate
        flRate = get_pcvar_float(cvar_rapides_elite)
        
        set_pdata_float(elite, 46, flRate, 4)
        set_pdata_float(elite, 47, flRate, 4)
        set_pdata_float(elite, 48, flRate, 4)
    }
    return HAM_IGNORED
}  

     public fw_Mp5navy_PrimaryAttack_Post(mp5navy)
     {
    new id = get_pdata_cbase(mp5navy, 41, 4)
    
    if(!is_user_alive(id))
        return HAM_IGNORED
    
    if(is_user_connected(id))
    {
        static Float:flRate
        flRate = get_pcvar_float(cvar_rapides_mp5navy)
        
        set_pdata_float(mp5navy, 46, flRate, 4)
        set_pdata_float(mp5navy, 47, flRate, 4)
        set_pdata_float(mp5navy, 48, flRate, 4)
    }
    return HAM_IGNORED
}  
     public fw_M3_PrimaryAttack_Post(m3)
     {
    new id = get_pdata_cbase(m3, 41, 4)
    
    if(!is_user_alive(id))
        return HAM_IGNORED
    
    if(is_user_connected(id))
    {
        static Float:flRate
        flRate = get_pcvar_float(cvar_rapides_m3)
        
        set_pdata_float(m3, 46, flRate, 4)
        set_pdata_float(m3, 47, flRate, 4)
        set_pdata_float(m3, 48, flRate, 4)
    }
    return HAM_IGNORED
}  


public on_new_round()
{
	g_enabled = get_pcvar_num(g_type)
	if(get_pcvar_num(g_recieved)) g_showrecieved = true   
}

public on_damage(id)
{
	if(g_enabled)
	{       
		static attacker; attacker = get_user_attacker(id)
		static damage; damage = read_data(2)  
		if(g_showrecieved)
		{
			set_hudmessage(255, 0, 0, 0.45, 0.50, 2, 0.1, 4.0, 0.1, 0.1, -1)
			ShowSyncHudMsg(id, g_hudmsg2, "%i", damage)       
		}
		if(is_user_connected(attacker))
		{
			switch(g_enabled)
			{
				case 1: {
					if (!g_zombie[attacker] || g_survivor[attacker])
					{
						g_damage_done[attacker] += damage
						remove_task(attacker+TASK_COMBO)
						set_task(0.1, "task_combo", attacker+TASK_COMBO)
						set_task(5.0, "bonificacion", attacker+TASK_COMBO)
						if (!g_happytime)
						{
							while(g_damage_done[attacker] >= g_combo[attacker] * 600)
							{
								if (Lvl[attacker] <= 60)
									g_combo[attacker] += 2
								else
								g_combo[attacker] += 1
							}
						}
						else if (g_happytime)
						{
							while(g_damage_done[attacker] >= g_combo[attacker] * 500)
							{
								if (Lvl[attacker] <= 60)
									g_combo[attacker] += 4
								else
									g_combo[attacker] += 2
							}
						}
						set_hudmessage(0, 100, 200, -1.0, 0.55, 2, 0.1, 4.0, 0.01, 0.01, -1)
						ShowSyncHudMsg(attacker, g_hudmsg1, "%i", damage)   
					}
					else
					{
						if (g_plagueround || g_nemround || g_swarmround || g_survround)
						{
							set_hudmessage(200, 100, 0, -1.0, 0.55, 2, 0.1, 4.0, 0.01, 0.01, -1)
							ShowSyncHudMsg(attacker, g_hudmsg1, "%i", damage)   
						}
						else
						{
							set_hudmessage(200, 100, 0, -1.0, 0.55, 2, 0.1, 4.0, 0.01, 0.01, -1)
							ShowSyncHudMsg(attacker, g_hudmsg1, "%i", damage)   
						}
					}
				}
				case 2:
				{
					set_hudmessage(0, 255, 0, -1.0, 0.55, 2, 0.1, 4.0, 0.01, 0.01, -1)
					ShowSyncHudMsg(attacker, g_hudmsg1, "%i", damage)    
				}
			}
		}
	}
}

public task_combo(attacker)
{
	attacker -= TASK_COMBO
	
	if (g_combo[attacker] < 49)
	{
		set_hudmessage(120, 120, 120, -1.0, 0.25, 0, 0.1, 4.0, 0.01, 0.01, -1)
		ShowSyncHudMsg(attacker, g_MsgSync3, "^n^n^n^n  Combo de %d ammo packs^nQue Buen Combo !!! %d damage", g_combo[attacker], g_damage_done[attacker])
	}
	if (g_combo[attacker] >= 50)
	{
		set_hudmessage(180, 0, 255, -1.0, 0.25, 0, 0.1, 4.0, 0.01, 0.01, -1)
		ShowSyncHudMsg(attacker, g_MsgSync3, "^n^n^n^n  Combo %d ammo packs^nQue Vicioso!!! %d damage^n", g_combo[attacker], g_damage_done[attacker])
	}
}

public bonificacion(attacker)
{
	attacker -= TASK_COMBO
	if (g_combo[attacker] == 1)
	{
		set_hudmessage(180, 0, 255, -1.0, 0.25, 0, 0.1, 4.0, 0.01, 0.01, -1)
		ShowSyncHudMsg(attacker, g_MsgSync3, "^n^n^n^n Combo finalizada (1)^nObtuviste 0 Ammos")
		return;
	}
	
	g_exp[attacker] += g_combo[attacker]
	g_exp[attacker] += g_combo[attacker]
	
	if (g_combo[attacker] >= 50)
	{
		set_hudmessage(180, 0, 255, -1.0, 0.25, 0, 0.1, 4.0, 0.01, 0.01, -1)
		ShowSyncHudMsg(attacker, g_MsgSync3, "^n^n^n^n Combo Terminado (%d)^nBonificacion de %d Ammo Packs", g_combo[attacker], g_combo[attacker] * 4)
	}
	else
	{
		set_hudmessage(255, 255, 255, -1.0, 0.25, 0, 0.1, 4.0, 0.01, 0.01, -1)
		ShowSyncHudMsg(attacker, g_MsgSync3, "^n^n^n^n  Combo Terminado (%d)^nObtuviste %d Ammo Packs", g_combo[attacker], g_combo[attacker] * 4)
	}
	
	g_damage_done[attacker] = 0
	g_combo[attacker] = 0
}


/* Menu asd */

public mh_asd(id, menu, item) {
	/* This event is called when someone presses a key on this menu */
}

public ma_asd(id) {
	/* This event is called when an item was selected */
}

public mcb_asd(id, menu, item) {
	/* This is the callback-event, here you can set items enabled or disabled. */
	/* If you want to enable an item, use: return ITEM_ENABLED */
	/* If you want to disable an item, use: return ITEM_DISABLED */
}
Andreita is offline
rak
Veteran Member
Join Date: Oct 2011
Location: banned country
Old 05-14-2012 , 02:49   Re: [ZP] Campo de fuerza
#16

Quote:
Originally Posted by Andreita View Post
Esque Lo puse de muchas maneras y no me jala u.u Este es mi CODE
Alguien me puede ayudaar a meterlo u.u Esque intente mil formas... Porfa!
Spoiler
PHP Code:
register_plugin("Zombie Fuerzas Especiales Aztecas"PLUGIN_VERSION"Andreiita"
no aprenden mas
__________________

www.amxmodx-es.com

Steam: Luchokoldo
rak is offline
Send a message via MSN to rak Send a message via Skype™ to rak
xLeoNNN
Veteran Member
Join Date: Sep 2010
Location: de_dust2
Old 05-14-2012 , 14:07   Re: [ZP] Campo de fuerza
#17

Quote:
Originally Posted by rak View Post
PHP Code:
register_plugin("Zombie Fuerzas Especiales Aztecas"PLUGIN_VERSION"Andreiita"
No cambies el autor de los plugins si tu no los hiciste, en caso de que lo hayas editado, también deja el autor anterior.
ahi esta mejor
__________________
xLeoNNN is offline
Send a message via MSN to xLeoNNN
Neeeeeeeeeel.-
Some Guy Yellin'
Join Date: Jul 2010
Location: Argentina
Old 05-14-2012 , 21:11   Re: [ZP] Campo de fuerza
#18

Baaaaaaaaaaaaaan
+report.
__________________
Neeeeeeeeeel.- is offline
Send a message via Skype™ to Neeeeeeeeeel.-
Jo4akiiTox
Member
Join Date: Dec 2011
Old 05-14-2012 , 21:31   Re: [ZP] Campo de fuerza
#19

Ademas aqui esta el qe edito gran parte de zp :S primojkoo
Jo4akiiTox is offline
 



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 19:47.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode