All pastes #82018 Raw Edit

Hawk552

public text v1 · immutable
·published 2006-07-08 01:02 UTC
rendered paste body
#include <amxmodx>
#include <amxmisc>
#include <fun>
#include <engine>
#include <cstrike>
#include <fakemeta>

/*

Copyleft 2006
Plugin thread: http://forums.alliedmods.net/showthread.php?t=40556

ZOMBIE MOD
==========

Description
This mod is basically an almost total rewrite of the Zombie Mod made by Apophis.
It has a few more features, and a few removed features that I felt were useless 
and too hard to maintain.

It's designed for player vs. player fighting, not bot vs. player or anything else.

At the beginning of the round, all players are transferred to CT. When the round 
begins, everyone is teleported to random locations across the map. Also, one player 
is turned into a zombie, who then tries to find and transform humans into zombies. 
The round ends when all players are zombies, or all zombies are dead.

Note: Random spawning uses a totally different method than the version made by apophis. 
Instead of gathering spawns from players walking around, this version picks a random 
point on the map, then searches upward until it finds an empty space. It then checks 
around if there's anything dangerous or could make a player stuck, and if not puts them 
there. Due to this, there is not 5 or so rounds needed before random spawning happens, 
but the spawning is slightly less accurate. To compensate for this, I added a client 
command, "say /stuck", to teleport them to another random spot. This method was done 
in an effort to reduce resource consumption, although I haven't benchmarked the two 
plugins against each other.

Commands
amx_zombie - toggles zombie mod on or off. Add the argument 0/off or 1/on to set it manually
amx_zombie_player - zombies target player

say /zombie - shows zombie help
say /stuck - unstucks you if you got stuck due to random spawning
say /flashlight - turns on powerful flashlight

Changelog:

	Jun 29, 2006 - v1.0 - 	Release
	
	Jun 30, 2006 - v1.1 -	[FEATURE] Zombie health display added
				[FEATURE] Random spawning added (amx_zombie_randomspawn)
				[FEATURE] Brainvision now has a cvar, "amx_zombie_brainvision_esp",
				which determines whether brainvision should act as ESP or not
				[FEATURE] Added lightning
				[BUG] Fixed weapons to not drop, instead switch to knife
				[BUG] Fixed messages to not display if zombie transtime < 3 seconds
				
	Jul 3, 2006  - v1.2 -	[FEATURE] Added amx_zombie_model cvar
				[BUG] Fixed a bug with second player joining
				[BUG] Fixed a bug where a player would turn into a zombie after round ends
				[BUG] Added precision to the random spawner
					
	
Credits:
VEN 		- force team win (I already had an idea how to do this, just forgot how
		to implement fake players)
XxAvalanchexX 	- Flashlight code
Twilight Suzuka - Random spawning method
apophis 	- idea and some code
	
*/

// the max coords of a map
// the real thing is 4096.0, but we don't really want to go off the map
#define MAP_MAX 3800.0
// the offset for flashlights in set_task
#define FLASHLIGHT_OFFSET 21301293
// the offset for random spawning in set_task
#define RANDOMSPAWN_OFFSET 92183985

// this is how long a user must wait to be unstucked
new const g_iUnstuckTime = 3
new bool:g_bUnstuck[33]

// this is to be used in conjunction with g_iZombie
enum
{
	// is the player a human?
	HUMAN = 0,
	// is the player transforming into a zombie? (ex.was just hit)
	TRANSFORMING,
	// is the player a zombie?
	ZOMBIE
}

// whether or not the round has ended
new bool:g_bRoundEnded

// whether or not the user has seen the welcome message
new bool:g_bSpawned[33]

// brainvision sprite
new g_iBrainvision

// used to detect if the user has flashlight on
new bool:g_bFlashlight[33]

// used to detect if nightvision should be allowed or not
new bool:g_bNightvision[33]

// what variant of zombie that the user is, as with the enum above
new g_iZombie[33]

// name of the zombie for cs_set_user_model
new g_szZombieModel[20]

// player model before being zombied
new g_szPlayerModel[33][20]

// scientist scream sounds
#define SCI_SCREAMS 9
new const g_szSciScreams[SCI_SCREAMS][] = 
{
	"scientist/scream01.wav",
	"scientist/scream02.wav",
	"scientist/scream03.wav",
	"scientist/scream04.wav",
	"scientist/scream05.wav",
	"scientist/scream06.wav",
	"scientist/scream07.wav",
	"scientist/scream08.wav",
	"scientist/scream09.wav"
}

// knife slash sounds
#define KNIFE_HITS 4
new const g_szKnifeHits[KNIFE_HITS][] =
{
	"weapons/knife_hit1.wav",
	"weapons/knife_hit2.wav",
	"weapons/knife_hit3.wav",
	"weapons/knife_hit4.wav"
}

// zombie slash sounds
#define ZOMBIE_HITS 3
new const g_szZombieHits[ZOMBIE_HITS][] =
{
	"zombie/claw_strike1.wav",
	"zombie/claw_strike2.wav",
	"zombie/claw_strike3.wav"
}

