#include maps/mp/zombies/_zm_perks;
#include maps/mp/zombies/_zm_utility;
#include maps/mp/_utility;
#include common_scripts/utility;

init() //checked matches cerberus output
{
	if ( !isDefined( level.script ) )
	{
		level.script = tolower( getDvar( "mapname" ) );
	}
	precacheshader( "overlay_low_health" );
	level.global_damage_func_ads = ::empty_kill_func;
	level.global_damage_func = ::empty_kill_func;
	level.difficultytype[ 0 ] = "easy";
	level.difficultytype[ 1 ] = "normal";
	level.difficultytype[ 2 ] = "hardened";
	level.difficultytype[ 3 ] = "veteran";
	level.difficultystring[ "easy" ] = &"GAMESKILL_EASY";
	level.difficultystring[ "normal" ] = &"GAMESKILL_NORMAL";
	level.difficultystring[ "hardened" ] = &"GAMESKILL_HARDENED";
	level.difficultystring[ "veteran" ] = &"GAMESKILL_VETERAN";
	/*
/#
	thread playerhealthdebug();
#/
	*/
	level.gameskill = 1;
	switch( level.gameskill )
	{
		case 0:
			setdvar( "currentDifficulty", "easy" );
			break;
		case 1:
			setdvar( "currentDifficulty", "normal" );
			break;
		case 2:
			setdvar( "currentDifficulty", "hardened" );
			break;
		case 3:
			setdvar( "currentDifficulty", "veteran" );
			break;
	}
	logstring( "difficulty: " + level.gameskill );
	level.player_deathinvulnerabletime = 1700;
	level.longregentime = 5000;
	level.healthoverlaycutoff = 0.2;
	level.invultime_preshield = 0.35;
	level.invultime_onshield = 0.5;
	level.invultime_postshield = 0.3;
	level.playerhealth_regularregendelay = 2400;
	level.worthydamageratio = 0.1;
	setdvar( "player_meleeDamageMultiplier", 0.4 );
	onplayerconnect_callback( ::onplayerconnect );
}

onplayerconnect() //checked matches cerberus output
{
	self thread onplayerspawned();
}

onplayerspawned() //checked changed to match cerberus output
{
	for ( ;; )
	{
		self waittill( "spawned_player" );
		self maps/mp/zombies/_zm_perks::perk_set_max_health_if_jugg( "health_reboot", 1, 0 );
		if ( level.createfx_enabled )
		{
			continue;
		}
		self notify( "noHealthOverlay" );
		self thread playerhealthregen();
	}
}

playerhurtcheck() //checked changed to match cerberus output
{
	self endon( "noHealthOverlay" );
	self.hurtagain = 0;
	for ( ;; )
	{
		self waittill( "damage", amount, attacker, dir, point, mod );
		if ( isDefined( attacker ) && isplayer( attacker ) && attacker.team == self.team )
		{
			continue;
		}
		self.hurtagain = 1;
		self.damagepoint = point;
		self.damageattacker = attacker;
	}
}

