#include maps\mp\_utility;
#include common_scripts\utility;
#include maps\mp\_snd_common_mp;

EXO_REPULSOR_RADIUS = 385;
EXO_REPULSOR_REPEL_VEL = 800;

exo_repulsor_think()	//self = player
{
	self notify( "exo_repulsor_taken" );			// Cleans up existing Exo Trophy System threads.
	
	level endon( "game_ended" );
	self endon( "death" );
	self endon( "disconnect" );
	self endon( "joined_team" );
	self endon( "faux_spawn" );
	self endon( "exo_repulsor_taken" );
	
	if ( !self HasWeapon( "exorepulsor_equipment_mp" ) )
		return;
	
	exoRepulsorInit();
	
	self thread MonitorPlayerDeath();
	self thread wait_for_game_end();
	
	while ( 1 )
	{
		self waittill( "exo_ability_activate", weapname );
		
		if ( weapname == "exorepulsor_equipment_mp" )
		{
			self thread tryUseRepulsor();
		}
	}
}

exoRepulsorInit()	//self = player
{
	self.repulsorActive = false;
	
	self BatterySetDischargeScale( "exorepulsor_equipment_mp", 1.0 );
	full_energy = self BatteryGetSize( "exorepulsor_equipment_mp" );
	self.projectilesStopped = 0;
	
	if ( self GetTacticalWeapon() == "exorepulsor_equipment_mp" )
	{
		self SetClientOmnvar( "exo_ability_nrg_req0", 0 );
		self SetClientOmnvar( "exo_ability_nrg_total0", full_energy );
		self SetClientOmnvar( "ui_exo_battery_level0", full_energy );
	}
	else if ( self GetLethalWeapon() == "exorepulsor_equipment_mp" )
	{
		self SetClientOmnvar( "exo_ability_nrg_req1", 0 );
		self SetClientOmnvar( "exo_ability_nrg_total1", full_energy );
		self SetClientOmnvar( "ui_exo_battery_level1", full_energy );
	}
	
	// VFX
	if ( !IsDefined( level.exo_repulsor_impact ) )
	{
		level.exo_repulsor_impact =	LoadFX( "vfx/explosion/exo_repulsor_impact" );
	}
	if ( !IsDefined( level.exo_repulsor_activate_vfx ) )
	{
		level.exo_repulsor_activate_vfx = LoadFX( "vfx/unique/repulsor_bubble" );
	}
	if ( !IsDefined( level.exo_repulsor_deactivate_vfx ) )
	{
		level.exo_repulsor_deactivate_vfx = LoadFX( "vfx/unique/repulsor_bubble_deactivate" );
	}
	if ( !IsDefined( level.exo_repulsor_player_vfx_active ) )
	{
		level.exo_repulsor_player_vfx_active = LoadFX( "vfx/unique/exo_repulsor_emitter" );
	}
	if ( !IsDefined( level.exo_repulsor_player_vfx_inactive ) )
	{
		level.exo_repulsor_player_vfx_inactive = LoadFX( "vfx/unique/exo_repulsor_inactive" );
	}
	
	wait( 0.05 );
	
	if ( !inVirtualLobby() )
	{
		PlayFXOnTag( level.exo_repulsor_player_vfx_inactive, self, "TAG_JETPACK" );
	}
}

tryUseRepulsor( duration )
{
	self endon( "exo_repulsor_taken" );
	
	if (self.repulsorActive == true)
	{
		self thread stop_repulsor( true );
	}
	else
	{
		self thread start_repulsor();
	}
}

killRepulsorFx()
{
	if ( IsDefined( self.repulsor_fx ) )
	{
		self.repulsor_fx delete();
		self.repulsor_fx = undefined;
	}
}

start_repulsor()
{
	self endon( "death" );
	self endon( "disconnect" );
	self endon( "joined_team" );
	self endon( "faux_spawn" );
	self endon( "stop_exo_repulsor" );
	self endon( "exo_repulsor_taken" );
	
	self.repulsorActive = true;
	
	self thread do_exo_repulsor();
	
	self BatteryDischargeBegin( "exorepulsor_equipment_mp" );
	
	self maps\mp\_exo_battery::set_exo_ability_hud_omnvar( "exorepulsor_equipment_mp", "ui_exo_battery_toggle", 1 );
	
	self thread maps\mp\_exo_battery::update_exo_battery_hud( "exorepulsor_equipment_mp" );
	
	// play sfx
	self snd_message( "mp_exo_repulsor_activate" );
	
	// play vfx
	killRepulsorFx();
	
	if ( !IsDefined( self.exo_cloak_on ) || self.exo_cloak_on == false )
	{
		self.repulsor_fx = SpawnLinkedFx( level.exo_repulsor_player_vfx_active, self, "TAG_JETPACK" );
		TriggerFX( self.repulsor_fx );
	}
	
	wait( 0.05 );
	
	if ( !self.repulsorActive ) //turned off during wait?
		return;
	
	if ( IsDefined( level.exo_repulsor_activate_vfx ) )
	{
		PlayFXOnTagForClients( level.exo_repulsor_activate_vfx, self, "j_head", self );
	}
}

