#include common_scripts\utility;

//////////////////////////////////////////////////////////////////////////////
//									CONSTANTS								//
//////////////////////////////////////////////////////////////////////////////
level_limit_pipe_fx = 8;
max_fires_from_entity = 4;
level_pipe_fx_chance = 33;


//////////////////////////////////////////////////////////////////////////////
//									LOGIC									//
//////////////////////////////////////////////////////////////////////////////
main()
{
	level._pipe_fx_time = 25;
	pipes = GetEntArray( "pipe_shootable", "targetname" );
	if ( !pipes.size )
		return;
	level._pipes = SpawnStruct();
	level._pipes.num_pipe_fx	 = 0;

	pipes thread precacheFX();
	pipes thread methodsInit();

	waittillframeend;// insure that structs are initialized
	array_thread( pipes, ::pipesetup );
}

pipesetup()
{
	self SetCanDamage( true );
	self SetCanRadiusDamage( false ); // optimization
	self.pipe_fx_array = [];

	node = undefined;

	if ( IsDefined( self.target ) )
	{
		node = getstruct( self.target, "targetname" );
		self.A = node.origin;
		vec = AnglesToForward( node.angles );
		vec = vector_multiply( vec, 128 );
		self.B = self.A + vec;
	}
	else
	{
		vec = AnglesToForward( self.angles );
		vec1 = vector_multiply( vec, 64 );
		self.A = self.origin + vec1;
		vec1 = vector_multiply( vec, -64 );
		self.B = self.origin + vec1;
	}

	self thread pipe_wait_loop();
}

pipe_wait_loop()
{
	P = ( 0, 0, 0 );// just to initialize P as a vector
	
	hasTakenDamage = false;
	remaining = max_fires_from_entity;
	
	while ( 1 )
	{
		self waittill( "damage", damage, other, direction_vec, P, type );
		
		// random so we don't get so many fx, but the very first time is guarenteed
		if ( hasTakenDamage )
		{
			if ( randomint( 100 ) <= level_pipe_fx_chance )
				continue;
		}
		hasTakenDamage = true;
		
		result = self pipe_logic( direction_vec, P, type, other );
		if ( result )
			remaining--;
		
		if ( remaining <= 0 )
			break;
	}
	
	self SetCanDamage( false );
}

pipe_logic( direction_vec, P, type, damageOwner )
{
	if ( level._pipes.num_pipe_fx > level_limit_pipe_fx )
		return false;

	if ( !isDefined( level._pipes._pipe_methods[ type ] ) )
		P = self pipe_calc_nofx( P, type );
	else
	P = self [[ level._pipes._pipe_methods[ type ] ]]( P, type );

	if ( !isdefined( P ) )
		return false;

	if ( IsDefined( damageOwner.classname ) && damageOwner.classname == "worldspawn" )
		return false;

	foreach ( value in self.pipe_fx_array )
	{
		if ( DistanceSquared( P, value.origin ) < 25 )
			return false;
	}

	//calculate the vector derived from the center line of our pipe and the point of damage
	vec = VectorFromLineToPoint( self.A, self.B, P );
	self thread pipefx( P, vec, damageOwner );
	return true;
}

