#using scripts\codescripts\struct;

#using scripts\shared\ai_shared;
#using scripts\shared\animation_shared;
#using scripts\shared\array_shared;
#using scripts\shared\callbacks_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\colors_shared;
#using scripts\shared\flag_shared;
#using scripts\shared\flagsys_shared;
#using scripts\shared\spawner_shared;
#using scripts\shared\system_shared;
#using scripts\shared\trigger_shared;
#using scripts\shared\util_shared;
#using scripts\shared\ai\systems\gib;
#using scripts\shared\hostmigration_shared;

                                                                                                                                                                                                          	     	                                                                                   
    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                                                            	  	  	              	   	                                                                                                                                       	                                                                                                                                                            	                                                                                                                                                                

#using_animtree( "generic" );

#namespace vehicle;

///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO:
//
// * Implement death anims
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

function autoexec __init__sytem__() {     system::register("vehicleriders",&__init__,undefined,undefined);    }

function __init__()
{
	level.vehiclerider_groups = [];
	level.vehiclerider_groups[ "all" ] = "all";
	level.vehiclerider_groups[ "driver" ] = "driver";
	level.vehiclerider_groups[ "passengers" ] = "passenger";
	level.vehiclerider_groups[ "crew" ] = "crew";
	level.vehiclerider_groups[ "gunners" ] = "gunner";
	
	a_registered_fields = [];
	foreach ( bundle in struct::get_script_bundles( "vehicleriders" ) )
	{
		foreach ( object in bundle.objects )
		{
			if ( IsString( object.VehicleEnterAnim ) )
			{
				array::add( a_registered_fields, object.position + "_enter", false );
			}
			
			if ( IsString( object.VehicleExitAnim ) )
			{
				array::add( a_registered_fields, object.position + "_exit", false );
			}
			
			if ( IsString( object.VehicleRiderDeathAnim ) )
			{
				array::add( a_registered_fields, object.position + "_death", false );
			}
		}
	}
	
	foreach ( str_clientfield in a_registered_fields )
	{
		clientfield::register( "vehicle", str_clientfield, 1, 1, "counter" );
	}
	
	
	level.vehiclerider_use_index = [];
	level.vehiclerider_use_index[ "driver" ] = 0;

	// Set up gunnner use indices.
	const MAX_USE_INDEX = 4;
	for ( i = 1; i <= MAX_USE_INDEX; i++ )
	{
		level.vehiclerider_use_index[ "gunner" + i ] = i;
	}
	
	// Setup passenger use indices
	const MAX_PASSENGER_INDEX = 10;
	passengerIndex = 1;
	for ( i = MAX_USE_INDEX + 1; i <= MAX_PASSENGER_INDEX; i++ )
	{
		level.vehiclerider_use_index[ "passenger" + passengerIndex ] = i;
		passengerIndex++;
	}
	
	/* FIX UP STUFF FROM THE GDT */
	foreach ( s in struct::get_script_bundles( "vehicleriders" ) )
	{
		if(!isdefined(s.LowExitHeight))s.LowExitHeight=0;
		if(!isdefined(s.HighExitLandHeight))s.HighExitLandHeight=32;
	}
	
	callback::on_vehicle_spawned( &on_vehicle_spawned );
	callback::on_ai_spawned( &on_ai_spawned );
	callback::on_vehicle_killed(&on_vehicle_killed);
}

function seat_position_to_index( str_position )
{
	return level.vehiclerider_use_index[ str_position ];
}

function on_vehicle_spawned()
{
	spawn_riders();
}

function on_ai_spawned()
{
	if ( IsVehicle( self ) )
	{
		self spawn_riders();
	}
}

function claim_position( vh, str_pos )
{
	array::add( vh.riders, self, false );
	vh flagsys::set( str_pos + "occupied" );
	self flagsys::set( "vehiclerider" );
	
	self thread _unclaim_position_on_death( vh, str_pos );
}

function unclaim_position( vh, str_pos )
{
	ArrayRemoveValue( vh.riders, self );
	vh flagsys::clear( str_pos + "occupied" );
	self flagsys::clear( "vehiclerider" );
}

function private _unclaim_position_on_death( vh, str_pos )
{
	vh endon( "death" );
	vh endon(  str_pos + "occupied" );
	
	self waittill( "death" );
	
	unclaim_position( vh, str_pos );
}