stop_repulsor( should_play_fx )			// self = player
{
	if ( !isDefined( self.repulsorActive ) || !self.repulsorActive )
		return;
	
	if ( !IsDefined( should_play_fx ) )
	{
		should_play_fx = true;
	}
	
	self notify( "stop_exo_repulsor" );
	
	self.repulsorActive = false;
	
	self BatteryDischargeEnd( "exorepulsor_equipment_mp" );
	
	self maps\mp\_exo_battery::set_exo_ability_hud_omnvar( "exorepulsor_equipment_mp", "ui_exo_battery_toggle", 0 );
	
	// stop vfx
	killRepulsorFx();
	
	if ( should_play_fx == true )
	{
		// play deactivate sfx
		self snd_message( "mp_exo_repulsor_deactivate" );
		
		// play inactive vfx
		if ( !IsDefined( self.exo_cloak_on ) || self.exo_cloak_on == false )
		{
			self.repulsor_fx = SpawnLinkedFx( level.exo_repulsor_player_vfx_inactive, self, "TAG_JETPACK" );
			TriggerFX( self.repulsor_fx );
		}
		
		wait( 0.05 );
		
		// play deactivate hud vfx
		if ( IsDefined( level.exo_repulsor_deactivate_vfx ) )
		{
			PlayFXOnTagForClients( level.exo_repulsor_deactivate_vfx, self, "j_head", self );
		}
	}
}

MonitorPlayerDeath()
{
	level endon( "game_ended" );
	self endon( "disconnect" );
	
	self waittill_any( "death", "joined_team", "faux_spawn", "exo_repulsor_taken" );
	
	self.projectilesStopped = 0;
	
	self thread stop_repulsor( false );
}

update_exo_battery_hud()
{
	battery_energy = self BatteryGetCharge( "exorepulsor_equipment_mp" );
	// Setting ui_exo_battery_level to the current energy level.
	self maps\mp\_exo_battery::set_exo_ability_hud_omnvar( "exorepulsor_equipment_mp", "ui_exo_battery_level", battery_energy );	
}