pipefx( P, vec, damageOwner )
{
	time 		 = level._pipes.fx_time[ self.script_noteworthy ] ;
	intervals 	 = Int( level._pipe_fx_time / time );// loops for 25 seconds
	hitsnd 		 = level._pipes._sound[ self.script_noteworthy + "_hit" ];
	loopsnd 	 = level._pipes._sound[ self.script_noteworthy + "_loop" ];
	endsnd 		 = level._pipes._sound[ self.script_noteworthy + "_end" ];

	snd = Spawn( "sound_emitter", P );
	snd Hide();
	snd PlaySound( hitsnd );
	snd PlayLoopSound( loopsnd );
	self.pipe_fx_array[ self.pipe_fx_array.size ] = snd;

	level._pipes.num_pipe_fx++;

		if ( isSP() || self.script_noteworthy != "steam" )
			self thread pipe_damage( P, vec, damageOwner, snd );

		//do it once without checking for newer fx being played ( we're the newest )
		PlayFX( level._pipes._effect[ self.script_noteworthy ], P, vec );
		wait time;
		intervals--;

		//now check	for other fx and rest of intervals
		while ( level._pipes.num_pipe_fx <= level_limit_pipe_fx && intervals > 0 )
		{
			PlayFX( level._pipes._effect[ self.script_noteworthy ], P, vec );
			wait time;
			intervals--;
		}
		snd PlaySound( endsnd );
		wait( .5 );
		snd StopLoopSound( loopsnd );
		snd Delete();
		self.pipe_fx_array = array_removeUndefined( self.pipe_fx_array );

	level._pipes.num_pipe_fx--;
}

pipe_damage( P, vec, damageOwner, fx )
{
	if ( !allow_pipe_damage() )
		return;
		
	fx endon( "death" );

	origin = fx.origin + vector_multiply( VectorNormalize( vec ), 40 );
	dmg = level._pipes._dmg[ self.script_noteworthy ];

	while ( 1 )
	{
		// do not pass damage owner if they have disconnected before the barrels explode.. the barrels?
		if ( !isdefined( self.damageOwner ) )
		{
			// MOD_TRIGGER_HURT so they dont do dirt on the player's screen
			self RadiusDamage( origin, 36, dmg, dmg * 0.75, undefined, "MOD_TRIGGER_HURT" );
		}
		else
		{
			// MOD_TRIGGER_HURT so they dont do dirt on the player's screen
			self RadiusDamage( origin, 36, dmg, dmg * 0.75, damageOwner, "MOD_TRIGGER_HURT" );
		}

		wait( 0.4 );
	}
}

allow_pipe_damage()
{
	if( !isSP() )
		return false;
	
	if ( !isDefined( level._pipesDamage ) )
		return true;
	
	return ( level._pipesDamage );
}

//////////////////////////////////////////////////////////////////////////////
//							CALCULATIONS / SETUP							//
//////////////////////////////////////////////////////////////////////////////

methodsInit()
{
	level._pipes._pipe_methods = [];
	level._pipes._pipe_methods[ "MOD_UNKNOWN" ] 				 = ::pipe_calc_splash;
	level._pipes._pipe_methods[ "MOD_PISTOL_BULLET" ] 		 = ::pipe_calc_ballistic;
	level._pipes._pipe_methods[ "MOD_RIFLE_BULLET" ] 			 = ::pipe_calc_ballistic;
	level._pipes._pipe_methods[ "MOD_GRENADE" ] 				 = ::pipe_calc_splash;
	level._pipes._pipe_methods[ "MOD_GRENADE_SPLASH" ] 		 = ::pipe_calc_splash;
	level._pipes._pipe_methods[ "MOD_PROJECTILE" ] 			 = ::pipe_calc_splash;
	level._pipes._pipe_methods[ "MOD_PROJECTILE_SPLASH" ] 	 = ::pipe_calc_splash;
	level._pipes._pipe_methods[ "MOD_TRIGGER_HURT" ] 			 = ::pipe_calc_splash;
	level._pipes._pipe_methods[ "MOD_EXPLOSIVE" ] 			 = ::pipe_calc_splash;
	level._pipes._pipe_methods[ "MOD_EXPLOSIVE_BULLET" ] 	 = ::pipe_calc_splash;
}

pipe_calc_ballistic( P, type )
{
	return P;
}

pipe_calc_splash( P, type )
{
	vec = VectorNormalize( VectorFromLineToPoint( self.A, self.B, P ) );
	P = PointOnSegmentNearestToPoint( self.A, self.B, P );
	return( P + vector_multiply( vec, 4 ) );
}

pipe_calc_nofx( P, type )
{
	return undefined;
}

