#using scripts\mp\_events;
#using scripts\mp\_util;
#using scripts\mp\gametypes\ctf;
#using scripts\mp\killstreaks\_supplydrop;
#using scripts\codescripts\struct;
#using scripts\shared\clientfield_shared;
#using scripts\shared\exploder_shared;
#using scripts\shared\gameobjects_shared;
#using scripts\shared\util_shared; 
#using scripts\shared\weapons\_weaponobjects;


#precache( "fx", "light/fx_light_red_train_track_warning" );
#precache( "fx", "water/fx_water_train_mist_kick_up_metro" );














	
function init()
{
	level.train_positions = [];
	level.train_angles = [];
	
	start1 = GetVehicleNode( "train_start_1", "targetname" );
	start2 = GetVehicleNode( "train_start_2", "targetname" );
		
	cars1 = [];
	cars2 = [];
	
	dividers1 = [];
	dividers2 = [];

	spawn_start_train( cars1, dividers1, start1, "train1" );
	spawn_start_train( cars2, dividers2, start2, "train2" );
	
	gate_inner_left = getentarray("metro_doors_inside_left", "targetname"); 
	gate_outer_left = getentarray("metro_doors_outside_left", "targetname");
	gate_end_left = getentarray("metro_doors_end_left", "targetname");
	gate_speakers_left =  struct::get_array( "metro_train_track_vox_left" );
	gate_inner_right = getentarray("metro_doors_inside_right", "targetname"); 
	gate_outer_right = getentarray("metro_doors_outside_right", "targetname");
	gate_end_right = getentarray("metro_doors_end_right", "targetname");
	gate_speakers_right =  struct::get_array( "metro_train_track_vox_right" );
	
	gate_kill_left = getent("train_killtrigger_left", "targetname"); 
	gate_kill_right = getent("train_killtrigger_right", "targetname"); 
	
	gate_end_kill_left = getent("train_killtrigger_left_end", "targetname"); 
	gate_end_kill_right = getent("train_killtrigger_right_end", "targetname"); 
	
	security_barriers_1 = getEntArray( "mp_metro_platform_edge_left", "targetname" );
	security_barriers_2 = getEntArray( "mp_metro_platform_edge_right", "targetname" ); 

	level._effect[ "fx_light_red_train_track_warning" ] = "light/fx_light_red_train_track_warning";
	level._effect[ "fx_water_train_mist_kick_up_metro" ] = "water/fx_water_train_mist_kick_up_metro";

	waittillframeend;

	if ( level.timelimit )
	{
		seconds = level.timelimit * 60;
		events::add_timed_event( Int( seconds * 0.25 ), "train_start_1" );
		events::add_timed_event( Int( seconds * 0.75 ), "train_start_2" );

	}
	else if ( level.scorelimit )
	{
		events::add_score_event( Int( level.scorelimit * 0.25 ), "train_start_1" );
		events::add_score_event( Int( level.scorelimit * 0.75 ), "train_start_2" );
	}
	else if( level.roundScoreLimit )
	{
		events::add_round_score_event( Int( level.roundScoreLimit * 0.25 ), "train_start_1" );
		events::add_round_score_event( Int( level.roundScoreLimit * 0.75 ), "train_start_2" );
	}

	wait ( 1 );
	if ( level.gameType == "escort" )
	{
		return;
	}
	level thread train_think( cars1, dividers1, "train_start_1", start1, gate_inner_left, gate_outer_left, gate_end_left, security_barriers_1, gate_kill_right, gate_end_kill_right, gate_speakers_right, "right" );
	level thread train_think( cars2, dividers2, "train_start_2", start2, gate_inner_right, gate_outer_right, gate_end_right, security_barriers_2, gate_kill_left, gate_end_kill_left, gate_speakers_left, "left" );
}

function setup_gate( gate, gate_kill )
{
	gate SetMovingPlatformEnabled(true);
	gate.gate_kill = gate_kill;
	gate.gate_kill EnableLinkTo();
	gate.gate_kill LinkTo( gate );
}

