abstract class VehicleTransition extends DefaultTransition
{
	const var stateMachineInitData : weak< VehicleTransitionInitData >;
	protected var m_exitSlot : CName;
	default m_exitSlot = 'default';

	public static function CanEnterDriverCombat() : Bool
	{
		return TDB.GetBool( T"player.vehicle.canEnterDriverCombat", false );
	}

	protected const function IsVehicleExitBlocked1Frame( stateContext : StateContext, scriptInterface : StateGameScriptInterface ) : Bool
	{
		return stateContext.GetBoolParameter( 'delayVehicleExit1Frame', false );
	}

	public static function DoesVehicleSupportCombat( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return VehicleComponent.GetVehicleAllowsCombat( scriptInterface.owner.GetGame(), ( ( VehicleObject )( scriptInterface.owner ) ) );
	}

	protected const function DeactivateTimeDilationCW( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( scriptInterface.GetTimeSystem().IsTimeDilationActive( TimeDilationHelper.GetSandevistanKey() ) )
		{
			stateContext.SetTemporaryBoolParameter( 'requestSandevistanDeactivation', true, true );
			stateContext.SetTemporaryBoolParameter( 'delayVehicleExit1Frame', true, true );
		}
		if( scriptInterface.GetTimeSystem().IsTimeDilationActive( TimeDilationHelper.GetKerenzikovKey() ) )
		{
			stateContext.SetTemporaryBoolParameter( 'requestKerenzikovDeactivation', true, true );
			stateContext.SetTemporaryBoolParameter( 'delayVehicleExit1Frame', true, true );
		}
	}

	protected const function IsPlayerAllowedToEnterDriverCombat( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var tier : Int32;
		var driverCombatForbiddenZone : StateResultBool;
		if( ( ( !( IsPlayerAllowedToEnterCombat( scriptInterface ) ) || IsNoCombatActionsForced( scriptInterface ) ) || !( CanEnterDriverCombat() ) ) || !( DoesVehicleSupportCombat( scriptInterface ) ) )
		{
			return false;
		}
		tier = scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.HighLevel );
		if( tier > ( ( Int32 )( gamePSMHighLevel.SceneTier1 ) ) )
		{
			return false;
		}
		driverCombatForbiddenZone = stateContext.GetPermanentBoolParameter( 'driverCombatForbiddenZone' );
		if( driverCombatForbiddenZone.value )
		{
			return false;
		}
		return true;
	}

	protected const function IsPlayerAllowedToEnterCombat( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsNoCombatActionsForced( scriptInterface ) )
		{
			return false;
		}
		return true;
	}

	protected const function IsPlayerAllowedToExitCombat( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'VehicleCombatBlockExit' ) || StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'FirearmsNoUnequip' ) )
		{
			return false;
		}
		return true;
	}

	protected function SetVehicleStatusEffects( stateContext : StateContext, scriptInterface : StateGameScriptInterface, shouleAdd : Bool )
	{
		var statusEffectsApplied : StateResultBool;
		statusEffectsApplied = stateContext.GetPermanentBoolParameter( 'vehicleStatusEffectsApplied' );
		if( statusEffectsApplied.value && shouleAdd )
		{
			return;
		}
		stateContext.SetPermanentBoolParameter( 'vehicleStatusEffectsApplied', shouleAdd, true );
		if( shouleAdd == true )
		{
			if( DoesVehicleSupportCombat( scriptInterface ) && DoesVehicleSupportFireArms( ( ( VehicleObject )( scriptInterface.owner ) ) ) )
			{
				if( ( ( BikeObject )( scriptInterface.owner ) ) )
				{
					StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.DriverCombatBikeWeapons" );
				}
				else
				{
					StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.DriverCombatFirearms" );
				}
			}
			else
			{
				StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoWeapons" );
			}
		}
		else
		{
			if( DoesVehicleSupportCombat( scriptInterface ) && DoesVehicleSupportFireArms( ( ( VehicleObject )( scriptInterface.owner ) ) ) )
			{
				if( ( ( BikeObject )( scriptInterface.owner ) ) )
				{
					StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.DriverCombatBikeWeapons" );
				}
				else
				{
					StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.DriverCombatFirearms" );
				}
			}
			else
			{
				StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoWeapons", ( ( Uint32 )( 1 ) ) );
			}
		}
	}

	protected function SetFirearmsGameplayRestriction( scriptInterface : StateGameScriptInterface, shouleAdd : Bool )
	{
		if( shouleAdd == true )
		{
			StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Firearms" );
		}
		else
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Firearms" );
		}
	}

	protected const function IsDriverInVehicle( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.IsDriverInVehicle();
	}

	protected const function IsPassengerInVehicle( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.IsPassengerInVehicle();
	}

	protected const function IsVehicleRemoteControlled( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return ( ( VehicleObject )( scriptInterface.owner ) ).IsVehicleRemoteControlled();
	}

	protected function SendAnimFeature( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var animFeature : AnimFeature_VehicleData;
		var vehicleDataPackage : VehicleDataPackage_Record;
		animFeature = new AnimFeature_VehicleData;
		vehicleDataPackage = GetVehicleDataPackage( stateContext );
		animFeature.isInVehicle = stateContext.GetBoolParameter( 'isInVehicle', true );
		animFeature.isDriver = stateContext.GetBoolParameter( 'isDriver', true );
		animFeature.vehType = stateContext.GetIntParameter( 'vehType', true );
		animFeature.vehSlot = stateContext.GetIntParameter( 'vehSlot', true );
		animFeature.isInCombat = stateContext.GetBoolParameter( 'isInVehCombat', true );
		animFeature.isInWindowCombat = stateContext.GetBoolParameter( 'isInVehWindowCombat', true );
		animFeature.isInDriverCombat = stateContext.GetBoolParameter( 'isInDriverCombat', true );
		animFeature.vehClass = stateContext.GetIntParameter( 'vehClass', true );
		animFeature.isEnteringCombat = stateContext.GetBoolParameter( 'isEnteringCombat', true );
		animFeature.enteringCombatDuration = vehicleDataPackage.ToCombat();
		animFeature.isExitingCombat = stateContext.GetBoolParameter( 'isExitingCombat', true );
		animFeature.exitingCombatDuration = vehicleDataPackage.FromCombat();
		animFeature.isEnteringVehicle = stateContext.GetBoolParameter( 'isEnteringVehicle', true );
		animFeature.isExitingVehicle = stateContext.GetBoolParameter( 'isExitingVehicle', true );
		animFeature.isWorldRenderPlane = stateContext.GetBoolParameter( 'isWorldRenderPlane', true );
		scriptInterface.SetAnimationParameterFeature( 'VehicleData', animFeature, scriptInterface.executionOwner );
		scriptInterface.SetAnimationParameterFeature( 'VehicleData', animFeature );
	}

	protected function ResetAnimFeature( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var animFeature : AnimFeature_VehicleData;
		animFeature = new AnimFeature_VehicleData;
		scriptInterface.SetAnimationParameterFeature( 'VehicleData', animFeature, scriptInterface.executionOwner );
		scriptInterface.SetAnimationParameterFeature( 'VehicleData', animFeature );
	}

	protected function ResetVehParams( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetIsInVehicle( stateContext, false );
		SetIsVehicleDriver( stateContext, false );
		SetVehicleType( stateContext, 0 );
		SetIsInVehicleCombat( stateContext, false );
		SetIsInVehicleWindowCombat( stateContext, false );
		SetIsInVehicleDriverCombat( stateContext, false );
		SetVehicleClass( stateContext, 0 );
		SetIsEnteringCombat( stateContext, false );
		SetIsExitingCombat( stateContext, false );
		SetIsWorldRenderPlane( stateContext, false );
		SetIsCar( stateContext, false );
		SetWasStolen( stateContext, false );
		stateContext.SetPermanentIntParameter( 'vehSlot', 0, true );
		stateContext.SetPermanentIntParameter( 'vehUnmountDir', 0, true );
	}

	protected function SendIsCar( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var animFeature : AnimFeature_VehiclePassenger;
		animFeature = new AnimFeature_VehiclePassenger;
		animFeature.isCar = stateContext.GetBoolParameter( 'isCar', true );
		scriptInterface.SetAnimationParameterFeature( 'VehiclePassenger', animFeature, scriptInterface.executionOwner );
	}

	protected function ResetIsCar( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var animFeature : AnimFeature_VehiclePassenger;
		animFeature = new AnimFeature_VehiclePassenger;
		animFeature.isCar = false;
		scriptInterface.SetAnimationParameterFeature( 'VehiclePassenger', animFeature, scriptInterface.executionOwner );
	}

	protected function SetIsInVehicle( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'isInVehicle', value, true );
	}

	protected function SetIsVehicleDriver( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'isDriver', value, true );
	}

	protected function SetVehicleType( stateContext : StateContext, value : Int32 )
	{
		stateContext.SetPermanentIntParameter( 'vehType', value, true );
	}

	protected function SetIsInVehicleCombat( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'isInVehCombat', value, true );
	}

	protected function SetIsInVehicleWindowCombat( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'isInVehWindowCombat', value, true );
	}

	protected function SetIsInVehicleDriverCombat( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'isInDriverCombat', value, true );
	}

	protected function SetVehicleClass( stateContext : StateContext, value : Int32 )
	{
		stateContext.SetPermanentIntParameter( 'vehClass', value, true );
	}

	protected function SetIsEnteringCombat( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'isEnteringCombat', value, true );
	}

	protected function SetIsExitingCombat( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'isExitingCombat', value, true );
	}

	protected function SetIsExitingVehicle( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'isExitingVehicle', value, true );
	}

	protected function SetIsWorldRenderPlane( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'isWorldRenderPlane', value, true );
	}

	protected function SetIsCar( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'isCar', value, true );
	}

	protected function SetWasStolen( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'wasStolen', value, true );
	}

	protected const function SetWasCombatForced( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'wasCombatForced', value, true );
	}

	protected const function SetRequestedTPPCamera( stateContext : StateContext, value : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'requestedTPPCamera', value, true );
	}

	protected function SetSide( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var value : Int32;
		var slotName : CName;
		var mountingInfo : MountingInfo;
		mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
		slotName = mountingInfo.slotId.id;
		if( slotName == 'seat_front_left' )
		{
			value = 1;
		}
		else if( slotName == 'seat_back_left' )
		{
			value = 1;
		}
		else if( slotName == 'seat_front_right' )
		{
			value = 2;
		}
		else if( slotName == 'seat_back_right' )
		{
			value = 2;
		}
		else
		{
			value = 0;
		}
		stateContext.SetPermanentIntParameter( 'vehSlot', value, true );
	}

	protected function IsUnmountDirectionClosest( stateContext : StateContext, unmountDirection : vehicleExitDirection ) : Bool
	{
		var side : Int32;
		side = stateContext.GetIntParameter( 'vehSlot', true );
		if( ( side == 1 ) && unmountDirection == vehicleExitDirection.Left )
		{
			return true;
		}
		if( ( side == 2 ) && unmountDirection == vehicleExitDirection.Right )
		{
			return true;
		}
		return false;
	}

	protected function IsUnmountDirectionOpposite( stateContext : StateContext, unmountDirection : vehicleExitDirection ) : Bool
	{
		var side : Int32;
		side = stateContext.GetIntParameter( 'vehSlot', true );
		if( ( side == 1 ) && unmountDirection == vehicleExitDirection.Right )
		{
			return true;
		}
		if( ( side == 2 ) && unmountDirection == vehicleExitDirection.Left )
		{
			return true;
		}
		return false;
	}

	public static function CheckVehicleDesiredTag( const scriptInterface : StateGameScriptInterface, desiredTag : CName ) : Bool
	{
		var recordID : TweakDBID;
		var vehicleRecord : Vehicle_Record;
		var tags : array< CName >;
		recordID = ( ( VehicleObject )( scriptInterface.owner ) ).GetRecordID();
		vehicleRecord = TweakDBInterface.GetVehicleRecord( recordID );
		if( !( vehicleRecord ) )
		{
			return false;
		}
		tags = vehicleRecord.Tags();
		if( tags.Contains( desiredTag ) )
		{
			return true;
		}
		return false;
	}

	protected function SetVehFppCameraParams( stateContext : StateContext, scriptInterface : StateGameScriptInterface, isPassenger : Bool, optional side : Bool, optional combat : Bool )
	{
		var recordID : TweakDBID;
		var vehicleRecord : Vehicle_Record;
		var camBodyOffset : AnimFeature_CameraBodyOffset;
		var camGameplay : AnimFeature_CameraGameplay;
		var vehCamParamsRecord : VehicleFPPCameraParams_Record;
		recordID = ( ( VehicleObject )( scriptInterface.owner ) ).GetRecordID();
		vehicleRecord = TweakDBInterface.GetVehicleRecord( recordID );
		camBodyOffset = new AnimFeature_CameraBodyOffset;
		camGameplay = new AnimFeature_CameraGameplay;
		if( combat )
		{
			if( !( isPassenger ) )
			{
				vehCamParamsRecord = vehicleRecord.VehDriverCombat_FPPCameraParams();
			}
			if( isPassenger )
			{
				if( side == true )
				{
					vehCamParamsRecord = vehicleRecord.VehPassCombatL_FPPCameraParams();
				}
				else
				{
					vehCamParamsRecord = vehicleRecord.VehPassCombatR_FPPCameraParams();
				}
			}
		}
		else
		{
			if( !( isPassenger ) )
			{
				vehCamParamsRecord = vehicleRecord.VehDriver_FPPCameraParams();
			}
			if( isPassenger )
			{
				if( side == true )
				{
					vehCamParamsRecord = vehicleRecord.VehPassL_FPPCameraParams();
				}
				else
				{
					vehCamParamsRecord = vehicleRecord.VehPassR_FPPCameraParams();
				}
			}
		}
		camBodyOffset.lookat_pitch_forward_offset = vehCamParamsRecord.Lookat_pitch_forward_offset();
		camBodyOffset.lookat_pitch_forward_down_ratio = vehCamParamsRecord.Lookat_pitch_forward_down_ratio();
		camBodyOffset.lookat_yaw_left_offset = vehCamParamsRecord.Lookat_yaw_left_offset();
		camBodyOffset.lookat_yaw_left_up_offset = vehCamParamsRecord.Lookat_yaw_left_up_offset();
		camBodyOffset.lookat_yaw_right_offset = vehCamParamsRecord.Lookat_yaw_right_offset();
		camBodyOffset.lookat_yaw_right_up_offset = vehCamParamsRecord.Lookat_yaw_right_up_offset();
		camBodyOffset.lookat_yaw_offset_active_angle = vehCamParamsRecord.Lookat_yaw_offset_active_angle();
		camBodyOffset.is_paralax = vehCamParamsRecord.Is_paralax();
		camBodyOffset.paralax_radius = vehCamParamsRecord.Paralax_radius();
		camBodyOffset.paralax_forward_offset = vehCamParamsRecord.Paralax_forward_offset();
		camBodyOffset.lookat_offset_vertical = vehCamParamsRecord.Lookat_offset_vertical();
		camGameplay.is_forward_offset = vehCamParamsRecord.Is_forward_offset();
		camGameplay.forward_offset_value = vehCamParamsRecord.Forward_offset_value();
		camGameplay.upperbody_pitch_weight = vehCamParamsRecord.Upperbody_pitch_weight();
		camGameplay.upperbody_yaw_weight = vehCamParamsRecord.Upperbody_yaw_weight();
		camGameplay.is_pitch_off = vehCamParamsRecord.Is_pitch_off();
		camGameplay.is_yaw_off = vehCamParamsRecord.Is_yaw_off();
		scriptInterface.SetAnimationParameterFeature( 'CameraBodyOffset', camBodyOffset, scriptInterface.executionOwner );
		scriptInterface.SetAnimationParameterFeature( 'CameraGameplay', camGameplay, scriptInterface.executionOwner );
	}

	protected function ResetVehFppCameraParams( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		scriptInterface.SetAnimationParameterFeature( 'CameraBodyOffset', new AnimFeature_CameraBodyOffset, scriptInterface.executionOwner );
		scriptInterface.SetAnimationParameterFeature( 'CameraGameplay', new AnimFeature_CameraGameplay, scriptInterface.executionOwner );
	}

	protected function GetVehType( stateContext : StateContext, scriptInterface : StateGameScriptInterface ) : Int32
	{
		var recordID : TweakDBID;
		var vehicleRecord : Vehicle_Record;
		var vehicleDataPackage : weak< VehicleDataPackage_Record >;
		var templateName : CName;
		recordID = ( ( VehicleObject )( scriptInterface.owner ) ).GetRecordID();
		vehicleRecord = TweakDBInterface.GetVehicleRecord( recordID );
		vehicleDataPackage = vehicleRecord.VehDataPackage();
		templateName = vehicleDataPackage.SeatingTemplateOverride();
		if( templateName == 'standard_vehicle' )
		{
			return 0;
		}
		else if( templateName == 'sport_vehicle' || templateName == 'sport1_vehicle' )
		{
			return 1;
		}
		return 0;
	}

	protected const function GetVehClass( stateContext : StateContext, scriptInterface : StateGameScriptInterface ) : Int32
	{
		var recordID : TweakDBID;
		var vehicleRecord : Vehicle_Record;
		var vehTypeRecord : VehicleType_Record;
		var vehClassName : String;
		var vehClassInt : Int32;
		recordID = ( ( VehicleObject )( scriptInterface.owner ) ).GetRecordID();
		vehicleRecord = TweakDBInterface.GetVehicleRecord( recordID );
		vehTypeRecord = vehicleRecord.Type();
		vehClassName = vehTypeRecord.EnumName();
		switch( vehClassName )
		{
			case "Car":
				vehClassInt = 0;
			break;
			case "Bike":
				vehClassInt = 1;
			break;
			case "Panzer":
				vehClassInt = 2;
			break;
			default:
				vehClassInt = 0;
			break;
		}
		return vehClassInt;
	}

	protected function GetAdjacentSeat( slotName : CName, out nextSlotName : CName ) : Bool
	{
		if( !( IsNameValid( slotName ) ) )
		{
			return false;
		}
		switch( slotName )
		{
			case 'seat_front_left':
				nextSlotName = 'seat_front_right';
			break;
			case 'seat_front_right':
				nextSlotName = 'seat_front_left';
			break;
			case 'seat_back_left':
				nextSlotName = 'seat_back_right';
			break;
			case 'seat_back_right':
				nextSlotName = 'seat_back_left';
			break;
		}
		return true;
	}

	protected function IsAdjacentSeatAvailable( stateContext : StateContext, scriptInterface : StateGameScriptInterface, slotName : CName ) : Bool
	{
		var vehicle : weak< VehicleObject >;
		var seatInteractionAvailable : Bool;
		var adjacentSeat : CName;
		var doorName : EVehicleDoor;
		if( !( IsNameValid( slotName ) ) )
		{
			return false;
		}
		vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
		GetAdjacentSeat( slotName, adjacentSeat );
		vehicle.GetVehiclePS().GetVehicleDoorEnum( doorName, adjacentSeat );
		seatInteractionAvailable = vehicle.GetVehiclePS().GetDoorInteractionState( doorName ) != VehicleDoorInteractionState.Disabled;
		if( !( seatInteractionAvailable ) )
		{
			return false;
		}
		if( !( VehicleComponent.IsSlotAvailable( scriptInterface.GetGame(), vehicle, 'seat_front_left' ) ) )
		{
			return false;
		}
		return true;
	}

	protected function SendEquipToHandsRequest( scriptInterface : StateGameScriptInterface, itemID : ItemID )
	{
		var equipmentSystem : EquipmentSystem;
		var equipRequest : EquipRequest;
		var drawItemRequest : DrawItemRequest;
		equipmentSystem = ( ( EquipmentSystem )( scriptInterface.GetScriptableSystem( 'EquipmentSystem' ) ) );
		equipRequest = new EquipRequest;
		equipRequest.itemID = itemID;
		equipRequest.addToInventory = true;
		equipRequest.owner = scriptInterface.executionOwner;
		equipmentSystem.QueueRequest( equipRequest );
		drawItemRequest = new DrawItemRequest;
		drawItemRequest.owner = scriptInterface.executionOwner;
		drawItemRequest.itemID = itemID;
		equipmentSystem.QueueRequest( drawItemRequest );
	}

	protected function RequestVehicleCinematicCamera( scriptInterface : StateGameScriptInterface )
	{
		scriptInterface.executionOwner.QueueEvent( new vehicleCinematicCameraToggleEvent );
	}

	protected function RequestToggleVehicleCamera( scriptInterface : StateGameScriptInterface )
	{
		var camEvent : vehicleRequestCameraPerspectiveEvent;
		if( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Vision ) == ( ( Int32 )( gamePSMVision.Focus ) ) )
		{
			return;
		}
		camEvent = new vehicleRequestCameraPerspectiveEvent;
		switch( ( ( VehicleObject )( scriptInterface.owner ) ).GetCameraManager().GetActivePerspective() )
		{
			case vehicleCameraPerspective.FPP:
				camEvent.cameraPerspective = vehicleCameraPerspective.TPPClose;
			break;
			case vehicleCameraPerspective.TPPClose:
				camEvent.cameraPerspective = vehicleCameraPerspective.TPPMedium;
			break;
			case vehicleCameraPerspective.TPPMedium:
				camEvent.cameraPerspective = vehicleCameraPerspective.TPPFar;
			break;
			case vehicleCameraPerspective.TPPFar:
				if( !( scriptInterface.localBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsDriverCombatInTPP ) ) )
				{
					camEvent.cameraPerspective = vehicleCameraPerspective.TPPClose;
				}
				else
				{
					camEvent.cameraPerspective = vehicleCameraPerspective.FPP;
				}
			break;
			case vehicleCameraPerspective.DriverCombatClose:
				camEvent.cameraPerspective = vehicleCameraPerspective.TPPClose;
			break;
			case vehicleCameraPerspective.DriverCombatMedium:
				camEvent.cameraPerspective = vehicleCameraPerspective.TPPMedium;
			break;
			case vehicleCameraPerspective.DriverCombatFar:
				camEvent.cameraPerspective = vehicleCameraPerspective.TPPFar;
			break;
		}
		scriptInterface.executionOwner.QueueEvent( camEvent );
	}

	protected function ResetVehicleCamera( scriptInterface : StateGameScriptInterface )
	{
		var camEvent : vehicleCameraResetEvent;
		camEvent = new vehicleCameraResetEvent;
		scriptInterface.executionOwner.QueueEvent( camEvent );
	}

	protected function ToggleWindowForOccupiedSeat( scriptInterface : StateGameScriptInterface, slotName : CName, shouldopen : Bool )
	{
		var VehWindowRequestEvent : VehicleExternalWindowRequestEvent;
		VehWindowRequestEvent = new VehicleExternalWindowRequestEvent;
		VehWindowRequestEvent.slotName = slotName;
		VehWindowRequestEvent.shouldOpen = shouldopen;
		scriptInterface.owner.QueueEvent( VehWindowRequestEvent );
	}

	protected const function GetUnmountingEvent( const stateContext : StateContext ) : MountEventData
	{
		var unmountEvent : MountEventData;
		unmountEvent = ( ( MountEventData )( stateContext.GetPermanentScriptableParameter( 'Unmount' ) ) );
		return unmountEvent;
	}

	protected const function IsExitForced( const stateContext : StateContext ) : Bool
	{
		return GetUnmountingEvent( stateContext );
	}

	protected function RemoveUnmountingRequest( stateContext : StateContext )
	{
		stateContext.RemovePermanentScriptableParameter( 'Unmount' );
	}

	protected function RemoveMountingRequest( stateContext : StateContext )
	{
		stateContext.RemovePermanentScriptableParameter( 'Mount' );
	}

	protected function StartLeavingVehicle( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var unmountEvent : MountEventData;
		var isInstant : Bool;
		var evt : VehicleStartedMountingEvent;
		var vehicle : VehicleObject;
		var vehicleUpsideDown : Bool;
		evt = new VehicleStartedMountingEvent;
		vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
		unmountEvent = GetUnmountingEvent( stateContext );
		if( unmountEvent )
		{
			isInstant = unmountEvent.isInstant;
		}
		else
		{
			isInstant = false;
		}
		vehicleUpsideDown = vehicle.IsVehicleUpsideDown();
		if( !( isInstant ) && vehicleUpsideDown )
		{
			ExitWorkspot( stateContext, scriptInterface, isInstant, true );
		}
		else
		{
			ExitWorkspot( stateContext, scriptInterface, isInstant );
		}
		SetIsInVehicle( stateContext, false );
		SendAnimFeature( stateContext, scriptInterface );
		evt.slotID = vehicle.GetSlotIdForMountedObject( scriptInterface.executionOwner );
		evt.isMounting = false;
		evt.character = scriptInterface.executionOwner;
		evt.animationSlotName = m_exitSlot;
		vehicle.QueueEvent( evt );
	}

	protected function PlayVehicleExitDoorAnimation( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var mountInfo : MountingInfo;
		var VehDoorRequestEvent : VehicleExternalDoorRequestEvent;
		var vehicle : VehicleObject;
		var tempDisableAutoCloseDoor : SetIgnoreAutoDoorCloseEvent;
		var doorOpensForDriverCombat : Bool;
		var vehiceCustomizationSwitchState : SwitchVehicleVisualCustomizationStateEvent;
		vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
		mountInfo = scriptInterface.GetMountingFacility().GetMountingInfoSingleWithObjects( scriptInterface.executionOwner );
		doorOpensForDriverCombat = GetVehicleDataPackage( stateContext ).DriverCombat().Type() == gamedataDriverCombatType.Doors;
		VehDoorRequestEvent = new VehicleExternalDoorRequestEvent;
		VehDoorRequestEvent.slotName = mountInfo.slotId.id;
		VehDoorRequestEvent.autoCloseTime = GetVehicleDataPackage( stateContext ).Normal_open();
		VehDoorRequestEvent.autoClose = !( VehicleComponent.IsDestroyed( scriptInterface.GetGame(), mountInfo.parentId ) ) && !( doorOpensForDriverCombat );
		tempDisableAutoCloseDoor = new SetIgnoreAutoDoorCloseEvent;
		tempDisableAutoCloseDoor.set = true;
		vehiceCustomizationSwitchState = new SwitchVehicleVisualCustomizationStateEvent;
		vehiceCustomizationSwitchState.on = false;
		vehicle.QueueEvent( tempDisableAutoCloseDoor );
		vehicle.QueueEvent( VehDoorRequestEvent );
	}

	protected virtual function ExitWorkspot( stateContext : StateContext, scriptInterface : StateGameScriptInterface, isInstant : Bool, optional upsideDown : Bool )
	{
		var workspotSystem : WorkspotGameSystem;
		var exitSlotName : CName;
		var unmountDirResult : StateResultInt;
		exitSlotName = m_exitSlot;
		SetSide( stateContext, scriptInterface );
		unmountDirResult = stateContext.GetPermanentIntParameter( 'vehUnmountDir' );
		if( upsideDown )
		{
			exitSlotName = 'exit_upside_down';
		}
		else if( unmountDirResult.valid && IsUnmountDirectionOpposite( stateContext, ( ( vehicleExitDirection )( unmountDirResult.value ) ) ) )
		{
			exitSlotName = 'exit_opposite';
		}
		workspotSystem = scriptInterface.GetWorkspotSystem();
		workspotSystem.UnmountFromVehicle( scriptInterface.owner, scriptInterface.executionOwner, isInstant, , , exitSlotName );
	}

	protected function PlayerStateChange( scriptInterface : StateGameScriptInterface, newstate : Int32 )
	{
		var activeVehicleBlackboard : IBlackboard;
		var data : VehEntityPlayerStateData;
		data.entID = scriptInterface.ownerEntityID;
		data.state = newstate;
		activeVehicleBlackboard = GetVehicleBlackboard( scriptInterface );
		activeVehicleBlackboard.SetVariant( GetAllBlackboardDefs().UI_ActiveVehicleData.VehPlayerStateData, data );
	}

	private function GetVehicleBlackboard( scriptInterface : StateGameScriptInterface ) : IBlackboard
	{
		var owner : GameObject;
		owner = scriptInterface.executionOwner;
		return GameInstance.GetBlackboardSystem( owner.GetGame() ).Get( GetAllBlackboardDefs().UI_ActiveVehicleData );
	}

	protected function SetupVehicleDataPackage( stateContext : StateContext, scriptInterface : StateGameScriptInterface ) : weak< VehicleDataPackage_Record >
	{
		var recordID : TweakDBID;
		var vehicleRecord : Vehicle_Record;
		var vehicleDataPackage : weak< VehicleDataPackage_Record >;
		recordID = ( ( VehicleObject )( scriptInterface.owner ) ).GetRecordID();
		vehicleRecord = TweakDBInterface.GetVehicleRecord( recordID );
		vehicleDataPackage = vehicleRecord.VehDataPackage();
		stateContext.SetConditionWeakScriptableParameter( 'VehicleDataPackage', vehicleDataPackage, true );
		return vehicleDataPackage;
	}

	protected const function GetVehicleDataPackage( const stateContext : StateContext ) : weak< VehicleDataPackage_Record >
	{
		return ( ( VehicleDataPackage_Record )( stateContext.GetConditionWeakScriptableParameter( 'VehicleDataPackage' ) ) );
	}

	protected function GetVehicleInventory( scriptInterface : StateGameScriptInterface ) {}

	protected final function SetVehicleCameraParameters( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var param : StateResultCName;
		var paramSecondary : StateResultCName;
		var vehClass : Int32;
		var cameraParamName : CName;
		param = GetStaticCNameParameter( "onEnterCameraParamsName" );
		paramSecondary = GetStaticCNameParameter( "onEnterCameraParamsNameSecondary" );
		vehClass = GetVehClass( stateContext, scriptInterface );
		if( ( vehClass == 1 ) && paramSecondary.valid )
		{
			cameraParamName = paramSecondary.value;
		}
		if( ( ( ( vehClass == 2 ) || ( vehClass == 0 ) ) && param.valid ) || ( ( vehClass == 1 ) && !( paramSecondary.valid ) ) )
		{
			cameraParamName = param.value;
		}
		stateContext.SetPermanentCNameParameter( 'VehicleCameraParams', cameraParamName, true );
		UpdateCameraParams( stateContext, scriptInterface );
	}

	protected const final function GetPuppetVehicleSceneTransition( const stateContext : StateContext ) : PuppetVehicleState
	{
		var puppetVehicleState : StateResultInt;
		var puppetVehicleStateValue : PuppetVehicleState;
		puppetVehicleState = stateContext.GetTemporaryIntParameter( 'scenePuppetVehicleState' );
		if( puppetVehicleState.valid )
		{
			puppetVehicleStateValue = ( ( PuppetVehicleState )( puppetVehicleState.value ) );
			return puppetVehicleStateValue;
		}
		puppetVehicleState = stateContext.GetPermanentIntParameter( 'scenePuppetVehicleState' );
		if( puppetVehicleState.valid )
		{
			puppetVehicleStateValue = ( ( PuppetVehicleState )( puppetVehicleState.value ) );
			return puppetVehicleStateValue;
		}
		return PuppetVehicleState.IdleStand;
	}

	protected const function TryToStopVehicle( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface, optional force : Bool )
	{
		var vehicle : weak< VehicleObject >;
		var vehicleBlackboard : IBlackboard;
		var speed : Float;
		vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
		vehicleBlackboard = vehicle.GetBlackboard();
		speed = vehicleBlackboard.GetFloat( GetAllBlackboardDefs().Vehicle.SpeedValue );
		if( force )
		{
			vehicle.ForceBrakesUntilStoppedOrFor( 4.0 );
		}
		else if( ( speed <= GetStaticFloatParameterDefault( "highSpeedThreshold", 20.0 ) ) && m_exitSlot != 'cool' )
		{
			vehicle.ForceBrakesUntilStoppedOrFor( 2.0 );
		}
	}

	protected const function IsInScene( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var highLevel : Int32;
		highLevel = scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.HighLevel );
		return ( highLevel >= ( ( Int32 )( gamePSMHighLevel.SceneTier3 ) ) ) && ( highLevel <= ( ( Int32 )( gamePSMHighLevel.SceneTier5 ) ) );
	}

	public function GetVehicleObject( scriptInterface : StateGameScriptInterface ) : weak< VehicleObject >
	{
		return ( ( VehicleObject )( scriptInterface.owner ) );
	}

	public function GetVehiclePS( scriptInterface : StateGameScriptInterface ) : weak< VehicleComponentPS >
	{
		return ( ( VehicleObject )( scriptInterface.owner ) ).GetVehiclePS();
	}

	public const function IsInVehicleWorkspot( const scriptInterface : StateGameScriptInterface, slotName : CName ) : Bool
	{
		var workspotSystem : WorkspotGameSystem;
		var res : Bool;
		workspotSystem = scriptInterface.GetWorkspotSystem();
		res = workspotSystem.IsInVehicleWorkspot( scriptInterface.owner, scriptInterface.executionOwner, slotName );
		return res;
	}

	protected const function DriverSwitchSeatsCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var questForceSwitchSeats : StateResultBool;
		var seatInteractionAvailable : Bool;
		var vehicle : weak< VehicleObject >;
		var switchExitRequest : StateResultBool;
		var exitAfterRequest : StateResultBool;
		questForceSwitchSeats = stateContext.GetTemporaryBoolParameter( 'switchSeats' );
		switchExitRequest = stateContext.GetPermanentBoolParameter( 'validSwitchSeatExitRequest' );
		exitAfterRequest = stateContext.GetPermanentBoolParameter( 'validExitAfterSwitchRequest' );
		if( switchExitRequest.value && exitAfterRequest.value )
		{
			return true;
		}
		if( questForceSwitchSeats.value )
		{
			vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
			seatInteractionAvailable = vehicle.GetVehiclePS().GetDoorInteractionState( EVehicleDoor.seat_front_right ) != VehicleDoorInteractionState.Disabled;
			if( seatInteractionAvailable )
			{
				if( VehicleComponent.IsSlotAvailable( scriptInterface.GetGame(), ( ( VehicleObject )( scriptInterface.owner ) ), 'seat_front_right' ) && ( GetInStateTime() >= 0.2 ) )
				{
					return true;
				}
			}
		}
		return false;
	}

	protected const function PassangerSwitchSeatsCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var switchSeatsDisabled : Bool;
		var slotName : CName;
		var seatInteractionAvailable : Bool;
		var vehicle : weak< VehicleObject >;
		var questForceSwitchSeats : StateResultBool;
		var debugBB : IBlackboard;
		var switchExitRequest : StateResultBool;
		var exitAfterRequest : StateResultBool;
		questForceSwitchSeats = stateContext.GetTemporaryBoolParameter( 'switchSeats' );
		switchSeatsDisabled = GetVehicleDataPackage( stateContext ).DisableSwitchSeats();
		debugBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().DebugData );
		if( switchSeatsDisabled || debugBB.GetBool( GetAllBlackboardDefs().DebugData.Vehicle_BlockSwitchSeats ) )
		{
			return false;
		}
		VehicleComponent.GetMountedSlotName( scriptInterface.GetGame(), scriptInterface.executionOwner, slotName );
		switchExitRequest = stateContext.GetPermanentBoolParameter( 'validSwitchSeatExitRequest' );
		exitAfterRequest = stateContext.GetPermanentBoolParameter( 'validExitAfterSwitchRequest' );
		if( switchExitRequest.value && exitAfterRequest.value )
		{
			return true;
		}
		if( exitAfterRequest.value )
		{
			return false;
		}
		if( slotName == 'seat_front_right' )
		{
			vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
			seatInteractionAvailable = vehicle.GetVehiclePS().GetDoorInteractionState( EVehicleDoor.seat_front_left ) != VehicleDoorInteractionState.Disabled;
			if( seatInteractionAvailable )
			{
				if( VehicleComponent.IsSlotAvailable( scriptInterface.GetGame(), ( ( VehicleObject )( scriptInterface.owner ) ), 'seat_front_left' ) && ( GetInStateTime() >= 0.2 ) )
				{
					return true;
				}
			}
		}
		if( questForceSwitchSeats.value )
		{
			if( slotName == 'seat_back_left' )
			{
				vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
				seatInteractionAvailable = vehicle.GetVehiclePS().GetDoorInteractionState( EVehicleDoor.seat_back_right ) != VehicleDoorInteractionState.Disabled;
				if( seatInteractionAvailable )
				{
					if( VehicleComponent.IsSlotAvailable( scriptInterface.GetGame(), ( ( VehicleObject )( scriptInterface.owner ) ), 'seat_back_right' ) && ( GetInStateTime() >= 0.2 ) )
					{
						return true;
					}
				}
			}
			else if( slotName == 'seat_back_right' )
			{
				vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
				seatInteractionAvailable = vehicle.GetVehiclePS().GetDoorInteractionState( EVehicleDoor.seat_back_left ) != VehicleDoorInteractionState.Disabled;
				if( seatInteractionAvailable )
				{
					if( VehicleComponent.IsSlotAvailable( scriptInterface.GetGame(), ( ( VehicleObject )( scriptInterface.owner ) ), 'seat_back_left' ) && ( GetInStateTime() >= 0.2 ) )
					{
						return true;
					}
				}
			}
		}
		return false;
	}

	protected function PauseStateMachines( stateContext : StateContext, executionOwner : GameObject )
	{
		var coverAction : PSMStopStateMachine;
		var stamina : PSMStopStateMachine;
		var crosshair : PSMStopStateMachine;
		var cameraContext : PSMStopStateMachine;
		coverAction = new PSMStopStateMachine;
		stamina = new PSMStopStateMachine;
		crosshair = new PSMStopStateMachine;
		cameraContext = new PSMStopStateMachine;
		coverAction.stateMachineIdentifier.definitionName = 'CoverAction';
		executionOwner.QueueEvent( coverAction );
		if( GetBlackboardIntVariable( executionOwner, GetAllBlackboardDefs().PlayerStateMachine.Stamina ) == ( ( Int32 )( gamePSMStamina.Rested ) ) )
		{
			stamina.stateMachineIdentifier.definitionName = 'Stamina';
			executionOwner.QueueEvent( stamina );
		}
		crosshair.stateMachineIdentifier.definitionName = 'Crosshair';
		executionOwner.QueueEvent( crosshair );
		cameraContext.stateMachineIdentifier.definitionName = 'CameraContext';
		executionOwner.QueueEvent( cameraContext );
	}

	protected function ResumeStateMachines( executionOwner : GameObject )
	{
		var upperBody : PSMStartStateMachine;
		var equipmentRightHand : PSMStartStateMachine;
		var equipmentLeftHand : PSMStartStateMachine;
		var coverAction : PSMStartStateMachine;
		var stamina : PSMStartStateMachine;
		var locomotion : PSMStartStateMachine;
		var crosshair : PSMStartStateMachine;
		var cameraContext : PSMStartStateMachine;
		upperBody = new PSMStartStateMachine;
		equipmentRightHand = new PSMStartStateMachine;
		equipmentLeftHand = new PSMStartStateMachine;
		coverAction = new PSMStartStateMachine;
		stamina = new PSMStartStateMachine;
		locomotion = new PSMStartStateMachine;
		crosshair = new PSMStartStateMachine;
		cameraContext = new PSMStartStateMachine;
		upperBody.stateMachineIdentifier.definitionName = 'UpperBody';
		executionOwner.QueueEvent( upperBody );
		equipmentRightHand.stateMachineIdentifier.referenceName = 'RightHand';
		equipmentRightHand.stateMachineIdentifier.definitionName = 'Equipment';
		executionOwner.QueueEvent( equipmentRightHand );
		equipmentLeftHand.stateMachineIdentifier.referenceName = 'LeftHand';
		equipmentLeftHand.stateMachineIdentifier.definitionName = 'Equipment';
		executionOwner.QueueEvent( equipmentLeftHand );
		coverAction.stateMachineIdentifier.definitionName = 'CoverAction';
		executionOwner.QueueEvent( coverAction );
		stamina.stateMachineIdentifier.definitionName = 'Stamina';
		executionOwner.QueueEvent( stamina );
		locomotion.stateMachineIdentifier.definitionName = 'Locomotion';
		executionOwner.QueueEvent( locomotion );
		crosshair.stateMachineIdentifier.definitionName = 'Crosshair';
		executionOwner.QueueEvent( crosshair );
		cameraContext.stateMachineIdentifier.definitionName = 'CameraContext';
		executionOwner.QueueEvent( cameraContext );
	}

	protected const function GetVehicleDriverCombatType( vehicle : VehicleObject ) : gamedataDriverCombatType
	{
		var vehicleRecord : Vehicle_Record;
		vehicleRecord = TweakDBInterface.GetVehicleRecord( vehicle.GetRecordID() );
		if( !( vehicleRecord.VehDataPackage() ) )
		{
			return gamedataDriverCombatType.Invalid;
		}
		return vehicleRecord.VehDataPackage().DriverCombat().Type();
	}

	protected const function DoesVehicleSupportFireArms( vehicle : VehicleObject ) : Bool
	{
		var driverCombatType : gamedataDriverCombatType;
		driverCombatType = GetVehicleDriverCombatType( vehicle );
		return driverCombatType == gamedataDriverCombatType.Doors || driverCombatType == gamedataDriverCombatType.Standard;
	}

	protected const function GetDriverCombatWeaponManipulationRequest( vehicle : VehicleObject ) : EquipmentManipulationAction
	{
		if( !( vehicle ) )
		{
			return EquipmentManipulationAction.Undefined;
		}
		if( ( ( BikeObject )( vehicle ) ) )
		{
			return EquipmentManipulationAction.RequestLastUsedOrFirstAvailableDriverCombatBikeWeapon;
		}
		else
		{
			return EquipmentManipulationAction.RequestLastUsedOrFirstAvailableDriverCombatRangedWeapon;
		}
	}

	protected const function GetDriverCombatWeaponTag( vehicle : VehicleObject ) : CName
	{
		if( !( vehicle ) )
		{
			return '';
		}
		if( ( ( BikeObject )( vehicle ) ) )
		{
			return WeaponObject.GetDriverCombatBikeWeaponTag();
		}
		else
		{
			return WeaponObject.GetDriverCombatRangedWeaponTag();
		}
	}

}