// knife miss sounds
#define KNIFE_ATTACKS 2
new const g_szKnifeAttacks[KNIFE_ATTACKS][] = 
{
	"weapons/knife_slash1.wav",
	"weapons/knife_slash2.wav"
}

// zombie miss sounds
#define ZOMBIE_ATTACKS 2
new const g_szZombieAttacks[ZOMBIE_ATTACKS][] =
{
	"zombie/zo_attack1.wav",
	"zombie/zo_attack2.wav"
}

// sound when the knife slashes with mouse2
new const g_szKnifeStab[] = "weapons/knife_stab.wav"
// sound when the knife hits the wall
new const g_szKnifeWall[] = "weapons/knife_hitwall1.wav"

// sound when transforming -> zombie
new g_szZombieSpawn[] = "zombie/zo_alert10.wav"

// nightvision on sound
new const g_szNvgOn[] = "items/nvg_on.wav"
// nightvision off sound
new const g_szNvgOff[] = "items/nvg_off.wav"

// pcvars
new g_pZombie
new g_pTransTime
new g_pHealth
new g_pSpeed
new g_pFlashlight
new g_pFlashlightR
new g_pFlashlightG
new g_pFlashlightB
new g_pFlashlightRadius
new g_pBrainvision
new g_pBrainvisionEsp
new g_pRandomSpawn
new g_pLightning
new g_pZombieSounds

// messages
new g_msgDeathMsg
new g_msgScoreInfo
new g_msgTextMsg

// version info
new const g_szVersion[] = "1.2"

// cvar stuff to set back
new g_iOldFlashlight
new g_iOldLimitTeams
new g_iOldAutoTeamBalance

// lightning
new g_iLastLights

public plugin_init()
{
	register_plugin("Zombie Mod",g_szVersion,"Hawk552")
	
	register_cvar("amx_zombiemod",g_szVersion,FCVAR_SERVER)
	
	g_pZombie = register_cvar("amx_zombie","1")
	g_pTransTime = register_cvar("amx_zombie_transtime","10")
	g_pHealth = register_cvar("amx_zombie_health","500")
	g_pSpeed = register_cvar("amx_zombie_speed","140")
	g_pFlashlight = register_cvar("amx_zombie_flashlight","1")
	g_pFlashlightR = register_cvar("amx_zombie_flashlight_r","255")
	g_pFlashlightG = register_cvar("amx_zombie_flashlight_g","255")
	g_pFlashlightB = register_cvar("amx_zombie_flashlight_b","255")
	g_pFlashlightRadius = register_cvar("amx_zombie_flashlight_radius","10")
	g_pBrainvision = register_cvar("amx_zombie_brainvision","1")
	g_pBrainvisionEsp = register_cvar("amx_zombie_brainvision_esp","0")
	g_pRandomSpawn = register_cvar("amx_zombie_randomspawn","1")
	g_pLightning = register_cvar("amx_zombie_lightning","1")
	g_pZombieSounds = register_cvar("amx_zombie_sounds","1")
	register_cvar("amx_zombie_model","models/player/zombie/zombie.mdl")

	register_concmd("amx_zombie","fnCmdZombie",ADMIN_BAN,"<on/off 0/1> omit to toggle")
	register_concmd("amx_zombie_player","fnCmdZombiePlayer",ADMIN_KICK,"<target> - zombies target")
	
	register_clcmd("nightvision","fnCmdNightvision")
	register_clcmd("jointeam","fnCmdJoinTeam")
	register_clcmd("say","fnCmdSay")
	
	register_menucmd(register_menuid("Team_Select",1),(1<<0)|(1<<1)|(1<<4)|(1<<5),"fnHandleTeamSelect")
	register_menucmd(register_menuid("#Buy",1),511,"fnBlockZombie")
	register_menucmd(register_menuid("BuyPistol",1),511,"fnBlockZombie")
	register_menucmd(register_menuid("BuyShotgun",1),511,"fnBlockZombie")
	register_menucmd(register_menuid("BuySub",1),511,"fnBlockZombie")
	register_menucmd(register_menuid("BuyRifle",1),511,"fnBlock")
	register_menucmd(register_menuid("BuyMachine",1),511,"fnBlock")
	register_menucmd(register_menuid("BuyItem",1),511,"fnBlockZombie")
	register_menucmd(-28,511,"fnBlockZombie")
	register_menucmd(-29,511,"fnBlockZombie")
	register_menucmd(-30,511,"fnBlockZombie")
	register_menucmd(-32,511,"fnBlockZombie")
	register_menucmd(-31,511,"fnBlock")
	register_menucmd(-33,511,"fnBlock")
	register_menucmd(-34,511,"fnBlockZombie")
	
	register_event("Damage","fnEventDamage","be")
	register_event("CurWeapon","fnEventCurWeapon","be","1=1")
	register_event("DeathMsg","fnEventDeathMsg","a")
	register_event("ResetHUD","fnEventResetHUD","be")
	register_logevent("fnEventRoundStart",2,"0=World triggered","1=Round_Start")
	register_event("SendAudio","fnEventRoundEnd","a","2=%!MRAD_terwin","2=%!MRAD_ctwin","2=%!MRAD_rounddraw")
	register_event("TextMsg","fnEventRoundEnd","a","2&#Game_C")
	
	register_forward(FM_EmitSound,"fnForwardEmitSound")
	
	g_iOldAutoTeamBalance = get_cvar_num("mp_autoteambalance")
	g_iOldFlashlight = get_cvar_num("mp_flashlight")
	g_iOldLimitTeams = get_cvar_num("mp_limitteams")
	
	set_cvar_num("mp_autoteambalance",0)
	set_cvar_num("mp_flashlight",1)
	set_cvar_num("mp_limitteams",0)
	
	new iEnt = create_entity("info_target")
	if(iEnt)
	{
		entity_set_string(iEnt,EV_SZ_classname,"zombiemod_lightning")
		DispatchSpawn(iEnt)
		entity_set_float(iEnt,EV_FL_nextthink,2.0)
		register_think("zombiemod_lightning","fnLightning")
	}
	
	g_msgDeathMsg = get_user_msgid("DeathMsg")
	g_msgScoreInfo = get_user_msgid("ScoreInfo")
	g_msgTextMsg = get_user_msgid("TextMsg")
}