function spawn_start_train( &cars, &dividers, start, name )
{
	cars[0] = SpawnVehicle( "train_test_mp", (0,-2000,-200), (0, 0, 0), name );
	cars[0] setteam( "neutral" );
	cars[0] Ghost();
	cars[0].isMagicBullet = true;
	max_cars = getdvarint( "train_length", 10 );
	for( i = 1; i < max_cars; i++ )
	{
		if( i == max_cars - 1 )
		{
			cars[i] = Spawn( "script_model", (0,-2000,-200) );
			cars[i] SetModel( "p7_zur_metro_train_cab_module" );
			cars[i].rotate180 = true;
		}
		else
		{
			cars[i] = Spawn( "script_model", (0,-2000,-200) );
			cars[i] SetModel( "p7_zur_metro_train_car_module" );
		}
		cars[i] Ghost();
		dividers[i] = Spawn( "script_model", (0,-2000,-200) );
		dividers[i] SetModel( "p7_zur_metro_train_divider" );
		dividers[i] Ghost();
	}
}

function showAfterTime( time ) 
{
	wait ( time ) ;
	self Show();
}


function rotatePieces( gatePieceArray, waitTime, rotateTime, rotateAngles, startFromTop )
{
	skip = startFromTop;
	foreach( gatePiece in gatePieceArray )
	{
		if ( !skip )
		{
			gatePiece rotateTo( gatePiece.originalAngles + rotateAngles, rotateTime );
			wait ( waitTime );
		}
		skip = !skip;
	}
	
	foreach( gatePiece in gatePieceArray )
	{
		if ( !skip )
		{
			gatePiece rotateTo( gatePiece.originalAngles + rotateAngles, rotateTime );
			wait ( waitTime );
		}
		skip = !skip;
	}
}


