/*================================================================================
	
	-------------------------
	-*- [ZP] Stamina 1.1c -*-
	-------------------------
	
	~~~~~~~~~~~~~~~
	- Description -
	~~~~~~~~~~~~~~~
	
	This plugin makes humans have a limited amount of energy, meaning
	running for too long will get you exhausted.
	
	~~~~~~~~~
	- CVARS -
	~~~~~~~~~
	
	* zp_stamina_duration <600> - How long you can run before getting tired
	* zp_stamina_survivor <0/1> - If set, the Survivor has limited energy too
	
	* zp_stamina_deplete <3> - How fast energy depletes when running
	* zp_stamina_regain_walking <1> - How fast energy refills when walking
	* zp_stamina_regain_standing <2> - How fast energy refills when standing still
	
	~~~~~~~~~~~~~~
	- Credits to -
	~~~~~~~~~~~~~~
	
	* Mlk27: for the idea
	
================================================================================*/

#include <amxmodx>
#include <fakemeta>
#include <xs>
#include <zombieplague>

/*================================================================================
 [Plugin Customization]
=================================================================================*/

// Sounds
new const g_sound_breathe[] = "player/breathe1.wav"

/*============================================================================*/

new g_runningcounter[33], g_breathing[33]
new cvar_duration, cvar_survivor, cvar_deplete, cvar_regain_walking, cvar_regain_standing

public plugin_precache()
{
	precache_sound(g_sound_breathe)
}

public plugin_init()
{
	register_plugin("[ZP] Stamina", "1.1c", "MeRcyLeZZ")
	
	register_forward(FM_StartFrame, "fw_StartFrame")
	
	register_event("HLTV", "event_round_start", "a", "1=0", "2=0")
	register_event("DeathMsg", "event_deathmsg", "a")
	
	cvar_duration = register_cvar("zp_stamina_duration", "600")
	cvar_survivor = register_cvar("zp_stamina_survivor", "0")
	
	cvar_deplete = register_cvar("zp_stamina_deplete", "3")
	cvar_regain_walking = register_cvar("zp_stamina_regain_walking", "1")
	cvar_regain_standing = register_cvar("zp_stamina_regain_standing", "2")
}

// Had to use FM_StartFrame for accurate checks
// since PreThink depends on the client's FPS
public fw_StartFrame()
{
	// We don't wannna check too fast, but fast enough...
	static Float:lastcheck
	if (get_gametime() - lastcheck < 0.1)
		return;
	lastcheck = get_gametime()
	
	// Loop through players
	static id
	for (id = 1; id <= 32; id++)
	{
		// Not alive or zombie
		if (!is_user_alive(id) || zp_get_user_zombie(id))
			continue;
		
		// Survivor cvar disabled
		if (!get_pcvar_num(cvar_survivor) && zp_get_user_survivor(id))
			continue;
		
		// Not on ground
		if (!(pev(id, pev_flags) & FL_ONGROUND))
			continue;
		
		// Get our current velocity
		static Float:velocity[3]
		pev(id, pev_velocity, velocity)		
		
		// Max running time exceeded?
		if (g_runningcounter[id] > get_pcvar_num(cvar_duration))
		{
			// Decrease speed gradually
			xs_vec_mul_scalar(velocity, (10-(g_runningcounter[id]-get_pcvar_num(cvar_duration)))*0.1, velocity)
			set_pev(id, pev_velocity, velocity)
		}
		
		// Start playing breathing sounds when we are close to getting tired
		if (g_runningcounter[id] > get_pcvar_num(cvar_duration)*0.75)
		{
			if (!g_breathing[id])
			{
				engfunc(EngFunc_EmitSound, id, CHAN_AUTO, g_sound_breathe, 1.0, ATTN_NORM, 0, PITCH_NORM)
				g_breathing[id] = true
			}
		}
		// If not, stop breathing sounds
		else if (g_breathing[id])
		{
			engfunc(EngFunc_EmitSound, id, CHAN_AUTO, g_sound_breathe, 1.0, ATTN_NORM, SND_STOP, PITCH_NORM)
			g_breathing[id] = false
		}
		
		// Get current speed
		static speed
		speed = floatround(vector_length(velocity))
		
		// Running
		if (speed > pev(id, pev_maxspeed)*0.6)
		{			
			// Increase distance counter
			g_runningcounter[id] = min(g_runningcounter[id]+get_pcvar_num(cvar_deplete), get_pcvar_num(cvar_duration)+10)			
		}
		// Walking
		else if (speed > pev(id, pev_maxspeed)*0.1)
		{
			// Decrease distance counter
			g_runningcounter[id] = max(0, g_runningcounter[id]-get_pcvar_num(cvar_regain_walking))
		}
		// Standing still
		else
		{
			// Decrease distance counter
			g_runningcounter[id] = max(0, g_runningcounter[id]-get_pcvar_num(cvar_regain_standing))
		}
	}
}

// Reset counters on new round
public event_round_start()
{
	for (new i = 1; i <= 32; i++) g_runningcounter[i] = 0
}

// Stop breathing sounds and reset counter when killed
public event_deathmsg()
{
	new victim = read_data(2)
	
	if (g_breathing[victim])
	{
		engfunc(EngFunc_EmitSound, victim, CHAN_AUTO, g_sound_breathe, 1.0, ATTN_NORM, SND_STOP, PITCH_NORM)
		g_breathing[victim] = false
	}
	g_runningcounter[victim] = 0
}

// Stop breathing sounds and reset counter when infected
public zp_user_infected_post(id, infector)
{
	if (g_breathing[id])
	{
		engfunc(EngFunc_EmitSound, id, CHAN_AUTO, g_sound_breathe, 1.0, ATTN_NORM, SND_STOP, PITCH_NORM)
		g_breathing[id] = false
	}
	g_runningcounter[id] = 0
}
