import class VehicleObject extends GameObject
{
	private var m_vehicleComponent : weak< VehicleComponent >;
	private var m_uiComponent : weak< worlduiWidgetComponent >;
	protected var m_crowdMemberComponent : CrowdMemberBaseComponent;
	private var m_attitudeAgent : AttitudeAgent;
	private var m_hitTimestamp : Float;
	private var m_drivingTrafficPattern : CName;
	private var m_onPavement : Bool;
	private var m_inTrafficLane : Bool;
	private var m_timesSentReactionEvent : Int32;
	private var m_timesToResendHandleReactionEvent : Int32;
	private var m_hasReactedToStimuli : Bool;
	private var m_gotStuckIncrement : Int32;
	private var m_waitForPassengersToSpawnEventDelayID : DelayID;
	private var m_triggerPanicDrivingEventDelayID : DelayID;
	private var m_reactionTriggerEvent : HandleReactionEvent;
	private var m_fearInside : Bool;
	private var m_vehicleUpsideDown : Bool;
	private var m_isQhackUploadInProgress : Bool;
	private var m_hitByPlayer : Bool;
	private var m_currentlyUploadingAction : weak< ScriptableDeviceAction >;
	private var m_bumpedRecently : Int32;
	private var m_bumpTimestamp : Float;
	private var m_minUnconsciousImpact : Float;
	private var m_driverUnconscious : Bool;
	private var m_abandoned : Bool;

	public const override function IsVehicle() : Bool
	{
		return true;
	}

	public const override function IsPrevention() : Bool
	{
		return m_vehicleComponent && m_vehicleComponent.HasPreventionPassenger();
	}

	public import final function GetBlackboard() : IBlackboard;
	public import const final function GetRecord() : weak< Vehicle_Record >;
	public import const final function IsVehicleRemoteControlled() : Bool;
	public import const final function IsVehicleAccelerateQuickhackActive() : Bool;
	public import const final function IsVehicleForceBrakesQuickhackActive() : Bool;
	public import const final function GetDistanceToPlayerSquared() : Float;
	public import const final function IsHackable() : Bool;
	public import const final function IsVehicleInsideInnerAreaOfAreaSpeedLimiter() : Bool;
	public import const final function IsPlayerMounted() : Bool;
	public import const final function IsPlayerDriver() : Bool;
	public import const final function HasPassengers() : Bool;
	public import const final function HasTrafficSlot() : Bool;
	public import final function PreHijackPrepareDriverSlot();
	public import final function CanUnmount( isPlayer : Bool, mountedObject : weak< GameObject >, optional checkSpecificDirection : vehicleExitDirection ) : vehicleUnmountPosition;
	public import final function DetermineCoolExitImpulseLevel( mountedObject : weak< GameObject >, maxImpulseHeightThreshold : Float, minImpulseHeightThreshold : Float ) : vehicleCoolExitImpulseLevel;
	public import final function ToggleRadioReceiver( toggle : Bool );
	public import final function SetRadioReceiverStation( stationIndex : Uint32 );
	public import final function NextRadioReceiverStation();
	public import final function SetRadioTier( radioTier : Uint32, overrideTier : Bool );
	public import final function ToggleHorn( toggle : Bool, optional isPolice : Bool );
	public import final function ToggleSiren( toggle : Bool );
	public import final function NotifyWindowChange( windowName : CName, isOpened : Bool );
	public import final function DetachPart( partName : CName );
	public import final function DetachAllParts();
	public import final function SetHasExploded();
	public import final function HasOccupantSlot( slotName : CName ) : Bool;
	public import final function GetRecordID() : TweakDBID;
	public import final function GetAccessoryController() : vehicleController;
	public import const final function IsAirControlEnabled() : Bool;
	public import final function EnableAirControl( toggle : Bool );
	public import const final function IsInAir() : Bool;
	public import const final function IsLeaningOnOneWheel() : Bool;
	public import const final function IsFlippedOver() : Bool;
	public import const final function IsSkidding( wheelSlipThreshold : Float ) : Bool;
	public import final function GetCameraManager() : VehicleCameraManager;
	public import const final function IsPlayerVehicle() : Bool;
	public import const final function IsPlayerActiveVehicle() : Bool;
	public import const final function IsCrowdVehicle() : Bool;
	public import const final function IsVehicleParked() : Bool;
	public import final function SetVehicleRemoteControlled( enable : Bool, shouldUnseatPassengers : Bool, shouldModifyInteractionState : Bool );
	public import final function ToggleVehicleRemoteControlCamera();
	public import final function SetIsHackable( enable : Bool );
	public import final function ActivateNetrunnerQuickhack( chooseHack : VehicleNetrunnerQuickhackType );
	public import final function IsRadioReceiverActive() : Bool;
	public import final function WasRadioReceiverPlaying() : Bool;
	public import final function GetCurrentRadioIndex() : Uint32;
	public import final function GetRadioReceiverStationName() : CName;
	public import final function GetRadioReceiverTrackName() : CName;
	public import final function GetAnimsetOverrideForPassenger( slotName : CName ) : CName;
	public import final function GetAnimsetOverrideForPassengerFromSlotName( slotName : CName ) : CName;
	public import final function GetAnimsetOverrideForPassengerFromBoneName( boneName : CName ) : CName;
	public import final function GetBoneNameFromSlot( slotName : CName ) : CName;
	public import final function GetSlotIdForMountedObject( mountedObject : weak< GameObject > ) : CName;
	public import final function ShouldDamageSystemIgnoreHit( hitComponentName : CName ) : Bool;
	public import final function TurnVehicleOn( on : Bool );
	public import final function TurnEngineOn( on : Bool );
	public import final function LockVehicleOnState( shouldLock : Bool );
	public import const final function IsVehicleTurnedOn() : Bool;
	public import const final function IsEngineTurnedOn() : Bool;
	public import const final function IsVehicleOnStateLocked() : Bool;
	public import final function ForceBrakesFor( seconds : Float );
	public import final function ForceBrakesUntilStoppedOrFor( secondsToTimeout : Float );
	public import final function ActivateTemporaryLossOfControl();
	public import final function PhysicsWakeUp();
	public import final function IsInTrafficPhysicsState() : Bool;
	public import const final function IsExecutingAnyCommand() : Bool;
	public import const final function GetAIComponent() : AIVehicleAgent;
	public import const final function IsChasingTarget() : Bool;
	public import const final function GetTimeChasingTarget() : Float;
	public import final function HasNavPathToTarget( targetID : EntityID, duration : Float, invert : Bool ) : Bool;
	public import const final function IsPerformingPanicDriving() : Bool;
	public import const final function IsPerformingSceneAnimation() : Bool;
	public import const final function CanStartPanicDriving() : Bool;
	public import final function EnableHighPriorityPanicDriving();
	public import final function ApplyPermanentStun();
	public import const final function CommandsFromDriverEnabled() : Bool;
	public import const final function GetPoliceStrategy() : vehiclePoliceStrategy;
	public import final function SetPoliceStrategy( strategy : vehiclePoliceStrategy );
	public import const final function GetPoliceStrategyDestination() : Vector3;
	public import final function SetPoliceStrategyDestination( dest : Vector4 );
	public import final function AreFrontWheelsCentered() : Bool;
	public import final function AddCollisionForce( force : Vector4 );
	public import final function GetCollisionForce() : Vector4;
	public import final function GetLinearVelocity() : Vector4;
	public import final function GetTotalMass() : Float;
	public import const final function CanSwitchWeapons() : Bool;
	public import const final function GetActiveWeapons( out weaponList : array< weak< WeaponObject > > );
	public import final function IsArmedVehicle() : Bool;
	public import final function EnableNPCCombat( enable : Bool );
	public import final function NPCShoot( target : Vector4, projectiles : Uint32 );
	public import final function IsNPCShooting() : Bool;
	public import final function EverPerformedChase() : Bool;
	public import final function TrySetHitCooldown() : Bool;
	public import final function ApplyAvgZOffset();

	public final function GetCurrentSpeed() : Float
	{
		return GetBlackboard().GetFloat( GetAllBlackboardDefs().Vehicle.SpeedValue );
	}

	public const final function IsAbandoned() : Bool
	{
		return m_abandoned;
	}

	public import final function SetDestructionGridPointValues( layer : Uint32, values : Float[ 15 ], accumulate : Bool );
	public import final function DestructionResetGrid();
	public import final function DestructionResetGlass();
	private import final function GetUIComponents() : array< worlduiWidgetComponent >;
	public import final function SendDelayedFinishedMountingEventToPS( isMounting : Bool, slotID : CName, character : GameObject, delay : Float );

	public const final function IsDestroyed() : Bool
	{
		return GetVehiclePS().GetIsDestroyed();
	}

	public const final function IsStolen() : Bool
	{
		return GetVehiclePS().GetIsStolen();
	}

	public const final function RecordHasTag( tag : CName ) : Bool
	{
		var vehicleRecord : Vehicle_Record;
		if( !( VehicleComponent.GetVehicleRecord( this, vehicleRecord ) ) )
		{
			return false;
		}
		return RecordHasTag( vehicleRecord, tag );
	}

	public const final function RecordHasTag( vehicleRecord : Vehicle_Record, tag : CName ) : Bool
	{
		var vehicleTags : array< CName >;
		vehicleTags = vehicleRecord.Tags();
		if( vehicleTags.Contains( tag ) )
		{
			return true;
		}
		return false;
	}

	public const override function IsGameplayRelevant() : Bool
	{
		return false;
	}

	protected event OnRequestComponents( ri : EntityRequestComponentsInterface )
	{
		EntityRequestComponentsInterface.RequestComponent( ri, 'controller', 'VehicleComponent', false );
		EntityRequestComponentsInterface.RequestComponent( ri, 'CrowdMember', 'CrowdMemberBaseComponent', false );
		EntityRequestComponentsInterface.RequestComponent( ri, 'AttitudeAgent', 'AttitudeAgent', true );
		super.OnRequestComponents( ri );
	}

	protected event OnTakeControl( ri : EntityResolveComponentsInterface )
	{
		m_vehicleComponent = ( ( VehicleComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'controller' ) ) );
		m_crowdMemberComponent = ( ( CrowdMemberBaseComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'CrowdMember' ) ) );
		m_attitudeAgent = ( ( AttitudeAgent )( EntityResolveComponentsInterface.GetComponent( ri, 'AttitudeAgent' ) ) );
		super.OnTakeControl( ri );
	}

	protected event OnGameAttached()
	{
		super.OnGameAttached();
		SetInteriorUIEnabled( false );
		m_hitByPlayer = false;
	}

	protected event OnDetach()
	{
		super.OnDetach();
	}

	protected event OnDeviceLinkRequest( evt : DeviceLinkRequest )
	{
		var link : VehicleDeviceLinkPS;
		if( IsCrowdVehicle() )
		{
			return false;
		}
		link = VehicleDeviceLinkPS.CreateAndAcquirVehicleDeviceLinkPS( GetGame(), GetEntityID() );
		if( link )
		{
			GameInstance.GetPersistencySystem( GetGame() ).QueuePSEvent( link.GetID(), link.GetClassName(), evt );
		}
	}

	protected event OnEventReceived( stimEvent : StimuliEvent )
	{
		var mountInfos : array< MountingInfo >;
		var delayReactionEvt : DelayReactionToMissingPassengersEvent;
		mountInfos = GameInstance.GetMountingFacility( GetGame() ).GetMountingInfoMultipleWithIds( , GetEntityID() );
		if( ( m_inTrafficLane && ( mountInfos.Size() == 0 ) ) && stimEvent.GetStimType() != gamedataStimType.Invalid )
		{
			delayReactionEvt = new DelayReactionToMissingPassengersEvent;
			delayReactionEvt.stimEvent = stimEvent;
			GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, delayReactionEvt, 2.0 );
		}
	}

	protected event OnDelayReactionToMissingPassengersEvent( evt : DelayReactionToMissingPassengersEvent )
	{
		var mountInfos : array< MountingInfo >;
		mountInfos = GameInstance.GetMountingFacility( GetGame() ).GetMountingInfoMultipleWithIds( , GetEntityID() );
		if( mountInfos.Size() == 0 )
		{
			if( !( evt.delayedAlready ) && m_inTrafficLane )
			{
				evt.delayedAlready = true;
				GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, evt, 2.0 );
			}
		}
		else
		{
			VehicleComponent.QueueEventToAllPassengers( GetGame(), GetEntityID(), evt.stimEvent );
		}
	}

	public const override function GetDeviceLink() : VehicleDeviceLinkPS
	{
		var link : VehicleDeviceLinkPS;
		link = VehicleDeviceLinkPS.AcquireVehicleDeviceLink( GetGame(), GetEntityID() );
		if( link )
		{
			return link;
		}
		return NULL;
	}

	protected override function SendEventToDefaultPS( evt : Event )
	{
		var persistentState : VehicleComponentPS;
		persistentState = GetVehiclePS();
		if( persistentState == NULL )
		{
			return;
		}
		GameInstance.GetPersistencySystem( GetGame() ).QueuePSEvent( persistentState.GetID(), persistentState.GetClassName(), evt );
	}

	protected event OnMountingEvent( evt : MountingEvent )
	{
		var mountChild : GameObject;
		mountChild = ( ( GameObject )( GameInstance.FindEntityByID( GetGame(), evt.request.lowLevelMountingInfo.childId ) ) );
		if( mountChild == NULL )
		{
			return false;
		}
		if( mountChild.IsPlayer() )
		{
			SetInteriorUIEnabled( true );
			SyncVehicleVisualCustomizationDefinition();
			GetVehicleComponent().EnableCustomizableAppearance( true );
			if( ReevaluateStealing( mountChild, evt.request.lowLevelMountingInfo.slotId.id, evt.request.mountData.mountEventOptions.occupiedByNonFriendly ) )
			{
				StealVehicle( mountChild );
			}
		}
	}

	protected event OnVehicleFinishedMounting( evt : VehicleFinishedMountingEvent )
	{
		if( ( evt.isMounting && evt.character ) && evt.character.IsPlayer() )
		{
			m_abandoned = false;
			if( GetVehiclePS().GetIsVehicleVisualCustomizationActive() && !( GetVehiclePS().GetIsVehicleVisualCustomizationBlockedByDamage() ) )
			{
				ExecuteVisualCustomizationWithDelay( true, false, true, 0.0, true );
			}
			else
			{
				if( GetVehiclePS().GetIsVehicleVisualCustomizationDefinitionDefined() && !( GetVehiclePS().GetIsVehicleVisualCustomizationBlockedByDamage() ) )
				{
					ExecuteVisualCustomizationWithDelay( true, false, false, 0.80000001, false );
				}
			}
		}
	}

	protected event OnUnmountingEvent( evt : UnmountingEvent )
	{
		var mountChild : GameObject;
		var isSilentUnmount : Bool;
		mountChild = ( ( GameObject )( GameInstance.FindEntityByID( GetGame(), evt.request.lowLevelMountingInfo.childId ) ) );
		isSilentUnmount = evt.request.mountData && evt.request.mountData.mountEventOptions.silentUnmount;
		if( mountChild && mountChild.IsPlayer() )
		{
			if( !( isSilentUnmount ) )
			{
				SetInteriorUIEnabled( false );
			}
		}
	}

	private function SetInteriorUIEnabled( enabled : Bool )
	{
		var uiComponents : array< worlduiWidgetComponent >;
		var component : worlduiWidgetComponent;
		var i, total : Int32;
		uiComponents = GetUIComponents();
		total = uiComponents.Size();
		if( total > 0 )
		{
			for( i = 0; i < total; i += 1 )
			{
				component = uiComponents[ i ];
				if( component )
				{
					component.Toggle( enabled );
				}
			}
			GetBlackboard().SetBool( GetAllBlackboardDefs().Vehicle.IsUIActive, enabled );
			GetBlackboard().FireCallbacks();
		}
	}

	private function ReevaluateStealing( character : weak< GameObject >, slotID : CName, stealingAction : Bool ) : Bool
	{
		var vehicleRecord : Vehicle_Record;
		if( !( character ) || !( character.IsPlayer() ) )
		{
			return false;
		}
		if( stealingAction )
		{
			return true;
		}
		if( ( IsStolen() || slotID != VehicleComponent.GetDriverSlotName() ) || IsPlayerVehicle() )
		{
			return false;
		}
		if( !( VehicleComponent.GetVehicleRecord( this, vehicleRecord ) ) )
		{
			return false;
		}
		if( vehicleRecord.Affiliation().Type() == gamedataAffiliation.NCPD || RecordHasTag( vehicleRecord, 'TriggerPrevention' ) )
		{
			return true;
		}
		return false;
	}

	private function StealVehicle( thief : weak< GameObject > )
	{
		StimBroadcasterComponent.BroadcastStim( thief, gamedataStimType.CrowdIllegalAction );
		StimBroadcasterComponent.BroadcastActiveStim( thief, gamedataStimType.CrimeWitness, 4.4000001 );
		GetVehiclePS().SetIsStolen( true );
	}

	protected event OnWorkspotFinished( componentName : CName )
	{
		if( componentName == 'trunkBodyDisposalPlayer' )
		{
			GetVehicleComponent().MountNpcBodyToTrunk();
		}
		else if( componentName == 'trunkBodyPickupPlayer' )
		{
			GetVehicleComponent().FinishTrunkBodyPickup();
		}
	}

	public const virtual function GetVehiclePS() : VehicleComponentPS
	{
		var ps : PersistentState;
		ps = GetControllerPersistentState();
		return ( ( VehicleComponentPS )( ps ) );
	}

	public const override function GetPSClassName() : CName
	{
		return GetVehiclePS().GetClassName();
	}

	protected const function GetControllerPersistentState() : PersistentState
	{
		var psID : PersistentID;
		psID = GetVehicleComponent().GetPersistentID();
		if( PersistentID.IsDefined( psID ) )
		{
			return GameInstance.GetPersistencySystem( GetGame() ).GetConstAccessToPSObject( psID, GetVehicleComponent().GetPSName() );
		}
		else
		{
			return NULL;
		}
	}

	public const virtual function GetVehicleComponent() : VehicleComponent
	{
		return m_vehicleComponent;
	}

	public const function GetCrowdMemberComponent() : CrowdMemberBaseComponent
	{
		return m_crowdMemberComponent;
	}

	public const override function GetAttitudeAgent() : AttitudeAgent
	{
		return m_attitudeAgent;
	}

	public const override function ShouldShowScanner() : Bool
	{
		if( GetHudManager().IsBraindanceActive() && !( m_scanningComponent.IsBraindanceClue() ) )
		{
			return false;
		}
		return true;
	}

	protected event OnHUDInstruction( evt : HUDInstruction )
	{
		if( evt.quickhackInstruction.ShouldProcess() )
		{
			TryOpenQuickhackMenu( evt.quickhackInstruction.ShouldOpen() );
		}
	}

	public const override function IsQuickHackAble() : Bool
	{
		var isNetrunner : Bool;
		var isQuickHacksExposed : Bool;
		var isQHBlockedByScene : Bool;
		isNetrunner = IsNetrunner();
		isQuickHacksExposed = IsQuickHacksExposed();
		isQHBlockedByScene = QuickhackModule.IsQuickhackBlockedByScene( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject() );
		return ( isNetrunner && isQuickHacksExposed ) && !( isQHBlockedByScene );
	}

	public const override function IsQuickHacksExposed() : Bool
	{
		return GetVehiclePS().IsQuickHacksExposed();
	}

	protected override function SendQuickhackCommands( shouldOpen : Bool )
	{
		var quickSlotsManagerNotification : RevealInteractionWheel;
		var context : GetActionsContext;
		var actions : array< DeviceAction >;
		var commands : array< QuickhackData >;
		quickSlotsManagerNotification = new RevealInteractionWheel;
		quickSlotsManagerNotification.lookAtObject = this;
		if( shouldOpen )
		{
			context = GetVehiclePS().GenerateContext( gamedeviceRequestType.Remote, Device.GetInteractionClearance(), GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerControlledGameObject(), GetEntityID() );
			GetVehiclePS().GetRemoteActions( actions, context );
			if( ( m_isQhackUploadInProgress && !( IsActionQueueEnabled() ) ) || IsActionQueueFull() )
			{
				ScriptableDeviceComponentPS.SetActionsInactiveAll( actions, "LocKey#7020" );
			}
			if( IsActionQueueEnabled() )
			{
				QuickHackableQueueHelper.CheckAndSetInactivityReasonForVehicleActions( actions, m_currentlyUploadingAction );
			}
			QuickHackableHelper.TranslateActionsIntoQuickSlotCommands( actions, commands, this, GetVehiclePS() );
			quickSlotsManagerNotification.commands = commands;
			quickSlotsManagerNotification.shouldReveal = actions.Size() > 0;
		}
		GameInstance.GetUISystem( GetGame() ).QueueEvent( quickSlotsManagerNotification );
	}

	protected event OnUploadProgressStateChanged( evt : UploadProgramProgressEvent )
	{
		if( evt.progressBarContext == EProgressBarContext.QuickHack && evt.progressBarType == EProgressBarType.UPLOAD )
		{
			switch( evt.state )
			{
				case EUploadProgramState.STARTED:
					m_isQhackUploadInProgress = true;
				break;
				case EUploadProgramState.COMPLETED:
					m_isQhackUploadInProgress = false;
				break;
			}
		}
	}

	public const override function CanRevealRemoteActionsWheel() : Bool
	{
		return IsQuickHackAble();
	}

	public const override function ShouldRegisterToHUD() : Bool
	{
		return true;
	}

	protected event OnSetExposeQuickHacks( evt : SetExposeQuickHacks )
	{
		RequestHUDRefresh();
	}

	public const override function GetDefaultHighlight() : FocusForcedHighlightData
	{
		var highlight : FocusForcedHighlightData;
		var currentOutlineType : EFocusOutlineType;
		if( IsDestroyed() || IsPlayerMounted() )
		{
			return NULL;
		}
		if( m_scanningComponent.IsBraindanceBlocked() || m_scanningComponent.IsPhotoModeBlocked() )
		{
			return NULL;
		}
		currentOutlineType = GetCurrentOutline();
		if( currentOutlineType == EFocusOutlineType.INVALID )
		{
			return NULL;
		}
		highlight = new FocusForcedHighlightData;
		highlight.sourceID = GetEntityID();
		highlight.sourceName = GetClassName();
		highlight.outlineType = currentOutlineType;
		if( highlight.outlineType == EFocusOutlineType.QUEST )
		{
			highlight.highlightType = EFocusForcedHighlightType.QUEST;
		}
		else if( highlight.outlineType == EFocusOutlineType.HACKABLE )
		{
			highlight.highlightType = EFocusForcedHighlightType.HACKABLE;
		}
		if( IsNetrunner() )
		{
			highlight.patternType = VisionModePatternType.Netrunner;
		}
		else
		{
			highlight.patternType = VisionModePatternType.Default;
		}
		return highlight;
	}

	public const override function GetCurrentOutline() : EFocusOutlineType
	{
		if( IsQuest() )
		{
			return EFocusOutlineType.QUEST;
		}
		if( IsNetrunner() )
		{
			return EFocusOutlineType.HACKABLE;
		}
		return EFocusOutlineType.INVALID;
	}

	public const override function IsNetrunner() : Bool
	{
		var isCyberdeckEquipped : Bool;
		isCyberdeckEquipped = EquipmentSystem.IsCyberdeckEquipped( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject() );
		return isCyberdeckEquipped;
	}

	public const override function CompileScannerChunks() : Bool
	{
		var record : Vehicle_Record;
		var uiData : VehicleUIData_Record;
		var vehicleNameChunk : ScannerVehicleName;
		var VehicleManufacturerChunk : ScannerVehicleManufacturer;
		var productionYearsChunk : ScannerVehicleProdYears;
		var driveLayoutChunk : ScannerVehicleDriveLayout;
		var horsepowerChunk : ScannerVehicleHorsepower;
		var massChunk : ScannerVehicleMass;
		var stateChunk : ScannerVehicleState;
		var infoChunk : ScannerVehicleInfo;
		var scannerBlackboard : weak< IBlackboard >;
		scannerBlackboard = GameInstance.GetBlackboardSystem( GetGame() ).Get( GetAllBlackboardDefs().UI_ScannerModules );
		scannerBlackboard.SetInt( GetAllBlackboardDefs().UI_ScannerModules.ObjectType, ( ( Int32 )( ScannerObjectType.VEHICLE ) ), true );
		record = GetRecord();
		uiData = record.VehicleUIData();
		vehicleNameChunk = new ScannerVehicleName;
		vehicleNameChunk.Set( LocKeyToString( record.DisplayName() ) );
		scannerBlackboard.SetVariant( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleName, vehicleNameChunk );
		VehicleManufacturerChunk = new ScannerVehicleManufacturer;
		VehicleManufacturerChunk.Set( record.Manufacturer().EnumName() );
		scannerBlackboard.SetVariant( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleManufacturer, VehicleManufacturerChunk );
		productionYearsChunk = new ScannerVehicleProdYears;
		productionYearsChunk.Set( uiData.ProductionYear() );
		scannerBlackboard.SetVariant( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleProductionYears, productionYearsChunk );
		massChunk = new ScannerVehicleMass;
		massChunk.Set( RoundMath( MeasurementUtils.ValueToImperial( uiData.Mass(), EMeasurementUnit.Kilogram ) ) );
		scannerBlackboard.SetVariant( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleMass, massChunk );
		infoChunk = new ScannerVehicleInfo;
		infoChunk.Set( uiData.Info() );
		scannerBlackboard.SetVariant( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleInfo, infoChunk );
		if( ( this == ( ( CarObject )( this ) ) ) || ( this == ( ( BikeObject )( this ) ) ) )
		{
			horsepowerChunk = new ScannerVehicleHorsepower;
			horsepowerChunk.Set( RoundMath( uiData.Horsepower() ) );
			scannerBlackboard.SetVariant( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleHorsepower, horsepowerChunk );
			stateChunk = new ScannerVehicleState;
			stateChunk.Set( m_vehicleComponent.GetVehicleStateForScanner() );
			scannerBlackboard.SetVariant( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleState, stateChunk );
			driveLayoutChunk = new ScannerVehicleDriveLayout;
			driveLayoutChunk.Set( uiData.DriveLayout() );
			scannerBlackboard.SetVariant( GetAllBlackboardDefs().UI_ScannerModules.ScannerVehicleDriveLayout, driveLayoutChunk );
		}
		return true;
	}

	protected event OnLookedAtEvent( evt : LookedAtEvent )
	{
		super.OnLookedAtEvent( evt );
		VehicleComponent.QueueEventToAllPassengers( GetGame(), this, evt );
	}

	protected event OnCrowdSettingsEvent( evt : CrowdSettingsEvent )
	{
		if( !( m_driverUnconscious ) )
		{
			m_drivingTrafficPattern = evt.movementType;
			m_crowdMemberComponent.ChangeMoveType( m_drivingTrafficPattern );
		}
	}

	protected event OnStuckEvent( evt : VehicleStuckEvent )
	{
		m_gotStuckIncrement += 1;
		m_drivingTrafficPattern = 'stop';
		m_crowdMemberComponent.ChangeMoveType( m_drivingTrafficPattern );
		GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, m_reactionTriggerEvent, 1.0 );
		if( IsPrevention() )
		{
			VehicleComponent.QueueEventToAllPassengers( GetGame(), GetEntityID(), evt );
		}
	}

	protected event OnVehicleDestructionEvent( evt : gameVehicleDestructionEvent )
	{
		if( evt.attackData.GetAttackType() == gamedataAttackType.Melee )
		{
			if( VehicleComponent.HasActiveDriverMounted( GetGame(), GetEntityID() ) && !( IsPlayerDriver() ) )
			{
				m_vehicleComponent.PlayDelayedHonk( TweakDBInterface.GetFloat( T"vehicles.honking.meleeHonkDuration", 1.0 ), TweakDBInterface.GetFloat( T"vehicles.honking.meleeHonkDelay", 0.30000001 ) );
			}
		}
	}

	protected event OnTrafficAudioEvent( evt : TrafficAudioEvent )
	{
		if( evt.audioAction == audioTrafficVehicleAudioAction.Horn )
		{
		}
	}

	protected event OnVehicleBumpEvent( evt : VehicleBumpEvent )
	{
		var isBike : Bool;
		m_vehicleComponent.CheckForDrag( evt.impactVelocityChange );
		isBike = this == ( ( BikeObject )( this ) );
		if( evt.isInTraffic && ( evt.impactVelocityChange > 0.0 ) )
		{
			HandleTrafficBump( evt.impactVelocityChange );
		}
		else if( evt.hitVehicle && isBike )
		{
			m_vehicleComponent.HandleBikeCollisionReaction( evt.impactVelocityChange, Vector4.Vector3To4( evt.hitNormal ) );
		}
	}

	private function HandleTrafficBump( impact : Float )
	{
		var impactNormal : Float;
		var threshold : Float;
		if( impact > 20.0 )
		{
			return;
		}
		if( IsExecutingAnyCommand() )
		{
			return;
		}
		if( m_minUnconsciousImpact == 0.0 )
		{
			m_minUnconsciousImpact = TweakDBInterface.GetFloat( T"AIGeneralSettings.minUnconsciousImpact", 6.5 );
		}
		impactNormal = ( impact - 20.0 ) * 0.11111;
		if( ( impact > m_minUnconsciousImpact ) && ( RandRangeF( 0.0, 1.0 ) < ( ( 100.0 - ( m_minUnconsciousImpact + ( ( impactNormal * impactNormal ) * ( 20.0 - m_minUnconsciousImpact ) ) ) ) / 100.0 ) ) )
		{
			TriggerUnconsciousBehaviorForPassengers();
		}
		else
		{
			EscalateBumpVehicleReaction();
		}
		threshold = TweakDBInterface.GetFloat( T"vehicles.honking.collisionHonkUpperThreshold", 100.0 ) / 3.5999999;
		if( ( ( impact < threshold ) && VehicleComponent.HasActiveDriverMounted( GetGame(), GetEntityID() ) ) && !( IsPlayerDriver() ) )
		{
			m_vehicleComponent.PlayDelayedHonk( TweakDBInterface.GetFloat( T"vehicles.honking.collisionHonkDuration", 1.5 ), TweakDBInterface.GetFloat( T"vehicles.honking.collisionHonkDelay", 0.5 ) );
		}
	}

	private function EscalateBumpVehicleReaction()
	{
		var broadcaster : StimBroadcasterComponent;
		var driver : GameObject;
		if( !( GameObject.IsCooldownActive( this, 'bumpCooldown' ) ) )
		{
			GameObject.StartCooldown( this, 'bumpCooldown', 1.0 );
			driver = VehicleComponent.GetDriverMounted( GetGame(), GetEntityID() );
			if( ( VehicleComponent.IsMountedToVehicle( GetGame(), driver ) && ( ( NPCPuppet )( driver ) ) ) && ScriptedPuppet.IsActive( driver ) )
			{
				GameObject.PlayVoiceOver( driver, 'vehicle_bump', 'Scripts:EscalateBumpVehicleReaction', , , true );
			}
			if( m_bumpTimestamp >= EngineTime.ToFloat( GameInstance.GetSimTime( GetGame() ) ) )
			{
				m_bumpedRecently += 1;
				if( m_bumpedRecently > 2 )
				{
					broadcaster = GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject().GetStimBroadcasterComponent();
					if( broadcaster && driver )
					{
						broadcaster.SendDrirectStimuliToTarget( this, gamedataStimType.Bump, driver );
					}
				}
			}
			else
			{
				m_bumpedRecently = 1;
				m_bumpTimestamp = EngineTime.ToFloat( GameInstance.GetSimTime( GetGame() ) ) + 60.0;
			}
		}
	}

	private function TriggerUnconsciousBehaviorForPassengers()
	{
		var mountInfos : array< MountingInfo >;
		var i : Int32;
		var passenger : GameObject;
		var delayBehaviorEvent : WaitForPassengersToSpawnEvent;
		var game : GameInstance;
		if( !( m_driverUnconscious ) )
		{
			m_drivingTrafficPattern = 'stop';
			m_crowdMemberComponent.ChangeMoveType( m_drivingTrafficPattern );
			m_driverUnconscious = true;
			ApplyPermanentStun();
		}
		game = GetGame();
		mountInfos = GameInstance.GetMountingFacility( game ).GetMountingInfoMultipleWithIds( , GetEntityID() );
		if( mountInfos.Size() == 0 )
		{
			GameInstance.GetDelaySystem( game ).CancelDelay( m_waitForPassengersToSpawnEventDelayID );
			delayBehaviorEvent = new WaitForPassengersToSpawnEvent;
			m_waitForPassengersToSpawnEventDelayID = GameInstance.GetDelaySystem( game ).DelayEvent( this, delayBehaviorEvent, 1.5 );
		}
		for( i = 0; i < mountInfos.Size(); i += 1 )
		{
			if( mountInfos[ i ].slotId.id == 'trunk_body' )
			{
				continue;
			}
			passenger = ( ( GameObject )( GameInstance.FindEntityByID( game, mountInfos[ i ].childId ) ) );
			if( passenger )
			{
				StatusEffectHelper.ApplyStatusEffect( passenger, T"BaseStatusEffect.Defeated" );
				if( VehicleComponent.IsDriver( GetGame(), passenger ) )
				{
					m_vehicleComponent.PlayHonkForDuration( 7.5 );
				}
			}
		}
	}

	protected event OnUnableToStartPanicDriving( evt : VehicleUnableToStartPanicDriving )
	{
		if( evt.forceExitVehicle )
		{
			TriggerExitBehavior();
		}
		else
		{
			TriggerFearInsideVehicleBehavior();
			ResendHandleReactionEvent();
		}
	}

	protected event OnWaitForPassengersToSpawnEvent( evt : WaitForPassengersToSpawnEvent )
	{
		TriggerUnconsciousBehaviorForPassengers();
	}

	protected event OnHandleReactionEvent( evt : HandleReactionEvent )
	{
		var randomDraw : Float;
		var prevention : PreventionSystem;
		var isMaxTacOnScene : Bool;
		if( IsPerformingPanicDriving() || IsExecutingAnyCommand() )
		{
			return NULL;
		}
		if( ( EngineTime.ToFloat( GameInstance.GetSimTime( GetGame() ) ) <= ( m_hitTimestamp + 2.0 ) ) && evt.stimEvent.sourceObject.IsPlayer() )
		{
			EnableHighPriorityPanicDriving();
		}
		if( !( GameObject.IsCooldownActive( this, 'vehicleReactionCooldown' ) ) && !( m_driverUnconscious ) )
		{
			m_reactionTriggerEvent = evt;
			GameObject.StartCooldown( this, 'vehicleReactionCooldown', 1.0 );
			randomDraw = RandRangeF( 0.0, 1.0 );
			prevention = ( ( PreventionSystem )( GameInstance.GetScriptableSystemsContainer( GetGame() ).Get( 'PreventionSystem' ) ) );
			isMaxTacOnScene = !( prevention.IsMaxTacDefeated() );
			if( ( ( ( m_gotStuckIncrement < 2 ) && !( m_abandoned ) ) && CanStartPanicDriving() ) && !( isMaxTacOnScene ) )
			{
				TriggerDrivingPanicBehavior( evt.stimEvent.sourcePosition );
				m_fearInside = false;
			}
			else
			{
				if( isMaxTacOnScene || ( ( ( ( randomDraw <= 0.30000001 ) || ( m_gotStuckIncrement > 2 ) ) && evt.stimEvent.sourceObject.IsPlayer() ) && CanNPCsLeaveVehicle() ) )
				{
					TriggerExitBehavior();
					m_fearInside = false;
				}
				else
				{
					if( !( m_fearInside ) )
					{
						TriggerFearInsideVehicleBehavior();
						m_fearInside = true;
					}
					ResendHandleReactionEvent();
				}
			}
		}
	}

	protected event OnTriggerPanicDrivingEvent( evt : TriggerPanicDrivingEvent )
	{
		PanicDrivingBehavior();
	}

	private function PanicDrivingBehavior()
	{
		if( !( m_abandoned ) && !( IsPlayerMounted() ) )
		{
			if( m_drivingTrafficPattern == 'stop' )
			{
				ResetReactionSequenceOfAllPassengers();
			}
			GameObject.PlayVoiceOver( VehicleComponent.GetDriverMounted( GetGame(), GetEntityID() ), 'fear_run', 'Scripts:PanicDrivingBehavior', , , true );
			m_drivingTrafficPattern = 'panic';
			m_crowdMemberComponent.ChangeMoveType( m_drivingTrafficPattern );
			ResetTimesSentReactionEvent();
		}
	}

	private function TriggerDrivingPanicBehavior( threatPosition : Vector4 )
	{
		var panicDrivingEvent : TriggerPanicDrivingEvent;
		GameInstance.GetDelaySystem( GetGame() ).CancelDelay( m_triggerPanicDrivingEventDelayID );
		panicDrivingEvent = new TriggerPanicDrivingEvent;
		if( EngineTime.ToFloat( GameInstance.GetSimTime( GetGame() ) ) <= ( m_hitTimestamp + 2.0 ) )
		{
			QueueEvent( panicDrivingEvent );
		}
		else if( Vector4.DistanceSquared( GetWorldPosition(), threatPosition ) < ( 15.0 * 15.0 ) )
		{
			m_triggerPanicDrivingEventDelayID = GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, panicDrivingEvent, RandRangeF( 0.40000001, 0.69999999 ) );
		}
		else
		{
			m_triggerPanicDrivingEventDelayID = GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, panicDrivingEvent, RandRangeF( 0.80000001, 1.5 ) );
		}
	}

	private function TriggerFearInsideVehicleBehavior()
	{
		var npcReactionEvent : DelayedCrowdReactionEvent;
		m_drivingTrafficPattern = 'stop';
		m_crowdMemberComponent.ChangeMoveType( m_drivingTrafficPattern );
		npcReactionEvent = new DelayedCrowdReactionEvent;
		npcReactionEvent.stimEvent = m_reactionTriggerEvent.stimEvent;
		npcReactionEvent.vehicleFearPhase = 2;
		VehicleComponent.QueueEventToAllPassengers( GetGame(), GetEntityID(), npcReactionEvent, , true );
	}

	public function TriggerExitBehavior( optional maxDelayOverride : Float )
	{
		var npcReactionEvent : DelayedCrowdReactionEvent;
		var passengersCanLeaveCar : array< weak< GameObject > >;
		var passengersCantLeaveCar : array< weak< GameObject > >;
		var exitEvent : AIEvent;
		VehicleComponent.CheckIfPassengersCanLeaveCar( GetGame(), GetEntityID(), passengersCanLeaveCar, passengersCantLeaveCar );
		m_drivingTrafficPattern = 'stop';
		m_crowdMemberComponent.ChangeMoveType( m_drivingTrafficPattern );
		npcReactionEvent = new DelayedCrowdReactionEvent;
		npcReactionEvent.stimEvent = m_reactionTriggerEvent.stimEvent;
		if( IsDestroyed() )
		{
			return;
		}
		if( ( passengersCanLeaveCar.Size() > 0 ) && !( IsA( 'vehicleAVBaseObject' ) ) )
		{
			if( ( ( ( IsPerformingPanicDriving() || ( ( ScriptedPuppet )( passengersCanLeaveCar[ 0 ] ) ).IsCrowd() ) && !( ( ( ScriptedPuppet )( passengersCanLeaveCar[ 0 ] ) ).IsPrevention() ) ) && !( ( ( ScriptedPuppet )( passengersCanLeaveCar[ 0 ] ) ).IsAggressive() ) ) && !( IsQuest() ) )
			{
				exitEvent = new AIEvent;
				exitEvent.name = 'ExitVehicleInPanic';
				VehicleComponent.QueueEventToPassengers( GetGame(), GetEntityID(), exitEvent, passengersCanLeaveCar, true, maxDelayOverride );
				npcReactionEvent.vehicleFearPhase = 3;
				VehicleComponent.QueueEventToPassengers( GetGame(), GetEntityID(), npcReactionEvent, passengersCanLeaveCar, true, maxDelayOverride );
			}
			else
			{
				exitEvent = new AIEvent;
				exitEvent.name = 'ExitVehicle';
				VehicleComponent.QueueEventToPassengers( GetGame(), GetEntityID(), exitEvent, passengersCanLeaveCar, true, maxDelayOverride );
			}
			ResetTimesSentReactionEvent();
		}
		if( passengersCantLeaveCar.Size() > 0 )
		{
			if( ( ( ScriptedPuppet )( passengersCantLeaveCar[ 0 ] ) ).IsCharacterCivilian() )
			{
				npcReactionEvent.vehicleFearPhase = 2;
			}
			VehicleComponent.QueueEventToPassengers( GetGame(), GetEntityID(), npcReactionEvent, passengersCantLeaveCar, true );
			ResendHandleReactionEvent();
		}
		m_abandoned = true;
	}

	private function ResendHandleReactionEvent()
	{
		var delayTime : Float;
		if( !( IsTargetClose( m_reactionTriggerEvent.stimEvent.sourceObject.GetWorldPosition(), 20.0 ) ) )
		{
			if( m_timesToResendHandleReactionEvent == 0 )
			{
				m_timesToResendHandleReactionEvent = TweakDBInterface.GetInt( T"AIGeneralSettings.timesToResendHandleReactionEvent", 3 );
			}
			if( m_timesSentReactionEvent >= m_timesToResendHandleReactionEvent )
			{
				return;
			}
			m_timesSentReactionEvent += 1;
		}
		else
		{
			m_timesSentReactionEvent = 0;
		}
		delayTime = RandRangeF( 2.0, 3.0 );
		GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, m_reactionTriggerEvent, delayTime );
	}

	private function ResetTimesSentReactionEvent()
	{
		m_timesSentReactionEvent = 0;
	}

	private function ResetReactionSequenceOfAllPassengers()
	{
		var mountingInfos : array< MountingInfo >;
		var count, i : Int32;
		var workspotSystem : WorkspotGameSystem;
		mountingInfos = GameInstance.GetMountingFacility( GetGame() ).GetMountingInfoMultipleWithObjects( , this );
		count = mountingInfos.Size();
		workspotSystem = GameInstance.GetWorkspotSystem( GetGame() );
		for( i = 0; i < count; i += 1 )
		{
			workspotSystem.HardResetPlaybackToStart( ( ( GameObject )( GameInstance.FindEntityByID( GetGame(), mountingInfos[ i ].childId ) ) ) );
		}
	}

	private function CanNPCsLeaveVehicle() : Bool
	{
		var direction : Vector4;
		var angleToTarget : Float;
		if( IsTargetClose( m_reactionTriggerEvent.stimEvent.sourceObject.GetWorldPosition(), 25.0 ) )
		{
			direction = m_reactionTriggerEvent.stimEvent.sourceObject.GetWorldPosition() - GetWorldPosition();
			angleToTarget = Vector4.GetAngleDegAroundAxis( direction, GetWorldForward(), GetWorldUp() );
			if( AbsF( angleToTarget ) < 85.0 )
			{
				return true;
			}
			return false;
		}
		return true;
	}

	private function IsTargetClose( targetPosition : Vector4, distance : Float ) : Bool
	{
		var distanceSquared : Float;
		distanceSquared = Vector4.DistanceSquared( targetPosition, GetWorldPosition() );
		if( distanceSquared < ( distance * distance ) )
		{
			return true;
		}
		return false;
	}

	protected event OnHit( evt : gameHitEvent )
	{
		super.OnHit( evt );
	}

	public function ShouldPreventionReactToExplosion() : Bool
	{
		return m_hitByPlayer && ( ( GetBlackboard() && GetBlackboard().GetBool( GetAllBlackboardDefs().Vehicle.IsCrowd ) ) || IsVehicleParked() );
	}

	public override function ReactToHitProcess( hitEvent : gameHitEvent )
	{
		var isFromPrevention : Bool;
		super.ReactToHitProcess( hitEvent );
		isFromPrevention = false;
		if( hitEvent.attackData.GetInstigator() )
		{
			isFromPrevention = hitEvent.attackData.GetInstigator().IsPrevention();
			if( !( m_hitByPlayer ) )
			{
				m_hitByPlayer = hitEvent.attackData.GetInstigator().IsPlayer();
			}
		}
		if( ( IsPrevention() && IsCrowdVehicle() ) && !( isFromPrevention ) )
		{
			m_vehicleComponent.InjectThreat( hitEvent.attackData.GetInstigator() );
		}
	}

	private override final function OnHitSounds( hitEvent : gameHitEvent )
	{
		if( !( AttackData.IsRangedOrDirect( hitEvent.attackData.GetAttackType() ) ) )
		{
			return;
		}
		if( !( hitEvent.attackData.GetInstigator().IsPlayer() ) )
		{
			return;
		}
		GameInstance.GetAudioSystem( GetGame() ).PlayImpact( 'w_feedback_hit_armor', hitEvent.hitPosition, this );
	}

	protected event OnDamageReceived( evt : gameDamageReceivedEvent )
	{
		super.OnDamageReceived( evt );
		if( !( IsDead() ) && IsPlayerMounted() )
		{
			GameInstance.GetTelemetrySystem( GetGame() ).LogPlayerVehicleDamageReceived( ( ( Int32 )( evt.totalDamageReceived ) ) );
		}
	}

	protected export override function DamagePipelineFinalized( evt : gameHitEvent )
	{
		var driver : GameObject;
		super.DamagePipelineFinalized( evt );
		if( !( GameObject.IsCooldownActive( this, 'vehicleHitCooldown' ) ) )
		{
			GameObject.StartCooldown( this, 'vehicleHitCooldown', 1.0 );
			m_hitTimestamp = EngineTime.ToFloat( GameInstance.GetSimTime( GetGame() ) );
		}
		driver = VehicleComponent.GetDriverMounted( GetGame(), this.GetEntityID() );
		if( driver && ( ( ScriptedPuppet )( driver ) ).GetHighLevelStateFromBlackboard() != gamedataNPCHighLevelState.Combat )
		{
			if( this.GetVehicleComponent().HasPreventionPassenger() )
			{
				StimBroadcasterComponent.SendStimDirectly( evt.attackData.GetInstigator(), gamedataStimType.CombatHit, driver );
			}
		}
		ApplyDamagesToDriver( evt );
	}

	public function ApplyDamagesToDriver( evt : gameHitEvent )
	{
		var instigator : weak< GameObject >;
		var attackContext : AttackInitContext;
		var attack : IAttack;
		var driverKillEvt : gameHitEvent;
		var health : Float;
		var maxHealth : Float;
		var damage : Float;
		var percentHealthDamage : Float;
		var curHealth : Float;
		var chance : Float;
		var baseNumberOfHits : Float;
		instigator = evt.attackData.GetInstigator();
		if( ( ( ( instigator.IsPlayer() && !( IsPlayerDriver() ) ) && ( VehicleComponent.GetDriverMounted( GetGame(), GetEntityID() ) != NULL ) ) && RPGManager.HasStatFlag( instigator, gamedataStatType.CanPlayerPierceDriver ) ) && AttackData.IsRangedOrDirect( evt.attackData.GetAttackType() ) )
		{
			health = GameInstance.GetStatPoolsSystem( GetGame() ).GetStatPoolValue( GetEntityID(), gamedataStatPoolType.Health, false );
			maxHealth = GameInstance.GetStatPoolsSystem( GetGame() ).GetStatPoolMaxPointValue( GetEntityID(), gamedataStatPoolType.Health );
			damage = evt.attackComputed.GetAttackValue( gamedataDamageType.Physical );
			curHealth = ( health - damage ) / maxHealth;
			percentHealthDamage = ClampF( damage / maxHealth, 0.0, 0.30000001 );
			baseNumberOfHits = 20.0;
			chance = TweakDBInterface.GetFloat( T"Attacks.DriverKill" + T".chance", 1.0 );
			chance = ( chance * percentHealthDamage ) * baseNumberOfHits;
			if( curHealth > 0.5 )
			{
				chance = chance * ( 1.5 - curHealth );
			}
			if( ( ( Float )( RandRange( 0, 100 ) ) ) < chance )
			{
				driverKillEvt = new gameHitEvent;
				driverKillEvt.attackData = new AttackData;
				attackContext.record = TweakDBInterface.GetAttackRecord( T"Attacks.DriverKill" );
				attackContext.instigator = evt.attackData.GetInstigator();
				attackContext.source = evt.attackData.GetSource();
				attack = IAttack.Create( attackContext );
				driverKillEvt.target = VehicleComponent.GetDriverMounted( GetGame(), GetEntityID() );
				driverKillEvt.attackData.SetAttackDefinition( attack );
				driverKillEvt.attackData.SetInstigator( evt.attackData.GetInstigator() );
				driverKillEvt.attackData.SetSource( evt.attackData.GetSource() );
				driverKillEvt.attackData.SetAttackType( gamedataAttackType.Effect );
				driverKillEvt.attackData.AddFlag( hitFlag.Kill, 'driver_kill' );
				GameInstance.GetDamageSystem( GetGame() ).QueueHitEvent( driverKillEvt, this );
			}
		}
	}

	public function IsOnPavement() : Bool
	{
		return m_onPavement;
	}

	protected event OnPavement( evt : OnPavement )
	{
		m_onPavement = true;
	}

	protected event OnOffPavement( evt : OffPavement )
	{
		m_onPavement = false;
	}

	private const function IsActionQueueEnabled() : Bool
	{
		var playerPuppet : PlayerPuppet;
		playerPuppet = GetPlayer( GetGame() );
		return QuickHackableQueueHelper.IsActionQueueEnabled( m_currentlyUploadingAction, playerPuppet );
	}

	private const function IsActionQueueFull() : Bool
	{
		return QuickHackableQueueHelper.IsActionQueueFull( m_currentlyUploadingAction );
	}

	public override function SetCurrentlyUploadingAction( action : ScriptableDeviceAction )
	{
		m_currentlyUploadingAction = action;
	}

	public override function GetCurrentlyUploadingAction() : ScriptableDeviceAction
	{
		return m_currentlyUploadingAction;
	}

	protected event OnInCrowd( evt : InCrowd )
	{
		var vehicleDriver : weak< GameObject >;
		var hls : gamedataNPCHighLevelState;
		m_inTrafficLane = true;
		if( !( m_driverUnconscious ) )
		{
			vehicleDriver = VehicleComponent.GetDriverMounted( GetGame(), GetEntityID() );
			if( vehicleDriver )
			{
				hls = ( ( ScriptedPuppet )( vehicleDriver ) ).GetHighLevelStateFromBlackboard();
				if( hls != gamedataNPCHighLevelState.Fear && m_drivingTrafficPattern == 'stop' )
				{
					m_drivingTrafficPattern = 'normal';
					m_crowdMemberComponent.ChangeMoveType( m_drivingTrafficPattern );
				}
			}
			m_fearInside = false;
		}
	}

	protected event OnOutOfCrowd( evt : OutOfCrowd )
	{
		m_inTrafficLane = false;
	}

	public function IsInTrafficLane() : Bool
	{
		return m_inTrafficLane;
	}

	public function IsVehicleUpsideDown() : Bool
	{
		return m_vehicleUpsideDown;
	}

	public function ComputeIsVehicleUpsideDown() : Bool
	{
		return Vector4.Dot( GetWorldUp(), Vector4.UP() ) < 0.0;
	}

	public function GetVehicleType() : gamedataVehicleType
	{
		var vehicleRecord : Vehicle_Record;
		var vehicleTypeRecord : VehicleType_Record;
		vehicleRecord = GetRecord();
		if( !( vehicleRecord ) )
		{
			return gamedataVehicleType.Invalid;
		}
		vehicleTypeRecord = vehicleRecord.Type();
		if( !( vehicleTypeRecord ) )
		{
			return gamedataVehicleType.Invalid;
		}
		return vehicleTypeRecord.Type();
	}

	protected event OnVehicleFlippedOverEvent( evt : VehicleFlippedOverEvent )
	{
		m_vehicleUpsideDown = evt.isFlippedOver;
	}

	protected event OnStealVehicleEvent( evt : StealVehicleEvent )
	{
		m_abandoned = true;
	}

	public const override function IsQuest() : Bool
	{
		return GetVehiclePS().IsMarkedAsQuest();
	}

	protected override function MarkAsQuest( isQuest : Bool )
	{
		GetVehiclePS().SetIsMarkedAsQuest( isQuest );
	}

	protected event OnSwitchVehicleVisualCustomizationStateEvent( evt : SwitchVehicleVisualCustomizationStateEvent )
	{
		if( GetVehiclePS().GetIsVehicleVisualCustomizationDefinitionDefined() && !( GetVehiclePS().GetIsVehicleVisualCustomizationBlockedByDamage() ) )
		{
			ExecuteVisualCustomizationWithDelay( evt.on, !( evt.on ), false, 0.80000001, evt.noVFX );
		}
	}

	protected event OnNewVehicleVisualCustomizationEvent( evt : NewVehicleVisualCustomizationEvent )
	{
		var PS : VehicleComponentPS;
		var set : vehicleVisualModdingDefinition;
		var oldSet : vehicleVisualModdingDefinition;
		var storageComponent : vehicleVisualCustomizationComponent;
		var componentEvent : StoreVisualCustomizationDataForIDEvent;
		var vehComponent : VehicleComponent;
		var customizationComponent : vehicleVisualCustomizationComponent;
		var colorsUnchanged : Bool;
		vehComponent = GetVehicleComponent();
		PS = GetVehiclePS();
		customizationComponent = GetPlayer( GetGame() ).GetVehicleVisualCustomizationComponent();
		if( ( !( vehComponent ) || !( PS ) ) || !( customizationComponent ) )
		{
			return false;
		}
		PS = GetVehiclePS();
		set = evt.modSet;
		oldSet = PS.GetVehicleVisualCustomizationDefinition();
		colorsUnchanged = customizationComponent.GetAreColorsUnchanged( set, oldSet );
		PS.SetVehicleVisualCustomizationDefinition( set );
		if( !( evt.reset ) )
		{
			if( !( colorsUnchanged ) && ( set.primaryColorDefined || set.secondaryColorDefined ) )
			{
				ExecuteVisualCustomizationWithDelay( true, false, false, 0.80000001 );
			}
			else
			{
				GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, new VehicleVisualCustomizationPerformedEvent, 0.80000001 );
				StatusEffectHelper.ApplyStatusEffect( GetPlayer( GetGame() ), T"BaseStatusEffect.VehicleVisualModCooldownInstant" );
			}
		}
		else
		{
			if( oldSet.primaryColorDefined || oldSet.secondaryColorDefined )
			{
				ExecuteVisualCustomizationWithDelay( true, true, false, 0.80000001 );
			}
			else
			{
				GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, new VehicleVisualCustomizationPerformedEvent, 0.80000001 );
				StatusEffectHelper.ApplyStatusEffect( GetPlayer( GetGame() ), T"BaseStatusEffect.VehicleVisualModCooldownInstant" );
				GetVehiclePS().SetVehicleVisualCustomizationActive( true );
			}
		}
		if( !( colorsUnchanged ) )
		{
			vehComponent.ProcessHeatLevelOnVisualCustomization( evt.modSet );
		}
		storageComponent = GetMainPlayer( GetGame() ).GetVehicleVisualCustomizationComponent();
		if( storageComponent && vehComponent.GetIsVehicleVisualCustomizationEnabled() )
		{
			componentEvent = new StoreVisualCustomizationDataForIDEvent;
			componentEvent.definition = set;
			componentEvent.ID = GetRecordID();
			storageComponent.QueueEntityEvent( componentEvent );
		}
	}

	protected function ExecuteVisualCustomizationWithDelay( set : Bool, reset : Bool, instant : Bool, optional delay : Float, optional noVFX : Bool )
	{
		var evt : ExecuteVehicleVisualCustomizationEvent;
		evt = new ExecuteVehicleVisualCustomizationEvent;
		evt.set = set;
		evt.reset = reset;
		evt.instant = instant;
		if( !( IsPlayerMounted() ) )
		{
			return;
		}
		if( !( noVFX ) )
		{
			GameObjectEffectHelper.StartEffectEvent( this, 'visual_customization_appearance_distortion' );
		}
		if( ( delay == 0.0 ) || instant )
		{
			QueueEvent( evt );
		}
		else
		{
			GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, evt, delay );
		}
	}

	protected event OnProcessVehicleVisualCustomizationLights( evt : VehicleCustomizationLightsEvent )
	{
		var lightsEvent : VehicleLightQuestChangeColorEvent;
		var ColorSet : vehicleVisualModdingDefinition;
		var color : Color;
		var vehicleRecord : Vehicle_Record;
		ColorSet = GetVehiclePS().GetVehicleVisualCustomizationDefinition();
		if( ColorSet.lightsColorDefined )
		{
			color = GetPlayer( GetGame() ).GetVehicleVisualCustomizationComponent().VehicleVisualCustomizationColorParamsToColor( ColorSet.lightsColorH, false, 0.5, 1.0 );
			lightsEvent = new VehicleLightQuestChangeColorEvent;
			lightsEvent.color = color;
			lightsEvent.lightType = vehicleELightType.Head;
			QueueEvent( lightsEvent );
			lightsEvent = new VehicleLightQuestChangeColorEvent;
			lightsEvent.color = color;
			lightsEvent.lightType = vehicleELightType.Interior;
			QueueEvent( lightsEvent );
		}
		else
		{
			vehicleRecord = GetRecord();
			lightsEvent = new VehicleLightQuestChangeColorEvent;
			lightsEvent.lightType = vehicleELightType.Head;
			if( vehicleRecord.GetHeadlightColorCount() == 4 )
			{
				lightsEvent.color = Color( ( ( Uint8 )( vehicleRecord.GetHeadlightColorItem( 0 ) ) ), ( ( Uint8 )( vehicleRecord.GetHeadlightColorItem( 1 ) ) ), ( ( Uint8 )( vehicleRecord.GetHeadlightColorItem( 2 ) ) ), ( ( Uint8 )( vehicleRecord.GetHeadlightColorItem( 3 ) ) ) );
			}
			else
			{
				lightsEvent.color = Color( 255, 255, 255, 255 );
			}
			QueueEvent( lightsEvent );
			lightsEvent = new VehicleLightQuestChangeColorEvent;
			lightsEvent.lightType = vehicleELightType.Interior;
			if( vehicleRecord.GetInteriorColorCount() == 4 )
			{
				lightsEvent.color = Color( ( ( Uint8 )( vehicleRecord.GetInteriorColorItem( 0 ) ) ), ( ( Uint8 )( vehicleRecord.GetInteriorColorItem( 1 ) ) ), ( ( Uint8 )( vehicleRecord.GetInteriorColorItem( 2 ) ) ), ( ( Uint8 )( vehicleRecord.GetInteriorColorItem( 3 ) ) ) );
			}
			else
			{
				lightsEvent.color = Color( 255, 255, 255, 255 );
			}
			QueueEvent( lightsEvent );
		}
	}

	protected event OnVehicleVisualCustomizationPerformedEvent( evt : VehicleVisualCustomizationPerformedEvent )
	{
		var blackboard : IBlackboard;
		blackboard = GetBlackboard();
		blackboard.SetBool( GetAllBlackboardDefs().Vehicle.VehicleCustomizationInstant, false );
		GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, new VehicleCustomizationLightsEvent, 0.5 );
	}

	protected event OnVehicleVisualCustomizationAppearanceChange( evt : VehicleVisualCustomizationAppearanceChange )
	{
		GetVehicleComponent().EnableCustomizableAppearance( evt.val );
	}

	public function GetCustomizationWidgets() : array< worlduiWidgetComponent >
	{
		var widgets : array< worlduiWidgetComponent >;
		widgets = GetUIComponents();
		return widgets;
	}

	private function SyncVehicleVisualCustomizationDefinition()
	{
		var PS : VehicleComponentPS;
		var set : vehicleVisualModdingDefinition;
		var component : vehicleVisualCustomizationComponent;
		PS = GetVehiclePS();
		component = GetPlayer( GetGame() ).GetVehicleVisualCustomizationComponent();
		if( GetVehicleComponent().GetIsVehicleVisualCustomizationEnabled() )
		{
			if( component )
			{
				set = component.RetriveVisualCustomizationDefinitionForID( GetRecordID() );
				PS.SetVehicleVisualCustomizationDefinition( set );
			}
		}
	}

}

