/***************************************************************************\
  ====================================================
  * || [Team_Umbrella] Mode Apocalipsis BY TR@VIESO || *
  ====================================================

	-------------------
	 *||DESCRIPCION||*
	-------------------

	Apocalipsis Mode: The final battle, a survivor, a sniper,
         a assassin, a nemesis, and part of humans infected.
	
\***************************************************************************/
#include < amxmodx >
#include < amxconst >
#include < fun >
#include < zombie_plague_advance >
#include < fakemeta_util >
#include < hamsandwich >

/************************************************************\
|                  Customizations Section                    |
|         You can edit here according to your liking         |
\************************************************************/

// Zombie plague no soporta que estas variablee sean cvars
// Tienen que estar definidas aqui en el codigo fuente!
new g_chance = 90 //Chance (1 in X)
new g_dmmode = 0 //Allow respawning on apocalipsis rounds

// This is the access flag required to start the game mode
// through the admin menu. Look in users.ini for more details
new const g_access_flag[] = "a"

// This is the sound which is played when the game mode is triggered
// Add as many as you want [Randomly chosen if more than one]
new const g_play_sounds[][] =
{
	"zombie_plague/sirena_alarma.wav" 
}

// Comment the following line to disable ambience sounds
// Just add two slashes ( // )
#define AMBIENCE_SOUNDS

#if defined AMBIENCE_SOUNDS
// Ambience Sounds (only .wav and .mp3 formats supported)
// Add as many as you want [Randomly chosen if more than one]
new const g_sound_ambience[][] =
{ 
	"zombie_plague/ambplaguemode.mp3"
}

// Duration in seconds of each sound
new const Float:g_sound_ambience_duration[] = { 168.0 }
#endif

/************************************************************\
|                  Customizations Ends Here..!!              |
|         You can edit the cvars in the plugin init          |
\************************************************************/

// Variables
new g_isalive[33], g_msgTeamInfo, g_gameid, g_maxplayers, cvar_survivorhp, cvar_survivornum, cvar_nemesishp, cvar_nemesisnum, cvar_assaaura, cvar_assaaurared, cvar_assaauragreen, cvar_assaaurablue, cvar_assaauraradio, cvar_minplayers, cvar_assaglow, cvar_ratio, cvar_sniperhp, cvar_snipernum, cvar_assahp, cvar_assanum, g_msg_sync

new Float:g_teams_targettime

// Ambience sounds task
#define TASK_AMB 3256

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



enum (+= 100)
{
	TASK_AURA,
        TASK_TEAM
}

#define ID_AURA (taskid - TASK_AURA)
#define ID_TEAM (taskid - TASK_TEAM)

const OFFSET_CSTEAMS = 114
const OFFSET_LINUX = 5

public plugin_init( )
{
	// Plugin registeration.
	register_plugin( "[ZP] Mode: Apocalypse","1.0", "TR@VIESO" )
	RegisterHam(Ham_Killed, "player", "fw_PlayerKilled")

	// Register some cvars
	// Edit these according to your liking
	cvar_minplayers = register_cvar("zp_apo_minplayers", "6")
        cvar_assaglow = register_cvar("zp_apo_assaglow", "1")
        cvar_assaaura = register_cvar("zp_apo_assaaura", "1")
        cvar_assaaurared = register_cvar("zp_apo_assaaura_red", "255")
        cvar_assaauragreen = register_cvar("zp_apo_assaaura_green", "150")
        cvar_assaaurablue = register_cvar("zp_apo_assaaura_blue", "0")
        cvar_assaauraradio = register_cvar("zp_apo_assaaura_radio", "20")
        cvar_survivorhp = register_cvar("zp_apo_survivor_hp", "1.0")
        cvar_survivornum = register_cvar("zp_apo_survivor_num", "1")
        cvar_nemesishp =  register_cvar("zp_apo_nemesis_hp", "1.0")
        cvar_nemesisnum = register_cvar("zp_apo_nemesis_num", "1")
	cvar_sniperhp =	  register_cvar("zp_apo_sniper_hp", "1.0")
        cvar_snipernum =  register_cvar("zp_apo_sniper_num", "1")
	cvar_assahp =	  register_cvar("zp_apo_assassin_hp", "1.0")
        cvar_assanum =	  register_cvar("zp_apo_assassin_num", "1")
	cvar_ratio = 	  register_cvar("zp_apo_inf_ratio", "0.2")

	// Get maxplayers
	g_maxplayers = get_maxplayers( )
	
	// Hud stuff
	g_msg_sync = CreateHudSyncObj()

        g_msgTeamInfo = get_user_msgid("TeamInfo")
}