abstract class VehicleEventsTransition extends VehicleTransition
{
	protected var isCameraTogglePressed : Bool;
	private var cameraToggleHoldToResetTimeSeconds : Float;
	default cameraToggleHoldToResetTimeSeconds = 0.35f;

	protected virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var animFeature : AnimFeature_Mounting;
		var exitActionPressCount : Uint32;
		animFeature = new AnimFeature_Mounting;
		animFeature.mountingState = 1;
		scriptInterface.SetAnimationParameterFeature( 'Mounting', animFeature );
		exitActionPressCount = scriptInterface.GetActionPressCount( 'Exit' );
		stateContext.SetPermanentIntParameter( 'exitPressCountOnEnter', ( ( Int32 )( exitActionPressCount ) ), true );
		SetupVehicleDataPackage( stateContext, scriptInterface );
		SetVehicleCameraParameters( stateContext, scriptInterface );
	}

	public export virtual function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var workspotSystem : WorkspotGameSystem;
		var animFeatureMounting : AnimFeature_Mounting;
		var wasSwitchingSeat : StateResultBool;
		isCameraTogglePressed = false;
		wasSwitchingSeat = stateContext.GetPermanentBoolParameter( 'wasSwitching' );
		if( wasSwitchingSeat.value )
		{
			return;
		}
		animFeatureMounting = new AnimFeature_Mounting;
		animFeatureMounting.mountingState = 0;
		scriptInterface.SetAnimationParameterFeature( 'Mounting', animFeatureMounting );
		ResetVehParams( stateContext, scriptInterface );
		ResetAnimFeature( stateContext, scriptInterface );
		ResetForceFlags( stateContext );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Default ) ) );
		workspotSystem = scriptInterface.GetWorkspotSystem();
		workspotSystem.UnmountFromVehicle( scriptInterface.owner, scriptInterface.executionOwner, true );
		SetVehicleStatusEffects( stateContext, scriptInterface, false );
		DisableCameraBobbing( stateContext, scriptInterface, false );
		SetWasStolen( stateContext, false );
		SetWasCombatForced( stateContext, false );
		SetRequestedTPPCamera( stateContext, false );
		stateContext.SetPermanentBoolParameter( 'teleportExitActive', false, true );
		ResetVehFppCameraParams( stateContext, scriptInterface );
		SetVehicleCameraParameters( stateContext, scriptInterface );
		stateContext.SetPermanentIntParameter( 'driverCombatType', ( ( Int32 )( gamedataDriverCombatType.Invalid ) ), true );
		GameInstance.GetTelemetrySystem( scriptInterface.GetGame() ).LogEnteringOrExitingVehicle( true );
	}

	protected function HandleCameraInput( scriptInterface : StateGameScriptInterface )
	{
		if( scriptInterface.IsActionJustReleased( 'ToggleVehCamera' ) && !( IsVehicleCameraChangeBlocked( scriptInterface ) ) )
		{
			RequestToggleVehicleCamera( scriptInterface );
		}
		if( scriptInterface.IsActionJustHeld( 'HoldCinematicCamera' ) && !( IsVehicleCameraChangeBlocked( scriptInterface ) ) )
		{
			RequestVehicleCinematicCamera( scriptInterface );
		}
	}

	protected function HandleExitRequest( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface ) : Bool
	{
		var stateTime : Float;
		var inputStateTime : Float;
		var currentTime : Float;
		var vehicleSubmergedTime : Float;
		var exitActionPressCount : Uint32;
		var exitPressCountResult : StateResultInt;
		var vehicle : weak< VehicleObject >;
		var validUnmount : vehicleUnmountPosition;
		var isTeleportExiting : StateResultBool;
		var isScheduledExit : StateResultBool;
		var isSwitchingSeats : StateResultBool;
		var mountingInfo : MountingInfo;
		var isSlotOccupied : Bool;
		var adjacentSeat : CName;
		var onDifferentExitPress : Bool;
		var shouldExitOnSubmerged : Bool;
		var shouldForceExitDelamain : Bool;
		var vehiclePS : VehicleComponentPS;
		var coolExit : Bool;
		var coolExitImpulseLevel : vehicleCoolExitImpulseLevel;
		var isValidExitAlreadyRequested : StateResultBool;
		shouldExitOnSubmerged = false;
		shouldForceExitDelamain = false;
		coolExit = false;
		isTeleportExiting = stateContext.GetPermanentBoolParameter( 'teleportExitActive' );
		isScheduledExit = stateContext.GetPermanentBoolParameter( 'validExitAfterSwitchRequest' );
		isSwitchingSeats = stateContext.GetPermanentBoolParameter( 'validSwitchSeatExitRequest' );
		if( ( isTeleportExiting.value || isScheduledExit.value ) || isSwitchingSeats.value )
		{
			return false;
		}
		vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
		vehiclePS = vehicle.GetVehiclePS();
		if( vehiclePS.GetIsSubmerged() && !( GameInstance.GetRacingSystem( scriptInterface.GetGame() ).IsRaceInProgress() ) )
		{
			vehicleSubmergedTime = vehiclePS.GetSubmergedTimestamp();
			currentTime = EngineTime.ToFloat( scriptInterface.GetTimeSystem().GetSimTime() );
			shouldExitOnSubmerged = ( currentTime - vehicleSubmergedTime ) > 0.5;
		}
		shouldForceExitDelamain = vehiclePS.ShouldForceExitDelamain();
		vehiclePS.SetShouldForceExitDelamain( false );
		if( shouldForceExitDelamain || !( IsExitVehicleBlocked( scriptInterface ) ) )
		{
			stateTime = GetInStateTime();
			exitActionPressCount = scriptInterface.GetActionPressCount( 'Exit' );
			exitPressCountResult = stateContext.GetPermanentIntParameter( 'exitPressCountOnEnter' );
			onDifferentExitPress = !( exitPressCountResult.valid ) || ( exitPressCountResult.value != ( ( Int32 )( exitActionPressCount ) ) );
			if( scriptInterface.IsActionJustPressed( 'QuickExit' ) )
			{
				coolExit = true;
				coolExitImpulseLevel = vehicle.DetermineCoolExitImpulseLevel( scriptInterface.executionOwner, GetStaticFloatParameterDefault( "coolExitMaxImpulseHeightThreshold", 3.5999999 ), GetStaticFloatParameterDefault( "coolExitLowImpulseHeightThreshold", 1.79999995 ) );
				if( coolExitImpulseLevel != vehicleCoolExitImpulseLevel.NoExit )
				{
					SetSide( stateContext, scriptInterface );
					stateContext.SetPermanentIntParameter( 'vehUnmountDir', ( ( Int32 )( vehicleExitDirection.Left ) ), true );
					stateContext.SetPermanentBoolParameter( 'coolExitRequest', true, true );
					DeactivateTimeDilationCW( stateContext, scriptInterface );
					return true;
				}
			}
			if( ( ( shouldExitOnSubmerged || coolExit ) || shouldForceExitDelamain ) || ( ( onDifferentExitPress && ( stateTime >= 0.30000001 ) ) && ( scriptInterface.GetActionValue( 'Exit' ) > 0.0 ) ) )
			{
				inputStateTime = scriptInterface.GetActionStateTime( 'Exit' );
				isValidExitAlreadyRequested = stateContext.GetPermanentBoolParameter( 'validExitRequest' );
				validUnmount = vehicle.CanUnmount( true, scriptInterface.executionOwner );
				stateContext.SetPermanentIntParameter( 'vehUnmountDir', ( ( Int32 )( validUnmount.direction ) ), true );
				DeactivateTimeDilationCW( stateContext, scriptInterface );
				if( ( ( shouldExitOnSubmerged || coolExit ) || shouldForceExitDelamain ) || ( ( inputStateTime >= 0.30000001 ) && !( isValidExitAlreadyRequested.value ) ) )
				{
					if( ( vehicle != ( ( CarObject )( vehicle ) ) ) && ( vehicle != ( ( BikeObject )( vehicle ) ) ) )
					{
						stateContext.SetPermanentBoolParameter( 'validExitRequest', true, true );
						return true;
					}
					SetSide( stateContext, scriptInterface );
					if( IsUnmountDirectionClosest( stateContext, validUnmount.direction ) || ( ( vehicle == ( ( BikeObject )( vehicle ) ) ) && IsUnmountDirectionOpposite( stateContext, validUnmount.direction ) ) )
					{
						if( shouldExitOnSubmerged )
						{
							stateContext.SetPermanentBoolParameter( 'submergedExitRequest', true, true );
						}
						else
						{
							stateContext.SetPermanentBoolParameter( 'validExitRequest', true, true );
						}
						return true;
					}
				}
				if( shouldExitOnSubmerged || ( scriptInterface.GetActionValue( 'Exit' ) > 0.0 ) )
				{
					if( ( inputStateTime >= 0.5 ) && ( vehicle == ( ( CarObject )( vehicle ) ) ) )
					{
						SetSide( stateContext, scriptInterface );
						if( IsUnmountDirectionOpposite( stateContext, validUnmount.direction ) )
						{
							mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
							GetAdjacentSeat( mountingInfo.slotId.id, adjacentSeat );
							isSlotOccupied = VehicleComponent.IsSlotOccupied( scriptInterface.GetGame(), scriptInterface.ownerEntityID, adjacentSeat );
							TryToStopVehicle( stateContext, scriptInterface, true );
							if( !( isSlotOccupied ) )
							{
								stateContext.SetPermanentBoolParameter( 'validSwitchSeatExitRequest', true, true );
								stateContext.SetPermanentBoolParameter( 'validExitAfterSwitchRequest', true, true );
							}
							else
							{
								ExitWithTeleport( stateContext, scriptInterface, validUnmount, true );
							}
							return true;
						}
					}
					if( shouldExitOnSubmerged || scriptInterface.IsActionJustHeld( 'Exit' ) )
					{
						if( ( ( validUnmount.direction == vehicleExitDirection.Front || validUnmount.direction == vehicleExitDirection.Back ) || validUnmount.direction == vehicleExitDirection.Top ) || validUnmount.direction == vehicleExitDirection.NoDirection )
						{
							TryToStopVehicle( stateContext, scriptInterface, true );
							ExitWithTeleport( stateContext, scriptInterface, validUnmount );
							return true;
						}
					}
				}
			}
		}
		return false;
	}

	protected function ExitWithTeleport( stateContext : StateContext, scriptInterface : StateGameScriptInterface, validUnmountDirection : vehicleUnmountPosition, optional moveVehicle : Bool, optional skipUnmount : Bool )
	{
		var unmountEvent : UnmountingRequest;
		var mountingInfo : MountingInfo;
		var teleportPosition : Vector4;
		var worldPos : Vector4;
		var vehicleTeleportPosition : Vector4;
		stateContext.SetPermanentBoolParameter( 'teleportExitActive', true, true );
		DeactivateTimeDilationCW( stateContext, scriptInterface );
		mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
		unmountEvent = new UnmountingRequest;
		unmountEvent.lowLevelMountingInfo = mountingInfo;
		unmountEvent.mountData = new MountEventData;
		unmountEvent.mountData.isInstant = true;
		scriptInterface.GetMountingFacility().Unmount( unmountEvent );
		if( validUnmountDirection.direction == vehicleExitDirection.NoDirection )
		{
			worldPos = scriptInterface.executionOwner.GetWorldPosition();
			worldPos.Z = worldPos.Z + 2.0;
			teleportPosition = worldPos;
		}
		else
		{
			teleportPosition = WorldPosition.ToVector4( validUnmountDirection.position );
		}
		if( moveVehicle )
		{
			vehicleTeleportPosition = scriptInterface.owner.GetWorldPosition();
			vehicleTeleportPosition.Z = vehicleTeleportPosition.Z + 0.25;
			WorldTransform.GetRight( scriptInterface.owner.GetWorldTransform() );
			teleportPosition = teleportPosition + WorldTransform.GetRight( scriptInterface.owner.GetWorldTransform() );
			vehicleTeleportPosition = vehicleTeleportPosition + WorldTransform.GetRight( scriptInterface.owner.GetWorldTransform() );
			GameInstance.GetTeleportationFacility( scriptInterface.GetGame() ).Teleport( scriptInterface.owner, vehicleTeleportPosition, Quaternion.ToEulerAngles( scriptInterface.owner.GetWorldOrientation() ) );
		}
		GameInstance.GetTeleportationFacility( scriptInterface.GetGame() ).Teleport( scriptInterface.executionOwner, teleportPosition, Quaternion.ToEulerAngles( scriptInterface.owner.GetWorldOrientation() ) );
	}

}