precacheFX()
{
	steam = false;
	fire = false;
	fire_short = false;
	steam_moon = false;
	fire_moon = false;
	foreach ( value in self )
	{
		if ( value.script_noteworthy == "water" )
			value.script_noteworthy = "steam";

		if ( value.script_noteworthy == "steam" )
		{
			value willNeverChange();
			steam = true;
		}
		else if ( value.script_noteworthy == "fire" )
		{
			value willNeverChange();
			fire = true;
		}
		else if ( value.script_noteworthy == "fire_short" )
		{
			value willNeverChange();
			fire_short = true;
		}
		else if ( value.script_noteworthy == "steam_moon" )
		{
			value willNeverChange();
			steam_moon = true;
		}
		else if ( value.script_noteworthy == "fire_moon" )
		{
			value willNeverChange();
			fire_moon = true;
		}
		else
		{
			println( "Unknown 'pipe_shootable' script_noteworthy type '%s'\n", value.script_noteworthy );
		}
	}

	if ( steam )
	{
		level._pipes._effect[ "steam" ]		 = LoadFX( "impacts/pipe_steam" );
		level._pipes._sound[ "steam_hit" ] 	 = "mtl_steam_pipe_hit";
		level._pipes._sound[ "steam_loop" ] = "mtl_steam_pipe_hiss_loop";
		level._pipes._sound[ "steam_end" ] = "mtl_steam_pipe_hiss_loop_end";
		level._pipes.fx_time[ "steam" ]		 = 3;
		level._pipes._dmg[ "steam" ]		 = 5;
	}

	if ( fire )
	{
		level._pipes._effect[ "fire" ]		 = LoadFX( "impacts/pipe_fire" );
		level._pipes._sound[ "fire_hit" ]	 = "mtl_gas_pipe_hit";
		level._pipes._sound[ "fire_loop" ]	 = "mtl_gas_pipe_flame_loop";
		level._pipes._sound[ "fire_end" ]	 = "mtl_gas_pipe_flame_end";
		level._pipes.fx_time[ "fire" ]		 = 3;
		level._pipes._dmg[ "fire" ]			 = 5;
	}

	if ( fire_short )
	{
		level._pipes._effect[ "fire_short" ]		= LoadFX( "nx/impacts/nx_pipe_fire" );
		level._pipes._sound[ "fire_short_hit" ]	 	= "mtl_gas_pipe_hit";
		level._pipes._sound[ "fire_short_loop" ]	= "mtl_gas_pipe_flame_loop";
		level._pipes._sound[ "fire_short_end" ]	 	= "mtl_gas_pipe_flame_end";
		level._pipes.fx_time[ "fire_short" ]		= 16;
		level._pipes._dmg[ "fire_short" ]			= 5;
	}

	if ( steam_moon )
	{
		level._pipes._effect[ "steam_moon" ]		 	= LoadFX( "nx/lunar/impacts/nx_lunar_pipe_steam" );
		level._pipes._sound[ "steam_moon_hit" ] 	 	= "mtl_steam_pipe_hit";
		level._pipes._sound[ "steam_moon_loop" ] 		= "mtl_steam_pipe_hiss_loop";
		level._pipes._sound[ "steam_moon_end" ] 		= "mtl_steam_pipe_hiss_loop_end";
		level._pipes.fx_time[ "steam_moon" ]			= 5;
		level._pipes._dmg[ "steam_moon" ]		 		= 10;
	}

	if ( fire_moon )
	{
		level._pipes._effect[ "fire_moon" ]			= LoadFX( "nx/lunar/impacts/nx_lunar_pipe_fire" );
		level._pipes._sound[ "fire_moon_hit" ]	 	= "mtl_gas_pipe_hit";
		level._pipes._sound[ "fire_moon_loop" ]	 	= "mtl_gas_pipe_flame_loop";
		level._pipes._sound[ "fire_moon_end" ]	 	= "mtl_gas_pipe_flame_end";
		level._pipes.fx_time[ "fire_moon" ]			= 5;
		level._pipes._dmg[ "fire_moon" ]			= 10;
	}
}