playerhealthregen() //checked changed to match cerberus output
{
	self notify( "playerHealthRegen" );
	self endon( "playerHealthRegen" );
	self endon( "death" );
	self endon( "disconnect" );
	if ( !isDefined( self.flag ) )
	{
		self.flag = [];
		self.flags_lock = [];
	}
	if ( !isDefined( self.flag[ "player_has_red_flashing_overlay" ] ) )
	{
		self player_flag_init( "player_has_red_flashing_overlay" );
		self player_flag_init( "player_is_invulnerable" );
	}
	self player_flag_clear( "player_has_red_flashing_overlay" );
	self player_flag_clear( "player_is_invulnerable" );
	self thread healthoverlay();
	oldratio = 1;
	health_add = 0;
	regenrate = 0.1;
	veryhurt = 0;
	playerjustgotredflashing = 0;
	invultime = 0;
	hurttime = 0;
	newhealth = 0;
	lastinvulratio = 1;
	self thread playerhurtcheck();
	if ( !isDefined( self.veryhurt ) )
	{
		self.veryhurt = 0;
	}
	self.bolthit = 0;
	if ( getDvar( "scr_playerInvulTimeScale" ) == "" )
	{
		setdvar( "scr_playerInvulTimeScale", 1 );
	}
	playerinvultimescale = getDvarFloat( "scr_playerInvulTimeScale" );
	for ( ;; )
	{
		wait 0.05;
		waittillframeend;
		if ( self.health == self.maxhealth )
		{
			if ( self player_flag( "player_has_red_flashing_overlay" ) )
			{
				player_flag_clear( "player_has_red_flashing_overlay" );
			}
			lastinvulratio = 1;
			playerjustgotredflashing = 0;
			veryhurt = 0;
			continue;
		}
		if ( self.health <= 0 )
		{
			/*
/#
			showhitlog();
#/
			*/
			return;
		}
		wasveryhurt = veryhurt;
		health_ratio = self.health / self.maxhealth;
		if ( health_ratio <= level.healthoverlaycutoff )
		{
			veryhurt = 1;
			if ( !wasveryhurt )
			{
				hurttime = getTime();
				self startfadingblur( 3.6, 2 );
				self player_flag_set( "player_has_red_flashing_overlay" );
				playerjustgotredflashing = 1;
			}
		}
		if ( self.hurtagain )
		{
			hurttime = getTime();
			self.hurtagain = 0;
		}
		if ( health_ratio >= oldratio )
		{
			if ( getTime() - hurttime < level.playerhealth_regularregendelay )
			{
				continue;
			}
			if ( veryhurt )
			{
				self.veryhurt = 1;
				newhealth = health_ratio;
				if ( getTime() > ( hurttime + level.longregentime ) )
				{
					newhealth += regenrate;
				}
			}
			else
			{
				newhealth = 1;
				self.veryhurt = 0;
			}
			if ( newhealth > 1 )
			{
				newhealth = 1;
			}
			if ( newhealth <= 0 )
			{
				return;
			}
			/*
/#
			if ( newhealth > health_ratio )
			{
				logregen( newhealth );
#/
			}
			*/
			self setnormalhealth( newhealth );
			oldratio = self.health / self.maxhealth;
			continue;
		}
		invulworthyhealthdrop = lastinvulratio - health_ratio > level.worthydamageratio;
		if ( self.health <= 1 )
		{
			self setnormalhealth( 2 / self.maxhealth );
			invulworthyhealthdrop = 1;
			/*
/#
			if ( !isDefined( level.player_deathinvulnerabletimeout ) )
			{
				level.player_deathinvulnerabletimeout = 0;
			}
			if ( level.player_deathinvulnerabletimeout < getTime() )
			{
				level.player_deathinvulnerabletimeout = getTime() + getDvarInt( "player_deathInvulnerableTime" );
#/
			}
			*/
		}
		oldratio = self.health / self.maxhealth;
		level notify( "hit_again" );
		health_add = 0;
		hurttime = getTime();
		self startfadingblur( 3, 0.8 );
		if ( !invulworthyhealthdrop || playerinvultimescale <= 0 )
		{
			/*
/#
			loghit( self.health, 0 );
#/
			*/
			continue;
		}
		if ( self player_flag( "player_is_invulnerable" ) )
		{
			continue;
		}
		self player_flag_set( "player_is_invulnerable" );
		level notify( "player_becoming_invulnerable" );
		if ( playerjustgotredflashing )
		{
			invultime = level.invultime_onshield;
			playerjustgotredflashing = 0;
		}
		else if ( veryhurt )
		{
			invultime = level.invultime_postshield;
		}
		else
		{
			invultime = level.invultime_preshield;
		}
		invultime *= playerinvultimescale;
		/*
/#
		loghit( self.health, invultime );
#/
		*/
		lastinvulratio = self.health / self.maxhealth;
		self thread playerinvul( invultime );
	}
}

playerinvul( timer ) //checked matches cerberus output
{
	self endon( "death" );
	self endon( "disconnect" );
	if ( timer > 0 )
	{
		/*
/#
		level.playerinvultimeend = getTime() + ( timer * 1000 );
#/	
		*/
		wait timer;
	}
	self player_flag_clear( "player_is_invulnerable" );
}