importonly class WheeledObject extends VehicleObject
{
	public import final function ToggleBrokenTire( tireID : Uint32, toggle : Bool ) : Bool;
	public import const final function GetFlatTireIndex() : Int32;
}

importonly class CarObject extends WheeledObject
{
}

importonly class BikeObject extends WheeledObject
{
	public import final function IsTiltControlEnabled() : Bool;
	public import final function EnableTiltControl( enable : Bool );
	public import final function GetCustomTargetTilt() : Float;
	public import final function SetCustomTargetTilt( targetTilt : Float );
	public import final function IsPerformingAWheelieOrEndo( minCOMOffset : Float, minPitchAngle : Float ) : Bool;
}

importonly class TankObject extends VehicleObject
{
}

import class AVObject extends VehicleObject
{

	public function TurnOffThrusters()
	{
		GameObjectEffectHelper.BreakEffectLoopEvent( this, 'thrusters' );
	}

	public function TurnOnThrusters()
	{
		GameObjectEffectHelper.StartEffectEvent( this, 'thrusters' );
	}

}

import class PreventionAVObject extends AVObject
{
}

class MetroPitchAdjustmentEvent extends Event
{
}

class MetroPlayerAdjustmentEvent extends Event
{
}

class ncartMetroObject extends AVObject
{
	private var m_pitchAdjustmentDelayID : DelayID;
	private var m_Z : Float;
	private var m_checkForLeveling : Bool;
	private var m_pitchingValue : Int32;
	editable var m_pitchAngleCheckInterval : Float;
	default m_pitchAngleCheckInterval = 0.4f;
	editable var m_pitchAngleReturnInterval : Float;
	default m_pitchAngleReturnInterval = 0.75f;
	editable var m_trainReverseDirectionFactName : CName;
	default m_trainReverseDirectionFactName = 'ue_metro_track_reverse';
	editable var m_pitchAngleAdjustmentTreshold : Float;
	default m_pitchAngleAdjustmentTreshold = 0.9f;
	editable var m_pitchAngleLevelOutTreshold : Float;
	default m_pitchAngleLevelOutTreshold = 0.5f;