public plugin_precache()
{
	new iCount
	
	for(iCount = 0;iCount < SCI_SCREAMS;iCount++)
		precache_sound(g_szSciScreams[iCount])
	
	for(iCount = 0;iCount < ZOMBIE_ATTACKS;iCount++)
		precache_sound(g_szZombieAttacks[iCount])
	
	for(iCount = 0;iCount < ZOMBIE_HITS;iCount++)
		precache_sound(g_szZombieHits[iCount])
	
	for(iCount = 0;iCount < KNIFE_ATTACKS;iCount++)
		precache_sound(g_szKnifeAttacks[iCount])
	
	for(iCount = 0;iCount < KNIFE_HITS;iCount++)
		precache_sound(g_szKnifeHits[iCount])
	
	precache_sound(g_szZombieSpawn)
	precache_sound(g_szKnifeStab)
	precache_sound(g_szKnifeWall)
	precache_sound(g_szNvgOn)
	precache_sound(g_szNvgOff)
	
	new szZombiePath[64]
	if(cvar_exists("amx_zombie_model"))
		get_cvar_string("amx_zombie_model",szZombiePath,63)
	else
		copy(szZombiePath,63,"models/player/zombie/zombie.mdl")
	
	precache_model(szZombiePath)
	remove_filepath(szZombiePath,g_szZombieModel,19)
	replace(g_szZombieModel,19,".mdl","")
		
	g_iBrainvision = precache_model("sprites/flare1.spr")
}

public fnForwardEmitSound(id,iChannel,szSound[])
{	
	if(id > 32 || id < 0 || !id || !is_user_alive(id) || !get_pcvar_num(g_pZombie) || !get_pcvar_num(g_pZombieSounds))
		return FMRES_IGNORED
	else if(g_iZombie[id] == TRANSFORMING)
		return FMRES_SUPERCEDE
	else if(g_iZombie[id] != ZOMBIE)
		return FMRES_IGNORED
	
	if(equali(szSound,g_szKnifeWall) || equali(szSound,g_szNvgOn) || equali(szSound,g_szNvgOff))
		return FMRES_SUPERCEDE
	else if(equali(szSound,g_szKnifeStab))
	{
		emit_sound(id,CHAN_AUTO,g_szZombieAttacks[random_num(0,ZOMBIE_ATTACKS - 1)],1.0,ATTN_NORM,0,PITCH_NORM)
		return FMRES_SUPERCEDE
	}
	
	for(new iCount = 0;iCount < KNIFE_ATTACKS;iCount++)
		if(equali(szSound,g_szKnifeAttacks[iCount]))
		{
			emit_sound(id,CHAN_AUTO,g_szZombieAttacks[random_num(0,ZOMBIE_ATTACKS - 1)],1.0,ATTN_NORM,0,PITCH_NORM)
			return FMRES_SUPERCEDE
		}
	
	for(new iCount = 0;iCount < KNIFE_HITS;iCount++)
		if(equali(szSound,g_szKnifeHits[iCount]))
		{
			emit_sound(id,CHAN_AUTO,g_szZombieHits[random_num(0,ZOMBIE_HITS - 1)],1.0,ATTN_NORM,0,PITCH_NORM)
			return FMRES_SUPERCEDE
		}
	
	return FMRES_IGNORED
}