// Game modes MUST be registered in plugin precache ONLY
public plugin_precache( )
{
	// Read the access flag
	new access_flag = read_flags( g_access_flag )
	new i
	
	// Precache the play sounds
	for (i = 0; i < sizeof g_play_sounds; i++)
		precache_sound( g_play_sounds[i] )
	
	// Precache the ambience sounds
	#if defined AMBIENCE_SOUNDS
	new sound[100]
	for (i = 0; i < sizeof g_sound_ambience; i++)
	{
		if (equal(g_sound_ambience[i][strlen(g_sound_ambience[i])-4], ".mp3"))
		{
			formatex(sound, sizeof sound - 1, "sound/%s", g_sound_ambience[i])
			precache_generic( sound )
		}
		else
		{
			precache_sound( g_sound_ambience[i] )
		}
	}
	#endif
	
	// Register our game mode
	g_gameid = zp_register_game_mode( "Modo Apocalipsis", access_flag, g_chance, 1, g_dmmode)
}

// Ham Player Killed Forward
public fw_PlayerKilled(id)
{
g_isalive[id] = false
remove_task(id+TASK_AURA)
}

// Player spawn post
public zp_player_spawn_post( id )
{
        remove_task(id+TASK_AURA)

        g_isalive[id] = true

	// Check for current mode
	if( zp_get_current_mode() == g_gameid )
	{
		// Check if the player is a zombie
		if( zp_get_user_zombie( id ))
		{
			zp_infect_user(id)
                }
	        else
		{
			zp_disinfect_user( id )			
		}
	}
}

public zp_round_started_pre( game )
{
	// Check if it is our game mode
	if( game == g_gameid )
	{
		// Check for min players
		if( fn_get_alive_players() < get_pcvar_num(cvar_minplayers) )
		{
			/**
			 * Note:
			 * This very necessary, you should return ZP_PLUGIN_HANDLED if
			 * some conditions required by your game mode are not met
			 * This will inform the main plugin that you have rejected
			 * the offer and so the main plugin will allow other game modes
			 * to be given a chance
			 */
			return ZP_PLUGIN_HANDLED
		}
		// Start our new mode
		start_apo_mode( )
	}
	// Make the compiler happy =)
	return PLUGIN_CONTINUE
}

public zp_round_started( game, id )
{
	// Check if it is our game mode
	if( game == g_gameid )
	{
		// Show HUD notice
		set_hudmessage(200, 200, 200, -1.0, 0.17, 1, 0.0, 10.0, 1.0, 1.0, -1)
		ShowSyncHudMsg(0, g_msg_sync, "Modo Apocalipsis !!!")
		
		// Play the starting sound
		client_cmd(0, "spk ^"%s^"", g_play_sounds[ random_num(0, sizeof g_play_sounds -1) ] )
		
		// Remove ambience task affects
		remove_task( TASK_AMB )
		
		// Set task to start ambience sounds
		#if defined AMBIENCE_SOUNDS
		set_task( 2.0, "start_ambience_sounds", TASK_AMB )
		#endif
	}
}