	protected event OnGameAttached()
	{
		super.OnGameAttached();
		m_Z = WorldPosition.GetZ( WorldTransform.GetWorldPosition( GetWorldTransform() ) );
		TogglePitchAdjustment( true );
	}

	protected event OnDetach()
	{
		super.OnDetach();
		TogglePitchAdjustment( false );
	}

	private function PerformYawAjustment()
	{
		var orientation : Quaternion;
		var angles : EulerAngles;
		orientation = WorldTransform.GetOrientation( GetWorldTransform() );
		angles = Quaternion.ToEulerAngles( orientation );
		angles.Yaw = AngleNormalize180( angles.Yaw + 180.0 );
		GameInstance.GetTeleportationFacility( this.GetGame() ).Teleport( this, GetWorldPosition(), angles );
	}

	private function TogglePitchAdjustment( on : Bool )
	{
		var delaySystem : DelaySystem;
		delaySystem = GameInstance.GetDelaySystem( GetGame() );
		if( on )
		{
			m_pitchAdjustmentDelayID = delaySystem.DelayEvent( this, new MetroPitchAdjustmentEvent, m_pitchAngleCheckInterval );
		}
		else
		{
			delaySystem.CancelDelay( m_pitchAdjustmentDelayID );
		}
	}

	private function PerformPitchAdjustment( z : Float )
	{
		var animPlay : gameTransformAnimationPlayEvent;
		if( m_Z > z )
		{
			animPlay = new gameTransformAnimationPlayEvent;
			animPlay.animationName = 'PitchDown';
			animPlay.timeScale = 1.0;
			animPlay.timesPlayed = 1;
			m_pitchingValue = -1;
			this.QueueEvent( animPlay );
		}
		else
		{
			animPlay = new gameTransformAnimationPlayEvent;
			animPlay.timeScale = 1.0;
			animPlay.animationName = 'PitchUp';
			animPlay.timesPlayed = 1;
			m_pitchingValue = 1;
			this.QueueEvent( animPlay );
		}
	}