function find_next_open_position( ai )
{
	foreach ( s_rider in get_bundle_for_ai( ai ).objects )
	{
		seat_index = seat_position_to_index(s_rider.position);
		if( seat_index <= 4 )	// IsVehicleSeatOccupied only works on code seats and not passenger seats
		{
			if( self IsVehicleSeatOccupied( seat_index ) )
				continue;
		}
		   
		if ( !flagsys::get( s_rider.position + "occupied" ) )
		{
			return s_rider.position;
		}
	}
}

function spawn_riders()
{
	self endon("death");
	
	self.riders = [];
	if ( isdefined( self.script_vehicleride ) )
	{
		
		a_spawners = GetSpawnerArray( self.script_vehicleride, "script_vehicleride" );
		foreach ( sp in a_spawners )
		{
			ai_rider = sp spawner::spawn( true );
			//ai_rider = util::spawn_anim_model( "c_hro_hendricks_base_fb" );
			
			if ( isdefined( ai_rider ) )
			{
				ai_rider get_in( self, ai_rider.script_startingposition, true );
			}
		}
	}
}

function get_bundle_for_ai( ai )
{
	vh = self;
	if ( (isdefined(ai.archetype) && ( ai.archetype == "robot" )) )
	{
		bundle = vh get_robot_bundle();
	}
	else
	{
		bundle = vh get_bundle();
	}
	return bundle;
}

function get_rider_info( vh, str_pos = "driver" )
{
	ai = self;
	bundle = undefined;
	bundle = vh get_bundle_for_ai( ai );
	
	foreach ( s_rider in bundle.objects )
	{
		if ( s_rider.position == str_pos )
		{
			return s_rider;
		}
	}
}

/@
"Summary: Makes an AI get in a vehicle (with animation)"
"Name: get_in( vh, str_pos, b_teleport = false )"
"CallOn: AI"
"MandatoryArg: <vh> The vehicle to ride in"
"OptionalArg: [str_pos] The position to ride in.  If undefined, will choose next available position."
"OptionalArg: [b_teleport] If true, teleport to rider position and don't play get in animation."
"Example: ai vehicle::get_in( vh_truck, "driver" );"
@/
function get_in( vh, str_pos, b_teleport = false )
{
	self endon( "death" );	
	vh endon( "death" );
	
	if ( !isdefined( str_pos ) )
	{
		str_pos = vh find_next_open_position( self );
	}
	
	Assert( isdefined( str_pos ), "No unoccupied seats for vehicle rider." );
	
	if( !isdefined( str_pos ) )
	{
		return;
	}
	
	//return if the seat is not available
	if ( !isdefined( vh.ignore_seat_check ) || !vh.ignore_seat_check )
	{
		seat_index = level.vehiclerider_use_index[ str_pos ];
		if( seat_index <= 4 )	// IsVehicleSeatOccupied only works on code seats and not passenger seats
		{
			seat_available = !(vh IsVehicleSeatOccupied( seat_index ) );
			Assert( seat_available, "This seat is already occupied." );
		
			if(!seat_available)
			{
				return;
			}
		}
	}
	
	claim_position( vh, str_pos );

	if ( !b_teleport && self flagsys::get( "in_vehicle" ) )
	{
		get_out();
	}
	
	if ( colors::is_color_ai() )
	{
		colors::disable();
	}

	_init_rider( vh, str_pos );
	
	if ( !b_teleport )
	{
		self animation::set_death_anim( self.rider_info.EnterDeathAnim );
		animation::reach( self.rider_info.EnterAnim, self.vehicle, self.rider_info.AlignTag );
		
		// Animate the door on the client.
		if ( isdefined( self.rider_info.VehicleEnterAnim ) )
		{
			vh clientfield::increment( self.rider_info.position + "_enter", 1 );
			self SetAnim( self.rider_info.VehicleEnterAnim, 1, 0, 1 );
		}

		self animation::play( self.rider_info.EnterAnim, self.vehicle, self.rider_info.AlignTag );
	}
	
	if ( isdefined(self.rider_info) && isdefined( self.rider_info.RideAnim ) )
	{
		//disable unlink after the animation is done since this will be handled by UseVehicle
		self thread animation::play( self.rider_info.RideAnim, self.vehicle, self.rider_info.AlignTag, 1, 0.2, 0.2, 0, 0, false, false );
	}
	else if ( !isdefined( level.vehiclerider_use_index[ str_pos ] ) )
	{
		assert( "Rider is missing ride animation for seat: " + str_pos );
	}
	else if ( isdefined(self.rider_info) )
	{
		// HACK: teleport to align tag in the case of no ride animation being available (mainly for gunners)
		// Since UseVehicle doesn't put them on the vehicle properly.
		v_tag_pos = vh GetTagOrigin( self.rider_info.aligntag );
		v_tag_ang = vh GetTagAngles( self.rider_info.aligntag );
		if (isdefined(v_tag_pos))
			self ForceTeleport( v_tag_pos, v_tag_ang );
	}
	else
	{
		/# ErrorMsg( "Missing rider_info" ); #/
	}
	
	if ( IsActor( self ) )
	{
		// Disable pathing while inside a vehicle.
		self PathMode( "dont move" );
		
		// Disable dropping ammo/weapon inside a vehicle.
		self.disableAmmoDrop = true;
		self.dontDropWeapon = true;
	}
	
	// If there is an associated use index, call UseVehicle.
	//
	if ( isdefined( level.vehiclerider_use_index[ str_pos ] ) )
	{
		//double check that the seat is still available
		if ( !isdefined( self.vehicle.ignore_seat_check ) || !self.vehicle.ignore_seat_check )
		{
			seat_index = level.vehiclerider_use_index[ str_pos ];
			if( seat_index <= 4 )	// IsVehicleSeatOccupied only works on code seats and not passenger seats
			{
				if( self.vehicle IsVehicleSeatOccupied( seat_index ) )
				{
					get_out();
					return;
				}
			}
		}
		
		self.vehicle UseVehicle( self, level.vehiclerider_use_index[ str_pos ] );
	}
	
	self flagsys::set( "in_vehicle" );
	
	self thread handle_rider_death();
}