struct VehEntityPlayerStateData
{
	var entID : EntityID;
	var state : Int32;
}

class IdleDecisions extends VehicleTransition
{

	public export const function ToExit( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsExitForced( stateContext ) || !( scriptInterface.owner ) )
		{
			return true;
		}
		return false;
	}

}

class IdleEvents extends VehicleEventsTransition
{

	protected function SetVehicleCombatType( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var vehicleRecord : Vehicle_Record;
		var driverCombatType : gamedataDriverCombatType;
		driverCombatType = gamedataDriverCombatType.Invalid;
		vehicleRecord = TweakDBInterface.GetVehicleRecord( ( ( VehicleObject )( scriptInterface.owner ) ).GetRecordID() );
		if( vehicleRecord.VehDataPackage() )
		{
			driverCombatType = vehicleRecord.VehDataPackage().DriverCombat().Type();
		}
		stateContext.SetPermanentIntParameter( 'driverCombatType', ( ( Int32 )( driverCombatType ) ), true );
	}

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var vehType : Int32;
		var vehClass : Int32;
		super.OnEnter( stateContext, scriptInterface );
		vehType = GetVehType( stateContext, scriptInterface );
		SetVehicleType( stateContext, vehType );
		vehClass = GetVehClass( stateContext, scriptInterface );
		SetVehicleClass( stateContext, vehClass );
		SetVehicleCombatType( stateContext, scriptInterface );
		VehicleComponent.SetAnimsetOverrideForPassenger( scriptInterface.executionOwner, 1.0 );
		if( !( IsInRpgContext( scriptInterface ) ) )
		{
			stateContext.SetPermanentBoolParameter( 'VisionToggled', false, true );
			ForceDisableVisionMode( stateContext );
		}
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Transition ) ) );
		PlayerStateChange( scriptInterface, 4 );
		DisableCameraBobbing( stateContext, scriptInterface, true );
		stateContext.SetPermanentBoolParameter( 'coolExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'submergedExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'validExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'validSwitchSeatExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'teleportExitActive', false, true );
		stateContext.RemoveConditionBoolParameter( 'CrouchToggled' );
	}

}

class EnteringDecisions extends VehicleTransition
{

	public export const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var currentTime : Float;
		var targetTime : Float;
		var wasStolen : StateResultBool;
		var combatEnter : StateResultBool;
		wasStolen = stateContext.GetPermanentBoolParameter( 'wasStolen' );
		currentTime = GetInStateTime();
		if( wasStolen.value )
		{
			targetTime = 3.70000005;
			return ( currentTime > targetTime ) || ( stateMachineInitData.instant && stateContext.IsStateActive( 'Locomotion', 'workspot' ) );
		}
		else
		{
			combatEnter = stateContext.GetPermanentBoolParameter( 'combatEnter' );
			if( combatEnter.value )
			{
				targetTime = GetVehicleDataPackage( stateContext ).CombatEntering();
			}
			else
			{
				targetTime = GetVehicleDataPackage( stateContext ).Entering();
			}
			return ( currentTime > targetTime ) || ( stateMachineInitData.instant && stateContext.IsStateActive( 'Locomotion', 'workspot' ) );
		}
	}

	public export const function ToExiting( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsExitForced( stateContext ) || !( scriptInterface.owner ) )
		{
			return true;
		}
		return false;
	}

	public export const function ToSwitchSeats( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsDriverInVehicle( scriptInterface ) )
		{
			return DriverSwitchSeatsCondition( stateContext, scriptInterface );
		}
		if( IsPassengerInVehicle( scriptInterface ) )
		{
			return PassangerSwitchSeatsCondition( stateContext, scriptInterface );
		}
		return false;
	}

}

class EnteringEvents extends VehicleEventsTransition
{

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var workspotSystem : WorkspotGameSystem;
		var mountingInfo : MountingInfo;
		var slideDuration : Float;
		var syncObjects : array< EntityID >;
		var animVariables : array< CName >;
		var entrySlotName : CName;
		var vehicle : VehicleObject;
		var playerOwner : PlayerPuppet;
		var shouldEnterDriverCombat : Bool;
		entrySlotName = 'default';
		super.OnEnter( stateContext, scriptInterface );
		shouldEnterDriverCombat = IsPlayerInCombat( scriptInterface ) && UpperBodyTransition.HasAnyWeaponEquipped( scriptInterface );
		playerOwner = ( ( PlayerPuppet )( scriptInterface.executionOwner ) );
		if( playerOwner )
		{
			shouldEnterDriverCombat = shouldEnterDriverCombat || playerOwner.PSIsInDriverCombat();
		}
		stateContext.SetPermanentBoolParameter( 'drawnWeapon', shouldEnterDriverCombat, true );
		stateContext.SetPermanentBoolParameter( 'vehicleStatusEffectsApplied', false, false );
		stateContext.SetPermanentBoolParameter( 'VisionToggled', false, true );
		ForceDisableVisionMode( stateContext );
		ForceDisableRadialWheel( scriptInterface );
		SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.UnequipAll );
		ForceIdleVehicle( stateContext );
		slideDuration = GetVehicleDataPackage( stateContext ).SlideDuration();
		if( stateMachineInitData.instant )
		{
			slideDuration = 0.0;
		}
		mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
		workspotSystem = scriptInterface.GetWorkspotSystem();
		animVariables = VehicleComponent.SetAnimsetOverrideForPassenger( scriptInterface.executionOwner, 1.0 );
		vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
		if( EntityID.IsDefined( stateMachineInitData.entityID ) && vehicle.GetVehiclePS().IsSlotOccupiedByNPC( mountingInfo.slotId.id ) )
		{
			syncObjects.PushBack( stateMachineInitData.entityID );
			workspotSystem.StopNpcInWorkspot( scriptInterface.executionOwner );
			if( stateMachineInitData.alive )
			{
				entrySlotName = 'stealing';
			}
			else
			{
				entrySlotName = 'deadstealing';
			}
			workspotSystem.MountToVehicle( scriptInterface.owner, scriptInterface.executionOwner, slideDuration, slideDuration, 'OccupantSlots', mountingInfo.slotId.id, syncObjects, entrySlotName, animVariables );
			SetWasStolen( stateContext, true );
		}
		else
		{
			if( ( ( !( stateMachineInitData.instant ) && IsPlayerInCombat( scriptInterface ) ) && ( GetVehClass( stateContext, scriptInterface ) == 0 ) ) && VehicleComponent.IsDriverSlot( mountingInfo.slotId.id ) )
			{
				entrySlotName = 'enter_fast';
				slideDuration = 0.5;
				stateContext.SetPermanentBoolParameter( 'combatEnter', true, true );
			}
			workspotSystem.StopNpcInWorkspot( scriptInterface.executionOwner );
			workspotSystem.MountToVehicle( scriptInterface.owner, scriptInterface.executionOwner, slideDuration, slideDuration, 'OccupantSlots', mountingInfo.slotId.id, , entrySlotName, animVariables );
		}
		if( stateMachineInitData.occupiedByNonFriendly )
		{
			VehicleComponent.QueueExitEventToAllNonFriendlyActivePassengers( scriptInterface.GetGame(), scriptInterface.ownerEntityID, scriptInterface.executionOwner, true );
		}
		if( !( VehicleComponent.IsDriverSlot( mountingInfo.slotId.id ) ) )
		{
			VehicleComponent.QueueHijackExitEventToInactiveDriver( scriptInterface.owner.GetGame(), ( ( VehicleObject )( scriptInterface.owner ) ) );
		}
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Transition ) ) );
		PlayerStateChange( scriptInterface, 4 );
	}

	public export function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		stateContext.SetPermanentBoolParameter( 'combatEnter', false, true );
		GameInstance.GetTelemetrySystem( scriptInterface.GetGame() ).LogEnteringOrExitingVehicle( false );
	}

}

class PassengerDecisions extends VehicleTransition
{

	public export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsPassengerInVehicle( scriptInterface ) )
		{
			return true;
		}
		return false;
	}

	public export const function ToCombat( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( GetPuppetVehicleSceneTransition( stateContext ) == PuppetVehicleState.CombatSeated )
		{
			return true;
		}
		return false;
	}

	public export const function ToSwitchSeats( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return PassangerSwitchSeatsCondition( stateContext, scriptInterface );
	}

}

class PassengerEvents extends VehicleEventsTransition
{
	private var noWeaponsRestrictionApplied : Bool;

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var camEvent : vehicleRequestCameraPerspectiveEvent;
		var audioEvt : VehicleAudioEvent;
		var mountingInfo : MountingInfo;
		var fppCamParamsSide : Bool;
		super.OnEnter( stateContext, scriptInterface );
		SetVehicleStatusEffects( stateContext, scriptInterface, true );
		mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
		SetSide( stateContext, scriptInterface );
		ForceIdleVehicle( stateContext );
		SetIsInVehicle( stateContext, true );
		SetIsCar( stateContext, true );
		if( mountingInfo.slotId.id == 'seat_back_left' )
		{
			fppCamParamsSide = true;
		}
		SetVehFppCameraParams( stateContext, scriptInterface, true, fppCamParamsSide );
		SendAnimFeature( stateContext, scriptInterface );
		SendIsCar( stateContext, scriptInterface );
		audioEvt = new VehicleAudioEvent;
		audioEvt.action = vehicleAudioEventAction.OnPlayerPassenger;
		scriptInterface.owner.QueueEvent( audioEvt );
		if( stateContext.GetBoolParameter( 'requestedTPPCamera', true ) )
		{
			RequestVehicleCameraPerspective( scriptInterface, vehicleCameraPerspective.TPPClose );
			SetRequestedTPPCamera( stateContext, false );
		}
		noWeaponsRestrictionApplied = false;
		if( stateMachineInitData.occupiedByNonFriendly )
		{
			if( mountingInfo.slotId.id == 'seat_front_right' )
			{
				noWeaponsRestrictionApplied = true;
				StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoWeapons" );
			}
		}
		RemoveMountingRequest( stateContext );
		PlayerStateChange( scriptInterface, 3 );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Passenger ) ) );
		camEvent = new vehicleRequestCameraPerspectiveEvent;
		camEvent.cameraPerspective = vehicleCameraPerspective.FPP;
		scriptInterface.executionOwner.QueueEvent( camEvent );
	}

	public export function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		isCameraTogglePressed = false;
		ResetVehFppCameraParams( stateContext, scriptInterface );
		if( GetPuppetVehicleSceneTransition( stateContext ) == PuppetVehicleState.CombatSeated )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon );
			stateContext.SetTemporaryBoolParameter( 'vehicleWindowedCombat', false, true );
		}
		if( noWeaponsRestrictionApplied )
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoWeapons", ( ( Uint32 )( 1 ) ) );
		}
	}

	public export function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetSide( stateContext, scriptInterface );
		HandleCameraInput( scriptInterface );
		HandleExitRequest( timeDelta, stateContext, scriptInterface );
	}

}

class GunnerDecisions extends VehicleTransition
{

	public export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var lowLevelMountingInfo : MountingInfo;
		var currentSlot : CName;
		lowLevelMountingInfo = scriptInterface.GetMountingFacility().GetMountingInfoSingleWithObjects( scriptInterface.executionOwner );
		currentSlot = lowLevelMountingInfo.slotId.id;
		if( currentSlot == 'gunner_back_left' || currentSlot == 'gunner_back_right' )
		{
			return true;
		}
		return false;
	}

	public const function ToExiting( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsExitForced( stateContext ) || !( scriptInterface.owner ) )
		{
			return true;
		}
		return false;
	}

}