	private function LevelOutPitch()
	{
		var animPlay : gameTransformAnimationPlayEvent;
		switch( m_pitchingValue )
		{
			case 1:
			{
				animPlay = new gameTransformAnimationPlayEvent;
				animPlay.animationName = 'PitchUp';
				animPlay.timeScale = -1.0;
				animPlay.timesPlayed = 1;
				m_pitchingValue = 0;
				this.QueueEvent( animPlay );
			}
			break;
			case -1:
			{
				animPlay = new gameTransformAnimationPlayEvent;
				animPlay.animationName = 'PitchDown';
				animPlay.timeScale = -1.0;
				animPlay.timesPlayed = 1;
				m_pitchingValue = 0;
				this.QueueEvent( animPlay );
			}
			break;
		}
	}

	protected event OnMetroPitchAdjustmentEvent( evt : MetroPitchAdjustmentEvent )
	{
		var z : Float;
		var disablingFact : Int32;
		var questSystem : QuestsSystem;
		questSystem = GameInstance.GetQuestsSystem( this.GetGame() );
		z = WorldPosition.GetZ( WorldTransform.GetWorldPosition( GetWorldTransform() ) );
		disablingFact = questSystem.GetFact( 'ue_metro_disable_pitch_adjustment' );
		if( disablingFact >= 1 )
		{
			if( m_checkForLeveling )
			{
				LevelOutPitch();
				m_checkForLeveling = false;
			}
			GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, new MetroPitchAdjustmentEvent, m_pitchAngleCheckInterval );
			m_Z = z;
		}
		else
		{
			if( !( m_checkForLeveling ) )
			{
				if( AbsF( m_Z - z ) > m_pitchAngleAdjustmentTreshold )
				{
					PerformPitchAdjustment( z );
					m_checkForLeveling = true;
				}
				GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, new MetroPitchAdjustmentEvent, m_pitchAngleCheckInterval );
			}
			else
			{
				if( AbsF( m_Z - z ) <= m_pitchAngleLevelOutTreshold )
				{
					LevelOutPitch();
					m_checkForLeveling = false;
				}
				GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, new MetroPitchAdjustmentEvent, m_pitchAngleReturnInterval );
				m_Z = z;
			}
		}
	}

}