function handle_rider_death()
{
	self endon( "exiting_vehicle" );
	self.vehicle endon( "death" );

	if ( IsDefined( self.rider_info.RideDeathAnim ) )
	{
		self animation::set_death_anim( self.rider_info.RideDeathAnim );
	}
	
	self waittill( "death" );
	
	if ( !IsDefined( self ) )
	{
		return;
	}

	if ( IsDefined( self.vehicle ) && IsDefined( self.rider_info ) && IsDefined( self.rider_info.VehicleRiderDeathAnim ) )
	{
		self.vehicle clientfield::increment( self.rider_info.position + "_death", 1 );
		self.vehicle SetAnimKnobRestart( self.rider_info.VehicleRiderDeathAnim, 1, 0, 1 );
	}
}

function delete_rider_asap( entity )
{
	wait .05;
	
	if ( IsDefined( entity ) )
	{
		entity Delete();
	}
}

function kill_rider( entity )
{
	if( IsDefined( entity ) )
	{
		if( IsAlive( entity ) && !GibServerUtils::IsGibbed( entity, 2 ) )
		{
			if ( entity IsPlayingAnimScripted() )
			{
				entity StopAnimScripted();
			}
			
			if ( GetDvarInt( "tu1_vehicleRidersInvincibility", 1 ) )
			{
				// TU1 crash fix when killing a vehicle that had invincible riders.
				util::stop_magic_bullet_shield( entity );
			}
		
			GibServerUtils::GibLeftArm( entity );
			GibServerUtils::GibRightArm( entity );
			GibServerUtils::GibLegs( entity );
			GibServerUtils::Annihilate( entity );
			
			entity Unlink();
			entity Kill();
		}
		
		// Ragdoll typically goes insane, hide and delete the entity.
		entity Ghost();
		level thread delete_rider_asap( entity );
	}
}

function on_vehicle_killed( params )
{
	// "self" is a removed entity in this case and IsDefined( self ) will always return false, even though
	// script variables on that entity are still available.
	if ( /* IsDefined( self ) && */ IsDefined( self.riders ) )
	{
		foreach ( rider in self.riders )
		{
			kill_rider( rider );
		}
	}
}

function is_seat_available( vh, str_pos )
{
	if ( vh flagsys::get( str_pos + "occupied" ) )
	{
		return false;
	}
	
	if ( AnglesToUp( vh.angles )[2] < 0.3 )
	{
		// Vehicle is flipped
		return false;
	}
	
	seat_index = seat_position_to_index( str_pos );
	if( seat_index <= 4 )	// IsVehicleSeatOccupied only works on code seats and not passenger seats
	{
		if( vh IsVehicleSeatOccupied( seat_index ) )
		{
			return false;
		}
	}
	return true;
}