class GunnerEvents extends VehicleEventsTransition
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var audioEvt : VehicleAudioEvent;
		super.OnEnter( stateContext, scriptInterface );
		stateContext.SetPermanentIntParameter( 'vehSlot', 3, true );
		ForceIdleVehicle( stateContext );
		SetIsInVehicle( stateContext, true );
		SetIsCar( stateContext, true );
		ResetVehFppCameraParams( stateContext, scriptInterface );
		SendIsCar( stateContext, scriptInterface );
		audioEvt = new VehicleAudioEvent;
		audioEvt.action = vehicleAudioEventAction.OnPlayerPassenger;
		scriptInterface.owner.QueueEvent( audioEvt );
		RemoveMountingRequest( stateContext );
		PlayerStateChange( scriptInterface, 3 );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Combat ) ) );
		SetIsInVehicleCombat( stateContext, true );
		SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableRangedWeapon );
		SendAnimFeature( stateContext, scriptInterface );
	}

	public function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		ResetVehFppCameraParams( stateContext, scriptInterface );
		if( GetPuppetVehicleSceneTransition( stateContext ) == PuppetVehicleState.CombatSeated )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon );
			stateContext.SetTemporaryBoolParameter( 'vehicleWindowedCombat', false, true );
		}
	}

	public override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnForcedExit( stateContext, scriptInterface );
	}

}

class DriveDecisions extends VehicleTransition
{

	public export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsDriverInVehicle( scriptInterface ) )
		{
			return true;
		}
		return false;
	}

	public export const function ToDriverCombatFirearms( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var questForceEnableCombat : StateResultBool;
		var drawnWeapon : StateResultBool;
		var equipWeaponActionTapped : Bool;
		var notificationEvent : UIInGameNotificationEvent;
		if( DoesVehicleSupportFireArms( ( ( VehicleObject )( scriptInterface.owner ) ) ) )
		{
			equipWeaponActionTapped = ( ( ( ( scriptInterface.IsActionJustTapped( 'SwitchItem' ) || scriptInterface.IsActionJustTapped( 'HolsterWeapon' ) ) || scriptInterface.IsActionJustTapped( 'NextWeapon' ) ) || scriptInterface.IsActionJustTapped( 'PreviousWeapon' ) ) && ( EquipmentSystem.GetData( scriptInterface.executionOwner ).GetLastUsedOrFirstAvailableDriverCombatWeapon( GetDriverCombatWeaponTag( ( ( VehicleObject )( scriptInterface.owner ) ) ) ) == ItemID.None() ) ) && ( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Vision ) != ( ( Int32 )( gamePSMVision.Focus ) ) );
			if( !( IsPlayerAllowedToEnterDriverCombat( stateContext, scriptInterface ) ) )
			{
				if( equipWeaponActionTapped )
				{
					notificationEvent = new UIInGameNotificationEvent;
					notificationEvent.m_notificationType = UIInGameNotificationType.ActionRestriction;
					scriptInterface.GetUISystem().QueueEvent( notificationEvent );
					return false;
				}
			}
			else
			{
				if( equipWeaponActionTapped || UpperBodyTransition.HasAnyWeaponEquipped( scriptInterface ) )
				{
					return true;
				}
				if( GetPuppetVehicleSceneTransition( stateContext ) == PuppetVehicleState.CombatSeated )
				{
					return true;
				}
				drawnWeapon = stateContext.GetPermanentBoolParameter( 'drawnWeapon' );
				if( drawnWeapon.value && ( EquipmentSystem.GetData( scriptInterface.executionOwner ).GetLastUsedOrFirstAvailableDriverCombatWeapon( GetDriverCombatWeaponTag( ( ( VehicleObject )( scriptInterface.owner ) ) ) ) == ItemID.None() ) )
				{
					return true;
				}
				questForceEnableCombat = stateContext.GetTemporaryBoolParameter( 'startVehicleCombat' );
				if( questForceEnableCombat.value )
				{
					return true;
				}
			}
		}
		return false;
	}

	public export const function ToDriverCombatMountedWeapons( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var questForceEnableCombat : StateResultBool;
		var drawnWeapon : StateResultBool;
		var equipWeaponActionTapped : Bool;
		var notificationEvent : UIInGameNotificationEvent;
		if( GetVehicleDriverCombatType( ( ( VehicleObject )( scriptInterface.owner ) ) ) == gamedataDriverCombatType.MountedWeapons )
		{
			equipWeaponActionTapped = ( ( ( ( ( scriptInterface.IsActionJustTapped( 'MountedWeapons_SwitchWeapons' ) || scriptInterface.IsActionJustTapped( 'MountedWeapons_HolsterWeapon' ) ) || scriptInterface.IsActionJustTapped( 'MountedWeapons_NextWeapon' ) ) || scriptInterface.IsActionJustTapped( 'MountedWeapons_PreviousWeapon' ) ) || scriptInterface.IsActionJustTapped( 'MountedWeapons_WeaponSlot1' ) ) || ( scriptInterface.IsActionJustTapped( 'MountedWeapons_WeaponSlot2' ) && ( ( VehicleObject )( scriptInterface.owner ) ).CanSwitchWeapons() ) ) && ( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Vision ) != ( ( Int32 )( gamePSMVision.Focus ) ) );
			if( !( IsPlayerAllowedToEnterDriverCombat( stateContext, scriptInterface ) ) || ( ( VehicleObject )( scriptInterface.owner ) ).GetVehicleComponent().IsVehicleInDecay() )
			{
				if( equipWeaponActionTapped )
				{
					notificationEvent = new UIInGameNotificationEvent;
					notificationEvent.m_notificationType = UIInGameNotificationType.ActionRestriction;
					scriptInterface.GetUISystem().QueueEvent( notificationEvent );
					return false;
				}
			}
			else
			{
				if( equipWeaponActionTapped )
				{
					return true;
				}
				if( GetPuppetVehicleSceneTransition( stateContext ) == PuppetVehicleState.CombatSeated )
				{
					return true;
				}
				drawnWeapon = stateContext.GetPermanentBoolParameter( 'drawnWeapon' );
				if( drawnWeapon.value )
				{
					return true;
				}
				questForceEnableCombat = stateContext.GetTemporaryBoolParameter( 'startVehicleCombat' );
				if( questForceEnableCombat.value )
				{
					return true;
				}
			}
		}
		return false;
	}

	public export const function ToSwitchSeats( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return DriverSwitchSeatsCondition( stateContext, scriptInterface );
	}

}

class DriveEvents extends VehicleEventsTransition
{
	private var m_inCombatBlockingForbiddenZone : Bool;

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var audioEvt : VehicleAudioEvent;
		super.OnEnter( stateContext, scriptInterface );
		SetVehicleStatusEffects( stateContext, scriptInterface, true );
		SetSide( stateContext, scriptInterface );
		SetIsInVehicle( stateContext, true );
		SetIsVehicleDriver( stateContext, true );
		ForceIdleVehicle( stateContext );
		PlayerStateChange( scriptInterface, 1 );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Driving ) ) );
		SendAnimFeature( stateContext, scriptInterface );
		SetVehFppCameraParams( stateContext, scriptInterface, false );
		audioEvt = new VehicleAudioEvent;
		audioEvt.action = vehicleAudioEventAction.OnPlayerDriving;
		scriptInterface.owner.QueueEvent( audioEvt );
		if( stateContext.GetBoolParameter( 'requestedTPPCamera', true ) )
		{
			RequestVehicleCameraPerspective( scriptInterface, vehicleCameraPerspective.TPPClose );
			SetRequestedTPPCamera( stateContext, false );
		}
		RemoveMountingRequest( stateContext );
		PauseStateMachines( stateContext, scriptInterface.executionOwner );
		GameInstance.GetRazerChromaEffectsSystem( scriptInterface.executionOwner.GetGame() ).SetIdleAnimation( 'Driving', true );
	}

	public export function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var transition : PuppetVehicleState;
		transition = GetPuppetVehicleSceneTransition( stateContext );
		if( transition == PuppetVehicleState.CombatSeated || transition == PuppetVehicleState.CombatWindowed )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon );
		}
		SetIsVehicleDriver( stateContext, false );
		SendAnimFeature( stateContext, scriptInterface );
		ResetVehFppCameraParams( stateContext, scriptInterface );
		isCameraTogglePressed = false;
		ResumeStateMachines( scriptInterface.executionOwner );
		GameInstance.GetRazerChromaEffectsSystem( scriptInterface.executionOwner.GetGame() ).SetHotKeysIdleAnimation();
		if( m_inCombatBlockingForbiddenZone )
		{
			m_inCombatBlockingForbiddenZone = false;
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoWeapons", ( ( Uint32 )( 1 ) ) );
		}
	}

	public override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnForcedExit( stateContext, scriptInterface );
		ResumeStateMachines( scriptInterface.executionOwner );
		if( m_inCombatBlockingForbiddenZone )
		{
			m_inCombatBlockingForbiddenZone = false;
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoWeapons", ( ( Uint32 )( 1 ) ) );
		}
	}

	public export function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var drawnWeapon : StateResultBool;
		var driverCombatForbiddenZone : StateResultBool;
		SendAnimFeature( stateContext, scriptInterface );
		HandleCameraInput( scriptInterface );
		HandleExitRequest( timeDelta, stateContext, scriptInterface );
		drawnWeapon = stateContext.GetPermanentBoolParameter( 'drawnWeapon' );
		if( ( drawnWeapon.value && ( EquipmentSystem.GetData( scriptInterface.executionOwner ).GetLastUsedOrFirstAvailableDriverCombatWeapon( GetDriverCombatWeaponTag( ( ( VehicleObject )( scriptInterface.owner ) ) ) ) != ItemID.None() ) ) && DoesVehicleSupportFireArms( ( ( VehicleObject )( scriptInterface.owner ) ) ) )
		{
			stateContext.SetPermanentBoolParameter( 'drawnWeapon', false, true );
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, GetDriverCombatWeaponManipulationRequest( ( ( VehicleObject )( scriptInterface.owner ) ) ), gameEquipAnimationType.Instant );
		}
		driverCombatForbiddenZone = stateContext.GetPermanentBoolParameter( 'driverCombatForbiddenZone' );
		if( driverCombatForbiddenZone.value != m_inCombatBlockingForbiddenZone )
		{
			m_inCombatBlockingForbiddenZone = driverCombatForbiddenZone.value;
			if( m_inCombatBlockingForbiddenZone )
			{
				StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoWeapons" );
			}
			else
			{
				StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoWeapons", ( ( Uint32 )( 1 ) ) );
			}
		}
	}

}

class SwitchSeatsDecisions extends VehicleTransition
{

	public constexpr const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return true;
	}

	public const function ToDrive( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var mountingRequest : MountingRequest;
		var lowLevelMountingInfo : MountingInfo;
		var mountData : MountEventData;
		var mountOptions : MountEventOptions;
		var currentSlot : CName;
		lowLevelMountingInfo = scriptInterface.GetMountingFacility().GetMountingInfoSingleWithIds( scriptInterface.executionOwnerEntityID,  );
		currentSlot = lowLevelMountingInfo.slotId.id;
		if( GetInStateTime() >= GetVehicleDataPackage( stateContext ).SwitchSeats() )
		{
			mountingRequest = new MountingRequest;
			mountData = new MountEventData;
			mountOptions = new MountEventOptions;
			lowLevelMountingInfo.parentId = scriptInterface.ownerEntityID;
			lowLevelMountingInfo.childId = scriptInterface.executionOwnerEntityID;
			mountData.isInstant = true;
			mountOptions.silentUnmount = true;
			if( currentSlot == 'seat_front_right' )
			{
				lowLevelMountingInfo.slotId.id = 'seat_front_left';
				mountingRequest.lowLevelMountingInfo = lowLevelMountingInfo;
				mountingRequest.mountData = mountData;
				mountingRequest.mountData.mountEventOptions = mountOptions;
				scriptInterface.GetMountingFacility().Mount( mountingRequest );
				VehicleComponent.CloseDoor( ( ( VehicleObject )( scriptInterface.owner ) ), lowLevelMountingInfo.slotId );
				return true;
			}
		}
		return false;
	}

	public const function ToPassenger( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var mountingRequest : MountingRequest;
		var lowLevelMountingInfo : MountingInfo;
		var mountData : MountEventData;
		var mountOptions : MountEventOptions;
		var currentSlot : CName;
		lowLevelMountingInfo = scriptInterface.GetMountingFacility().GetMountingInfoSingleWithIds( scriptInterface.executionOwnerEntityID,  );
		currentSlot = lowLevelMountingInfo.slotId.id;
		if( GetInStateTime() >= GetVehicleDataPackage( stateContext ).SwitchSeats() )
		{
			mountingRequest = new MountingRequest;
			mountData = new MountEventData;
			mountOptions = new MountEventOptions;
			lowLevelMountingInfo.parentId = scriptInterface.ownerEntityID;
			lowLevelMountingInfo.childId = scriptInterface.executionOwnerEntityID;
			mountData.isInstant = true;
			mountOptions.silentUnmount = true;
			if( currentSlot == 'seat_back_left' )
			{
				lowLevelMountingInfo.slotId.id = 'seat_back_right';
				mountingRequest.lowLevelMountingInfo = lowLevelMountingInfo;
				mountingRequest.mountData = mountData;
				mountingRequest.mountData.mountEventOptions = mountOptions;
				scriptInterface.GetMountingFacility().Mount( mountingRequest );
				return true;
			}
			if( currentSlot == 'seat_back_right' )
			{
				lowLevelMountingInfo.slotId.id = 'seat_back_left';
				mountingRequest.lowLevelMountingInfo = lowLevelMountingInfo;
				mountingRequest.mountData = mountData;
				mountingRequest.mountData.mountEventOptions = mountOptions;
				scriptInterface.GetMountingFacility().Mount( mountingRequest );
				return true;
			}
			if( currentSlot == 'seat_front_left' )
			{
				lowLevelMountingInfo.slotId.id = 'seat_front_right';
				mountingRequest.lowLevelMountingInfo = lowLevelMountingInfo;
				mountingRequest.mountData = mountData;
				mountingRequest.mountData.mountEventOptions = mountOptions;
				scriptInterface.GetMountingFacility().Mount( mountingRequest );
				return true;
			}
		}
		return false;
	}

}

class SwitchSeatsEvents extends VehicleEventsTransition
{
	var workspotSystem : WorkspotGameSystem;
	var enabledSceneMode : Bool;

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var animVariablesActivate : array< CName >;
		var animVariablesDeactivate : array< CName >;
		var vehicle : weak< VehicleObject >;
		var evtNextSeat : AnimWrapperWeightSetter;
		var evtPrevSeat : AnimWrapperWeightSetter;
		var evtNextSlot : AnimWrapperWeightSetter;
		var evtPrevSlot : AnimWrapperWeightSetter;
		var mountingInfo : MountingInfo;
		var curSlotName : CName;
		var nextSlotName : CName;
		stateContext.SetPermanentBoolParameter( 'validSwitchSeatExitRequest', false, true );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Transition ) ) );
		DeactivateTimeDilationCW( stateContext, scriptInterface );
		vehicle = GetVehicleObject( scriptInterface );
		mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
		curSlotName = mountingInfo.slotId.id;
		GetAdjacentSeat( curSlotName, nextSlotName );
		SetRequestedTPPCamera( stateContext, false );
		evtNextSeat = new AnimWrapperWeightSetter;
		evtNextSeat.key = vehicle.GetAnimsetOverrideForPassenger( nextSlotName );
		evtNextSeat.value = 1.0;
		animVariablesActivate.PushBack( evtNextSeat.key );
		scriptInterface.executionOwner.QueueEvent( evtNextSeat );
		evtNextSlot = new AnimWrapperWeightSetter;
		evtNextSlot.key = nextSlotName;
		evtNextSlot.value = 1.0;
		animVariablesActivate.PushBack( evtNextSlot.key );
		scriptInterface.executionOwner.QueueEvent( evtNextSlot );
		evtPrevSeat = new AnimWrapperWeightSetter;
		evtPrevSeat.key = vehicle.GetAnimsetOverrideForPassenger( curSlotName );
		evtPrevSeat.value = 0.0;
		animVariablesDeactivate.PushBack( evtPrevSeat.key );
		scriptInterface.executionOwner.QueueEvent( evtPrevSeat );
		evtPrevSlot = new AnimWrapperWeightSetter;
		evtPrevSlot.key = curSlotName;
		evtPrevSlot.value = 0.0;
		animVariablesDeactivate.PushBack( evtPrevSlot.key );
		scriptInterface.executionOwner.QueueEvent( evtPrevSlot );
		workspotSystem = scriptInterface.GetWorkspotSystem();
		workspotSystem.SwitchSeatVehicle( scriptInterface.owner, scriptInterface.executionOwner, 'OccupantSlots', nextSlotName, 'switch_seat', animVariablesActivate, animVariablesDeactivate );
		SetVehicleCameraSceneMode( scriptInterface, true );
		enabledSceneMode = true;
		super.OnEnter( stateContext, scriptInterface );
	}

	public function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		DeactivateTimeDilationCW( stateContext, scriptInterface );
		if( enabledSceneMode )
		{
			SetVehicleCameraSceneMode( scriptInterface, false );
			enabledSceneMode = false;
		}
	}

	public function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface ) {}

	public override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExit( stateContext, scriptInterface );
	}

}

class EnteringCombatDecisions extends VehicleTransition
{

	public export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var audioEvt : VehicleAudioEvent;
		var questForceEnableCombat : StateResultBool;
		var hasTurret : Bool;
		var scenePuppetVehicleTransition : PuppetVehicleState;
		if( !( IsPlayerAllowedToEnterCombat( scriptInterface ) ) )
		{
			return false;
		}
		questForceEnableCombat = stateContext.GetTemporaryBoolParameter( 'startVehicleCombat' );
		hasTurret = CheckVehicleDesiredTag( scriptInterface, 'Turret' );
		scenePuppetVehicleTransition = GetPuppetVehicleSceneTransition( stateContext );
		if( hasTurret )
		{
			return false;
		}
		if( questForceEnableCombat.value && !( hasTurret ) )
		{
			SetWasCombatForced( stateContext, true );
			return true;
		}
		if( scenePuppetVehicleTransition == PuppetVehicleState.CombatWindowed )
		{
			SetWasCombatForced( stateContext, true );
			return true;
		}
		audioEvt = new VehicleAudioEvent;
		audioEvt.action = vehicleAudioEventAction.OnPlayerExitCombat;
		scriptInterface.owner.QueueEvent( audioEvt );
		if( UpperBodyTransition.HasAnyWeaponEquipped( scriptInterface ) )
		{
			return true;
		}
		return false;
	}

	public const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetInStateTime() > GetVehicleDataPackage( stateContext ).ToCombat();
	}

}

class EnteringCombatEvents extends VehicleEventsTransition
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var weaponID : ItemID;
		var equipmentManipulationAction : EquipmentManipulationAction;
		var equipmentSystem : EquipmentSystem;
		var drawItemRequest : DrawItemRequest;
		super.OnEnter( stateContext, scriptInterface );
		if( stateContext.GetBoolParameter( 'wasCombatForced', true ) && !( UpperBodyTransition.HasRangedWeaponEquipped( scriptInterface.executionOwner ) ) )
		{
			if( StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DriverCombatFirearms' ) )
			{
				weaponID = EquipmentSystem.GetData( scriptInterface.executionOwner ).GetLastUsedOrFirstAvailableDriverCombatWeapon( GetDriverCombatWeaponTag( ( ( VehicleObject )( scriptInterface.owner ) ) ) );
				equipmentManipulationAction = GetDriverCombatWeaponManipulationRequest( ( ( VehicleObject )( scriptInterface.owner ) ) );
			}
			else
			{
				weaponID = EquipmentSystem.GetData( scriptInterface.executionOwner ).GetLastUsedOrFirstAvailableRangedWeapon();
				equipmentManipulationAction = EquipmentManipulationAction.RequestLastUsedOrFirstAvailableRangedWeapon;
			}
			if( ItemID.IsValid( weaponID ) )
			{
				SendEquipmentSystemWeaponManipulationRequest( scriptInterface, equipmentManipulationAction );
			}
			else
			{
				equipmentSystem = ( ( EquipmentSystem )( scriptInterface.GetScriptableSystem( 'EquipmentSystem' ) ) );
				drawItemRequest = new DrawItemRequest;
				drawItemRequest.owner = scriptInterface.executionOwner;
				drawItemRequest.itemID = ItemID.CreateQuery( T"Items.Preset_V_Unity_Cutscene" );
				equipmentSystem.QueueRequest( drawItemRequest );
			}
		}
		SetIsEnteringCombat( stateContext, true );
		SendAnimFeature( stateContext, scriptInterface );
		PlayerStateChange( scriptInterface, 2 );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Transition ) ) );
		SetVehicleCameraSceneMode( scriptInterface, true );
	}

	public function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetIsEnteringCombat( stateContext, false );
		SendAnimFeature( stateContext, scriptInterface );
		if( !( stateContext.GetBoolParameter( 'wasCombatForced', true ) ) )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon );
		}
		stateContext.SetTemporaryBoolParameter( 'vehicleWindowedCombat', true, true );
		SetWasCombatForced( stateContext, false );
		SetVehicleCameraSceneMode( scriptInterface, false );
	}

	public override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExit( stateContext, scriptInterface );
	}

}

class ExitingCombatDecisions extends VehicleTransition
{

	public const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetInStateTime() > GetVehicleDataPackage( stateContext ).FromCombat();
	}

}

class ExitingCombatEvents extends VehicleEventsTransition
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var audioEvt : VehicleAudioEvent;
		super.OnEnter( stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Transition ) ) );
		SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.UnequipAll );
		SetVehicleCameraSceneMode( scriptInterface, true );
		SetIsExitingCombat( stateContext, true );
		SendAnimFeature( stateContext, scriptInterface );
		audioEvt = new VehicleAudioEvent;
		audioEvt.action = vehicleAudioEventAction.OnPlayerExitCombat;
		scriptInterface.owner.QueueEvent( audioEvt );
	}

	public function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetVehicleCameraSceneMode( scriptInterface, false );
		SetIsExitingCombat( stateContext, false );
		SendAnimFeature( stateContext, scriptInterface );
	}

	public override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExit( stateContext, scriptInterface );
	}

}