public fnLightning(iEnt)
{
	if(!get_pcvar_num(g_pZombie))
		return entity_set_float(iEnt,EV_FL_nextthink,2.0)
	
	if(get_pcvar_num(g_pLightning)) 
	{
		if(random_num(0,14) == 1) 
		{
			g_iLastLights = 1
			new iRand = random_num(1,5)
			
			switch (iRand) 
			{
				case 1: 
					set_lights("aaaaaaaaabcdefdbaa")
				case 2: 
					set_lights("aaaaaagcdaaaaaa")
				case 3: 
					set_lights("aaacdefdbaaaa")
				case 4: 
					set_lights("aaaabbbaaaa")
				case 5: 
					set_lights("aaaacbbcaaaab")
			}
		} 
		else if (g_iLastLights)
		{
			g_iLastLights = 0
			set_lights("aaaaaaaaaaaaaaaaaaabbbaaaa")
		}
	} 
	else
		set_lights("a")
		
	return entity_set_float(iEnt,EV_FL_nextthink,2.0)
}

public fnBlock(id)
	return get_pcvar_num(g_pZombie) ? PLUGIN_HANDLED : PLUGIN_CONTINUE

public fnBlockZombie(id)
	return ((get_pcvar_num(g_pZombie) ? PLUGIN_HANDLED : PLUGIN_CONTINUE) && (g_iZombie[id] == ZOMBIE || g_iZombie[id] == TRANSFORMING))