healthoverlay() //checked changed to match cerberus output
{
	self endon( "disconnect" );
	self endon( "noHealthOverlay" );
	if ( !isDefined( self._health_overlay ) )
	{
		self._health_overlay = newclienthudelem( self );
		self._health_overlay.x = 0;
		self._health_overlay.y = 0;
		self._health_overlay setshader( "overlay_low_health", 640, 480 );
		self._health_overlay.alignx = "left";
		self._health_overlay.aligny = "top";
		self._health_overlay.horzalign = "fullscreen";
		self._health_overlay.vertalign = "fullscreen";
		self._health_overlay.alpha = 0;
	}
	overlay = self._health_overlay;
	self thread healthoverlay_remove( overlay );
	self thread watchhideredflashingoverlay( overlay );
	pulsetime = 0.8;
	while ( overlay.alpha > 0 )
	{
		overlay fadeovertime( 0.5 );
		overlay.alpha = 0;
		self player_flag_wait( "player_has_red_flashing_overlay" );
		self redflashingoverlay( overlay );
	}
}

fadefunc( overlay, severity, mult, hud_scaleonly ) //checkec matches cerberus output
{
	pulsetime = 0.8;
	scalemin = 0.5;
	fadeintime = pulsetime * 0.1;
	stayfulltime = pulsetime * ( 0.1 + severity * 0.2 );
	fadeouthalftime = pulsetime * ( 0.1 + severity * 0.1 );
	fadeoutfulltime = pulsetime * 0.3;
	remainingtime = pulsetime - fadeintime - stayfulltime - fadeouthalftime - fadeoutfulltime;
	/*
/#
	assert( remainingtime >= -0.001 );
#/
	*/
	if ( remainingtime < 0 )
	{
		remainingtime = 0;
	}
	halfalpha = 0.8 + severity * 0.1;
	leastalpha = 0.5 + severity * 0.3;
	overlay fadeovertime( fadeintime );
	overlay.alpha = mult * 1;
	wait ( fadeintime + stayfulltime );
	overlay fadeovertime( fadeouthalftime );
	overlay.alpha = mult * halfalpha;
	wait fadeouthalftime;
	overlay fadeovertime( fadeoutfulltime );
	overlay.alpha = mult * leastalpha;
	wait fadeoutfulltime;
	wait remainingtime;
}

watchhideredflashingoverlay( overlay ) //checked matches cerberus output
{
	self endon( "death_or_disconnect" );
	while ( isDefined( overlay ) )
	{
		self waittill( "clear_red_flashing_overlay" );
		self player_flag_clear( "player_has_red_flashing_overlay" );
		overlay fadeovertime( 0.05 );
		overlay.alpha = 0;
		setclientsysstate( "levelNotify", "rfo3", self );
		self notify( "hit_again" );
	}
}

redflashingoverlay( overlay ) //checked matches cerberus output
{
	self endon( "hit_again" );
	self endon( "damage" );
	self endon( "death" );
	self endon( "disconnect" );
	self endon( "clear_red_flashing_overlay" );
	self.stopflashingbadlytime = getTime() + level.longregentime;
	if ( !is_true( self.is_in_process_of_zombify ) && !is_true( self.is_zombie ) )
	{
		fadefunc( overlay, 1, 1, 0 );
		while ( getTime() < self.stopflashingbadlytime && isalive( self ) && !is_true( self.is_in_process_of_zombify ) && !is_true( self.is_zombie ) )
		{
			fadefunc( overlay, 0.9, 1, 0 );
		}
		if ( !is_true( self.is_in_process_of_zombify ) && !is_true( self.is_zombie ) )
		{
			if ( isalive( self ) )
			{
				fadefunc( overlay, 0.65, 0.8, 0 );
			}
			fadefunc( overlay, 0, 0.6, 1 );
		}
	}
	overlay fadeovertime( 0.5 );
	overlay.alpha = 0;
	self player_flag_clear( "player_has_red_flashing_overlay" );
	setclientsysstate( "levelNotify", "rfo3", self );
	wait 0.5;
	self notify( "hit_again" );
}

healthoverlay_remove( overlay ) //checked matches cerberus output
{
	self endon( "disconnect" );
	self waittill_any( "noHealthOverlay", "death" );
	overlay fadeovertime( 3.5 );
	overlay.alpha = 0;
}

empty_kill_func( type, loc, point, attacker, amount ) //checked matches cerberus output
{
}

loghit( newhealth, invultime ) //checked matches cerberus output
{
	/*
/#
#/
	*/
}

logregen( newhealth ) //checked matches cerberus output
{
	/*
/#
#/
	*/
}

showhitlog() //checked matches cerberus output
{
	/*
/#
#/
	*/
}