function can_get_in( vh, str_pos )
{
	if ( !is_seat_available( vh, str_pos ) )
	{
		return false;
	}
	
	rider_info = self get_rider_info( vh, str_pos );
	
	v_tag_org = vh GetTagOrigin( rider_info.AlignTag );
	v_tag_ang = vh GetTagAngles( rider_info.AlignTag );
	
	v_enter_pos = GetStartOrigin( v_tag_org, v_tag_ang, rider_info.EnterAnim );
	
	if ( !self FindPath( self.origin, v_enter_pos ) )
	{
		return false;
	}
	
	return true;
}



/@
"Summary: Makes an AI get out of a vehicle (with animation)"
"Name: get_out()"
"CallOn: AI"
"Example: ai vehicle::get_out();"
@/
function get_out( str_mode )
{
	ai = self;
	self endon( "death" );
	
	self notify( "exiting_vehicle" );
	
	Assert( IsAlive( self ), "Dead or undefined vehicle rider." );
	Assert( isdefined( self.vehicle ), "AI is not on vehicle." );
	
	if ( ( isdefined(self.vehicle.vehicleclass) && (self.vehicle.vehicleclass == "helicopter" ) ) || ( isdefined(self.vehicle.vehicleclass) && (self.vehicle.vehicleclass == "plane") ) )
	{
		if(!isdefined(str_mode))str_mode="variable";
	}
	else
	{
		if(!isdefined(str_mode))str_mode="ground";
	}
	
	bundle = self.vehicle get_bundle_for_ai( ai );
	n_hover_height = bundle.LowExitHeight;
	
	// Animate the door on the client.
	if ( isdefined( self.rider_info.VehicleExitAnim ) )
	{
		self.vehicle clientfield::increment( self.rider_info.position + "_exit", 1 );
		self.vehicle SetAnim( self.rider_info.VehicleExitAnim, 1, 0, 1 );
	}

	switch ( str_mode )
	{
		case "ground":
			
			exit_ground();
			break;
			
		case "low":
			
			exit_low();
			break;
			
		case "variable":
			
			exit_variable();
			break;
			
		default: AssertMsg( "Invalid mode for vehicle unload." );
	}
	
	if ( IsActor( self ) )
	{
		// Re-enable pathing once an AI leaves a vehicle.
		self PathMode( "move allowed" );
		
		// Allow dropping ammo/weapon after leaving the vehicle.
		self.disableAmmoDrop = false;
		self.dontDropWeapon = false;
	}
	
	if( isdefined( self.vehicle ) )
	{
		unclaim_position( self.vehicle, self.rider_info.position );
		
		// If there is an associated use index, call UseVehicle.
		//
		if ( isdefined( level.vehiclerider_use_index[ self.rider_info.position ] ) && (self flagsys::get( "in_vehicle" )) )
		{
			self.vehicle UseVehicle( self, level.vehiclerider_use_index[ self.rider_info.position ] );
		}
	}
	
	self flagsys::clear( "in_vehicle" );

	self.vehicle = undefined;	
	self.rider_info = undefined;
	self animation::set_death_anim( undefined );
	
	set_goal();
	
	self notify( "exited_vehicle" );
}

function set_goal()
{
	if ( colors::is_color_ai() )
	{
		colors::enable();
	}
	else if ( !isdefined( self.target ) )
	{
		self SetGoal( self.origin );
	}
}

/@
"Summary: Unload riders from a vehicle"
"Name: unload( str_group )"
"CallOn: Vehicle"
"OptionalArg: [str_group] Unload a specific group instead of all riders (all, driver, passengers, crew, gunners)."
"Example: vh_truck vehicle::unload( "all" );"
"Example: vh_truck vehicle::unload( "gunners" );"
@/
function unload( str_group = "all", str_mode, remove_rider_before_unloading, remove_riders_wait_time )
{
	self notify( "unload", str_group );
	
	Assert( isdefined( level.vehiclerider_groups[ str_group ] ), str_group + " is not a valid unload group." );
	
	str_group = level.vehiclerider_groups[ str_group ]; // look up position subtring to use
	
	a_ai_unloaded = [];
	foreach ( ai_rider in self.riders )
	{
		if ( ( str_group == "all" ) || IsSubStr( ai_rider.rider_info.position, str_group ) )
		{
			ai_rider thread get_out( str_mode );
			if ( !isdefined( a_ai_unloaded ) ) a_ai_unloaded = []; else if ( !IsArray( a_ai_unloaded ) ) a_ai_unloaded = array( a_ai_unloaded ); a_ai_unloaded[a_ai_unloaded.size]=ai_rider;;
		}
	}

	if ( a_ai_unloaded.size > 0 )
	{
		if ( remove_rider_before_unloading === true )
		{
			remove_riders_after_wait( remove_riders_wait_time, a_ai_unloaded );
		}	

		array::flagsys_wait_clear( a_ai_unloaded, "in_vehicle", (isdefined(self.unloadTimeout)?self.unloadTimeout:4) );
		self notify( "unload", a_ai_unloaded );
	}
}