class SceneExitingCombatDecisions extends VehicleTransition
{

	public const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( ( GetInStateTime() >= 0.5 ) || !( scriptInterface.IsSceneAnimationActive() ) )
		{
			return true;
		}
		return false;
	}

}

class SceneExitingCombatEvents extends VehicleEventsTransition
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var mountingInfo : MountingInfo;
		var slotName : CName;
		super.OnEnter( stateContext, scriptInterface );
		SetVehicleCameraSceneMode( scriptInterface, true );
		mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
		slotName = mountingInfo.slotId.id;
		SetIsInVehicleCombat( stateContext, true );
		SetIsInVehicleWindowCombat( stateContext, true );
		SetIsWorldRenderPlane( stateContext, true );
		SendAnimFeature( stateContext, scriptInterface );
		ToggleWindowForOccupiedSeat( scriptInterface, slotName, true );
		SetFirearmsGameplayRestriction( scriptInterface, true );
		SetVehFppCameraParams( stateContext, scriptInterface, true, false, true );
	}

	public function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var mountingInfo : MountingInfo;
		var slotName : CName;
		SetIsInVehicleCombat( stateContext, false );
		SetIsInVehicleWindowCombat( stateContext, false );
		SetIsWorldRenderPlane( stateContext, true );
		SetVehicleCameraSceneMode( scriptInterface, false );
		SetIsExitingCombat( stateContext, false );
		SendAnimFeature( stateContext, scriptInterface );
		mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
		slotName = mountingInfo.slotId.id;
		ToggleWindowForOccupiedSeat( scriptInterface, slotName, false );
		SetFirearmsGameplayRestriction( scriptInterface, false );
		ResetVehFppCameraParams( stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Transition ) ) );
		if( !( StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'FirearmsNoUnequip' ) ) )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.UnequipAll );
		}
	}

	public override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExit( stateContext, scriptInterface );
	}

}

class CombatDecisions extends VehicleTransition
{

	public const function ToExitingCombat( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var questForceDisableCombat : StateResultBool;
		questForceDisableCombat = stateContext.GetTemporaryBoolParameter( 'stopVehicleCombat' );
		if( questForceDisableCombat.value )
		{
			return true;
		}
		if( !( IsPlayerAllowedToExitCombat( scriptInterface ) ) )
		{
			return false;
		}
		if( IsInEmptyHandsState( stateContext ) && ( GetInStateTime() >= 0.5 ) )
		{
			return true;
		}
		if( scriptInterface.IsActionJustPressed( 'Exit' ) )
		{
			return true;
		}
		if( scriptInterface.IsActionJustReleased( 'ToggleVehCamera' ) )
		{
			SetRequestedTPPCamera( stateContext, true );
			return true;
		}
		if( !( IsPlayerAllowedToEnterCombat( scriptInterface ) ) )
		{
			return true;
		}
		return false;
	}

	public const function ToSceneExitingCombat( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsPlayerAllowedToExitCombat( scriptInterface ) )
		{
			return false;
		}
		if( !( IsInScene( stateContext, scriptInterface ) ) )
		{
			return false;
		}
		if( !( scriptInterface.IsSceneAnimationActive() ) )
		{
			return false;
		}
		return true;
	}

}

class CombatEvents extends VehicleEventsTransition
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var mountingInfo : MountingInfo;
		var slotName : CName;
		var fppCamParamsSide : Bool;
		super.OnEnter( stateContext, scriptInterface );
		mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
		slotName = mountingInfo.slotId.id;
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Combat ) ) );
		SetIsWorldRenderPlane( stateContext, false );
		SetIsInVehicleCombat( stateContext, true );
		SetIsInVehicleWindowCombat( stateContext, stateContext.GetBoolParameter( 'vehicleWindowedCombat', false ) );
		SendAnimFeature( stateContext, scriptInterface );
		ToggleWindowForOccupiedSeat( scriptInterface, slotName, true );
		SetFirearmsGameplayRestriction( scriptInterface, true );
		if( mountingInfo.slotId.id == 'seat_back_left' )
		{
			fppCamParamsSide = true;
		}
		SetVehFppCameraParams( stateContext, scriptInterface, true, fppCamParamsSide, true );
	}

	public function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var mountingInfo : MountingInfo;
		var slotName : CName;
		mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
		slotName = mountingInfo.slotId.id;
		SetIsInVehicleCombat( stateContext, false );
		SetIsInVehicleWindowCombat( stateContext, false );
		SetIsWorldRenderPlane( stateContext, true );
		SendAnimFeature( stateContext, scriptInterface );
		ToggleWindowForOccupiedSeat( scriptInterface, slotName, false );
		SetFirearmsGameplayRestriction( scriptInterface, false );
		ResetVehFppCameraParams( stateContext, scriptInterface );
	}

}

class DriverCombatDecisions extends VehicleTransition
{

	public const function ToDriveCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( !( IsPlayerAllowedToEnterCombat( scriptInterface ) ) )
		{
			return true;
		}
		return false;
	}

	public const function ToCombatExiting( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var exitRequest : StateResultBool;
		if( GetVehClass( stateContext, scriptInterface ) == 2 )
		{
			return false;
		}
		exitRequest = stateContext.GetPermanentBoolParameter( 'validExitRequest' );
		return exitRequest.value;
	}

	public export const function ToSwitchSeats( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return DriverSwitchSeatsCondition( stateContext, scriptInterface );
	}

}

class DriverCombatFirearmsDecisions extends DriverCombatDecisions
{

	public const function ToDrive( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( ToDriveCondition( stateContext, scriptInterface ) )
		{
			return true;
		}
		if( ( stateContext.IsStateActive( 'UpperBody', 'emptyHands' ) && ( GetInStateTime() >= 0.5 ) ) && ( stateContext.IsStateActive( 'Equipment', 'selfRemoval' ) || !( stateContext.IsStateMachineActive( 'Equipment' ) ) ) )
		{
			return true;
		}
		return false;
	}

}

class DriverCombatMountedWeaponsDecisions extends DriverCombatDecisions
{

	public const function ToDrive( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var questForceEnableCombat : StateResultBool;
		var driverCombatForbiddenZone : StateResultBool;
		if( ToDriveCondition( stateContext, scriptInterface ) )
		{
			return true;
		}
		if( ( ( VehicleObject )( scriptInterface.owner ) ).GetVehicleComponent().IsVehicleInDecay() )
		{
			return true;
		}
		if( scriptInterface.IsActionJustReleased( 'Exit' ) || scriptInterface.IsActionJustTapped( 'MountedWeapons_HolsterWeapon' ) )
		{
			return true;
		}
		questForceEnableCombat = stateContext.GetTemporaryBoolParameter( 'stopVehicleCombat' );
		if( questForceEnableCombat.value )
		{
			return true;
		}
		driverCombatForbiddenZone = stateContext.GetPermanentBoolParameter( 'driverCombatForbiddenZone' );
		if( driverCombatForbiddenZone.value )
		{
			return true;
		}
		return false;
	}

}

class DriverCombatEvents extends VehicleEventsTransition
{
	protected var m_executionOwner : weak< GameObject >;
	protected var m_owner : weak< GameObject >;
	protected var m_newTargetComponent : Bool;
	protected var m_targetComponent : weak< IPlacedComponent >;
	protected var m_vehicleInTPP : Bool;
	protected var m_driverCombatInTPP : Bool;
	protected var m_targetComponentCallback : CallbackHandle;
	protected var m_vehicleInTPPCallback : CallbackHandle;
	protected var m_driverCombatInTPPCallback : CallbackHandle;
	protected var m_curTarget : weak< GameObject >;
	protected var m_curTargetHostile : Bool;
	protected var m_highlightData : FocusForcedHighlightData;
	protected var m_requirePerspectiveUpdate : Bool;
	protected var m_aimPressed : Bool;
	protected var m_vehicleManeuversTime : Float;
	protected var m_exitReleasedTime : Float;

	private function RequestToggleVehicleDriverCombatCamera( scriptInterface : StateGameScriptInterface )
	{
		var camEvent : vehicleRequestCameraPerspectiveEvent;
		camEvent = new vehicleRequestCameraPerspectiveEvent;
		switch( ( ( VehicleObject )( scriptInterface.owner ) ).GetCameraManager().GetActivePerspective() )
		{
			case vehicleCameraPerspective.FPP:
				camEvent.cameraPerspective = vehicleCameraPerspective.DriverCombatClose;
			break;
			case vehicleCameraPerspective.TPPClose:
				camEvent.cameraPerspective = vehicleCameraPerspective.DriverCombatClose;
			break;
			case vehicleCameraPerspective.TPPMedium:
				camEvent.cameraPerspective = vehicleCameraPerspective.DriverCombatMedium;
			break;
			case vehicleCameraPerspective.TPPFar:
				camEvent.cameraPerspective = vehicleCameraPerspective.DriverCombatFar;
			break;
			case vehicleCameraPerspective.DriverCombatClose:
				camEvent.cameraPerspective = vehicleCameraPerspective.DriverCombatMedium;
			break;
			case vehicleCameraPerspective.DriverCombatMedium:
				camEvent.cameraPerspective = vehicleCameraPerspective.DriverCombatFar;
			break;
			case vehicleCameraPerspective.DriverCombatFar:
				if( !( scriptInterface.localBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsDriverCombatInTPP ) ) )
				{
					camEvent.cameraPerspective = vehicleCameraPerspective.DriverCombatClose;
				}
				else
				{
					camEvent.cameraPerspective = vehicleCameraPerspective.FPP;
				}
			break;
		}
		scriptInterface.executionOwner.QueueEvent( camEvent );
	}

	private function ClearTarget( scriptInterface : StateGameScriptInterface )
	{
		var highlightEvt : ForceVisionApperanceEvent;
		if( m_curTarget )
		{
			highlightEvt = new ForceVisionApperanceEvent;
			highlightEvt.forcedHighlight = m_highlightData;
			highlightEvt.apply = false;
			m_curTarget.QueueEvent( highlightEvt );
			m_curTarget = NULL;
		}
	}

	private function SetTargetHighlight( attitude : EAIAttitude, highlight : FocusForcedHighlightData )
	{
		if( attitude == EAIAttitude.AIA_Hostile )
		{
			m_highlightData.highlightType = EFocusForcedHighlightType.INVALID;
			m_highlightData.outlineType = EFocusOutlineType.INVALID;
		}
		else
		{
			m_highlightData.highlightType = EFocusForcedHighlightType.INVALID;
			m_highlightData.outlineType = EFocusOutlineType.INVALID;
		}
	}

	private function UpdateTargetHighlight( playerOwner : PlayerPuppet )
	{
		var highlightEvt : ForceVisionApperanceEvent;
		var attitude : EAIAttitude;
		if( m_curTarget )
		{
			attitude = GameObject.GetAttitudeTowards( playerOwner, m_curTarget );
			if( !( m_curTargetHostile ) )
			{
				if( attitude == EAIAttitude.AIA_Hostile )
				{
					m_curTargetHostile = true;
					highlightEvt = new ForceVisionApperanceEvent;
					highlightEvt.forcedHighlight = m_highlightData;
					highlightEvt.apply = false;
					m_curTarget.QueueEvent( highlightEvt );
					highlightEvt = new ForceVisionApperanceEvent;
					highlightEvt.forcedHighlight = m_highlightData;
					highlightEvt.apply = true;
					SetTargetHighlight( attitude, m_highlightData );
					m_curTarget.QueueEvent( highlightEvt );
				}
			}
			else
			{
				if( attitude == EAIAttitude.AIA_Neutral )
				{
					m_curTargetHostile = true;
					highlightEvt = new ForceVisionApperanceEvent;
					highlightEvt.forcedHighlight = m_highlightData;
					highlightEvt.apply = false;
					m_curTarget.QueueEvent( highlightEvt );
					highlightEvt = new ForceVisionApperanceEvent;
					highlightEvt.forcedHighlight = m_highlightData;
					highlightEvt.apply = true;
					SetTargetHighlight( attitude, m_highlightData );
					m_curTarget.QueueEvent( highlightEvt );
				}
			}
		}
	}

	private function OnNewTargetAcquired( playerOwner : PlayerPuppet, scriptInterface : StateGameScriptInterface )
	{
		var highlightEvt : ForceVisionApperanceEvent;
		var target : weak< GameObject >;
		m_newTargetComponent = false;
		target = GameInstance.GetTargetingSystem( playerOwner.GetGame() ).GetTrackedTargetObject( playerOwner );
		if( ( m_curTarget == target ) && ( m_curTarget != NULL ) )
		{
			return;
		}
		ClearTarget( scriptInterface );
		if( target )
		{
			m_curTarget = target;
			highlightEvt = new ForceVisionApperanceEvent;
			m_highlightData = new FocusForcedHighlightData;
			m_highlightData.sourceID = playerOwner.GetEntityID();
			m_highlightData.sourceName = playerOwner.GetClassName();
			if( GameObject.GetAttitudeTowards( playerOwner, m_curTarget ) == EAIAttitude.AIA_Hostile )
			{
				m_curTargetHostile = true;
				SetTargetHighlight( EAIAttitude.AIA_Hostile, m_highlightData );
			}
			else
			{
				m_curTargetHostile = false;
				SetTargetHighlight( EAIAttitude.AIA_Neutral, m_highlightData );
			}
			m_highlightData.inTransitionTime = 0.0;
			m_highlightData.outTransitionTime = 0.0;
			m_highlightData.priority = EPriority.High;
			m_highlightData.isRevealed = true;
			highlightEvt.forcedHighlight = m_highlightData;
			highlightEvt.apply = true;
			m_curTarget.QueueEvent( highlightEvt );
		}
	}

	protected function UpdateWeaponData( scriptInterface : StateGameScriptInterface, itemType : gamedataItemType )
	{
		var animFeature : AnimFeature_DriverCombatWeaponData;
		animFeature = new AnimFeature_DriverCombatWeaponData;
		animFeature.weaponType = -1;
		if( itemType == gamedataItemType.Wea_Handgun || itemType == gamedataItemType.Wea_Revolver )
		{
			animFeature.weaponType = 0;
		}
		else if( itemType == gamedataItemType.Wea_SubmachineGun )
		{
			animFeature.weaponType = 1;
		}
		else if( itemType == gamedataItemType.Wea_VehiclePowerWeapon || itemType == gamedataItemType.Wea_VehicleMissileLauncher )
		{
			animFeature.weaponType = 2;
		}
		else if( ( ( ( ( ( ( itemType == gamedataItemType.Wea_Katana || itemType == gamedataItemType.Wea_Sword ) || itemType == gamedataItemType.Wea_OneHandedClub ) || itemType == gamedataItemType.Wea_Machete ) || itemType == gamedataItemType.Wea_LongBlade ) || itemType == gamedataItemType.Wea_ShortBlade ) || itemType == gamedataItemType.Wea_TwoHandedClub ) || itemType == gamedataItemType.Wea_Chainsword )
		{
			animFeature.weaponType = 3;
		}
		else if( itemType == gamedataItemType.Wea_Axe || itemType == gamedataItemType.Wea_Knife )
		{
			animFeature.weaponType = 4;
		}
		AnimationControllerComponent.ApplyFeature( m_executionOwner, 'DriverCombatWeaponData', animFeature );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.DriverCombatWeaponType, ( ( Int32 )( itemType ) ) );
	}

	private function IsPerformingAWheelieOrEndo( vehicleObject : VehicleObject ) : Bool
	{
		var bikeObject : BikeObject;
		bikeObject = ( ( BikeObject )( vehicleObject ) );
		if( !( bikeObject ) )
		{
			return false;
		}
		return bikeObject.IsPerformingAWheelieOrEndo( GetStaticFloatParameterDefault( "wheelieMinCenterOfMassOffset", 0.25 ), GetStaticFloatParameterDefault( "wheelieMinPitch", 30.0 ) );
	}

	private function UpdateVehicleManeuversPerk( scriptInterface : StateGameScriptInterface, timeDelta : Float )
	{
		var vehicleObject : VehicleObject;
		var hasVehicleManeuvers : Bool;
		hasVehicleManeuvers = m_vehicleManeuversTime > 0.0;
		m_vehicleManeuversTime -= timeDelta;
		vehicleObject = ( ( VehicleObject )( scriptInterface.owner ) );
		if( ( vehicleObject.IsInAir() || vehicleObject.IsSkidding( 2.5 ) ) || IsPerformingAWheelieOrEndo( vehicleObject ) )
		{
			m_vehicleManeuversTime = 0.5;
		}
		if( !( hasVehicleManeuvers ) && ( m_vehicleManeuversTime > 0.0 ) )
		{
			StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.DriverCombatVehicleManeuvers" );
		}
		if( hasVehicleManeuvers && ( m_vehicleManeuversTime <= 0.0 ) )
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.DriverCombatVehicleManeuvers" );
		}
	}

	protected virtual function OnAimChange() {}

	protected virtual function OnPerspectiveUpdate( scriptInterface : StateGameScriptInterface ) {}

	protected event OnDriverCombatTargetChange( value : Variant )
	{
		m_newTargetComponent = true;
		if( value.IsValid() )
		{
			m_targetComponent = ( ( weak< weak< IPlacedComponent > > )value );
		}
		else
		{
			m_targetComponent = NULL;
		}
	}

	protected event OnDriverCombatInTPPChange( value : Bool )
	{
		m_driverCombatInTPP = value;
	}

	protected event OnVehicleInTPPChange( value : Bool )
	{
		m_vehicleInTPP = value;
		m_requirePerspectiveUpdate = true;
	}

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var camPerspective : vehicleCameraPerspective;
		var camEvent : vehicleRequestCameraPerspectiveEvent;
		var playerOwner : PlayerPuppet;
		super.OnEnter( stateContext, scriptInterface );
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.InfiniteAmmo" );
		m_executionOwner = scriptInterface.executionOwner;
		m_owner = scriptInterface.owner;
		m_exitReleasedTime = 0.0;
		playerOwner = ( ( PlayerPuppet )( m_executionOwner ) );
		if( playerOwner )
		{
			playerOwner.SetPSIsInDriverCombat( true );
		}
		stateContext.SetPermanentBoolParameter( 'drawnWeapon', false, true );
		m_targetComponentCallback = scriptInterface.localBlackboard.RegisterListenerVariant( GetAllBlackboardDefs().PlayerStateMachine.TrackedTarget, this, 'OnDriverCombatTargetChange' );
		m_driverCombatInTPPCallback = scriptInterface.localBlackboard.RegisterListenerBool( GetAllBlackboardDefs().PlayerStateMachine.IsDriverCombatInTPP, this, 'OnDriverCombatInTPPChange', true );
		m_vehicleInTPPCallback = scriptInterface.localBlackboard.RegisterListenerBool( GetAllBlackboardDefs().PlayerStateMachine.IsVehicleInTPP, this, 'OnVehicleInTPPChange', true );
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.DriverCombat" );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.DriverCombat ) ) );
		SetIsInVehicleDriverCombat( stateContext, true );
		SetVehFppCameraParams( stateContext, scriptInterface, false, , true );
		SetIsWorldRenderPlane( stateContext, true );
		SendAnimFeature( stateContext, scriptInterface );
		camPerspective = ( ( VehicleObject )( scriptInterface.owner ) ).GetCameraManager().GetPersistentPerspective();
		if( camPerspective == vehicleCameraPerspective.TPPClose )
		{
			camEvent = new vehicleRequestCameraPerspectiveEvent;
			camEvent.cameraPerspective = vehicleCameraPerspective.DriverCombatClose;
			scriptInterface.executionOwner.QueueEvent( camEvent );
		}
		else if( camPerspective == vehicleCameraPerspective.TPPMedium )
		{
			camEvent = new vehicleRequestCameraPerspectiveEvent;
			camEvent.cameraPerspective = vehicleCameraPerspective.DriverCombatMedium;
			scriptInterface.executionOwner.QueueEvent( camEvent );
		}
		else if( camPerspective == vehicleCameraPerspective.TPPFar )
		{
			camEvent = new vehicleRequestCameraPerspectiveEvent;
			camEvent.cameraPerspective = vehicleCameraPerspective.DriverCombatFar;
			scriptInterface.executionOwner.QueueEvent( camEvent );
		}
		m_vehicleManeuversTime = 0.0;
	}

	protected virtual function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var playerOwner : PlayerPuppet;
		playerOwner = ( ( PlayerPuppet )( scriptInterface.executionOwner ) );
		m_aimPressed = scriptInterface.GetActionValue( 'CameraAim' ) > 0.0;
		if( scriptInterface.IsActionJustPressed( 'CameraAim' ) || scriptInterface.IsActionJustReleased( 'CameraAim' ) )
		{
			OnAimChange();
		}
		if( m_requirePerspectiveUpdate )
		{
			m_requirePerspectiveUpdate = false;
			OnPerspectiveUpdate( scriptInterface );
		}
		if( m_newTargetComponent )
		{
			OnNewTargetAcquired( playerOwner, scriptInterface );
		}
		if( m_targetComponent )
		{
			UpdateTargetHighlight( playerOwner );
		}
		if( scriptInterface.IsActionJustReleased( 'ToggleVehCamera' ) && !( IsVehicleCameraChangeBlocked( scriptInterface ) ) )
		{
			RequestToggleVehicleDriverCombatCamera( scriptInterface );
		}
		if( scriptInterface.IsActionJustHeld( 'HoldCinematicCamera' ) && !( IsVehicleCameraChangeBlocked( scriptInterface ) ) )
		{
			RequestVehicleCinematicCamera( scriptInterface );
		}
		UpdateVehicleManeuversPerk( scriptInterface, timeDelta );
		if( scriptInterface.IsActionJustReleased( 'Exit' ) )
		{
			m_exitReleasedTime = GetInStateTime();
		}
		if( HandleExitRequest( timeDelta, stateContext, scriptInterface ) )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.UnequipAll, gameEquipAnimationType.Instant );
		}
		else if( ( m_exitReleasedTime != 0.0 ) && ( m_exitReleasedTime < ( GetInStateTime() - 0.2 ) ) )
		{
			m_exitReleasedTime = 0.0;
			stateContext.SetPermanentBoolParameter( 'ForceSafeState', false );
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.UnequipAll );
		}
	}

	protected virtual function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var camEvent : vehicleRequestCameraPerspectiveEvent;
		var playerOwner : PlayerPuppet;
		playerOwner = ( ( PlayerPuppet )( m_executionOwner ) );
		if( playerOwner )
		{
			playerOwner.SetPSIsInDriverCombat( false );
		}
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.InfiniteAmmo" );
		if( m_vehicleManeuversTime > 0.0 )
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.DriverCombatVehicleManeuvers" );
		}
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.DriverCombat", ( ( Uint32 )( 1 ) ) );
		StatusEffectHelper.RemoveStatusEffectsWithTag( m_executionOwner, 'DriverCombatWeaponVFXScaling' );
		scriptInterface.localBlackboard.UnregisterListenerVariant( GetAllBlackboardDefs().PlayerStateMachine.TrackedTarget, m_targetComponentCallback );
		scriptInterface.localBlackboard.UnregisterListenerBool( GetAllBlackboardDefs().PlayerStateMachine.IsVehicleInTPP, m_vehicleInTPPCallback );
		scriptInterface.localBlackboard.UnregisterListenerBool( GetAllBlackboardDefs().PlayerStateMachine.IsDriverCombatInTPP, m_driverCombatInTPPCallback );
		ClearTarget( scriptInterface );
		m_targetComponent = NULL;
		m_newTargetComponent = false;
		stateContext.SetPermanentBoolParameter( 'ForceSafeState', false );
		SetIsInVehicleDriverCombat( stateContext, false );
		ResetVehFppCameraParams( stateContext, scriptInterface );
		SetIsWorldRenderPlane( stateContext, true );
		SendAnimFeature( stateContext, scriptInterface );
		UpdateWeaponData( scriptInterface, gamedataItemType.Invalid );
		if( ( ( VehicleObject )( scriptInterface.owner ) ).GetCameraManager().GetActivePerspective() == vehicleCameraPerspective.DriverCombatClose )
		{
			camEvent = new vehicleRequestCameraPerspectiveEvent;
			camEvent.cameraPerspective = vehicleCameraPerspective.TPPClose;
			scriptInterface.executionOwner.QueueEvent( camEvent );
		}
		else if( ( ( VehicleObject )( scriptInterface.owner ) ).GetCameraManager().GetActivePerspective() == vehicleCameraPerspective.DriverCombatMedium )
		{
			camEvent = new vehicleRequestCameraPerspectiveEvent;
			camEvent.cameraPerspective = vehicleCameraPerspective.TPPMedium;
			scriptInterface.executionOwner.QueueEvent( camEvent );
		}
		else if( ( ( VehicleObject )( scriptInterface.owner ) ).GetCameraManager().GetActivePerspective() == vehicleCameraPerspective.DriverCombatFar )
		{
			camEvent = new vehicleRequestCameraPerspectiveEvent;
			camEvent.cameraPerspective = vehicleCameraPerspective.TPPFar;
			scriptInterface.executionOwner.QueueEvent( camEvent );
		}
	}

	public override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExit( stateContext, scriptInterface );
		super.OnForcedExit( stateContext, scriptInterface );
	}

}