playerhealthdebug() //checked changed to match cerberus output
{
	/*
/#
	if ( getDvar( "scr_health_debug" ) == "" )
	{
		setdvar( "scr_health_debug", "0" );
	}
	waittillframeend;
	while ( 1 )
	{
		while ( 1 )
		{
			if ( getDvar( "scr_health_debug" ) != "0" )
			{
				break;
			}
			wait 0.5;
		}
		thread printhealthdebug();
		while ( 1 )
		{
			if ( getDvar( "scr_health_debug" ) == "0" )
			{
				break;
			}
			wait 0.5;
		}
		level notify( "stop_printing_grenade_timers" );
		destroyhealthdebug();
#/
	}
	*/
}

printhealthdebug() //checked changed to match cerberus output
{
	/*
/#
	level notify( "stop_printing_health_bars" );
	level endon( "stop_printing_health_bars" );
	x = 40;
	y = 40;
	level.healthbarhudelems = [];
	level.healthbarkeys[ 0 ] = "Health";
	level.healthbarkeys[ 1 ] = "No Hit Time";
	level.healthbarkeys[ 2 ] = "No Die Time";
	if ( !isDefined( level.playerinvultimeend ) )
	{
		level.playerinvultimeend = 0;
	}
	if ( !isDefined( level.player_deathinvulnerabletimeout ) )
	{
		level.player_deathinvulnerabletimeout = 0;
	}
	for ( i = 0; i < level.healthbarkeys.size; i++ )
	{
		key = level.healthbarkeys[ i ];
		textelem = newhudelem();
		textelem.x = x;
		textelem.y = y;
		textelem.alignx = "left";
		textelem.aligny = "top";
		textelem.horzalign = "fullscreen";
		textelem.vertalign = "fullscreen";
		textelem settext( key );
		bgbar = newhudelem();
		bgbar.x = x + 79;
		bgbar.y = y + 1;
		bgbar.alignx = "left";
		bgbar.aligny = "top";
		bgbar.horzalign = "fullscreen";
		bgbar.vertalign = "fullscreen";
		bgbar.maxwidth = 3;
		bgbar setshader( "white", bgbar.maxwidth, 10 );
		bgbar.color = vectorScale( ( 1, 1, 1 ), 0.5 );
		bar = newhudelem();
		bar.x = x + 80;
		bar.y = y + 2;
		bar.alignx = "left";
		bar.aligny = "top";
		bar.horzalign = "fullscreen";
		bar.vertalign = "fullscreen";
		bar setshader( "black", 1, 8 );
		textelem.bar = bar;
		textelem.bgbar = bgbar;
		textelem.key = key;
		y += 10;
		level.healthbarhudelems[ key ] = textelem;
	}
	flag_wait( "start_zombie_round_logic" );
	while ( 1 )
	{
		wait 0.05;
		players = get_players();
		for ( i = 0; i < level.healthbarkeys.size && players.size > 0; i++ )
		{
			key = level.healthbarkeys[ i ];
			player = players[ 0 ];
			width = 0;
			if ( i == 0 )
			{
				width = ( player.health / player.maxhealth ) * 300;
			}
			else if ( i == 1 )
			{
				width = ( ( level.playerinvultimeend - getTime() ) / 1000 ) * 40;
			}
			else if ( i == 2 )
			{
				width = ( ( level.player_deathinvulnerabletimeout - getTime() ) / 1000 ) * 40;
			}
			width = int( max( width, 1 ) );
			width = int( min( width, 300 ) );
			bar = level.healthbarhudelems[ key ].bar;
			bar setshader( "black", width, 8 );
			bgbar = level.healthbarhudelems[ key ].bgbar;
			if ( ( width + 2 ) > bgbar.maxwidth )
			{
				bgbar.maxwidth = width + 2;
				bgbar setshader( "white", bgbar.maxwidth, 10 );
				bgbar.color = vectorScale( ( 1, 1, 1 ), 0.5 );
			}
		}
#/
	}
	*/
}

destroyhealthdebug() //checked changed to match cerberus output
{
	/*
/#
	if ( !isDefined( level.healthbarhudelems ) )
	{
		return;
	}
	while ( i = 0; i < level.healthbarkeys.size; i++ )
	{
		level.healthbarhudelems[ level.healthbarkeys[ i ] ].bgbar destroy();
		level.healthbarhudelems[ level.healthbarkeys[ i ] ].bar destroy();
		level.healthbarhudelems[ level.healthbarkeys[ i ] ] destroy();
#/
	}
	*/
}