function GetMountedVehicle( object : GameObject ) : weak< VehicleObject >
{
	var game : GameInstance;
	var mountingFacility : IMountingFacility;
	var mountingInfo : MountingInfo;
	var vehicle : weak< VehicleObject >;
	game = object.GetGame();
	mountingFacility = GameInstance.GetMountingFacility( game );
	mountingInfo = mountingFacility.GetMountingInfoSingleWithObjects( object );
	vehicle = ( ( VehicleObject )( GameInstance.FindEntityByID( game, mountingInfo.parentId ) ) );
	return vehicle;
}

import enum vehicleExitDirection
{
	NoDirection,
	Left,
	Right,
	Front,
	Back,
	Top,
}

import enum vehicleCoolExitImpulseLevel
{
	NoExit,
	NoImpulse,
	LowImpulse,
	MaxImpulse,
}

importonly struct vehicleUnmountPosition
{
	import var direction : vehicleExitDirection;
	import var position : WorldPosition;
}

class HandleReactionEvent extends Event
{
	var fearPhase : Int32;
	var stimEvent : StimuliEvent;
}

class WaitForPassengersToSpawnEvent extends Event
{
}

class TriggerPanicDrivingEvent extends Event
{
}

class DelayReactionToMissingPassengersEvent extends Event
{
	var stimEvent : StimuliEvent;
	var delayedAlready : Bool;
}