public fnHandleTeamSelect(id,iKey)
{
	if(!get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
		
	if(iKey != 1)
	{
		engclient_cmd(id,"chooseteam")
		client_cmd(id,"spk ^"access denied^"")
		return PLUGIN_HANDLED
	}
	
	if(get_playersnum(true) == 2 && cs_get_user_team(id) != CS_TEAM_CT && cs_get_user_team(id) != CS_TEAM_T)
		set_task(2.0,"fnEventRoundStart")
	
	return PLUGIN_CONTINUE
}

public fnCmdZombie(id,level,cid)
{
	new iArgs = read_argc()
	if(!access(id,level) && !(iArgs == 1 || iArgs == 2))
		return PLUGIN_HANDLED
	
	if(iArgs == 1)
		get_pcvar_num(g_pZombie) ? fnDisableZombie() : fnEnableZombie()
	else
	{
		static szArg[5]
		read_argv(1,szArg,4)
		
		if(equali(szArg,"1") || equali(szArg,"on"))
			fnEnableZombie()
		else if(equali(szArg,"0") || equali(szArg,"off"))
			fnDisableZombie()
	}
	
	return PLUGIN_HANDLED
}

public fnCmdJoinTeam(id)
{
	if(!get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
	
	static szArg[2]
	read_args(szArg,1)
	
	if(str_to_num(szArg) != 2)
	{
		engclient_cmd(id,"chooseteam")
		client_cmd(id,"spk ^"access denied^"")
		return PLUGIN_HANDLED
	}
	
	if(get_playersnum(true) == 2 && cs_get_user_team(id) != CS_TEAM_CT && cs_get_user_team(id) != CS_TEAM_T)
		set_task(2.0,"fnEventRoundStart")
	
	return PLUGIN_CONTINUE
}

public fnRestartRound()
	set_cvar_num("sv_restartround",3)

public fnCmdZombiePlayer(id,level,cid)
{
	if(!cmd_access(id,level,cid,2) || !get_pcvar_num(g_pZombie))
		return PLUGIN_HANDLED
	
	static szArg[33]
	read_args(szArg,32)
	
	new iTarget = cmd_target(id,szArg)
	if(!iTarget)
		return PLUGIN_HANDLED
	
	fnTransform(iTarget)
	
	return PLUGIN_HANDLED
}

public fnCmdSay(id)
{
	if(!get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE

	static szArgs[15]
	read_args(szArgs,14)
	
	remove_quotes(szArgs)
	
	if(equali(szArgs,"/flashlight") && !(g_iZombie[id] == ZOMBIE || g_iZombie[id] == TRANSFORMING))
	{
		g_bFlashlight[id] = g_bFlashlight[id] ? false : true	
		client_print(id,print_chat,"[ZOMB] Your flashlight has been %s.",g_bFlashlight[id] ? "enabled" : "disabled")	
		
		return PLUGIN_HANDLED
	}
	else if(equali(szArgs,"/zombie"))
	{
		static szMotd[512]
		new iPos
		
		iPos += format(szMotd[iPos],511-iPos,"Welcome to Zombie Mod.<br>")
		iPos += format(szMotd[iPos],511-iPos,"The objective of this game is to defeat either the zombies, or the humans.<br>")
		iPos += format(szMotd[iPos],511-iPos,"Each round, one person spawns as a zombie. The humans must kill that zombie, and anyone he infects.<br>")
		iPos += format(szMotd[iPos],511-iPos,"As a human, you will be able to buy weapons but will only have a flashlight.<br>")
		if(get_pcvar_num(g_pFlashlight))
			iPos += format(szMotd[iPos],511-iPos,"To use a more powerful flashlight, say ^"/flashlight^".<br>")
		if(get_pcvar_num(g_pRandomSpawn))
			iPos += format(szMotd[iPos],511-iPos,"Say /stuck if you get stuck due to random spawning.<br>")
		iPos += format(szMotd[iPos],511-iPos,"As a zombie, you will have nightvision%s.<br>",get_pcvar_num(g_pBrainvision) ? " and brainvision" : "")
		iPos += format(szMotd[iPos],511-iPos,"While you are a zombie, try to infect humans by attacking them.<br>")
		iPos += format(szMotd[iPos],511-iPos,"Have fun!")
		
		show_motd(id,szMotd,"Zombie Mod Help")
		
		return PLUGIN_HANDLED
	}
	else if(equali(szArgs,"/stuck"))
	{
		if(g_bUnstuck[id])
			return client_print(id,print_chat,"[ZOMB] You have already used your unstuck.") + PLUGIN_HANDLED
		else if(!get_pcvar_num(g_pRandomSpawn))
			return client_print(id,print_chat,"[ZOMB] Random respawing is not enabled, there is no need for this.") + PLUGIN_HANDLED
		
		g_bUnstuck[id] = true
		
		static iOrigin[3]
		get_user_origin(id,iOrigin)
		
		client_print(id,print_chat,"[ZOMB] Please stand still for %i seconds.",g_iUnstuckTime)
		
		set_task(float(g_iUnstuckTime),"fnUnstuck",id,iOrigin,3)
		
		return PLUGIN_HANDLED
	}	
	
	return PLUGIN_CONTINUE
}

public fnUnstuck(iOrigin[3],id)
{
	static iCurOrigin[3]
	get_user_origin(id,iCurOrigin)
	
	for(new iCount = 0;iCount < 3;iCount++)
		if(iCurOrigin[iCount] != iOrigin[iCount])
			return PLUGIN_CONTINUE
	
	return fnSetRandomLocation(id)
}

public fnCmdNightvision(id)
{
	if(g_bNightvision[id] && get_pcvar_num(g_pZombie))
		return PLUGIN_HANDLED
	
	return PLUGIN_CONTINUE
}

public client_PreThink(id)
{
	if(!get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
	
	if(entity_get_int(id, EV_INT_effects) & 8 && g_iZombie[id] == ZOMBIE || g_iZombie[id] == TRANSFORMING && !task_exists(id + FLASHLIGHT_OFFSET) && !is_user_bot(id))
		set_task(1.0,"fnRemoveFlashlight",id + FLASHLIGHT_OFFSET)
	
	if(g_iZombie[id] == TRANSFORMING)
		entity_set_int(id,EV_INT_button,IN_CANCEL)
		
	if(g_iZombie[id] == ZOMBIE && get_pcvar_num(g_pBrainvision))
	{
		static iPlayers[32],iPlayersnum,iPlayer
		get_players(iPlayers,iPlayersnum,"a")
		
		static iOrigin[3],Float:vOrigin[3],Float:vPlayerOrigin[3]
		entity_get_vector(id,EV_VEC_origin,vPlayerOrigin)
		
		for(new iCount;iCount < iPlayersnum;iCount++)
		{
			iPlayer = iPlayers[iCount]
			
			if(g_iZombie[iPlayer] != HUMAN)
				continue
			
			entity_get_vector(iPlayer,EV_VEC_origin,vOrigin)
			
			if(!get_pcvar_num(g_pBrainvisionEsp))
			{
				new iTrace = trace_line(id,vPlayerOrigin,vOrigin,vOrigin)
				if(iTrace != iPlayer)
					continue
			}
			else
				trace_line(id,vPlayerOrigin,vOrigin,vOrigin)
			
			FVecIVec(vOrigin,iOrigin)
			
			message_begin(MSG_ONE_UNRELIABLE,SVC_TEMPENTITY,{0,0,0},id)
			write_byte(17)
			write_coord(iOrigin[0])
			write_coord(iOrigin[1])
			write_coord(iOrigin[2])
			write_short(g_iBrainvision)
			write_byte(10)
			write_byte(20)
			message_end()
		}
	}
	
	if(!g_bFlashlight[id] || !get_pcvar_num(g_pFlashlight))
		return PLUGIN_CONTINUE
	
	static iOrigin[3]
	get_user_origin(id,iOrigin,3)
	message_begin(MSG_BROADCAST,SVC_TEMPENTITY)
	write_byte(27)
	write_coord(iOrigin[0])
	write_coord(iOrigin[1])
	write_coord(iOrigin[2])
	write_byte(get_pcvar_num(g_pFlashlightRadius))
	write_byte(get_pcvar_num(g_pFlashlightR))
	write_byte(get_pcvar_num(g_pFlashlightG))
	write_byte(get_pcvar_num(g_pFlashlightB))
	write_byte(1)
	write_byte(30)
	message_end()
	
	return PLUGIN_CONTINUE
}

public fnRemoveFlashlight(id)
	if(entity_get_int(id - FLASHLIGHT_OFFSET, EV_INT_effects) & 8 && get_pcvar_num(g_pZombie))
		client_cmd(id - FLASHLIGHT_OFFSET,"impulse 100")

public plugin_log() 
{     
	if(read_logargc() != 2 || get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
	
	new szArg[16]
	read_logargv(1,szArg, 15)
	if(equali(szArg,"Restart_Round_("))
		return fnEventRoundEnd()
	
	return PLUGIN_CONTINUE
}

// I hate ResetHUD. So why am I using it? In this case, it's actually faster
// than wrapping around fnEventRoundStart(). Also, it'll detect right when
// the player spawns, not when the round starts.
public fnEventResetHUD(id)
{
	if(!get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
		
	cs_get_user_model(id,g_szPlayerModel[id],19)
	
	if(g_bSpawned[id])
		return PLUGIN_CONTINUE
		
	g_bSpawned[id] = true
	
	client_print(id,print_chat,"[ZOMB] Welcome to Zombie Mod by Doug ^"Hawk552^".")
	client_print(id,print_chat,"[ZOMB] For help, say ^"/zombie^" to bring up a window with details on this mod.")
	
	return PLUGIN_CONTINUE
}

public fnEventRoundStart()
{
	if(!get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
		
	g_bRoundEnded = false
	
	set_lights("a")
	
	new iEnt
	while((iEnt = find_ent_by_class(iEnt, "hostage_entity")) != 0) 
	{
		entity_set_float(iEnt,EV_FL_health,-1.0)
		fakedamage(iEnt,"worldspawn",10.0,1)
	}
	
	static iPlayers[32],iPlayersnum,Float:vTerStart[3],szName[33]
	get_players(iPlayers,iPlayersnum)
	
	new iRand = random_num(0,iPlayersnum - 1),iPlayer = iPlayers[iRand]
	iEnt = find_ent_by_class(-1,"info_player_deathmatch")
	if(iEnt && iPlayer)
	{
		entity_get_vector(iEnt,EV_VEC_origin,vTerStart)
		entity_set_vector(iPlayer,EV_VEC_origin,vTerStart)
	
		g_iZombie[iPlayer] = ZOMBIE
	
		fnTransform(iPlayer)
	
		set_task(0.1,"fnEventCurWeapon",iPlayer)
	
		get_user_name(iPlayer,szName,32)
	
		set_hudmessage(255,0,0,0.05,0.45,0,6.0,6.0,0.5,0.15,-1)
		show_hudmessage(0,"%s is the first zombie!",szName)
		
		if(get_pcvar_num(g_pRandomSpawn))
			fnSetRandomLocation(iPlayer)
			
		g_bUnstuck[iPlayer] = false
	}
	
	for(new iCount;iCount < iPlayersnum;iCount++)
	{
		if(iCount == iRand)
			continue
		
		iPlayer = iPlayers[iCount]
		
		if(!is_user_alive(iPlayer))
			continue
		
		g_iZombie[iPlayer] = HUMAN
		cs_set_user_team(iPlayer,CS_TEAM_CT)
		fnSetModel(iPlayer)
		
		if(get_pcvar_num(g_pRandomSpawn))
			fnSetRandomLocation(iPlayer)
			
		g_bUnstuck[iPlayer] = false
	}
	
	return PLUGIN_CONTINUE
}

public fnEventRoundEnd()
{
	if(!get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
	
	static iPlayers[32],iPlayersnum,iPlayer
	get_players(iPlayers,iPlayersnum)
	
	for(new iCount;iCount < iPlayersnum;iCount++)
	{
		iPlayer = iPlayers[iCount]
		
		cs_set_user_team(iPlayer,CS_TEAM_CT)
		g_iZombie[iPlayer] = HUMAN
		fnSetModel(iPlayer)
		
		if(task_exists(iPlayer))
			remove_task(iPlayer)
	}
	
	return PLUGIN_CONTINUE
}

public fnEventDeathMsg()
	if(get_pcvar_num(g_pZombie))
		fnCheckRound()

public fnEventCurWeapon(id)
{
	if(!get_pcvar_num(g_pZombie) || !id)
		return PLUGIN_CONTINUE
	
	switch(g_iZombie[id])
	{
		case TRANSFORMING :
		{
			new iClip,iAmmo,iWeap = get_user_weapon(id,iClip,iAmmo)
			if(iWeap != CSW_KNIFE)
				client_cmd(id,"weapon_knife")
			
			entity_set_string(id, EV_SZ_viewmodel, "")
			entity_set_string(id, EV_SZ_weaponmodel, "")
			
			set_user_maxspeed(id,get_pcvar_float(g_pSpeed) / 2)
		}
		case ZOMBIE :
		{
			new iClip,iAmmo,iWeap = get_user_weapon(id,iClip,iAmmo)
			if(iWeap != CSW_KNIFE)
				client_cmd(id,"weapon_knife")
			
			entity_set_string(id, EV_SZ_viewmodel, "")
			entity_set_string(id, EV_SZ_weaponmodel, "")
			
			set_user_maxspeed(id,get_pcvar_float(g_pSpeed))
		}
	}
	
	return PLUGIN_CONTINUE
}

public fnEventDamage(id)
{
	if(!id || !is_user_alive(id) || !get_pcvar_num(g_pZombie) ||  read_data(2) < 1)
		return PLUGIN_CONTINUE
	
	if(g_iZombie[id] == ZOMBIE || g_iZombie[id] == TRANSFORMING)
		fnShowHealth(id)
	
	if(g_iZombie[id] == ZOMBIE || g_iZombie[id] == TRANSFORMING)
		return PLUGIN_CONTINUE
	
	new iAttacker = get_user_attacker(id)
	
	if(!iAttacker || iAttacker == id || !is_valid_ent(iAttacker))
		return PLUGIN_CONTINUE
	
	if(g_iZombie[iAttacker] == ZOMBIE)
	{
		fnTransform(id)
	
		static szName[33]
		get_user_name(id,szName,32)
		
		fnAddFrag(iAttacker)
		fnAddDeath(id)
	
		set_hudmessage(255,0,0,0.05,0.45,0,6.0,6.0,0.5,0.15,-1)
		show_hudmessage(0,"%s is now a zombie (%i/%i)",szName,fnGetZombies(),get_playersnum())
	
		fnCheckRound()
	}
	
	return PLUGIN_CONTINUE
}

fnTransform(id)
{
	if(!get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
	
	g_iZombie[id] = TRANSFORMING
	
	emit_sound(id,CHAN_AUTO,g_szSciScreams[random(SCI_SCREAMS)],1.0,ATTN_NORM,0,PITCH_NORM)
	
	if(!task_exists(id))
		set_task(get_pcvar_float(g_pTransTime),"fnSetZombie",id)
	
	cs_set_user_team(id,CS_TEAM_T)
	
	fnSetModel(id)
	
	// defaults to 1, but adding the extra ,1 makes it more clear and readable
	cs_set_user_nvg(id,1)
	engclient_cmd(id,"nightvision")
	g_bNightvision[id] = true
	
	g_bFlashlight[id] = false
	
	cs_set_user_bpammo(id, CSW_HEGRENADE, 0)
	cs_set_user_bpammo(id, CSW_SMOKEGRENADE, 0)
	cs_set_user_bpammo(id, CSW_FLASHBANG, 0)
	
	if(get_pcvar_num(g_pTransTime) > 3)
		client_print(id,print_chat,"[ZOMB] You are being transformed into a zombie.")
	
	fnEventCurWeapon(id)
	
	set_task(1.0,"fnShowHealth",id)
	
	return PLUGIN_CONTINUE
}

public fnShowHealth(id)
{
	if(g_iZombie[id] != ZOMBIE && g_iZombie[id] != TRANSFORMING || !get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
	
	new iHealth = get_user_health(id),Float:flR = float(iHealth),Float:flG = float(iHealth)
	flR *= 2.55
	flG /= 2.55
	
	set_hudmessage(floatround(flR),floatround(flG),0,0.05,0.90,0,1.0,1.0,0.5,0.15,4)
	
	show_hudmessage(id,"Health: %d",iHealth)
	
	return set_task(1.0,"fnShowHealth",id)
}

fnSetModel(id)
	switch(g_iZombie[id])
	{
		case HUMAN : 
			cs_set_user_model(id,g_szPlayerModel[id])
		case TRANSFORMING || ZOMBIE :
		{
			cs_get_user_model(id,g_szPlayerModel[id],19)
			cs_set_user_model(id,g_szZombieModel)
		}
	}

fnGetZombies()
{
	static iPlayers[32]
	new iZombies,iPlayersnum,iPlayer
	
	get_players(iPlayers,iPlayersnum,"a")
	
	for(new iCount;iCount < iPlayersnum;iCount++)
	{
		iPlayer = iPlayers[iCount]
		if(g_iZombie[iPlayer] == ZOMBIE || g_iZombie[iPlayer] == TRANSFORMING)
			iZombies++
	}
	
	return iZombies
}

public fnSetZombie(id)
{
	if(!is_user_alive(id) || !get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
	
	g_iZombie[id] = ZOMBIE
	
	emit_sound(id,CHAN_AUTO,g_szZombieSpawn,1.0,ATTN_NORM,0,PITCH_NORM)
	
	client_print(id,print_chat,"[ZOMB] You are now a zombie. Attack humans to win the round!")
	
	set_user_health(id,get_pcvar_num(g_pHealth))
	
	fnEventCurWeapon(id)
	
	return PLUGIN_CONTINUE
}

public client_disconnect(id)
{
	g_iZombie[id] = HUMAN
	g_bFlashlight[id] = false
	g_bSpawned[id] = false
	
	fnCheckRound()
}

fnCheckRound()
{
	if(!get_pcvar_num(g_pZombie))
		return PLUGIN_CONTINUE
	
	static iPlayers[32],iPlayersnum
	get_players(iPlayers,iPlayersnum,"e","CT")
	
	if(!iPlayersnum && !g_bRoundEnded)
	{
		g_bRoundEnded = true
		client_print(0,print_chat,"[ZOMB] The zombies have won.")
		
		new id = engfunc(EngFunc_CreateFakeClient,"Hawk552_Pwns")
		if(!id)
			return PLUGIN_CONTINUE
			
		set_msg_block(g_msgTextMsg,BLOCK_SET)	
		dllfunc(DLLFunc_ClientPutInServer,id)
		
		cs_set_user_team(id,CS_TEAM_CT)
		cs_user_spawn(id)
		entity_set_vector(id,EV_VEC_origin,Float:{8191.0, 8191.0, 8191.0})
		set_msg_block(g_msgDeathMsg,BLOCK_ONCE)
		fakedamage(id,"internet",200.0,DMG_CRUSH)
		
		server_cmd("kick #%d",get_user_userid(id))
		server_exec()
		
		set_msg_block(g_msgTextMsg,BLOCK_NOT)
	}
	else if(!fnGetZombies() && !g_bRoundEnded)
	{
		g_bRoundEnded = true
		client_print(0,print_chat,"[ZOMB] The humans have won.")
	}
		
	return PLUGIN_CONTINUE
}

fnEnableZombie()
{
	set_pcvar_num(g_pZombie,1)
	
	fnEventRoundEnd()
	
	set_cvar_num("sv_restartround",3)
	
	client_print(0,print_chat,"[ZOMB] Zombie Mod has been enabled.")
	
	set_cvar_num("mp_autoteambalance",0)
	set_cvar_num("mp_flashlight",1)
	set_cvar_num("mp_limitteams",0)
	
	return PLUGIN_CONTINUE
}

fnDisableZombie()
{
	fnEventRoundEnd()
	
	set_pcvar_num(g_pZombie,0)
	
	set_lights("m")
	
	set_cvar_num("sv_restartround",3)
	
	client_print(0,print_chat,"[ZOMB] Zombie Mod has been disabled.")
	
	set_cvar_num("mp_autoteambalance",g_iOldAutoTeamBalance)
	set_cvar_num("mp_flashlight",g_iOldFlashlight)
	set_cvar_num("mp_limitteams",g_iOldLimitTeams)
	
	return PLUGIN_CONTINUE
}

fnAddFrag(id)
{
	new iFrags = get_user_frags(id) + 1
	set_user_frags(id,iFrags)
	
	message_begin(MSG_BROADCAST,g_msgScoreInfo)
	write_byte(id)
	write_short(iFrags)
	write_short(get_user_deaths(id))
	write_short(0)
	write_short(get_user_team(id))
	message_end()
}

fnAddDeath(id)
{
	new iDeaths = cs_get_user_deaths(id) + 1
	cs_set_user_deaths(id,iDeaths)
	
	message_begin(MSG_BROADCAST,g_msgScoreInfo)
	write_byte(id)
	write_short(get_user_frags(id))
	write_short(iDeaths)
	write_short(0)
	write_short(get_user_team(id))
	message_end()
}

public fnSetRandomLocation(id)
{
	static Float:vOrigin[3],iContents
	
	vOrigin[0] = random_float(-MAP_MAX,MAP_MAX)
	vOrigin[1] = random_float(-MAP_MAX,MAP_MAX)	
	vOrigin[2] = -MAP_MAX
	
	do
	{
		if(vOrigin[2] > MAP_MAX)
			return fnSetRandomLocation(id)
			
		vOrigin[2] += 10.0
		iContents = PointContents(vOrigin)
	}
	while(iContents != CONTENTS_EMPTY)
	
	vOrigin[2] += 200.0
	if(PointContents(vOrigin) != CONTENTS_EMPTY)
		return fnSetRandomLocation(id)
	vOrigin[2] -= 160.0
	
	for(new iCount = 0;iCount < 2;iCount++)
	{
		for(new Float:flDist = -36.0;flDist < 36.0;flDist += 36.0)
		{
			vOrigin[2] += flDist
			
			vOrigin[iCount] += 33.0
			if(PointContents(vOrigin) != CONTENTS_EMPTY)
				return fnSetRandomLocation(id)
			vOrigin[iCount] -= 33.0
			
			vOrigin[iCount] -= 33.0
			if(PointContents(vOrigin) != CONTENTS_EMPTY)
				return fnSetRandomLocation(id)
			vOrigin[iCount] += 33.0		
			
			vOrigin[2] -= flDist
		}
	}
	
	entity_set_vector(id,EV_VEC_origin,vOrigin)
	
	if(entity_get_int(id,EV_INT_flags) & FL_INWATER)
		return PLUGIN_CONTINUE
		
	new iEnts[1]
	find_sphere_class(id,"player",200.0,iEnts,1)
	
	if(iEnts[0])
		return fnSetRandomLocation(id)
		
	set_task(0.1,"fnCheckLocation",id)
	
	return PLUGIN_CONTINUE
}

public fnCheckLocation(id)
{
	new iFlags = entity_get_int(id,EV_INT_flags)
	if(iFlags & FL_INWATER || iFlags & FL_SWIM || iFlags & FL_FLOAT)
		fnSetRandomLocation(id)
}