function train_think( cars, dividers, notifier, start, gate_a, gate_b, gate_end, security_barriers, gate_kill_trigger, gate_end_kill_trigger, train_speakers, trackside )
{
	level endon ( "game_ended" );
	
	foreach( gate in gate_a )
	{
		gate.originalAngles = gate.angles;
	}
	foreach( gate in gate_b )
	{
		gate.originalAngles = gate.angles;
	}
	foreach( gate in gate_end )
	{
		gate.originalAngles = gate.angles;
	}
	
	foreach( barrier in security_barriers )
	{
		barrier.originalOrigin = barrier.origin; 
	}

	rotateDirection = ( 0, 90, 0 );
	if ( trackside == "left" )
	{
		rotateDirection *= -1;
	}	
	for ( ;; )
	{
		level waittill( notifier );
		
		foreach( speaker in train_speakers )
		{
			PlaySoundAtPosition( "vox_metr_metro_approaching", speaker.origin );
		}

		metro_vox_wait_time = getdvarfloat( "metro_vox_wait_time", 4.0 );
		wait( metro_vox_wait_time );

		gate_move_time = getdvarfloat( "gate_move_time", 2.0 );
		gate_end_move_time = getdvarfloat( "gate_end_move_time", 1.0 );
		gate_piece_wait_time = getdvarfloat( "gate_wait_time", 0.3 );
		
		gate_a[0] PlayLoopSound ( "amb_train_alarm" );
		gate_b[0] PlayLoopSound ( "amb_train_alarm" );

		barrier_move_time = getdvarfloat( "barrier_move_time", 2.0 );
		barrier_move_height = getdvarfloat( "barrier_move_height", 30.0 );
		foreach( barrier in security_barriers )
		{
			barrier moveto( barrier.origin + ( 0, 0 , barrier_move_height ), barrier_move_time );
			barrier playsound ("evt_wall_up");
		}

		gate_wait_train_time = getdvarfloat( "gate_wait_train_time", 5.0 );
		wait( gate_wait_train_time );
		cars[0] AttachPath( start );
		cars[0] StartPath();
		cars[0] showAfterTime( 0.1 );
		cars[0] thread record_positions(trackside);
		cars[0] PlayLoopSound ( "amb_train_by" );
		
		max_cars = getdvarint( "train_length", 10 );
		for( i = 1; i < max_cars; i++ )
		{
			wait( .30 );
			dividers[i] thread car_move(trackside);
			dividers[i] thread watch_player_touch();
			wait( .30 );
			cars[i] thread car_move(trackside);
			cars[i] thread watch_player_touch();
			cars[i] PlayLoopSound ( "amb_train_by" );
		}
		foreach( speaker in train_speakers )
		{
			PlaySoundAtPosition( "vox_metr_metro_gap", speaker.origin );
		}
		level thread rotatePieces( gate_end, 1, gate_end_move_time, -rotateDirection, 0 );
		gate_end[0] playsound ("evt_gate_open");
		gate_end_kill_trigger security_door_close_think( false, 0, gate_end_move_time );

		level thread rotatePieces( gate_a, gate_piece_wait_time, gate_move_time, rotateDirection, 0 );
		gate_a[0] playsound ("evt_gate_open");
		level thread rotatePieces( gate_b, gate_piece_wait_time, gate_move_time, rotateDirection, 1 );
		gate_b[0] playsound ("evt_gate_open");
		gate_kill_trigger security_door_close_think( true, 0, gate_move_time );
		
		wait ( getdvarfloat( "gate_wait_close_door_end", 8.0 ) );

		level thread rotatePieces( gate_end, 1, gate_move_time, (0,0,0), 0 );
		gate_end[0] playsound ("evt_gate_close");
		gate_end_kill_trigger security_door_close_think( false, 0, gate_move_time );
		wait ( getdvarfloat( "gate_wait_close_doors", 4.0 ) );

		level thread rotatePieces( gate_a, gate_piece_wait_time, gate_move_time, (0,0,0), 0 );
		gate_a[0] playsound ("evt_gate_close");
		level thread rotatePieces( gate_b, gate_piece_wait_time, gate_move_time, (0,0,0), 1 );
		gate_b[0] playsound ("evt_gate_close");
		
		gate_kill_trigger security_door_close_think( false, 0, gate_move_time );
		gate_kill_trigger security_door_close_think( true, gate_move_time, 0.25 );
		
		foreach( barrier in security_barriers )
		{
			barrier moveto(barrier.originalOrigin, barrier_move_time );
			barrier playsound ("evt_wall_down");
		}
		
		gate_a[0] StopLoopSound ( 2 );
		gate_b[0] StopLoopSound ( 2 );

		cars[0] waittill( "reached_end_node" );
		cars[0] StopLoopSound ( 2 );
		for( i = 1; i < max_cars; i++ )
		{
			cars[i] ghost();
			cars[i] notify( "stop_kill" );
			dividers[i] ghost();
			dividers[i] notify( "stop_kill" );
			cars[i] StopLoopSound ( 2 );
		}
		cars[0] notify( "stop_kill" );
		cars[0] ghost();
	}
}