function remove_riders_after_wait( wait_time, a_riders_to_remove )
{
	wait wait_time;

	if ( isdefined( a_riders_to_remove ) )
	{
		foreach( ai in a_riders_to_remove )
		{
			ArrayRemoveValue( self.riders, ai );
		}
	}
}

function ragdoll_dead_exit_rider()
{
	self endon( "exited_vehicle" );

	self waittill( "death" );

	if ( IsActor( self ) && !self IsRagdoll() )
	{
		self Unlink();
		self StartRagdoll();
	}
}

function exit_ground()
{	
	self animation::set_death_anim( self.rider_info.ExitGroundDeathAnim );
	
	if ( !IsDefined( self.rider_info.ExitGroundDeathAnim ) )
	{
		self thread ragdoll_dead_exit_rider();
	}
	
	Assert( IsString( self.rider_info.ExitGroundAnim ), "No exit animation for '" + self.rider_info.position + "'. Can't unload specified group." );
	
	if ( IsString( self.rider_info.ExitGroundAnim ) )
	{
		animation::play( self.rider_info.ExitGroundAnim, self.vehicle, self.rider_info.AlignTag );
	}
}

function exit_low()
{
	self animation::set_death_anim( self.rider_info.ExitLowDeathAnim );
	Assert( isdefined( self.rider_info.ExitLowAnim ), "No exit animation for '" + self.rider_info.position + "'. Can't unload specified group." );
	animation::play( self.rider_info.ExitLowAnim, self.vehicle, self.rider_info.AlignTag );
}

function private handle_falling_death()
{
	self endon( "landed" );
	
	self waittill( "death" );
	
	if ( IsActor( self ) )
	{
		self Unlink();
		self StartRagdoll();
	}
}

function private forward_euler_integration( e_move, v_target_landing, n_initial_speed )
{
	// Sympletic euler integration.
	landed = false;
	integrationStep = 0.1;  // Seconds
	position = self.origin;
	velocity = (0, 0, -n_initial_speed);
	gravity = (0, 0, -385.8); // Gravity in inches/second^2 moving downward
	
	while ( !landed )
	{
		previousPosition = position;
	
		// Update the velocity and position based on the integration step.
		velocity = velocity + gravity * integrationStep;
		// Calculating velocity before position ensure sympletic integration.
		position = position + velocity * integrationStep;
		
		// If the next integration step will take us past our landing, just move to that position instead.
		if ( ( position[2] + velocity[2] * integrationStep ) <= v_target_landing[2] )
		{
			landed = true;
			
			position = v_target_landing;
		}
	
		/#
		recordLine( previousPosition, position, ( 1, .5, 0 ), "Animscript", self );
		#/
			
		hostmigration::waitTillHostMigrationDone();
		e_move MoveTo( position, integrationStep );
	
		if ( !landed )
		{
			wait integrationStep;
		}
	}
}