public zp_game_mode_selected( gameid, id )
{
	// Check if our game mode was called
	if( gameid == g_gameid )
		start_apo_mode( )
	
	// Make the compiler happy again =)
	return PLUGIN_CONTINUE
}

// This function contains the whole code behind this game mode
start_apo_mode( )
{
	// Create and initialize some important vars
	new id, i_alive, i_zombies, i_max_zombies
	i_alive = fn_get_alive_players( )
	id = 0

    // Convertir un monto especifico de jugadores en Survivors
	new i_survivors, i_max_survivors
	i_max_survivors = get_pcvar_num(cvar_survivornum)
	i_survivors = 0
	while (i_survivors < i_max_survivors)
    {
          id = fnGetRandomAlive(random_num(1, i_alive))
          if( zp_get_user_survivor( id ))
              continue; 

          zp_make_user_survivor(id)
          set_user_health( id, floatround(get_user_health(id) * get_pcvar_float(cvar_survivorhp)) )
          i_survivors++
    }
    

	// Convertir un monto especifico de jugadores en Nemesis
	new i_nemesis, i_max_nemesis
	i_max_nemesis = get_pcvar_num(cvar_nemesisnum)
	i_nemesis = 0
	while (i_nemesis < i_max_nemesis)
    {
          id = fnGetRandomAlive(random_num(1, i_alive))
          if( zp_get_user_nemesis( id ) || zp_get_user_survivor( id ))
              continue;

          zp_make_user_nemesis(id)
          set_user_health( id, floatround(get_user_health(id) * get_pcvar_float(cvar_nemesishp)) )
          i_nemesis++
    }
	

	// Convertir un monto especifico de jugadores en Asesinos
	new i_assassins, i_max_assassins
	i_max_assassins = get_pcvar_num(cvar_assanum)
	i_assassins = 0
	while (i_assassins < i_max_assassins)
	{
	      id = fnGetRandomAlive(random_num(1, i_alive))
              if( zp_get_user_nemesis( id ) || zp_get_user_assassin( id ) ||zp_get_user_survivor( id ))
                  continue;

              zp_make_user_assassin(id)
              if  (get_pcvar_num(cvar_assaglow))
		  fm_set_rendering(id, kRenderFxGlowShell, 250, 250, 0, kRenderNormal, 25)

              if (get_pcvar_num(cvar_assaaura))
                  set_task(0.1, "assasin_aura", id+TASK_AURA, _, _, "b")
			
              set_user_health( id, floatround(get_user_health(id) * get_pcvar_float(cvar_assahp)) )
              i_assassins++
	}
	
	// Convertir un monto especifico de jugadores en Snipers
	new i_snipers, i_max_snipers
	i_max_snipers = get_pcvar_num(cvar_snipernum)  //floatround( ( i_alive * get_pcvar_float( cvar_ratio ) ), floatround_ceil )
	i_snipers = 0
	while (i_snipers < i_max_snipers)
    {
          id = fnGetRandomAlive(random_num(1, i_alive))
          if( zp_get_user_nemesis( id ) || zp_get_user_survivor( id ) || zp_get_user_assassin( id ) || zp_get_user_sniper( id ))
              continue;

          zp_make_user_sniper(id)
          set_user_health( id, floatround(get_user_health(id) * get_pcvar_float(cvar_sniperhp)) )
          i_snipers++
    }


    // Convertir un porcentaje de los jugadores restantes en Zombies
	i_max_zombies = floatround((i_alive-(get_pcvar_num(cvar_survivornum)+get_pcvar_num(cvar_nemesisnum)+get_pcvar_num(cvar_assanum)+get_pcvar_num(cvar_snipernum)))*get_pcvar_float(cvar_ratio), floatround_ceil)
	i_zombies = 0
	while (i_zombies < i_max_zombies)
    {
          if (++id > g_maxplayers) id = 1
          if( zp_get_user_zombie(id) || !g_isalive[id] || zp_get_user_nemesis( id ) || zp_get_user_survivor( id ) || zp_get_user_assassin( id ) || zp_get_user_sniper( id ))
              continue;

          zp_infect_user(id)

          i_zombies++
    }
    
	// Convertir el resto de jugadores en Humanos
	for (id = 1; id <= g_maxplayers; id++)
    {
		if (!g_isalive[id] || zp_get_user_zombie(id) || zp_get_user_nemesis( id ) || zp_get_user_survivor( id ) || zp_get_user_assassin( id ) || zp_get_user_sniper( id ))
			continue;

		if (fm_cs_get_user_team(id) != FM_CS_TEAM_CT)	// need to change team?
		{
			remove_task(id+TASK_TEAM)
			zp_disinfect_user(id)
			fm_cs_set_user_team(id, FM_CS_TEAM_CT)
			fm_user_team_update(id)
		}
    } 
}