function record_positions( tracknum )
{
	self endon( "reached_end_node" );
	
	level.train_positions[tracknum] = [];
	level.train_angles[tracknum] = [];
	
	
	if ( tracknum == "left" )
	{
		train_position_start_water = getdvarint( "train_position_start_water_left", 205 );
		train_dust_kickup_1 = getdvarint( "train_dust_kickup_1_left", 150 );
		train_dust_kickup_2 = getdvarint( "train_dust_kickup_2_left", 174 );
		train_dust_kickup_3 = getdvarint( "train_dust_kickup_3_left", 200 );
	}
	else
	{
		train_position_start_water = getdvarint( "train_position_start_water_right", 205 );
		train_dust_kickup_1 = getdvarint( "train_dust_kickup_1_right", 150 );
		train_dust_kickup_2 = getdvarint( "train_dust_kickup_1_right", 174 );
		train_dust_kickup_3 = getdvarint( "train_dust_kickup_1_right", 200 );
	}

	for ( ;; )
	{
		if ( !isdefined( self ) )
			return;
		
		level.train_positions[tracknum][ level.train_positions[tracknum].size ] = self.origin;
		level.train_angles[tracknum][ level.train_angles[tracknum].size ] = self.angles;
		if ( level.train_angles[tracknum].size == train_position_start_water )
		{
			playfxontag( level._effect[ "fx_water_train_mist_kick_up_metro" ], self, "tag_origin" );
		}
		else if ( level.train_angles[tracknum].size == train_dust_kickup_1 )
		{
			level thread dust_kickup( 1, tracknum );
		}
		else if ( level.train_angles[tracknum].size == train_dust_kickup_2 )
		{
			level thread dust_kickup( 2, tracknum );
		}
		else if ( level.train_angles[tracknum].size == train_dust_kickup_3 )
		{
			level thread dust_kickup( 3, tracknum );
		}
		
		wait( 0.05 );
	}
}

function dust_kickup( index, trackside )
{
	exploderName = "Train_dust_kickup_" + index + "_" + trackside;
	exploder::exploder( exploderName );
	wait( 5.5 );
	exploder::stop_exploder( exploderName );
}

function car_move( tracknum )
{
	self endon( "stop_kill" );
	if ( tracknum == "left" )
	{
		train_position_start_water = getdvarint( "train_position_start_water_left", 205 );
	}
	else
	{
		train_position_start_water = getdvarint( "train_position_start_water_right", 205 );
	}
	for( i = 0; i < level.train_positions[tracknum].size; i++ )
	{
		if ( i == train_position_start_water )
		{
			playfxontag( level._effect[ "fx_water_train_mist_kick_up_metro" ], self, "tag_origin" );
		}
		self.origin = level.train_positions[tracknum][ i ];
		self.angles = level.train_angles[tracknum][ i ];
		if ( isdefined( self.rotate180 ) && self.rotate180 == true )
		{
			self.angles += ( 0, 180, 0 );
		}

		wait( 0.05 );
		if ( i == 4 ) 
		{
			self Show();
		}
	}
}

function watch_player_touch()
{
	self endon( "end_of_track" );
	self endon( "stop_kill" );
	self endon( "delete" );
	self endon( "death" );
	self.disableFinalKillcam = true;

	for(;;)
	{
		self waittill( "touch", entity );
		if ( isplayer( entity ) )
		{
			entity DoDamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" );
		}
	}
}


function train_setup_clock()
{
	metro_clock_1 = getent("MP_Metro_clock_1", "targetname"); 
	metro_clock_2 = getent("MP_Metro_clock_2", "targetname"); 

	if ( !isdefined( metro_clock_1 ) || !isdefined( metro_clock_2 ) )
	{ 
		return false;
	}
	
	level.clockModel1 = util::spawn_model( "tag_origin", metro_clock_1.origin, metro_clock_1.angles );
	level.clockModel1 clientfield::set( "mp_metro_train_timer", 1 );	
	
	level.clockModel2 = util::spawn_model( "tag_origin", metro_clock_2.origin, metro_clock_2.angles );
	level.clockModel2 clientfield::set( "mp_metro_train_timer", 1 );	
	
	return true;
}