class DriverCombatFirearmsEvents extends DriverCombatEvents
{
	protected var m_attachmentSlotListener : AttachmentSlotsScriptListener;
	protected var m_posAnimFeature : AnimFeature_ProceduralDriverCombatData;
	protected var m_vehicleRecord : Vehicle_Record;
	protected var m_angleDelta : EulerAngles;
	protected var m_localOrientation : EulerAngles;
	protected var m_updateItemType : gamedataItemType;
	protected var m_photoModeActiveListener : CallbackHandle;
	protected var m_isPhotoModeActive : Bool;
	protected const var m_minSwaySpeed : Float;
	default m_minSwaySpeed = 0.1f;
	protected var m_prevSpeed : Float;

	private function UpdateOrientations( scriptInterface : StateGameScriptInterface, playerOwner : PlayerPuppet )
	{
		var targetPosition : Vector4;
		var playerPosition : Vector4;
		var playerForward : Vector4;
		var oldForward : Vector4;
		var newForward : Vector4;
		var playerForwardAngle : EulerAngles;
		var oldForwardAngles : EulerAngles;
		var newForwardAngles : EulerAngles;
		var blackboard : IBlackboard;
		playerForward = playerOwner.GetWorldForward();
		playerForwardAngle = Vector4.ToRotation( playerForward );
		if( m_vehicleInTPP )
		{
			playerPosition = playerOwner.GetWorldPosition();
			playerPosition.Z += 0.75;
			newForward = Vector4.Normalize( targetPosition - playerPosition );
			oldForward = playerOwner.GetWorldForward();
		}
		else
		{
			playerPosition = Matrix.GetTranslation( playerOwner.GetFPPCameraComponent().GetLocalToWorld() );
			oldForward = Vector4.Normalize( Matrix.GetDirectionVector( playerOwner.GetFPPCameraComponent().GetLocalToWorld() ) );
		}
		if( m_targetComponent )
		{
			targetPosition = Matrix.GetTranslation( m_targetComponent.GetLocalToWorld() );
			newForward = Vector4.Normalize( targetPosition - playerPosition );
		}
		else
		{
			blackboard = GameInstance.GetBlackboardSystem( playerOwner.GetGame() ).GetLocalInstanced( playerOwner.GetEntityID(), GetAllBlackboardDefs().PlayerStateMachine );
			targetPosition = blackboard.GetVector4( GetAllBlackboardDefs().PlayerStateMachine.TPPAimPosition );
			newForward = Vector4.Normalize( targetPosition - playerPosition );
		}
		newForward = Vector4.Normalize( newForward );
		oldForward = Vector4.Normalize( oldForward );
		GameInstance.GetDebugDrawHistorySystem( playerOwner.GetGame() ).DrawArrow( playerPosition, newForward, Color( 0, 0, 255, 255 ), "TPPCarOrientationNewForward" );
		GameInstance.GetDebugDrawHistorySystem( playerOwner.GetGame() ).DrawWireSphere( targetPosition, 0.25, Color( 255, 0, 0, 255 ), "TPPCarOrientationTargetPos" );
		GameInstance.GetDebugDrawHistorySystem( playerOwner.GetGame() ).DrawArrow( playerPosition, oldForward, Color( 0, 255, 0, 255 ), "TPPCarOrientationOldForward" );
		newForwardAngles = Vector4.ToRotation( newForward );
		oldForwardAngles = Vector4.ToRotation( oldForward );
		m_angleDelta.Yaw = -( AngleDistance( oldForwardAngles.Yaw, newForwardAngles.Yaw ) );
		m_angleDelta.Pitch = AngleDistance( oldForwardAngles.Pitch, newForwardAngles.Pitch );
		m_angleDelta.Roll = AngleDistance( oldForwardAngles.Roll, newForwardAngles.Roll );
		m_localOrientation.Yaw = AngleDistance( newForwardAngles.Yaw, playerForwardAngle.Yaw );
		m_localOrientation.Pitch = AngleDistance( newForwardAngles.Pitch, playerForwardAngle.Pitch );
	}

	private function UpdateAimingDirectionAnimFeature( playerOwner : PlayerPuppet )
	{
		var animFeatureYawDelta : Float;
		if( !( m_vehicleInTPP ) && !( m_targetComponent ) )
		{
			m_posAnimFeature.isEnabled = false;
			m_posAnimFeature.yaw = 0.0;
			m_posAnimFeature.pitch = 0.0;
			m_posAnimFeature.roll = 0.0;
			return;
		}
		m_posAnimFeature.isEnabled = true;
		if( ( AbsF( m_angleDelta.Yaw ) > 167.0 ) && ( SgnF( m_angleDelta.Yaw ) != SgnF( m_posAnimFeature.yaw ) ) )
		{
			animFeatureYawDelta = 180.0 * SgnF( m_posAnimFeature.yaw );
		}
		else
		{
			animFeatureYawDelta = m_angleDelta.Yaw;
		}
		animFeatureYawDelta = ClampF( animFeatureYawDelta, -167.0, 167.0 );
		if( ( ( SgnF( m_posAnimFeature.yaw ) != SgnF( animFeatureYawDelta ) ) && ( AbsF( animFeatureYawDelta ) > 90.0 ) ) && ( AbsF( m_posAnimFeature.yaw ) > 90.0 ) )
		{
			m_posAnimFeature.yawDirectionFlipped = true;
		}
		else
		{
			m_posAnimFeature.yawDirectionFlipped = false;
		}
		m_posAnimFeature.yaw = animFeatureYawDelta;
		m_posAnimFeature.pitch = m_angleDelta.Pitch;
		m_posAnimFeature.roll = m_angleDelta.Roll;
	}

	private function UpdateSafeMode( scriptInterface : StateGameScriptInterface, stateContext : StateContext, yaw : Float )
	{
		var weaponBounds : weak< WeaponSafeModeBounds_Record >;
		var windshieldBound : weak< WeaponSafeModeBound_Record >;
		var backBound : weak< WeaponSafeModeBound_Record >;
		var lookingAtWindshield : Bool;
		var lookingBehind : Bool;
		var forceSafeState : StateResultBool;
		weaponBounds = m_vehicleRecord.WeaponSafeModeBounds();
		if( !( weaponBounds.EnableSafeModeBounds() ) )
		{
			return;
		}
		windshieldBound = weaponBounds.WindshieldBound();
		backBound = weaponBounds.BackBound();
		lookingAtWindshield = ( yaw < windshieldBound.YawMax() ) && ( yaw > windshieldBound.YawMin() );
		lookingBehind = ( yaw > backBound.YawMax() ) || ( yaw < backBound.YawMin() );
		forceSafeState = stateContext.GetTemporaryBoolParameter( 'ForceWeaponSafeState' );
		if( lookingAtWindshield || ( lookingBehind && !( m_vehicleInTPP ) ) )
		{
			if( !( forceSafeState.value ) )
			{
				stateContext.SetTemporaryBoolParameter( 'ForceWeaponSafeState', true, true );
			}
		}
		else if( forceSafeState.value )
		{
			stateContext.SetTemporaryBoolParameter( 'ForceWeaponSafeState', false );
		}
	}

	protected function ApplyWeaponFxScalings( itemType : gamedataItemType )
	{
		var statusEffect : TweakDBID;
		if( itemType == gamedataItemType.Wea_Handgun )
		{
			statusEffect = ( ( m_driverCombatInTPP ) ? ( T"BaseStatusEffect.DriverCombatHandgunVFXScale" ) : ( T"BaseStatusEffect.DriverCombatHandgunFPPVFXScale" ) );
		}
		else if( itemType == gamedataItemType.Wea_Revolver )
		{
			if( m_driverCombatInTPP )
			{
				statusEffect = T"BaseStatusEffect.DriverCombatRevolverVFXScale";
			}
			else
			{
				statusEffect = T"BaseStatusEffect.DriverCombatRevolverFPPVFXScale";
			}
		}
		else if( itemType == gamedataItemType.Wea_SubmachineGun )
		{
			if( m_driverCombatInTPP )
			{
				statusEffect = T"BaseStatusEffect.DriverCombatSMGVFXScale";
			}
			else
			{
				statusEffect = T"BaseStatusEffect.DriverCombatSMGFPPVFXScale";
			}
		}
		StatusEffectHelper.RemoveStatusEffectsWithTag( m_executionOwner, 'DriverCombatWeaponVFXScaling' );
		if( TDBID.IsValid( statusEffect ) )
		{
			StatusEffectHelper.ApplyStatusEffect( m_executionOwner, statusEffect );
		}
	}

	protected override function OnPerspectiveUpdate( scriptInterface : StateGameScriptInterface )
	{
		ApplyWeaponFxScalings( WeaponObject.GetWeaponType( scriptInterface.GetTransactionSystem().GetItemInSlot( scriptInterface.executionOwner, T"AttachmentSlots.WeaponRight" ).GetItemID() ) );
		UpdateWeaponSwayRemoval( m_vehicleInTPP );
		UpdateWeaponSwayPause( !( m_vehicleInTPP ) && ( AbsF( ( ( VehicleObject )( m_owner ) ).GetCurrentSpeed() ) > m_minSwaySpeed ) );
		if( m_vehicleInTPP )
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.PhotoModeForceFPPCamera" );
		}
		else
		{
			StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.PhotoModeForceFPPCamera" );
		}
	}

	private override function OnItemEquipped( slot : TweakDBID, item : ItemID )
	{
		if( slot == T"AttachmentSlots.WeaponRight" )
		{
			m_updateItemType = WeaponObject.GetWeaponType( item );
		}
	}

	private function UpdateItemEquipped( scriptInterface : StateGameScriptInterface, itemType : gamedataItemType )
	{
		UpdateWeaponData( scriptInterface, itemType );
		ApplyWeaponFxScalings( itemType );
		EnableSmartGunHandler( false );
		UpdatePistolADSSpread( itemType == gamedataItemType.Wea_Handgun || itemType == gamedataItemType.Wea_Revolver );
	}

	private function EnableSmartGunHandler( enable : Bool )
	{
		var weapon : WeaponObject;
		var transactionSystem : TransactionSystem;
		var evt : EnableSmartGunHandlerEvent;
		var weaponRecData : WeaponItem_Record;
		transactionSystem = GameInstance.GetTransactionSystem( m_executionOwner.GetGame() );
		weapon = ( ( WeaponObject )( transactionSystem.GetItemInSlot( m_executionOwner, T"AttachmentSlots.WeaponRight" ) ) );
		weaponRecData = weapon.GetWeaponRecord();
		if( weaponRecData.Evolution().Type() == gamedataWeaponEvolution.Smart )
		{
			evt = new EnableSmartGunHandlerEvent;
			evt.owner = m_executionOwner;
			evt.enable = enable;
			weapon.QueueEvent( evt );
		}
	}

	protected override function OnAimChange()
	{
		super.OnAimChange();
		EnableSmartGunHandler( m_aimPressed );
	}

	private function RollDownWindowsForCombat( scriptInterface : StateGameScriptInterface, value : Bool )
	{
		ToggleWindowForOccupiedSeat( scriptInterface, 'seat_front_right', value );
		ToggleWindowForOccupiedSeat( scriptInterface, 'seat_front_left', value );
	}

	private function UpdatePistolADSSpread( applyEffect : Bool )
	{
		if( applyEffect )
		{
			StatusEffectHelper.ApplyStatusEffect( m_executionOwner, T"BaseStatusEffect.DriverCombatPistol" );
		}
		else
		{
			StatusEffectHelper.RemoveStatusEffect( m_executionOwner, T"BaseStatusEffect.DriverCombatPistol" );
		}
	}

	private function UpdateWeaponSwayRemoval( applyEffect : Bool )
	{
		if( applyEffect )
		{
			StatusEffectHelper.ApplyStatusEffect( m_executionOwner, T"BaseStatusEffect.DriverCombatSwayRemoval" );
		}
		else
		{
			StatusEffectHelper.RemoveStatusEffect( m_executionOwner, T"BaseStatusEffect.DriverCombatSwayRemoval" );
		}
	}

	private function UpdateWeaponSwayPause( applyEffect : Bool )
	{
		if( applyEffect )
		{
			StatusEffectHelper.ApplyStatusEffect( m_executionOwner, T"BaseStatusEffect.DriverCombatSwayPause" );
		}
		else
		{
			StatusEffectHelper.RemoveStatusEffect( m_executionOwner, T"BaseStatusEffect.DriverCombatSwayPause" );
		}
	}

	protected event OnPhotomodeUpdate( isInPhotoMode : Bool )
	{
		m_isPhotoModeActive = isInPhotoMode;
	}

	protected export function OnAttach( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface )
	{
		m_photoModeActiveListener = GameInstance.GetBlackboardSystem( scriptInterface.executionOwner.GetGame() ).Get( GetAllBlackboardDefs().PhotoMode ).RegisterListenerBool( GetAllBlackboardDefs().PhotoMode.IsActive, this, 'OnPhotomodeUpdate' );
		m_isPhotoModeActive = false;
	}

	protected export function OnDetach( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface )
	{
		GameInstance.GetBlackboardSystem( scriptInterface.executionOwner.GetGame() ).Get( GetAllBlackboardDefs().PhotoMode ).UnregisterListenerBool( GetAllBlackboardDefs().PhotoMode.IsActive, m_photoModeActiveListener );
		m_photoModeActiveListener = NULL;
	}

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var attachmentSlotCallback : DefaultTransitionAttachmentSlotsCallback;
		var drawItemRequest : DrawItemRequest;
		super.OnEnter( stateContext, scriptInterface );
		m_prevSpeed = ( ( VehicleObject )( m_owner ) ).GetCurrentSpeed();
		m_posAnimFeature = new AnimFeature_ProceduralDriverCombatData;
		attachmentSlotCallback = new DefaultTransitionAttachmentSlotsCallback;
		attachmentSlotCallback.m_transitionOwner = this;
		attachmentSlotCallback.slotID = T"AttachmentSlots.WeaponRight";
		m_attachmentSlotListener = scriptInterface.GetTransactionSystem().RegisterAttachmentSlotListener( scriptInterface.executionOwner, attachmentSlotCallback );
		RollDownWindowsForCombat( scriptInterface, true );
		m_vehicleRecord = TweakDBInterface.GetVehicleRecord( ( ( VehicleObject )( scriptInterface.owner ) ).GetRecordID() );
		if( !( UpperBodyTransition.HasAnyWeaponEquipped( scriptInterface ) ) )
		{
			drawItemRequest = new DrawItemRequest;
			drawItemRequest.owner = scriptInterface.executionOwner;
			drawItemRequest.itemID = ItemID.CreateQuery( T"Items.Preset_V_Unity_Cutscene" );
			( ( EquipmentSystem )( scriptInterface.GetScriptableSystem( 'EquipmentSystem' ) ) ).QueueRequest( drawItemRequest );
		}
		else
		{
			OnItemEquipped( T"AttachmentSlots.WeaponRight", scriptInterface.GetTransactionSystem().GetItemInSlot( scriptInterface.executionOwner, T"AttachmentSlots.WeaponRight" ).GetItemID() );
		}
		SetFactValue( scriptInterface.executionOwner.GetGame(), 'player_tried_veh_combat_firearms', 1 );
		if( !( m_vehicleInTPP ) )
		{
			StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.PhotoModeForceFPPCamera" );
		}
	}

	protected override function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var vehicleSpeed : Float;
		var weaponObject : WeaponObject;
		var ammoType : ItemID;
		var magazineCapacity : Uint32;
		var ammoCount : Int32;
		var ammoDiff : Int32;
		var questForceEnableCombat : StateResultBool;
		var driverCombatForbiddenZone : StateResultBool;
		super.OnUpdate( timeDelta, stateContext, scriptInterface );
		if( !( m_isPhotoModeActive ) )
		{
			UpdateOrientations( scriptInterface, ( ( PlayerPuppet )( m_executionOwner ) ) );
			UpdateAimingDirectionAnimFeature( ( ( PlayerPuppet )( m_executionOwner ) ) );
			UpdateSafeMode( scriptInterface, stateContext, m_localOrientation.Yaw );
			stateContext.SetPermanentFloatParameter( 'TPPVehiclePlayerYaw', m_posAnimFeature.yaw, true );
		}
		if( m_updateItemType != gamedataItemType.Invalid )
		{
			UpdateItemEquipped( scriptInterface, m_updateItemType );
			m_updateItemType = gamedataItemType.Invalid;
			weaponObject = GetActiveWeapon( scriptInterface );
			if( weaponObject )
			{
				ammoType = WeaponObject.GetAmmoType( weaponObject );
				ammoCount = scriptInterface.GetTransactionSystem().GetItemQuantity( scriptInterface.executionOwner, ammoType );
				magazineCapacity = WeaponObject.GetMagazineCapacity( weaponObject );
				ammoDiff = ( ( Int32 )( ( magazineCapacity * 2 ) ) ) - ammoCount;
				if( ammoDiff > 0 )
				{
					scriptInterface.GetTransactionSystem().GiveItem( scriptInterface.executionOwner, ammoType, ammoDiff );
				}
			}
		}
		questForceEnableCombat = stateContext.GetTemporaryBoolParameter( 'stopVehicleCombat' );
		driverCombatForbiddenZone = stateContext.GetPermanentBoolParameter( 'driverCombatForbiddenZone' );
		if( ( questForceEnableCombat.valid && questForceEnableCombat.value ) || ( driverCombatForbiddenZone.valid && driverCombatForbiddenZone.value ) )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.UnequipAll );
		}
		vehicleSpeed = ( ( VehicleObject )( m_owner ) ).GetCurrentSpeed();
		if( !( m_vehicleInTPP ) && ( AbsF( vehicleSpeed ) > m_minSwaySpeed ) != ( AbsF( m_prevSpeed ) > m_minSwaySpeed ) )
		{
			UpdateWeaponSwayPause( AbsF( vehicleSpeed ) > m_minSwaySpeed );
		}
		m_prevSpeed = vehicleSpeed;
		if( !( m_isPhotoModeActive ) )
		{
			scriptInterface.SetAnimationParameterFeature( 'ProceduralDriverCombatData', m_posAnimFeature, scriptInterface.executionOwner );
		}
	}

	protected override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnForcedExit( stateContext, scriptInterface );
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.PhotoModeForceFPPCamera" );
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnExit( stateContext, scriptInterface );
		scriptInterface.GetTransactionSystem().UnregisterAttachmentSlotListener( scriptInterface.executionOwner, m_attachmentSlotListener );
		UpdateWeaponSwayRemoval( false );
		UpdateWeaponSwayPause( false );
		UpdatePistolADSSpread( false );
		m_posAnimFeature.yaw = 0.0;
		m_posAnimFeature.pitch = 0.0;
		m_posAnimFeature.roll = 0.0;
		scriptInterface.SetAnimationParameterFeature( 'ProceduralDriverCombatData', m_posAnimFeature, scriptInterface.executionOwner );
		stateContext.SetTemporaryBoolParameter( 'ForceWeaponSafeState', false );
		RollDownWindowsForCombat( scriptInterface, false );
		SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.UnequipAll );
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.PhotoModeForceFPPCamera" );
	}

}