function exit_variable()
{
	ai = self;
	self endon( "death" );
	
	self notify( "exiting_vehicle" );
	
	self thread handle_falling_death();
	
	self animation::set_death_anim( self.rider_info.ExitHighDeathAnim );
	Assert( isdefined( self.rider_info.ExitHighAnim ), "No exit animation for '" + self.rider_info.position + "'. Can't unload specified group." );
	animation::play( self.rider_info.ExitHighAnim, self.vehicle, self.rider_info.AlignTag, 1, 0, 0 );
	
	self animation::set_death_anim( self.rider_info.ExitHighLoopDeathAnim );
	
	n_cur_height = get_height( self.vehicle );
	
	bundle = self.vehicle get_bundle_for_ai( ai );
	n_target_height = bundle.HighExitLandHeight;
	
	if( ( isdefined( self.rider_info.DropUnderVehicleOrigin ) && self.rider_info.DropUnderVehicleOrigin ) || ( isdefined( self.DropUnderVehicleOriginOverride ) && self.DropUnderVehicleOriginOverride ) )
		v_target_landing = ( self.vehicle.origin[0], self.vehicle.origin[1], self.origin[2] - n_cur_height + n_target_height );
	else
		v_target_landing = ( self.origin[0], self.origin[1], self.origin[2] - n_cur_height + n_target_height );
	
	if( isdefined( self.overrideDropPosition ) )
		v_target_landing = ( self.overrideDropPosition[0], self.overrideDropPosition[1], v_target_landing[2] );
	
	if( isdefined( self.targetAngles ) )
		angles = self.targetAngles;
	else
		angles = self.angles;
	
	// Create the tag origin
	e_move = util::spawn_model( "tag_origin", self.origin, angles );
	
	self thread exit_high_loop_anim( e_move );
	
	// Move the tag origin downward.
	distance = n_target_height - n_cur_height;
	initialSpeed = bundle.DropSpeed;
	acceleration = 385.8;  // Gravity in inches/second^2
	
	// Kinematic Equation to compute distance given, time, velocity, and acceleration.
	// distance = velocity(init) * time + (1/2) * acceleration * time^2;
	
	// Use the quadratic equation to solve for time.
	n_fall_time = ( -initialSpeed + Sqrt( Pow( initialSpeed, 2 ) - 2 * acceleration * distance ) ) / acceleration;
	
	self notify( "falling", n_fall_time );
	
	forward_euler_integration( e_move, v_target_landing, bundle.DropSpeed );
	
	e_move waittill( "movedone" );
	
	self notify( "landing" );
	
	self animation::set_death_anim( self.rider_info.ExitHighLandDeathAnim );
	animation::play( self.rider_info.ExitHighLandAnim, e_move, "tag_origin" );
	
	self notify( "landed" );
	
	self Unlink();
	
	{wait(.05);};
	
	// Detach from tag origin and delete.
	e_move Delete();
}

function exit_high_loop_anim( e_parent )
{
	self endon( "death" );
	self endon( "landing" );
	
	while ( true )
	{
		animation::play( self.rider_info.ExitHighLoopAnim, e_parent, "tag_origin" );
	}
}

function get_height( e_ignore )
{
	if(!isdefined(e_ignore))e_ignore=self;
	
	const height_diff = 10;
	trace = GroundTrace( self.origin + (0,0,height_diff), self.origin + ( 0, 0, -10000 ), false, e_ignore, false );
	
	/#
	recordLine( self.origin + (0,0,height_diff), trace[ "position" ], ( 1, .5, 0 ), "Animscript", self );
	#/
	
	return Distance( self.origin, trace[ "position" ] );
}

function get_bundle()
{
	Assert( isdefined( self.vehicleridersbundle ), "No vehicleriders bundle specified for this vehicle (in the vehiclesettings gdt)." );
	return struct::get_script_bundle( "vehicleriders", self.vehicleridersbundle );
}

function get_robot_bundle()
{
	Assert( isdefined( self.vehicleridersrobotbundle ), "No vehicleriders robot bundle specified for this vehicle (in the vehiclesettings gdt)." );
	return struct::get_script_bundle( "vehicleriders", self.vehicleridersrobotbundle );
}

/@
"Summary: Get a specific rider from a vehicle.  Look at vehiclerider GDT for possible positions."
"Name: get_rider( str_pos )"
"CallOn: Vehicle"
"MandatoryArg: <str_group> The rider position to unload."
"Example: ai_rider = vh_truck vehicle::get_rider( "passenger1" );"
@/
function get_rider( str_pos )  // self = vehicle
{
	if ( isdefined( self.riders ) )
	{
		foreach ( ai in self.riders )
		{
			if ( IsDefined( ai ) && ( ai.rider_info.position == str_pos ) )
			{
				return ai;
			}
		}
	}
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Private
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function private _init_rider( vh, str_pos )
{
	Assert( isdefined( self.vehicle ) || isdefined( vh ), "No vehicle specified for rider." );
	Assert( isdefined( self.rider_info ) || isdefined( str_pos ), "No position specified for rider." );
	
	if ( isdefined( vh ) )
	{
		self.vehicle = vh;
	}
	
	if(!isdefined(str_pos))str_pos=self.rider_info.position;

	self.rider_info = self get_rider_info( self.vehicle, str_pos );
}