#if defined AMBIENCE_SOUNDS
public start_ambience_sounds( )
{
	// Variables
	static amb_sound[64], sound, Float:duration
	
	// Select our ambience sound
	sound = random_num( 0, sizeof g_sound_ambience - 1 )
	copy( amb_sound, sizeof amb_sound - 1 , g_sound_ambience[ sound ] )
	duration = g_sound_ambience_duration[ sound ]
	
	// Check whether it's a wav or mp3, then play it on clients
	if ( equal( amb_sound[ strlen( amb_sound ) - 4 ], ".mp3" ) )
		client_cmd( 0, "mp3 play ^"sound/%s^"", amb_sound )
	else
		client_cmd( 0, "spk ^"%s^"", sound )
	
	// Start the ambience sounds
	set_task( duration, "start_ambience_sounds", TASK_AMB )
}
public zp_round_ended( winteam )
{
	// Stop ambience sounds on round end
	remove_task( TASK_AMB )
}

public assasin_aura(taskid)
{

	// Get player's origin
	static origin[3]
	get_user_origin(ID_AURA, origin)
	
	// Colored Aura
	message_begin(MSG_PVS, SVC_TEMPENTITY, origin)
	write_byte(TE_DLIGHT) // TE id
	write_coord(origin[0]) // x
	write_coord(origin[1]) // y
	write_coord(origin[2]) // z
	write_byte(get_pcvar_num(cvar_assaauraradio)) // radius
	
	// Aura color for assassin
	
	write_byte(get_pcvar_num(cvar_assaaurared)) // r
	write_byte(get_pcvar_num(cvar_assaauragreen)) // g
	write_byte(get_pcvar_num(cvar_assaaurablue)) // b
	
	write_byte(2) // life
	write_byte(0) // decay rate
	message_end()
}

#endif

// This function returns the no. of alive players
// Feel free to use this in your plugin when you 
// are making your own game modes.
fn_get_alive_players()
{
	static i_alive, id
	i_alive = 0
	
	for ( id = 1; id <= g_maxplayers; id++ )
	{
		if( is_user_alive( id ) )
			i_alive++
	}
	return i_alive;
}

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

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

// Get User Team
stock fm_cs_get_user_team(id)
{
	return get_pdata_int(id, OFFSET_CSTEAMS, 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_cs_set_user_team_msg", id+TASK_TEAM)
		g_teams_targettime = current_time + 0.1
	}
	else
	{
		set_task((g_teams_targettime + 0.1) - current_time, "fm_cs_set_user_team_msg", id+TASK_TEAM)
		g_teams_targettime = g_teams_targettime + 0.1
	}
}

// Send User Team Message
public fm_cs_set_user_team_msg(taskid)
{
	// Note to self: this next message can now be received by other plugins
	
	// Tell everyone my new team
	emessage_begin(MSG_ALL, g_msgTeamInfo)
	ewrite_byte(ID_TEAM) // player
	ewrite_string(CS_TEAM_NAMES[fm_cs_get_user_team(ID_TEAM)]) // team
	emessage_end()
}