class DriverCombatMountedWeaponsEvents extends DriverCombatEvents
{
	private var m_activeWeapons : array< weak< WeaponObject > >;

	protected function GetVehicleWeaponType( vehicle : VehicleObject ) : gamedataItemType
	{
		var weapons : array< weak< WeaponObject > >;
		vehicle.GetActiveWeapons( weapons );
		if( ( weapons.Size() > 0 ) && weapons[ 0 ] )
		{
			return WeaponObject.GetWeaponType( weapons[ 0 ].GetItemID() );
		}
		return gamedataItemType.Invalid;
	}

	protected function ApplyWeaponFxScalings()
	{
		var i : Int32;
		var statusEffect : TweakDBID;
		statusEffect = T"BaseStatusEffect.DriverCombatMountedWeaponVFXScale";
		for( i = 0; i < m_activeWeapons.Size(); i += 1 )
		{
			StatusEffectHelper.RemoveStatusEffectsWithTag( m_activeWeapons[ i ], 'DriverCombatWeaponVFXScaling' );
			StatusEffectHelper.ApplyStatusEffect( m_activeWeapons[ i ], statusEffect );
		}
	}

	protected override function OnPerspectiveUpdate( scriptInterface : StateGameScriptInterface )
	{
		if( m_activeWeapons.Size() <= 0 )
		{
			return;
		}
		ApplyWeaponFxScalings();
		if( WeaponObject.GetWeaponType( m_activeWeapons[ 0 ].GetItemID() ) == gamedataItemType.Wea_VehiclePowerWeapon )
		{
			SetWeaponPreviews( false, scriptInterface );
			SetWeaponPreviews( true, scriptInterface );
		}
	}

	protected function SetWeaponPreviews( active : Bool, scriptInterface : StateGameScriptInterface )
	{
		var weapon : WeaponObject;
		var tppEffectScale : Float;
		var i : Int32;
		for( i = 0; i < m_activeWeapons.Size(); i += 1 )
		{
			if( active )
			{
				tppEffectScale = 1.0;
				if( m_vehicleInTPP )
				{
					weapon = ( ( WeaponObject )( m_activeWeapons[ i ] ) );
					if( weapon && weapon.IsVehiclePowerWeaponRear( m_owner ) )
					{
						tppEffectScale = 2.0;
					}
				}
				m_activeWeapons[ i ].GetCurrentAttack().SetVehicleWeaponPreviewActive( true, IPositionProvider.CreateEntityPositionProvider( m_activeWeapons[ i ] ), IOrientationProvider.CreateEntityOrientationProvider( NULL, '', m_activeWeapons[ i ] ), 200.0, 0.0, ( ( Uint32 )( i ) ), m_vehicleInTPP, tppEffectScale );
			}
			else
			{
				m_activeWeapons[ i ].GetCurrentAttack().SetPreviewActive( false );
			}
		}
	}

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnEnter( stateContext, scriptInterface );
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.InfiniteAmmo" );
		SetFactValue( scriptInterface.executionOwner.GetGame(), 'player_tried_veh_combat_mounted_weapons', 1 );
	}

	protected override function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var weapons : array< weak< WeaponObject > >;
		super.OnUpdate( timeDelta, stateContext, scriptInterface );
		( ( VehicleObject )( scriptInterface.owner ) ).GetActiveWeapons( weapons );
		if( ( ( weapons.Size() > 0 ) && ( m_activeWeapons.Size() != weapons.Size() ) ) && ( weapons[ 0 ] != m_activeWeapons[ 0 ] ) )
		{
			if( WeaponObject.GetWeaponType( m_activeWeapons[ 0 ].GetItemID() ) == gamedataItemType.Wea_VehiclePowerWeapon )
			{
				SetWeaponPreviews( false, scriptInterface );
			}
			m_activeWeapons = weapons;
			UpdateWeaponData( scriptInterface, WeaponObject.GetWeaponType( m_activeWeapons[ 0 ].GetItemID() ) );
			ApplyWeaponFxScalings();
			if( WeaponObject.GetWeaponType( m_activeWeapons[ 0 ].GetItemID() ) == gamedataItemType.Wea_VehiclePowerWeapon )
			{
				SetWeaponPreviews( true, scriptInterface );
			}
		}
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnExit( stateContext, scriptInterface );
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.InfiniteAmmo" );
		SetWeaponPreviews( false, scriptInterface );
		m_activeWeapons.Clear();
	}

}

class ExitingDecisions extends VehicleTransition
{

	public export const virtual function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var exitRequest : StateResultBool;
		var submergedExitRequest : StateResultBool;
		var exitAfterRequest : StateResultBool;
		var switchExitRequest : StateResultBool;
		exitRequest = stateContext.GetPermanentBoolParameter( 'validExitRequest' );
		submergedExitRequest = stateContext.GetPermanentBoolParameter( 'submergedExitRequest' );
		switchExitRequest = stateContext.GetPermanentBoolParameter( 'validSwitchSeatExitRequest' );
		exitAfterRequest = stateContext.GetPermanentBoolParameter( 'validExitAfterSwitchRequest' );
		if( IsVehicleExitBlocked1Frame( stateContext, scriptInterface ) )
		{
			return false;
		}
		if( submergedExitRequest.value )
		{
			return true;
		}
		if( exitRequest.value )
		{
			return true;
		}
		if( ( !( switchExitRequest.value ) && exitAfterRequest.value ) && ( GetInStateTime() >= 0.05 ) )
		{
			return true;
		}
		if( IsExitForced( stateContext ) || !( scriptInterface.owner ) )
		{
			return true;
		}
		return false;
	}

	public export const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var unmountData : MountEventData;
		if( IsExitForced( stateContext ) )
		{
			unmountData = GetUnmountingEvent( stateContext );
			return !( IsInVehicleWorkspot( scriptInterface, unmountData.slotName ) );
		}
		else
		{
			return !( scriptInterface.GetWorkspotSystem().IsActorInWorkspot( scriptInterface.executionOwner ) );
		}
	}

	protected const function IsCoolExitAllowed( stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( stateContext.GetIntParameter( 'vehClass', true ) == 2 )
		{
			return false;
		}
		if( !( PlayerDevelopmentSystem.GetData( scriptInterface.executionOwner ).IsNewPerkBoughtAnyLevel( gamedataNewPerkType.Reflexes_Left_Milestone_1 ) ) )
		{
			return false;
		}
		return true;
	}

}

class ExitingEventsBase extends VehicleEventsTransition
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnEnter( stateContext, scriptInterface );
		stateContext.SetPermanentBoolParameter( 'coolExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'submergedExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'validExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'validExitAfterSwitchRequest', false, true );
		stateContext.SetConditionBoolParameter( 'VisionToggled', false, true );
		ForceDisableVisionMode( stateContext );
		TryToStopVehicle( stateContext, scriptInterface );
		PlayVehicleExitDoorAnimation( stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Transition ) ) );
		PlayerStateChange( scriptInterface, 4 );
	}

	public export virtual function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetVehicleStatusEffects( stateContext, scriptInterface, false );
		SendAnimFeature( stateContext, scriptInterface );
		if( IsPlayerInCombat( scriptInterface ) )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedWeapon );
		}
	}

	protected function StartExiting( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var audioEvt : VehicleAudioEvent;
		StartLeavingVehicle( stateContext, scriptInterface );
		audioEvt = new VehicleAudioEvent;
		audioEvt.action = vehicleAudioEventAction.OnPlayerExitVehicle;
		scriptInterface.owner.QueueEvent( audioEvt );
		stateContext.SetPermanentBoolParameter( 'startedExiting', true, true );
	}

}

class ExitingEvents extends ExitingEventsBase
{
	var m_fromDriverCombat : Bool;
	default m_fromDriverCombat = false;

	public function OnEnterFromDriverCombatFirearms( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		m_fromDriverCombat = true;
		OnEnter( stateContext, scriptInterface );
	}

	public function OnEnterFromDriverCombatMountedWeapons( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		m_fromDriverCombat = true;
		OnEnter( stateContext, scriptInterface );
	}

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var exitDelay : Float;
		super.OnEnter( stateContext, scriptInterface );
		exitDelay = GetVehicleDataPackage( stateContext ).ExitDelay();
		if( exitDelay == 0.0 )
		{
			StartExiting( stateContext, scriptInterface );
		}
	}

	public export virtual function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var exitDelay : Float;
		var startedExiting : StateResultBool;
		var vehicle : weak< VehicleObject >;
		var validUnmount : vehicleUnmountPosition;
		var unmountDirResult : StateResultInt;
		var isTeleportExiting : StateResultBool;
		var oldExitDirection : vehicleExitDirection;
		exitDelay = GetVehicleDataPackage( stateContext ).ExitDelay();
		startedExiting = stateContext.GetPermanentBoolParameter( 'startedExiting' );
		isTeleportExiting = stateContext.GetPermanentBoolParameter( 'teleportExitActive' );
		if( exitDelay > 0.0 )
		{
			if( ( GetInStateTime() >= exitDelay ) && !( startedExiting.value ) )
			{
				StartExiting( stateContext, scriptInterface );
			}
		}
		if( ( startedExiting.value && !( isTeleportExiting.value ) ) && ( GetInStateTime() >= 1.0 ) )
		{
			vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
			unmountDirResult = stateContext.GetPermanentIntParameter( 'vehUnmountDir' );
			if( unmountDirResult.valid )
			{
				oldExitDirection = ( ( vehicleExitDirection )( unmountDirResult.value ) );
				validUnmount = vehicle.CanUnmount( true, scriptInterface.executionOwner, oldExitDirection );
				if( validUnmount.direction != oldExitDirection )
				{
					validUnmount = vehicle.CanUnmount( true, scriptInterface.executionOwner, vehicleExitDirection.Back );
					validUnmount = vehicle.CanUnmount( true, scriptInterface.executionOwner, vehicleExitDirection.Back );
					if( validUnmount.direction == vehicleExitDirection.NoDirection )
					{
						validUnmount = vehicle.CanUnmount( true, scriptInterface.executionOwner );
					}
					if( validUnmount.direction != vehicleExitDirection.NoDirection )
					{
						scriptInterface.GetWorkspotSystem().StopNpcInWorkspot( scriptInterface.executionOwner );
						ExitWithTeleport( stateContext, scriptInterface, validUnmount, false, true );
					}
				}
			}
		}
	}

	public override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnForcedExit( stateContext, scriptInterface );
	}

	public override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnExit( stateContext, scriptInterface );
		stateContext.SetTemporaryFloatParameter( 'unmountDelay', GetStaticFloatParameterDefault( "brakingDelay", 0.0 ), true );
		if( m_fromDriverCombat )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon, gameEquipAnimationType.Instant );
		}
	}

}

class ImmediateExitWithForceEvents extends ExitingEventsBase
{
	var exitForce : StateResultVector;
	var bikeForce : StateResultVector;
	var knockOverBike : KnockOverBikeEvent;

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnEnter( stateContext, scriptInterface );
		knockOverBike = new KnockOverBikeEvent;
		knockOverBike.forceKnockdown = true;
		Unmount( scriptInterface, stateContext );
		scriptInterface.owner.QueueEvent( knockOverBike );
		exitForce = stateContext.GetTemporaryVectorParameter( 'ExitForce' );
		bikeForce = stateContext.GetTemporaryVectorParameter( 'BikeForce' );
	}

	public override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnForcedExit( stateContext, scriptInterface );
		ApplyCounterForce( scriptInterface, stateContext );
	}

	public override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnExit( stateContext, scriptInterface );
		ApplyCounterForce( scriptInterface, stateContext );
	}

	protected override function ExitWorkspot( stateContext : StateContext, scriptInterface : StateGameScriptInterface, isInstant : Bool, optional isUpsidedown : Bool )
	{
		var workspotSystem : WorkspotGameSystem;
		workspotSystem = scriptInterface.GetWorkspotSystem();
		workspotSystem.StopNpcInWorkspot( scriptInterface.executionOwner );
	}

	protected function Unmount( scriptInterface : StateGameScriptInterface, stateContext : StateContext )
	{
		var unmountEvent : UnmountingRequest;
		var mountingInfo : MountingInfo;
		unmountEvent = new UnmountingRequest;
		mountingInfo.childId = scriptInterface.executionOwnerEntityID;
		unmountEvent.lowLevelMountingInfo = mountingInfo;
		unmountEvent.mountData = new MountEventData;
		unmountEvent.mountData.isInstant = true;
		scriptInterface.GetMountingFacility().Unmount( unmountEvent );
	}

	protected function ApplyCounterForce( scriptInterface : StateGameScriptInterface, stateContext : StateContext )
	{
		var impulseEvent : PSMImpulse;
		var bikeImpulseEvent : PhysicalImpulseEvent;
		var vehicle : weak< VehicleObject >;
		var tempVec4 : Vector4;
		if( exitForce.valid )
		{
			impulseEvent = new PSMImpulse;
			impulseEvent.id = 'impulse';
			impulseEvent.impulse = exitForce.value;
			scriptInterface.executionOwner.QueueEvent( impulseEvent );
		}
		if( bikeForce.valid )
		{
			vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
			bikeImpulseEvent = new PhysicalImpulseEvent;
			tempVec4 = vehicle.GetWorldPosition();
			bikeImpulseEvent.worldPosition.X = tempVec4.X;
			bikeImpulseEvent.worldPosition.Y = tempVec4.Y;
			bikeImpulseEvent.worldPosition.Z = tempVec4.Z;
			tempVec4 = bikeForce.value;
			bikeImpulseEvent.worldImpulse.X = tempVec4.X;
			bikeImpulseEvent.worldImpulse.Y = tempVec4.Y;
			bikeImpulseEvent.worldImpulse.Z = tempVec4.Z;
			vehicle.QueueEvent( bikeImpulseEvent );
		}
	}

}

class CollisionExitingDecisions extends ExitingDecisions
{

	public export const override function EnterCondition( stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var recordID : TweakDBID;
		var vehicleRecord : Vehicle_Record;
		var vehicleDataPackage : weak< VehicleDataPackage_Record >;
		var bike : BikeObject;
		var collisionForce : Vector4;
		var vehicleUp : Vector4;
		var collisionUp : Vector4;
		var impulse : Vector4;
		var collForceSqr : Float;
		var knockOffForceSqr : Float;
		bike = ( ( BikeObject )( scriptInterface.owner ) );
		if( bike )
		{
			collisionForce = bike.GetCollisionForce();
			collForceSqr = Vector4.LengthSquared( collisionForce );
			if( collForceSqr > 0.1 )
			{
				recordID = ( ( VehicleObject )( scriptInterface.owner ) ).GetRecordID();
				vehicleRecord = TweakDBInterface.GetVehicleRecord( recordID );
				vehicleDataPackage = vehicleRecord.VehDataPackage();
				knockOffForceSqr = vehicleDataPackage.KnockOffForce();
				knockOffForceSqr *= knockOffForceSqr;
				if( ( collForceSqr > knockOffForceSqr ) || ( bike.ComputeIsVehicleUpsideDown() && ( collForceSqr > 25.0 ) ) )
				{
					if( bike.IsAirControlEnabled() )
					{
						vehicleUp = bike.GetWorldUp();
						collisionUp = vehicleUp * Vector4.Dot( collisionForce, vehicleUp );
						collisionForce -= collisionUp;
					}
					impulse = -( collisionForce );
					impulse += ( 4.0 * bike.GetWorldUp() );
					stateContext.SetTemporaryVectorParameter( 'ExitForce', impulse, true );
					SetBikeForce( stateContext, bike, collisionForce );
					return true;
				}
				else
				{
					bike.EnableAirControl( true );
					bike.EnableTiltControl( true );
				}
			}
		}
		return false;
	}

	public const function SetBikeForce( stateContext : StateContext, vehicle : VehicleObject, collisionForce : Vector4 )
	{
		var bikeImpulse : Vector4;
		var bikeMass : Float;
		bikeImpulse = collisionForce;
		bikeImpulse = Vector4.Normalize( bikeImpulse );
		bikeMass = vehicle.GetTotalMass();
		bikeImpulse *= ( bikeMass * 3.79999995 );
		stateContext.SetTemporaryVectorParameter( 'BikeForce', bikeImpulse, true );
	}

}

class CollisionExitingEvents extends ImmediateExitWithForceEvents
{
	var m_animFeatureStatusEffect : AnimFeature_StatusEffect;

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var impulse : StateResultVector;
		var collisionDirection : Vector4;
		var statusEffectRecord : weak< StatusEffect_Record >;
		var stackcount : Uint32;
		collisionDirection = Vector4( 0.0, 0.0, 0.0, 0.0 );
		stackcount = 1;
		super.OnEnter( stateContext, scriptInterface );
		impulse = stateContext.GetTemporaryVectorParameter( 'ExitForce' );
		if( impulse.valid )
		{
			collisionDirection = -( impulse.value );
		}
		statusEffectRecord = TweakDBInterface.GetStatusEffectRecord( T"BaseStatusEffect.BikeKnockdown" );
		GameInstance.GetStatusEffectSystem( scriptInterface.GetGame() ).ApplyStatusEffect( scriptInterface.executionOwnerEntityID, statusEffectRecord.GetID(), GameObject.GetTDBID( scriptInterface.owner ), scriptInterface.ownerEntityID, stackcount, collisionDirection );
		m_animFeatureStatusEffect = new AnimFeature_StatusEffect;
		StatusEffectHelper.PopulateStatusEffectAnimData( scriptInterface.executionOwner, statusEffectRecord, EKnockdownStates.Start, collisionDirection, m_animFeatureStatusEffect );
		scriptInterface.SetAnimationParameterFeature( 'StatusEffect', m_animFeatureStatusEffect, scriptInterface.executionOwner );
		stateContext.SetPermanentFloatParameter( StatusEffectHelper.GetStateStartTimeKey(), EngineTime.ToFloat( scriptInterface.GetTimeSystem().GetSimTime() ), true );
		stateContext.SetPermanentScriptableParameter( StatusEffectHelper.GetForceKnockdownKey(), statusEffectRecord, true );
		if( exitForce.valid )
		{
			stateContext.SetPermanentVectorParameter( StatusEffectHelper.GetForcedKnockdownImpulseKey(), exitForce.value, true );
		}
		PlaySound( 'v_mbike_dst_crash_fall', scriptInterface );
	}

}

class DeathExitingDecisions extends ExitingDecisions
{

	public export const override function EnterCondition( stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var playerOwner : PlayerPuppet;
		var vehicle : VehicleObject;
		var impulse : Vector4;
		var vehicleVelocity : Vector4;
		if( stateContext.GetIntParameter( 'vehClass', true ) != 1 )
		{
			return false;
		}
		playerOwner = ( ( PlayerPuppet )( scriptInterface.executionOwner ) );
		if( !( playerOwner ) )
		{
			return false;
		}
		if( !( playerOwner.IsDead() ) && !( scriptInterface.owner.IsDead() ) )
		{
			return false;
		}
		if( scriptInterface.owner.IsDead() )
		{
			impulse = playerOwner.GetWorldForward();
		}
		else
		{
			vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
			vehicleVelocity = vehicle.GetLinearVelocity();
			if( Vector4.LengthSquared( vehicleVelocity ) < 0.1 )
			{
				impulse = playerOwner.GetWorldForward();
			}
			else
			{
				impulse = Vector4.Normalize( vehicleVelocity );
			}
		}
		impulse *= -9.0;
		stateContext.SetTemporaryVectorParameter( 'ExitForce', impulse, true );
		return true;
	}

}

class DeathExitingEvents extends ImmediateExitWithForceEvents
{
}

class CombatExitingDecisions extends ExitingDecisions
{

	public export const override function EnterCondition( stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var exitRequest : StateResultBool;
		var vehicleObject : weak< VehicleObject >;
		if( GetVehClass( stateContext, scriptInterface ) == 2 )
		{
			return false;
		}
		if( IsVehicleExitBlocked1Frame( stateContext, scriptInterface ) )
		{
			return false;
		}
		exitRequest = stateContext.GetPermanentBoolParameter( 'validExitRequest' );
		if( exitRequest.value )
		{
			if( IsPlayerInCombat( scriptInterface ) )
			{
				return true;
			}
			if( VehicleComponent.GetVehicle( scriptInterface.GetGame(), scriptInterface.executionOwnerEntityID, vehicleObject ) )
			{
				if( vehicleObject.GetVehicleComponent().IsVehicleInDecay() )
				{
					return true;
				}
			}
		}
		return false;
	}

}

class CombatExitingEvents extends ExitingEvents
{
	default m_exitSlot = 'combat';

	public export override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnExit( stateContext, scriptInterface );
		SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon, gameEquipAnimationType.Instant );
	}

}

class SpeedExitingDecisions extends ExitingDecisions
{

	public export const override function EnterCondition( stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var exitRequest : StateResultBool;
		var vehicle : VehicleObject;
		var vehClass : Int32;
		var exitDirection : vehicleUnmountPosition;
		vehClass = stateContext.GetIntParameter( 'vehClass', true );
		if( vehClass == 2 )
		{
			return false;
		}
		if( IsVehicleExitBlocked1Frame( stateContext, scriptInterface ) )
		{
			return false;
		}
		exitRequest = stateContext.GetPermanentBoolParameter( 'validExitRequest' );
		if( exitRequest.value )
		{
			vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
			if( vehClass == 1 )
			{
				exitDirection = vehicle.CanUnmount( true, scriptInterface.executionOwner, vehicleExitDirection.Left );
				if( exitDirection.direction == vehicleExitDirection.NoDirection )
				{
					return false;
				}
			}
			return vehicle.GetCurrentSpeed() > GetStaticFloatParameterDefault( "highSpeedThreshold", 20.0 );
		}
		return false;
	}

}