function security_door_close_think( killPlayers, waittime, scantime )
{
	self endon( "end_kill_trigger" );
	self.disableFinalKillcam = true;
	door = self;
	corpse_delay = 0;
	if ( waittime > 0 )
	{
		wait( waittime );
	}
	timescanned = 0;
	while( scantime > timescanned )
	{
//		iprintlnbold("doing it" );
		wait( 0.2 );
		timescanned += 0.2;
		entities = GetDamageableEntArray( self.origin, 200 );
		
		foreach( entity in entities )
		{
			if ( !entity IsTouching( self ) )
			{
				continue;
			}
			
			if ( !IsAlive( entity ) )
			{
				continue;
			}
						
			if ( IsDefined( entity.targetname ) )
			{
				if ( entity.targetname == "talon" )
				{
					entity notify( "death" );
					continue;
				}
			}

			if ( IsDefined( entity.helitype ) && entity.helitype == "qrdrone" )
			{
				watcher = entity.owner weaponobjects::getWeaponObjectWatcher( "qrdrone" );
				watcher thread weaponobjects::waitAndDetonate( entity, 0.0, undefined );
				continue;
			}

			if ( entity.classname == "grenade" )
			{
				if( !IsDefined( entity.name ) )
				{
					continue;
				}

				if( !IsDefined( entity.owner ) )
				{
					continue;
				}

				if ( entity.name == "proximity_grenade_mp" )
				{
					watcher = entity.owner weaponobjects::getWatcherForWeapon( entity.name );
					watcher thread weaponobjects::waitAndDetonate( entity, 0.0, undefined, "script_mover_mp" );
					continue;
				}

				if( !entity.isEquipment )
				{
					continue;
				}

				watcher = entity.owner weaponobjects::getWatcherForWeapon( entity.name );

				if( !IsDefined( watcher ) )
				{
					continue;
				}

				watcher thread weaponobjects::waitAndDetonate( entity, 0.0, undefined, "script_mover_mp" );
				continue;
			}
						
			if ( entity.classname == "auto_turret" )
			{
				if ( !IsDefined( entity.damagedToDeath ) || !entity.damagedToDeath )
				{
					entity util::DoMaxDamage( self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" );
				}
				continue;
			}
			
			if( IsVehicle( entity ) && ( !isdefined( entity.team ) || entity.team != "neutral" ) ) // vehicles are immune from MOD_CRUSH
			{
				entity kill();
				continue;
			}
			
			if( killPlayers == false && IsPlayer( entity ) )
			{
				continue;
			}

			entity DoDamage( entity.health * 2, self.origin + ( 0, 0, 1 ), self, self, 0, "MOD_CRUSH" );

			if( IsPlayer( entity ) )
			{
				corpse_delay = GetTime() + 1000;
			}
		}

		self destroy_supply_crates();

		if ( GetTime() > corpse_delay )
		{
			self destroy_corpses();
		}

		if ( level.gameType == "ctf" )
		{
			foreach( flag in level.flags )
			{
				if ( flag.visuals[0] IsTouching( self ) )
				{
					flag ctf::returnFlag();
				}
			}
		}
		else if ( level.gameType == "sd" && !level.multiBomb )
		{
			if ( level.sdBomb.visuals[0] IsTouching( self ) )
			{
				level.sdBomb gameobjects::return_home();
			}
		}
	}
}


function destroy_supply_crates()
{
	crates = GetEntArray( "care_package", "script_noteworthy" );

	foreach( crate in crates )
	{
		if ( DistanceSquared( crate.origin, self.origin ) < 200 * 200 )
		{
			if( crate IsTouching( self ) ) 
			{
				PlayFX( level._supply_drop_explosion_fx, crate.origin );
				PlaySoundAtPosition( "wpn_grenade_explode", crate.origin );
				wait ( 0.1 );
				crate supplydrop::crateDelete();
			}
		}
	}
}

function destroy_corpses()
{
	corpses = GetCorpseArray();

	for ( i = 0; i < corpses.size; i++ )
	{
		if ( DistanceSquared( corpses[i].origin, self.origin ) < 200 * 200 )
		{
			corpses[i] delete();
		}
	}
}


function get_closest( org, array )
{
	dist = 9999999;

	distsq = dist*dist;
	if( array.size < 1 )
	{
		return;
	}
	index = undefined;
	for( i = 0;i < array.size;i++ )
	{
		newdistsq = distancesquared( array[ i ].origin, org );
		if( newdistsq >= distsq )
		{
			continue;
		}
		distsq = newdistsq;
		index = i;
	}
	return array[index];
}