do_exo_repulsor()
{
	level endon( "game_ended" );
	self endon( "death" );
	self endon( "disconnect" );
	self endon( "joined_team" );
	self endon( "faux_spawn" );
	self endon( "stop_exo_repulsor" );
	self endon( "exo_repulsor_taken" );
	
	while( self BatteryGetCharge( "exorepulsor_equipment_mp" ) > 0 )
	{
		for ( i = 0; i < level.grenades.size; i++ )
		{
			grenade = level.grenades[i];
			
			// do not repel grenades without a weaponName.
			if ( !IsDefined( grenade.weaponName ) )
			    continue;
			
			// do not repel Exo Abilities.
			if ( IsDefined( grenade.weaponName ) && is_exo_ability_weapon( grenade.weaponName ) )
				continue;
			
			// don't repel grenades with no owner
			if ( !IsDefined( grenade.owner ) )
			   continue;
			
			// don't repel your own grenades
			if ( IsDefined( grenade.owner ) && grenade.owner == self )
				continue;
			
			// don't repel teammate grenades
			if ( level.teamBased && Isdefined( grenade.owner.team ) && grenade.owner.team == self.team )
				continue;
			
			player_to_grenade_dist = Distance( grenade.origin, self.origin );
			
			if ( player_to_grenade_dist < EXO_REPULSOR_RADIUS )
			{
				if ( SightTracePassed( self GetEye(), grenade.origin, false, self ) )
				{
					// play vfx
					player_to_grenade_vector = grenade.origin - self.origin;
					player_to_grenade_angles = VectorToAngles( player_to_grenade_vector );
					player_to_grenade_up = AnglesToUp( player_to_grenade_angles );
					player_to_grenade_forward = AnglesToForward( player_to_grenade_angles );
					player_to_grenade_forward_norm = VectorNormalize( player_to_grenade_forward );
					fx_origin = grenade.origin - ( 0.2 * player_to_grenade_dist * player_to_grenade_forward_norm );
					PlayFX( level.exo_repulsor_impact, fx_origin, player_to_grenade_forward_norm, player_to_grenade_up );
					
					// play sfx
					grenade snd_message( "mp_exo_repulsor_repel" );
					
					// explosive drone special case to remove "head" of the grenade
					if ( grenade.weaponname == "explosive_drone_mp" )
				    {
						grenade notify( "mp_exo_repulsor_repel" );
						
						grenade thread maps\mp\_explosive_drone::explosiveGrenadeDeath();
				    }
					else
					{
						grenade delete();
					}
					self.projectilesStopped++;
					
					//Trophy - destroy a projectile
					self maps\mp\gametypes\_missions::processChallenge("ch_exoability_repulser");
					
					self BatteryDischargeOnce( "exorepulsor_equipment_mp", int( self BatteryGetSize( "exorepulsor_equipment_mp" ) / 2 ) );
					self update_exo_battery_hud();
				}
			}
		}
		
		for ( i = 0; i < level.missiles.size; i++ )
		{
			rocket = level.missiles[i];
			
			// do not repel rockets with no owner
			if ( !IsDefined( rocket.owner ) )
			   continue;
			
			// don't repel your own rockets
			if ( IsDefined( rocket.owner ) && rocket.owner == self )
				continue;
			
			// don't repel teammate rockets
			if ( level.teamBased && Isdefined( rocket.owner.team ) && rocket.owner.team == self.team )
				continue;
			
			player_to_rocket_dist = Distance( rocket.origin, self.origin );
			
			if ( player_to_rocket_dist < EXO_REPULSOR_RADIUS )
			{
				if ( SightTracePassed( self GetEye(), rocket.origin, false, self ) )
				{
					// play vfx
					player_to_rocket_vector = rocket.origin - self.origin;
					player_to_rocket_angles = VectorToAngles( player_to_rocket_vector );
					player_to_rocket_up = AnglesToUp( player_to_rocket_angles );
					player_to_rocket_forward = AnglesToForward( player_to_rocket_angles );
					player_to_rocket_forward_norm = VectorNormalize( player_to_rocket_forward );
					fx_origin = rocket.origin - ( 0.2 * player_to_rocket_dist * player_to_rocket_forward_norm );
					PlayFX( level.exo_repulsor_impact, fx_origin, player_to_rocket_forward_norm, player_to_rocket_up );
					
					// play sfx
					rocket snd_message( "mp_exo_repulsor_repel" );
					
					// cleanup tag vfx
					if ( IsDefined( rocket.weaponname ) && rocket.weaponname == "iw5_exocrossbow_mp" )
					{
						StopFXOnTag( getfx( "exocrossbow_sticky_blinking" ), rocket.fx_origin, "tag_origin" );
					}
					
					rocket delete();
					self.projectilesStopped++;
					
					//Trophy - destroy a projectile						
					self maps\mp\gametypes\_missions::processChallenge("ch_exoability_repulser");
					
					self BatteryDischargeOnce( "exorepulsor_equipment_mp", int( self BatteryGetSize( "exorepulsor_equipment_mp" ) / 2 ) );
					self update_exo_battery_hud();	
				}
			}
		}
		
		for ( i = 0; i < level.explosivedrones.size; i++ )
		{
			explosiveDrone = level.explosivedrones[i];
			
			if( IsDefined(explosiveDrone) ) // just in case clean up timing is off
			{
				// do not repel explosive drones with no owner
				if ( !IsDefined( explosiveDrone.owner ) )
				   continue;
				
				// don't repel your own explosive drones
				if ( IsDefined( explosiveDrone.owner ) && explosiveDrone.owner == self )
					continue;
				
				// don't repel teammate explosive drones
				if ( level.teamBased && Isdefined( explosiveDrone.owner.team ) && explosiveDrone.owner.team == self.team )
					continue;
				
				player_to_explosiveDrone_dist = Distance( explosiveDrone.origin, self.origin );
				
				if ( player_to_explosiveDrone_dist < EXO_REPULSOR_RADIUS )
				{
					if ( SightTracePassed( self GetEye(), explosiveDrone.origin, false, self ) )
					{
						// play vfx
						player_to_explosiveDrone_vector = explosiveDrone.origin - self.origin;
						player_to_explosiveDrone_angles = VectorToAngles( player_to_explosiveDrone_vector );
						player_to_explosiveDrone_up = AnglesToUp( player_to_explosiveDrone_angles );
						player_to_explosiveDrone_forward = AnglesToForward( player_to_explosiveDrone_angles );
						player_to_explosiveDrone_forward_norm = VectorNormalize( player_to_explosiveDrone_forward );
						fx_origin = explosiveDrone.origin - ( 0.2 * player_to_explosiveDrone_dist * player_to_explosiveDrone_forward_norm );
						PlayFX( level.exo_repulsor_impact, fx_origin, player_to_explosiveDrone_forward_norm, player_to_explosiveDrone_up );
						
						// play sfx
						explosiveDrone snd_message( "mp_exo_repulsor_repel" );
						
						if (IsDefined (explosiveDrone.explosiveDrone) )
					    {
					    	explosiveDrone.explosiveDrone delete();
					    }
						
						explosiveDrone delete();
						self.projectilesStopped++;
						
						//Trophy - destroy a projectile						
						self maps\mp\gametypes\_missions::processChallenge("ch_exoability_repulser");
						
						self BatteryDischargeOnce( "exorepulsor_equipment_mp", int( self BatteryGetSize( "exorepulsor_equipment_mp" ) / 2 ) );
						self update_exo_battery_hud();
					}
				}
			}
		}
		
		foreach ( tdrone in level.trackingDrones )
		{
			// don't destroy tracking drones with no owner
			if ( !IsDefined( tdrone.owner ) )
			   continue;
			
			// don't destroy your own tracking drones
			if ( IsDefined( tdrone.owner ) && tdrone.owner == self )
				continue;
			
			// don't destroy teammate tracking drones
			if ( level.teamBased && Isdefined( tdrone.owner.team ) && tdrone.owner.team == self.team )
				continue;
			
			player_to_tdrone_dist = Distance( tdrone.origin, self.origin );
			
			if ( player_to_tdrone_dist < EXO_REPULSOR_RADIUS )
			{
				if ( SightTracePassed( self GetEye(), tdrone.origin, false, self ) )
				{
					// play vfx
					player_to_tdrone_vector = tdrone.origin - self.origin;
					player_to_tdrone_angles = VectorToAngles( player_to_tdrone_vector );
					player_to_tdrone_up = AnglesToUp( player_to_tdrone_angles );
					player_to_tdrone_forward = AnglesToForward( player_to_tdrone_angles );
					player_to_tdrone_forward_norm = VectorNormalize( player_to_tdrone_forward );
					fx_origin = tdrone.origin - ( 0.2 * player_to_tdrone_dist * player_to_tdrone_forward_norm );
					PlayFX( level.exo_repulsor_impact, fx_origin, player_to_tdrone_forward_norm, player_to_tdrone_up );
					
					// play sfx
					tdrone snd_message( "mp_exo_repulsor_repel" );
					
					if ( !IsRemovedEntity( tdrone ) && IsDefined( tdrone ) )
					{
						tdrone notify( "death" );
						decrementFauxVehicleCount();
					}
					
					self.projectilesStopped++;
					
					//Trophy - destroy a projectile						
					self maps\mp\gametypes\_missions::processChallenge("ch_exoability_repulser");
						
					self BatteryDischargeOnce( "exorepulsor_equipment_mp", int( self BatteryGetSize( "exorepulsor_equipment_mp" ) / 2 ) );
					self update_exo_battery_hud();
				}
			}
		}
		
		// The medal used to be "Four Play" when you could block 4 enemy projectiles. Now that you can only block 2, we've changed it to "Secretary of Defense".
		if ( self.projectilesStopped >= 2 )
		{
			if ( !isdefined ( level.isHorde ) )
				self thread maps\mp\_events::fourPlayEvent();
			self.projectilesStopped -= 2;
		}
		
		wait 0.05;
	}
	
	// Exo Repulsor is out of energy.
	self thread stop_repulsor( true );
}

take_exo_repulsor()	//self = player
{
	self notify( "kill_battery" );
	self notify( "exo_repulsor_taken" );
	self takeWeapon( "exorepulsor_equipment_mp" );
}

give_exo_repulsor()	//self = player
{
	self giveWeapon( "exorepulsor_equipment_mp" );
	self thread exo_repulsor_think();
}

wait_for_game_end()	// self = player
{
	self endon( "death" );
	self endon( "disconnect" );
	self endon( "joined_team" );
	self endon( "faux_spawn" );
	self endon( "exo_repulsor_taken" );
	
	level waittill( "game_ended" );
	
	self thread stop_repulsor( false );
}