class SpeedExitingEvents extends ExitingEvents
{
	default m_exitSlot = 'speed';
	var m_exitForce : Vector4;

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var vehicle : VehicleObject;
		stateContext.SetPermanentIntParameter( 'vehUnmountDir', ( ( Int32 )( vehicleExitDirection.Left ) ), true );
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.VehicleExitKnockdownProtection", scriptInterface.executionOwnerEntityID );
		super.OnEnter( stateContext, scriptInterface );
		m_exitForce = Vector4( 0.0, 0.0, 0.0, 0.0 );
		vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
		if( vehicle )
		{
			m_exitForce = vehicle.GetLinearVelocity() / 2.0;
			if( m_exitForce.Z < 0.0 )
			{
				m_exitForce.Z = 0.0;
			}
			m_exitForce += ( vehicle.GetWorldUp() * 4.0 );
		}
	}

	protected export override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var statusEffectRecord : weak< StatusEffect_Record >;
		var stackcount : Uint32;
		stackcount = 1;
		super.OnExit( stateContext, scriptInterface );
		statusEffectRecord = TweakDBInterface.GetStatusEffectRecord( T"BaseStatusEffect.BikeKnockdown" );
		GameInstance.GetStatusEffectSystem( scriptInterface.GetGame() ).ApplyStatusEffect( scriptInterface.executionOwnerEntityID, statusEffectRecord.GetID(), GameObject.GetTDBID( scriptInterface.owner ), scriptInterface.ownerEntityID, stackcount, -( m_exitForce ) );
		stateContext.SetTemporaryVectorParameter( 'impulse', m_exitForce, true );
	}

}

class SlideExitingDecisions extends ExitingDecisions
{

	public export const override function EnterCondition( stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var exitRequest : StateResultBool;
		var vehicle : VehicleObject;
		var exitDirection : vehicleUnmountPosition;
		if( !( IsCoolExitAllowed( stateContext, scriptInterface ) ) )
		{
			return false;
		}
		if( IsVehicleExitBlocked1Frame( stateContext, scriptInterface ) )
		{
			return false;
		}
		vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
		if( vehicle.GetCurrentSpeed() <= GetStaticFloatParameterDefault( "highSpeedThreshold", 20.0 ) )
		{
			return false;
		}
		exitRequest = stateContext.GetPermanentBoolParameter( 'validExitRequest' );
		if( !( exitRequest.value ) )
		{
			return false;
		}
		if( stateContext.GetIntParameter( 'vehClass', true ) == 1 )
		{
			exitDirection = vehicle.CanUnmount( true, scriptInterface.executionOwner, vehicleExitDirection.Left );
			if( exitDirection.direction == vehicleExitDirection.NoDirection )
			{
				return false;
			}
		}
		return true;
	}

}

class SlideExitingEvents extends ExitingEvents
{
	default m_exitSlot = 'combat';
	var m_exitMomentum : Vector4;

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var vehicle : VehicleObject;
		stateContext.SetPermanentIntParameter( 'vehUnmountDir', ( ( Int32 )( vehicleExitDirection.Left ) ), true );
		super.OnEnter( stateContext, scriptInterface );
		vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
		m_exitMomentum = vehicle.GetLinearVelocity();
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.VehicleExitKnockdownProtection", scriptInterface.executionOwnerEntityID );
	}

	protected export override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnExit( stateContext, scriptInterface );
		stateContext.SetTemporaryBoolParameter( 'forceSlide', true, true );
		stateContext.SetTemporaryVectorParameter( 'impulse', m_exitMomentum, true );
		if( m_fromDriverCombat )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon, gameEquipAnimationType.Instant );
		}
		BlockAimingForTime( stateContext, scriptInterface, 0.1 );
	}

}

class CoolExitingDecisions extends ExitingDecisions
{

	public export const override function EnterCondition( stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var exitRequest : StateResultBool;
		exitRequest = stateContext.GetPermanentBoolParameter( 'coolExitRequest' );
		if( IsVehicleExitBlocked1Frame( stateContext, scriptInterface ) )
		{
			return false;
		}
		if( !( exitRequest.value ) )
		{
			return false;
		}
		stateContext.SetPermanentBoolParameter( 'coolExitRequest', false, true );
		if( !( IsCoolExitAllowed( stateContext, scriptInterface ) ) )
		{
			return false;
		}
		return true;
	}

}

class CoolExitingEvents extends ExitingEvents
{
	default m_exitSlot = 'cool';
	var m_exitMomentum : Vector4;
	var m_coolExitMagnitude : vehicleCoolExitImpulseLevel;
	var m_willEquipMeleeWeapon : Bool;
	var m_cwArmsEquipRequested : Bool;
	var m_cwArmsEquipCompleted : Bool;
	var m_vehicleInTPP : Bool;
	var m_vehicleInTPPCallback : CallbackHandle;

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var vehicle : VehicleObject;
		var lastUsedWeapon : ItemID;
		stateContext.SetPermanentIntParameter( 'vehUnmountDir', ( ( Int32 )( vehicleExitDirection.Left ) ), true );
		super.OnEnter( stateContext, scriptInterface );
		vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
		m_exitMomentum = vehicle.GetLinearVelocity() / 2.0;
		m_coolExitMagnitude = vehicleCoolExitImpulseLevel.MaxImpulse;
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.VehicleExitKnockdownProtection", scriptInterface.executionOwnerEntityID );
		if( m_exitMomentum.Z < 0.0 )
		{
			m_exitMomentum.Z = 0.0;
		}
		m_vehicleInTPPCallback = scriptInterface.localBlackboard.RegisterListenerBool( GetAllBlackboardDefs().PlayerStateMachine.IsVehicleInTPP, this, 'OnVehicleInTPPChange', true );
		m_vehicleInTPP = scriptInterface.localBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsVehicleInTPP );
		lastUsedWeapon = EquipmentSystem.GetLastUsedItemByType( scriptInterface.executionOwner, ELastUsed.Weapon );
		if( ItemID.IsValid( lastUsedWeapon ) )
		{
			if( WeaponObject.IsCyberwareWeapon( lastUsedWeapon ) )
			{
				m_cwArmsEquipRequested = true;
			}
			else
			{
				m_willEquipMeleeWeapon = WeaponObject.IsMelee( lastUsedWeapon );
			}
		}
	}

	protected event OnVehicleInTPPChange( value : Bool )
	{
		m_vehicleInTPP = value;
	}

	protected override function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var exitDelay : Float;
		var startedExiting : StateResultBool;
		var vehicle : weak< VehicleObject >;
		var validUnmount : vehicleUnmountPosition;
		var isTeleportExiting : StateResultBool;
		exitDelay = GetVehicleDataPackage( stateContext ).ExitDelay();
		startedExiting = stateContext.GetPermanentBoolParameter( 'startedExiting' );
		isTeleportExiting = stateContext.GetPermanentBoolParameter( 'teleportExitActive' );
		if( ( m_cwArmsEquipRequested && !( m_cwArmsEquipCompleted ) ) && !( m_vehicleInTPP ) )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon, gameEquipAnimationType.HACK_ForceInstantEquip );
			m_cwArmsEquipCompleted = true;
		}
		if( exitDelay > 0.0 )
		{
			if( ( GetInStateTime() >= exitDelay ) && !( startedExiting.value ) )
			{
				StartExiting( stateContext, scriptInterface );
			}
		}
		if( ( startedExiting.value && !( isTeleportExiting.value ) ) && ( GetInStateTime() >= 1.0 ) )
		{
			vehicle = ( ( VehicleObject )( scriptInterface.owner ) );
			m_coolExitMagnitude = vehicle.DetermineCoolExitImpulseLevel( scriptInterface.executionOwner, GetStaticFloatParameterDefault( "coolExitMaxImpulseHeightThreshold", 3.5999999 ), GetStaticFloatParameterDefault( "coolExitLowImpulseHeightThreshold", 1.79999995 ) );
			if( m_coolExitMagnitude == vehicleCoolExitImpulseLevel.NoExit )
			{
				validUnmount = vehicle.CanUnmount( true, scriptInterface.executionOwner, vehicleExitDirection.Back );
				if( validUnmount.direction == vehicleExitDirection.NoDirection )
				{
					validUnmount = vehicle.CanUnmount( true, scriptInterface.executionOwner );
				}
				if( validUnmount.direction != vehicleExitDirection.NoDirection )
				{
					scriptInterface.GetWorkspotSystem().StopNpcInWorkspot( scriptInterface.executionOwner );
					ExitWithTeleport( stateContext, scriptInterface, validUnmount, false, true );
				}
			}
		}
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnExit( stateContext, scriptInterface );
		stateContext.SetTemporaryVectorParameter( 'exitMomentum', m_exitMomentum, true );
		stateContext.SetTemporaryBoolParameter( 'requestCoolExitJump', true, true );
		stateContext.SetTemporaryIntParameter( 'coolExitMagnitude', ( ( Int32 )( m_coolExitMagnitude ) ), true );
		scriptInterface.localBlackboard.UnregisterListenerBool( GetAllBlackboardDefs().PlayerStateMachine.IsVehicleInTPP, m_vehicleInTPPCallback );
		if( m_cwArmsEquipRequested && m_cwArmsEquipCompleted )
		{
			return;
		}
		if( m_willEquipMeleeWeapon || ( m_cwArmsEquipRequested && !( m_cwArmsEquipCompleted ) ) )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon, gameEquipAnimationType.HACK_ForceInstantEquip );
		}
		else
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon, gameEquipAnimationType.Instant );
		}
	}

}

class ExitEvents extends VehicleEventsTransition
{

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var unmountEvent : UnmountingRequest;
		var mountingInfo : MountingInfo;
		var startedExitingResult : StateResultBool;
		var startedExiting : Bool;
		var unmountDelay : StateResultFloat;
		super.OnEnter( stateContext, scriptInterface );
		startedExitingResult = stateContext.GetPermanentBoolParameter( 'startedExiting' );
		startedExiting = startedExitingResult.valid && startedExitingResult.value;
		stateContext.SetPermanentBoolParameter( 'startedExiting', false, true );
		VehicleComponent.SetAnimsetOverrideForPassenger( scriptInterface.executionOwner, 0.0 );
		RemoveUnmountingRequest( stateContext );
		unmountEvent = new UnmountingRequest;
		mountingInfo.childId = scriptInterface.executionOwnerEntityID;
		unmountEvent.lowLevelMountingInfo = mountingInfo;
		unmountEvent.delay = 0.0;
		unmountDelay = stateContext.GetTemporaryFloatParameter( 'unmountDelay' );
		if( unmountDelay.valid )
		{
			unmountEvent.delay = unmountDelay.value;
		}
		if( !( startedExiting ) )
		{
			unmountEvent.mountData = new MountEventData;
			unmountEvent.mountData.isInstant = true;
		}
		scriptInterface.GetMountingFacility().Unmount( unmountEvent );
		ResetAnimFeature( stateContext, scriptInterface );
		ResetIsCar( stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Default ) ) );
		PlayerStateChange( scriptInterface, 0 );
		DisableCameraBobbing( stateContext, scriptInterface, false );
		SetWasStolen( stateContext, false );
		SetWasCombatForced( stateContext, false );
		SetRequestedTPPCamera( stateContext, false );
		stateContext.SetPermanentBoolParameter( 'coolExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'submergedExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'validExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'validExitAfterSwitchRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'validSwitchSeatExitRequest', false, true );
		stateContext.SetPermanentBoolParameter( 'teleportExitActive', false, true );
		stateContext.SetPermanentIntParameter( 'driverCombatType', ( ( Int32 )( gamedataDriverCombatType.Invalid ) ), true );
		GameInstance.GetTelemetrySystem( scriptInterface.GetGame() ).LogEnteringOrExitingVehicle( true );
	}

	protected export override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface ) {}
}

class WaitingForSceneDecisions extends VehicleTransition
{

	public export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( stateContext.GetBoolParameter( 'sceneActionInProgress', false ) )
		{
			return true;
		}
		return false;
	}

	public export const function ToExit( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsExitForced( stateContext ) || !( scriptInterface.owner ) )
		{
			return true;
		}
		return false;
	}

	public export const function ToEntering( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( stateContext.GetBoolParameter( 'sceneActionFinished', false ) )
		{
			return true;
		}
		return false;
	}

}

class WaitingForSceneEvents extends VehicleTransition
{
}

class SceneDecisions extends VehicleTransition
{
	var m_sceneTierCallback : CallbackHandle;

	protected export function OnAttach( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface )
	{
		m_sceneTierCallback = scriptInterface.localBlackboard.RegisterListenerInt( GetAllBlackboardDefs().PlayerStateMachine.SceneTier, this, 'OnSceneTierChanged', true );
	}

	protected export function OnDetach( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface )
	{
		scriptInterface.localBlackboard.UnregisterListenerInt( GetAllBlackboardDefs().PlayerStateMachine.SceneTier, m_sceneTierCallback );
	}

	protected function OnSceneTierChanged( sceneTier : Int32 )
	{
		EnableOnEnterCondition( ( sceneTier >= ( ( Int32 )( gamePSMHighLevel.SceneTier3 ) ) ) && ( sceneTier <= ( ( Int32 )( gamePSMHighLevel.SceneTier5 ) ) ) );
	}

	public export const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( ( IsExitForced( stateContext ) || !( IsInScene( stateContext, scriptInterface ) ) ) || !( scriptInterface.owner ) )
		{
			return true;
		}
		return false;
	}

	public const function ToVehicleTurret( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetPuppetVehicleSceneTransition( stateContext ) == PuppetVehicleState.Turret;
	}

	public const function ToCombat( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsPassengerInVehicle( scriptInterface ) )
		{
			if( CanTransitionToCombat( stateContext ) )
			{
				return true;
			}
		}
		return false;
	}

	public const function ToDriverCombatFirearms( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( ( ( IsDriverInVehicle( scriptInterface ) && CanEnterDriverCombat() ) && CanTransitionToCombat( stateContext ) ) && DoesVehicleSupportFireArms( ( ( VehicleObject )( scriptInterface.owner ) ) ) )
		{
			return true;
		}
		return false;
	}

	public const function ToDriverCombatMountedWeapons( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( ( ( IsDriverInVehicle( scriptInterface ) && CanEnterDriverCombat() ) && CanTransitionToCombat( stateContext ) ) && GetVehicleDriverCombatType( ( ( VehicleObject )( scriptInterface.owner ) ) ) == gamedataDriverCombatType.MountedWeapons )
		{
			return true;
		}
		return false;
	}

	protected const function CanTransitionToCombat( const stateContext : StateContext ) : Bool
	{
		var puppetVehicleState : PuppetVehicleState;
		puppetVehicleState = GetPuppetVehicleSceneTransition( stateContext );
		if( puppetVehicleState == PuppetVehicleState.CombatSeated || puppetVehicleState == PuppetVehicleState.CombatWindowed )
		{
			if( !( IsInEmptyHandsState( stateContext ) ) )
			{
				return true;
			}
		}
		return false;
	}

}

class SceneEvents extends VehicleEventsTransition
{

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var mountingInfo : MountingInfo;
		mountingInfo = scriptInterface.GetMountingInfo( scriptInterface.executionOwner );
		SetSide( stateContext, scriptInterface );
		ForceIdleVehicle( stateContext );
		SetIsCar( stateContext, true );
		SendIsCar( stateContext, scriptInterface );
		PlayerStateChange( scriptInterface, 3 );
		SetVehicleCameraSceneMode( scriptInterface, true );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vehicle, ( ( Int32 )( gamePSMVehicle.Scene ) ) );
		SendAnimFeature( stateContext, scriptInterface );
		if( !( scriptInterface.GetWorkspotSystem().IsActorInWorkspot( scriptInterface.executionOwner ) ) && !( scriptInterface.IsSceneAnimationActive() ) )
		{
			MountToWorkspot( scriptInterface, mountingInfo );
		}
	}

	protected export function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var puppetVehicleState : StateResultInt;
		var sceneGameplayTransition : PuppetVehicleState;
		var isInVehicleCombat : Bool;
		var weaponItemID : ItemID;
		isInVehicleCombat = false;
		puppetVehicleState = stateContext.GetTemporaryIntParameter( 'scenePuppetVehicleState' );
		if( puppetVehicleState.valid )
		{
			stateContext.SetPermanentIntParameter( 'scenePuppetVehicleState', puppetVehicleState.value, true );
			sceneGameplayTransition = GetPuppetVehicleSceneTransition( stateContext );
			if( sceneGameplayTransition == PuppetVehicleState.GunnerSlot )
			{
				stateContext.SetPermanentIntParameter( 'vehSlot', 3, true );
				isInVehicleCombat = true;
			}
			else if( sceneGameplayTransition == PuppetVehicleState.CombatWindowed || sceneGameplayTransition == PuppetVehicleState.CombatSeated )
			{
				isInVehicleCombat = true;
			}
			if( ( sceneGameplayTransition == PuppetVehicleState.IdleMounted || sceneGameplayTransition == PuppetVehicleState.CombatWindowed ) || sceneGameplayTransition == PuppetVehicleState.CombatSeated )
			{
				SetSide( stateContext, scriptInterface );
			}
			if( sceneGameplayTransition != PuppetVehicleState.IdleStand )
			{
				if( !( scriptInterface.GetWorkspotSystem().IsActorInWorkspot( scriptInterface.executionOwner ) ) && !( scriptInterface.IsSceneAnimationActive() ) )
				{
					MountToWorkspot( scriptInterface, scriptInterface.GetMountingInfo( scriptInterface.executionOwner ) );
				}
			}
			if( isInVehicleCombat )
			{
				weaponItemID = EquipmentSystem.GetData( scriptInterface.executionOwner ).GetLastUsedOrFirstAvailableWeapon();
				if( WeaponObject.IsRanged( weaponItemID ) )
				{
					SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon );
				}
				else
				{
					weaponItemID = EquipmentSystem.GetData( scriptInterface.executionOwner ).GetSlotActiveWeapon();
					if( WeaponObject.IsRanged( weaponItemID ) )
					{
						SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestSlotActiveWeapon );
					}
					else
					{
						SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableRangedWeapon );
					}
				}
			}
			SetIsInVehicleWindowCombat( stateContext, sceneGameplayTransition == PuppetVehicleState.CombatWindowed );
			SetIsInVehicle( stateContext, sceneGameplayTransition != PuppetVehicleState.IdleStand );
			SetIsInVehicleCombat( stateContext, isInVehicleCombat );
			SetIsExitingVehicle( stateContext, sceneGameplayTransition == PuppetVehicleState.IdleStand );
		}
		SendAnimFeature( stateContext, scriptInterface );
	}

	public export function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var sceneGameplayTransition : PuppetVehicleState;
		sceneGameplayTransition = GetPuppetVehicleSceneTransition( stateContext );
		stateContext.RemovePermanentIntParameter( 'scenePuppetVehicleState' );
		stateContext.SetTemporaryBoolParameter( 'vehicleWindowedCombat', sceneGameplayTransition == PuppetVehicleState.CombatWindowed, true );
		stateContext.SetTemporaryIntParameter( 'scenePuppetVehicleState', ( ( Int32 )( sceneGameplayTransition ) ), true );
		SetIsExitingVehicle( stateContext, false );
		SendAnimFeature( stateContext, scriptInterface );
		SetVehicleCameraSceneMode( scriptInterface, false );
		SetVehicleStatusEffects( stateContext, scriptInterface, false );
		if( sceneGameplayTransition != PuppetVehicleState.IdleStand )
		{
			if( !( IsExitForced( stateContext ) ) && !( scriptInterface.GetWorkspotSystem().IsActorInWorkspot( scriptInterface.executionOwner ) ) )
			{
				MountToWorkspot( scriptInterface, scriptInterface.GetMountingInfo( scriptInterface.executionOwner ) );
			}
		}
	}

	protected export override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExit( stateContext, scriptInterface );
	}

	public function MountToWorkspot( scriptInterface : StateGameScriptInterface, mountingInfo : MountingInfo )
	{
		var workspotSystem : WorkspotGameSystem;
		workspotSystem = scriptInterface.GetWorkspotSystem();
		workspotSystem.MountToVehicle( scriptInterface.owner, scriptInterface.executionOwner, 0.0, 0.0, 'OccupantSlots', mountingInfo.slotId.id );
	}

}

class SceneExitingDecisions extends VehicleTransition
{

	public export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsExitForced( stateContext ) || !( scriptInterface.owner ) )
		{
			return true;
		}
		return false;
	}

	public export const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( !( scriptInterface.GetWorkspotSystem().IsActorInWorkspot( scriptInterface.executionOwner ) ) || !( scriptInterface.owner ) )
		{
			return true;
		}
		return false;
	}

}

class SceneExitingEvents extends VehicleEventsTransition
{

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var unmountEvent : MountEventData;
		var startedMountingEvent : VehicleStartedMountingEvent;
		super.OnEnter( stateContext, scriptInterface );
		unmountEvent = GetUnmountingEvent( stateContext );
		if( unmountEvent != NULL )
		{
			startedMountingEvent = new VehicleStartedMountingEvent;
			startedMountingEvent.slotID = unmountEvent.slotName;
			startedMountingEvent.isMounting = false;
			startedMountingEvent.character = scriptInterface.executionOwner;
			startedMountingEvent.instant = false;
			scriptInterface.owner.QueueEvent( startedMountingEvent );
			stateContext.SetPermanentBoolParameter( 'startedExiting', true, true );
		}
		if( IsExitForced( stateContext ) && scriptInterface.GetWorkspotSystem().IsActorInWorkspot( scriptInterface.executionOwner ) )
		{
			if( !( scriptInterface.IsSceneAnimationActive() ) )
			{
				ExitWorkspot( stateContext, scriptInterface, unmountEvent.isInstant );
				PlayVehicleExitDoorAnimation( stateContext, scriptInterface );
			}
		}
		SetIsInVehicle( stateContext, false );
		SendAnimFeature( stateContext, scriptInterface );
		RemoveUnmountingRequest( stateContext );
	}

}

