enum ETargetManagerAnimGraphState
{
	MODELOOKAT = 0,
	IDLE = 1,
	JAMMED = 2,
}

enum ESensorDeviceWakeState
{
	NONE = -1,
	CLOSED = 0,
	WAKEN = 1,
	OPEN = 2,
}

enum ESensorDeviceStates
{
	NONE = 0,
	IDLE = 1,
	IDLEFORCED = 2,
	TARGETLOCK = 3,
	TARGETLOSE = 4,
	TARGETRECEIVED = 5,
	REPRIMAND = 6,
	JAMMER = 7,
}

struct PlayerControlDeviceData
{
	var m_currentYawModifier : Float;
	var m_currentPitchModifier : Float;
}

struct CameraRotationData
{
	var m_pitch : Float;
	var m_maxPitch : Float;
	var m_minPitch : Float;
	var m_yaw : Float;
	var m_maxYaw : Float;
	var m_minYaw : Float;
}

class ReactoToPreventionSystem extends Event
{
	var wakeUp : Bool;
}

class ResolveSensorDeviceBehaviour extends Event
{
	var iteration : Int32;
}

class LostTargetDelayFalsePositivesDelay extends Event
{
	var target : weak< GameObject >;
}

class SetDetectionMultiplier extends Event
{
	var multiplier : Float;
}

class TurnOnVisibilitySenseComponent extends Event
{
}

class HostileUpdateTowardsPlayerHostiles extends Event
{
}

class AnimFeature_SensorDevice extends AnimFeature
{
	var isCeiling : Bool;
	var isInitialized : Bool;
	default isInitialized = true;
	editable var isTurnedOn : Bool;
	editable var isDestroyed : Bool;
	editable var wasHit : Bool;
	editable var state : Int32;
	editable var wakeState : Int32;
	editable var isControlled : Bool;
	editable var overrideRootRotation : Float;
	editable var pitchAngle : Float;
	editable var maxRotationAngle : Float;
	editable var rotationSpeed : Float;
	editable var currentRotation : Vector4;
}

class DisableAreaIndicatorEvent extends Event
{
}

class KillTaggedTargetEvent extends Event
{
	var taggedObject : weak< GameObject >;
}

class TargetLockedEvent extends Event
{
}

class ReevaluateTargetsEvent extends Event
{
}

class SetJammedEvent extends Event
{
	var newJammedState : Bool;
	var instigator : weak< WeaponObject >;
}

class QuestForceAttitude extends ActionName
{

	public function SetProperties( atttitudeName : CName )
	{
		actionName = 'QuestForceAttitude';
		prop = DeviceActionPropertyFunctions.SetUpProperty_Name( 'atttitudeName', atttitudeName );
	}

}

class UnregisterListenerOnTargetHPEvent extends Event
{
	var listener : TargetedObjectDeathListener;
	var isFromListenerEvent : Bool;
}

class TargetedObjectDeathListener extends CustomValueStatPoolsListener
{
	var m_lsitener : weak< SensorDevice >;
	var m_lsitenTarget : weak< GameObject >;

	protected event OnStatPoolMinValueReached( value : Float )
	{
		if( m_lsitenTarget )
		{
			m_lsitener.UnregisterListenerOnTargetHP( m_lsitener, this );
		}
	}

}

struct LedColors_SensorDevice
{
	var off : ScriptLightSettings;
	var red : ScriptLightSettings;
	var green : ScriptLightSettings;
	var blue : ScriptLightSettings;
	var yellow : ScriptLightSettings;
	var white : ScriptLightSettings;
}

class SensorDevice extends ExplosiveDevice
{
	protected var m_attitudeAgent : AttitudeAgent;
	protected var m_senseComponent : SenseComponent;
	protected var m_visibleObjectComponent : VisibleObjectComponent;
	private var m_forwardFaceSlotComponent : SlotComponent;
	private var m_targetingComponent : TargetingComponent;
	private var m_targetTrackerComponent : TargetTrackerComponent;
	protected var m_cameraComponentInverted : CameraComponent;
	private var m_targets : array< Target >;
	private var m_currentlyFollowedTarget : weak< GameObject >;
	protected var m_currentLookAtEventVert : LookAtAddEvent;
	protected var m_currentLookAtEventHor : LookAtAddEvent;
	private var m_HPListenersList : array< TargetedObjectDeathListener >;
	private var m_sensorDeviceState : ESensorDeviceStates;
	default m_sensorDeviceState = ESensorDeviceStates.IDLE;
	private var m_sensorWakeState : ESensorDeviceWakeState;
	default m_sensorWakeState = ESensorDeviceWakeState.NONE;
	private var m_sensorWakeStatePrevious : ESensorDeviceWakeState;
	private var m_targetingDelayEventID : DelayID;
	private var hack_isTargetingDelayEventFilled : Bool;
	private var m_currentResolveDelayEventID : DelayID;
	private var hack_isResolveDelayEventFilled : Bool;
	private var m_animFeatureData : AnimFeature_SensorDevice;
	private var m_animFeatureDataName : CName;
	private var m_targetLostBySensesDelayEventID : DelayID;
	private var hack_isTargetLostBySensesDelEvtFilled : Bool;
	private var m_initialAttitude : CName;
	private var m_detectionFactorMultiplier : Float;
	private var m_taggedListenerCallback : CallbackHandle;
	protected var m_lightScanRefs : array< gameLightComponent >;
	protected var m_lightAttitudeRefs : array< gameLightComponent >;
	protected var m_lightInfoRefs : array< gameLightComponent >;
	protected var m_lightColors : LedColors_SensorDevice;
	protected var m_deviceFXRecord : DeviceFX_Record;
	protected var m_scanGameEffect : EffectInstance;
	protected var m_scanFXSlotName : CName;
	default m_scanFXSlotName = 'laser';
	protected var m_visionConeEffectInstance : EffectInstance;
	protected var m_idleGameEffectInstance : EffectInstance;
	private var m_targetForcedFormTagKill : Bool;
	private var m_hasSupport : Bool;
	protected var m_defaultSensePreset : TweakDBID;
	default m_defaultSensePreset = T"Senses.BasicCamera";
	private var m_keepHostilityTowardsPlayerHostiles : Bool;
	private var m_hostileUpdateTowardsPlayerHostilesDelayed : Bool;
	[ category = "Sensor entity specific data" ]
	protected const editable var m_elementsToHideOnTCS : array< CName >;
	protected var m_elementsToHideOnTCSRefs : array< IPlacedComponent >;
	var m_previoustagKillList : array< weak< GameObject > >;
	[ category = "Sensor entity specific data" ]
	protected editable var m_playIdleSoundOnIdle : Bool;
	default m_playIdleSoundOnIdle = true;
	[ category = "Sensor entity specific data" ][ customEditor = "AudioEvent" ]
	protected editable var m_idleSound : CName;
	[ category = "Sensor entity specific data" ][ customEditor = "AudioEvent" ]
	protected editable var m_idleSoundStop : CName;
	[ category = "Sensor entity specific data" ][ customEditor = "AudioEvent" ]
	protected editable var m_soundDeviceON : CName;
	[ category = "Sensor entity specific data" ][ customEditor = "AudioEvent" ]
	protected editable var m_soundDeviceOFF : CName;
	private var m_idleSoundIsPlaying : Bool;
	protected var m_soundDeviceDestroyed : CName;
	protected var m_soundDetectionLoop : CName;
	protected var m_soundDetectionLoopStop : CName;
	private var m_isPLAYERSAFETargetLock : Bool;
	private var m_playerDetected : Bool;
	private var m_clientForceSetAnimFeature : Bool;
	default m_clientForceSetAnimFeature = false;
	private var m_playerControlData : PlayerControlDeviceData;
	private var engineTimeInSec : Float;
	private var TCExitEngineTime : Float;
	private var hack_wasTargetReevaluated : Bool;
	private var hack_wasSSOutupFromSelf : Bool;
	private var degbu_SS_inputsSend : Int32;
	private var debug_SS_inputsSendTargetLock : Int32;
	private var debug_SS_inputsSendIntresting : Int32;
	private var debug_SS_inputsSendLoseTarget : Int32;
	private var debug_SS_outputRecieved : Int32;
	private var debug_SS_outputFormSelfRecieved : Int32;
	private var debug_SS_outputFromElseRecieved : Int32;
	private var debug_SS_reevaluatesDone : Int32;
	private var debug_SS_trespassingRecieved : Int32;
	private var debug_SS_TargetAssessmentRequest : Int32;
	[ category = "Sensor entity specific data" ]
	protected editable var m_minPitch : Float;
	default m_minPitch = -70;
	[ category = "Sensor entity specific data" ]
	protected editable var m_maxPitch : Float;
	default m_maxPitch = 70;
	[ category = "Sensor entity specific data" ]
	protected editable var m_minYaw : Float;
	default m_minYaw = 0;
	[ category = "Sensor entity specific data" ]
	protected editable var m_maxYaw : Float;
	default m_maxYaw = 0;

	protected function ResolveConnectionWithSecuritySystemByTask()
	{
		GameInstance.GetDelaySystem( GetGame() ).QueueTask( this, NULL, 'ResolveConnectionWithSecuritySystemTask', gameScriptTaskExecutionStage.Any );
	}

	protected function ResolveConnectionWithSecuritySystemTask( data : ScriptTaskData )
	{
		ResolveConnectionWithSecuritySystem();
	}

	protected function ResolveConnectionWithSecuritySystem()
	{
		var secSys : SecuritySystemControllerPS;
		secSys = GetSecuritySystem();
		if( secSys )
		{
			secSys.RequestLatestOutput( GetEntityID() );
			if( !( ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsAttitudeChanged() ) )
			{
				if( m_attitudeAgent )
				{
					m_attitudeAgent.SetAttitudeGroup( secSys.GetSecuritySystemAttitudeGroupName() );
				}
			}
		}
	}

	protected function HandleSecuritySystemOutputByTask()
	{
		GameInstance.GetDelaySystem( GetGame() ).QueueTask( this, NULL, 'HandleSecuritySystemOutputTask', gameScriptTaskExecutionStage.Any );
	}

	protected export function HandleSecuritySystemOutputTask( data : ScriptTaskData )
	{
		HandleSecuritySystemOutput();
	}

	protected function HandleSecuritySystemOutput()
	{
		if( ( GetDevicePS().IsControlledByPlayer() || GetDevicePS().IsSecurityWakeUpBlocked() ) || ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsAttitudeChanged() )
		{
			return;
		}
		SetSensePresetBasedOnSSState();
		BlinkSecurityLight( 2 );
		DetermineLightInfoRefs( m_lightColors.blue );
	}

	protected event OnRequestComponents( ri : EntityRequestComponentsInterface )
	{
		var i : Int32;
		super.OnRequestComponents( ri );
		EntityRequestComponentsInterface.RequestComponent( ri, 'AttitudeAgent', 'AttitudeAgent', true );
		EntityRequestComponentsInterface.RequestComponent( ri, 'detectionAreaIndicator', 'MeshComponent', false );
		EntityRequestComponentsInterface.RequestComponent( ri, 'senseComponent', 'SenseComponent', true );
		EntityRequestComponentsInterface.RequestComponent( ri, 'slot', 'SlotComponent', true );
		EntityRequestComponentsInterface.RequestComponent( ri, 'TargetTracker', 'TargetTrackerComponent', true );
		EntityRequestComponentsInterface.RequestComponent( ri, 'cameraComponentInvert', 'CameraComponent', false );
		EntityRequestComponentsInterface.RequestComponent( ri, 'senseVisibleObject', 'VisibleObjectComponent', false );
		for( i = 0; i < m_elementsToHideOnTCS.Size(); i += 1 )
		{
			EntityRequestComponentsInterface.RequestComponent( ri, m_elementsToHideOnTCS[ i ], 'IPlacedComponent', false );
		}
	}

	protected event OnTakeControl( ri : EntityResolveComponentsInterface )
	{
		var i : Int32;
		var component : IPlacedComponent;
		m_attitudeAgent = ( ( AttitudeAgent )( EntityResolveComponentsInterface.GetComponent( ri, 'AttitudeAgent' ) ) );
		m_senseComponent = ( ( SenseComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'senseComponent' ) ) );
		m_visibleObjectComponent = ( ( VisibleObjectComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'senseVisibleObject' ) ) );
		m_forwardFaceSlotComponent = ( ( SlotComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'slot' ) ) );
		m_targetingComponent = ( ( TargetingComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'targeting' ) ) );
		m_targetTrackerComponent = ( ( TargetTrackerComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'TargetTracker' ) ) );
		m_cameraComponentInverted = ( ( CameraComponent )( EntityResolveComponentsInterface.GetComponent( ri, 'cameraComponentInvert' ) ) );
		m_cameraComponentInverted.SetIsHighPriority( true );
		for( i = 0; i < m_elementsToHideOnTCS.Size(); i += 1 )
		{
			component = ( ( IPlacedComponent )( EntityResolveComponentsInterface.GetComponent( ri, m_elementsToHideOnTCS[ i ] ) ) );
			if( component )
			{
				m_elementsToHideOnTCSRefs.PushBack( component );
			}
		}
		m_animFeatureData = new AnimFeature_SensorDevice;
		m_animFeatureDataName = 'SensorDeviceData';
		super.OnTakeControl( ri );
	}

	public override function OnMaraudersMapDeviceDebug( sink : MaraudersMapDevicesSink )
	{
		var i : Int32;
		var targets : array< Target >;
		var targetVisible : String;
		super.OnMaraudersMapDeviceDebug( sink );
		sink.BeginCategory( "sensorDevice specific" );
		sink.BeginCategory( "Targets" );
		targets = GetCurrentTargets();
		for( i = 0; i < targets.Size(); i += 1 )
		{
			if( targets[ i ].IsVisible() )
			{
				targetVisible = "|V| ";
			}
			else
			{
				targetVisible = "|N| ";
			}
			sink.PushString( "Target " + i, targetVisible + EntityID.ToDebugString( targets[ i ].GetTarget().GetEntityID() ) );
		}
		sink.EndCategory();
		sink.PushBool( "Is Part of Prevention", IsPrevention() );
		sink.PushString( "Sensor Device State", EnumValueToString( "ESensorDeviceStates", ( ( Int32 )( GetSensorDeviceState() ) ) ) );
		sink.PushString( "Currnet Target", EntityID.ToDebugString( GetCurrentlyFollowedTarget().GetEntityID() ) );
		sink.PushBool( "HasSupport", m_hasSupport );
		sink.PushBool( "PlayerSafeTargeLock", IsPlayerSafeTargetLock() );
		sink.PushBool( "Is Quest Target Spotted", ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsQuestTargetSpotted() );
		sink.PushString( "Quest Target to Spot", EntityID.ToDebugString( ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).GetQuestSpotTargetID() ) );
		sink.PushString( "Quest Forced TargetID", EntityID.ToDebugString( ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).GetForcedTargetID() ) );
		sink.PushString( "Attitude", NameToString( GetAttitudeAgent().GetAttitudeGroup() ) );
		sink.PushBool( "Is Attitude Changed", ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsAttitudeChanged() );
		sink.PushBool( "Is Temporary Attitude Changed", IsTemporaryAttitudeChanged() );
		sink.PushBool( "Is in follow mode", ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsInFollowMode() );
		sink.PushBool( "Is in Tag Kill Mode", ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsInTagKillMode() );
		sink.PushBool( "Is Target Forced Tag Kill", IsTargetForcedFromTagKill() );
		sink.PushBool( "Is Idle Forced", ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsIdleForced() );
		sink.PushBool( "Is Detecting", ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsDetectingDebug() );
		sink.PushBool( "Can Rotate", ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).GetBehaviourCanRotate() );
		sink.BeginCategory( "Anim Feature" );
		sink.PushBool( "Is Turned On", m_animFeatureData.isTurnedOn );
		sink.PushBool( "Is Destroyed", m_animFeatureData.isDestroyed );
		sink.PushBool( "Was Hit", m_animFeatureData.wasHit );
		sink.PushInt32( "State", m_animFeatureData.state );
		sink.PushBool( "Is Controlled", m_animFeatureData.isControlled );
		sink.PushFloat( "Override Root Rotation", m_animFeatureData.overrideRootRotation );
		sink.PushFloat( "Max Rotation Angle", m_animFeatureData.maxRotationAngle );
		sink.EndCategory();
		sink.EndCategory();
	}

	protected override function ResolveGameplayState()
	{
		super.ResolveGameplayState();
		InitializeDeviceFXRecord();
		InitializeLights();
		ToggleActiveEffect( true );
	}

	protected event OnPostInitialize( evt : entPostInitializeEvent )
	{
		super.OnPostInitialize( evt );
		m_senseComponent.Toggle( false );
		m_defaultSensePreset = m_senseComponent.GetCurrentPreset();
		if( m_visibleObjectComponent )
		{
			m_visibleObjectComponent.Toggle( false );
		}
		ResolveConnectionWithSecuritySystem();
	}

	protected event OnPreUninitialize( evt : entPreUninitializeEvent )
	{
		super.OnPreUninitialize( evt );
		if( IsPrevention() )
		{
			PreventionSystem.UnRegisterToPreventionSystem( GetGame(), this );
		}
		TerminateGameEffect( m_scanGameEffect );
		TerminateGameEffect( m_visionConeEffectInstance );
		TerminateGameEffect( m_idleGameEffectInstance );
		ClearAllHPListeners();
		( ( SensorDeviceControllerPS )( GetDevicePS() ) ).NotifyAboutSpottingPlayer( false );
	}

	protected event OnGameAttached()
	{
		super.OnGameAttached();
		if( IsPrevention() )
		{
			PreventionSystem.RegisterToPreventionSystem( GetGame(), this );
		}
		if( IsClient() )
		{
			m_clientForceSetAnimFeature = true;
		}
		StartBehaviourResolve( ESensorDeviceStates.IDLE );
		if( IsClient() )
		{
			m_clientForceSetAnimFeature = false;
		}
		CreateLightSettings();
	}

	protected event OnDetach()
	{
		var tcsEvt : TCSTakeOverControlDeactivate;
		super.OnDetach();
		ForceCancelAllForcedBehaviours();
		if( EntityID.IsDynamic( GetEntityID() ) )
		{
			if( GetDevicePS().IsControlledByPlayer() )
			{
				( ( SensorDeviceControllerPS )( GetDevicePS() ) ).QuestReleaseCurrentObject();
				tcsEvt = new TCSTakeOverControlDeactivate;
				OnTCSTakeOverControlDeactivate( tcsEvt );
			}
		}
		KeepHostilityTowardsPlayerHostiles( false );
	}

	protected event OnAttitudeChanged( evt : AttitudeChangedEvent )
	{
		var agentPuppet : ScriptedPuppet;
		super.OnAttitudeChanged( evt );
		if( evt.attitude != EAIAttitude.AIA_Friendly )
		{
			agentPuppet = ( ( ScriptedPuppet )( evt.otherAgent.GetEntity() ) );
			if( agentPuppet.IsPlayer() )
			{
				KeepHostilityTowardsPlayerHostiles( false );
			}
		}
	}

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

	public const override function IsPrevention() : Bool
	{
		return ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsPartOfPrevention();
	}

	public const function GetDeviceFXRecord() : DeviceFX_Record
	{
		return m_deviceFXRecord;
	}

	public const virtual function IsSurveillanceCamera() : Bool
	{
		return false;
	}

	public const function HasSupport() : Bool
	{
		return m_hasSupport;
	}

	protected function SetHasSupport( value : Bool )
	{
		m_hasSupport = value;
	}

	protected function CreateLightSettings()
	{
		m_lightColors.off.strength = 0.0;
		m_lightColors.off.color = Color( 0, 0, 0, 0 );
		m_lightColors.red.strength = 1.0;
		m_lightColors.red.color = Color( 251, 147, 46, 0 );
		m_lightColors.green.strength = 1.0;
		m_lightColors.green.color = Color( 28, 236, 130, 0 );
		m_lightColors.off.strength = 1.0;
		m_lightColors.blue.strength = 1.0;
		m_lightColors.blue.color = Color( 40, 40, 130, 0 );
		m_lightColors.yellow.strength = 1.0;
		m_lightColors.yellow.color = Color( 50, 50, 0, 0 );
		m_lightColors.white.strength = 1.0;
		m_lightColors.white.color = Color( 255, 255, 255, 0 );
	}

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

	public const override function GetTargetTrackerComponent() : TargetTrackerComponent
	{
		return m_targetTrackerComponent;
	}

	public const override function GetSensesComponent() : SenseComponent
	{
		return m_senseComponent;
	}

	public const function GetVisibleObjectComponent() : VisibleObjectComponent
	{
		return m_visibleObjectComponent;
	}

	private const override function GetController() : SensorDeviceController
	{
		return ( ( SensorDeviceController )( m_controller ) );
	}

	public const override function GetDevicePS() : SensorDeviceControllerPS
	{
		return GetController().GetPS();
	}

	public const function GetAnimFeatureInCurrentState() : AnimFeature_SensorDevice
	{
		return m_animFeatureData;
	}

	public const function IsPlayerSafeTargetLock() : Bool
	{
		return m_isPLAYERSAFETargetLock;
	}

	public const function IsTargetForcedFromTagKill() : Bool
	{
		return m_targetForcedFormTagKill;
	}

	public const function GetCurrentTargets() : array< Target >
	{
		return m_targets;
	}

	public const function GetSensorDeviceState() : ESensorDeviceStates
	{
		return m_sensorDeviceState;
	}

	public const virtual function GetRotationData() : CameraRotationData
	{
		var res : CameraRotationData;
		res.m_pitch = m_playerControlData.m_currentPitchModifier;
		res.m_minPitch = m_minPitch;
		res.m_maxPitch = m_maxPitch;
		res.m_yaw = m_playerControlData.m_currentYawModifier;
		res.m_minYaw = m_minYaw;
		res.m_maxYaw = m_maxYaw;
		return res;
	}

	private function UpdateAnimFeatureWakeState()
	{
		m_animFeatureData.wakeState = ( ( Int32 )( m_sensorWakeState ) );
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
	}

	public override function ApplyAnimFeatureToReplicate( obj : GameObject, inputName : CName, value : AnimFeature )
	{
		if( m_clientForceSetAnimFeature )
		{
			AnimationControllerComponent.ApplyFeature( obj, inputName, value );
		}
		else
		{
			super.ApplyAnimFeatureToReplicate( obj, inputName, value );
		}
	}

	public const function GetCurrentlyFollowedTarget() : weak< GameObject >
	{
		return m_currentlyFollowedTarget;
	}

	protected override function TurnOffDevice()
	{
		super.TurnOffDevice();
		RemoveLinkedStatusEffects();
		RemoveAllTargets();
		TerminateGameEffect( m_scanGameEffect );
		StopSoundEvent( this, m_soundDetectionLoop );
		ToggleActiveEffect( false );
		BreakTargeting();
		BreakBehaviourResolve();
		LookAtStop();
		OnAllValidTargetsDisappears();
		CancelLosetargetFalsePositiveDelay();
		TurnOffSenseComponent();
		if( m_visibleObjectComponent )
		{
			m_visibleObjectComponent.Toggle( false );
		}
		ToggleAreaIndicator( false );
		m_isPLAYERSAFETargetLock = false;
		m_animFeatureData.isTurnedOn = false;
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
		StopSoundEvent( this, m_idleSound );
		m_idleSoundIsPlaying = false;
		PlaySoundEvent( this, m_soundDeviceOFF );
		gameLightComponent.ChangeAllLightsSettings( this, m_lightColors.off, 0.5, 'glitch' );
		m_targetTrackerComponent.ClearThreats();
	}

	private function TurnOffSenseComponent()
	{
		m_senseComponent.ToggleComponent( false );
		GetDevicePS().NotifyAboutSpottingPlayer( false );
	}

	protected event OnTurnOnVisibilitySenseComponent( evt : TurnOnVisibilitySenseComponent )
	{
		if( m_visibleObjectComponent )
		{
			m_visibleObjectComponent.Toggle( true );
		}
	}

	protected override function TurnOnDevice()
	{
		if( GetDevicePS().GetDurabilityState() == EDeviceDurabilityState.BROKEN )
		{
			return;
		}
		if( !( GetDevicePS().IsControlledByPlayer() ) )
		{
			m_senseComponent.ToggleComponent( true );
		}
		if( ( !( GetDevicePS().IsControlledByPlayer() ) && !( GetDevicePS().IsInFollowMode() ) ) && !( HasSupport() ) )
		{
			ForceStartBehaviorResolve( ESensorDeviceStates.IDLE );
		}
		InitializeLights();
		ToggleActiveEffect( true );
		PlaySoundEvent( this, m_soundDeviceON );
		m_animFeatureData.isTurnedOn = true;
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
	}

	protected event OnHit( hit : gameHitEvent )
	{
		hit.attackData.AddFlag( hitFlag.FriendlyFire, 'sensorDevice' );
		super.OnHit( hit );
		if( GetDevicePS().IsON() )
		{
			if( m_animFeatureData.wasHit )
			{
				m_animFeatureData.wasHit = false;
			}
			else
			{
				m_animFeatureData.wasHit = true;
			}
			ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
			OneShotLookAtPosition( hit.attackData.GetInstigator().GetWorldPosition() );
		}
	}

	protected export override function DamagePipelineFinalized( evt : gameHitEvent )
	{
		super.DamagePipelineFinalized( evt );
	}

	protected event OnDeath( evt : gameDeathEvent )
	{
		super.OnDeath( evt );
		DestroySensor();
		if( GetDevicePS().IsControlledByPlayer() )
		{
			TakeOverControlSystem.ReleaseControl( GetGame() );
		}
	}

	protected function DestroySensor()
	{
		if( IsLogicReady() )
		{
			PlaySoundEvent( this, m_soundDeviceDestroyed );
			GameObjectEffectHelper.StartEffectEvent( this, 'broken' );
		}
		m_animFeatureData.isDestroyed = true;
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
		FindAndRewardKiller( gameKillType.Normal );
		GetDevicePS().SetDurabilityState( EDeviceDurabilityState.BROKEN );
		m_senseComponent.RemoveSenseMappin();
		if( m_visibleObjectComponent )
		{
			m_visibleObjectComponent.Toggle( false );
		}
		GetDevicePS().NotifyAboutSpottingPlayer( false );
		RequestHUDRefresh();
	}

	protected override function GetHitSourcePosition( hitSourceEntityID : EntityID ) : Vector4
	{
		return GetPotentialHitSourcePosition( hitSourceEntityID );
	}

	private function GetPotentialHitSourcePosition( hitSourceEntityID : EntityID ) : Vector4
	{
		var target : Target;
		if( m_playerDetected )
		{
			target = SimpleTargetManager.GetSpecificTarget( m_targets, hitSourceEntityID );
			if( target )
			{
				return target.GetTarget().GetWorldPosition();
			}
		}
		return this.GetWorldPosition();
	}

	private function RegisterListenerOnTargetHP( target : GameObject )
	{
		var targetID : EntityID;
		var HPStatListener : TargetedObjectDeathListener;
		var i : Int32;
		targetID = target.GetEntityID();
		for( i = 0; i < m_HPListenersList.Size(); i += 1 )
		{
			if( m_HPListenersList[ i ].m_lsitenTarget == target )
			{
				return;
			}
		}
		HPStatListener = new TargetedObjectDeathListener;
		HPStatListener.m_lsitener = this;
		HPStatListener.m_lsitenTarget = target;
		GameInstance.GetStatPoolsSystem( GetGame() ).RequestRegisteringListener( targetID, gamedataStatPoolType.Health, HPStatListener );
		m_HPListenersList.PushBack( HPStatListener );
	}

	public const function UnregisterListenerOnTargetHP( listeningObject : weak< GameObject >, listener : TargetedObjectDeathListener )
	{
		var evt : UnregisterListenerOnTargetHPEvent;
		evt = new UnregisterListenerOnTargetHPEvent;
		evt.listener = listener;
		evt.isFromListenerEvent = true;
		listeningObject.QueueEvent( evt );
	}

	protected function UnregisterListenerOnTargetHP( listeningObject : weak< GameObject >, lostObject : weak< GameObject > )
	{
		var evt : UnregisterListenerOnTargetHPEvent;
		var listener : TargetedObjectDeathListener;
		var i : Int32;
		evt = new UnregisterListenerOnTargetHPEvent;
		for( i = 0; i < m_HPListenersList.Size(); i += 1 )
		{
			if( m_HPListenersList[ i ].m_lsitenTarget == lostObject )
			{
				listener = m_HPListenersList[ i ];
				break;
			}
		}
		if( listener )
		{
			evt.listener = listener;
			OnUnregisterListenerOnTargetHPEvent( evt );
		}
		else
		{
			if( !( IsFinal() ) )
			{
			}
		}
	}

	protected event OnUnregisterListenerOnTargetHPEvent( evt : UnregisterListenerOnTargetHPEvent )
	{
		if( m_targetForcedFormTagKill && ( evt.listener.m_lsitenTarget == m_currentlyFollowedTarget ) )
		{
			RevertTemporaryAttitude();
			m_targetForcedFormTagKill = false;
		}
		if( !( IsFinal() ) )
		{
		}
		if( GetDevicePS().IsInTagKillMode() )
		{
			GameInstance.GetBlackboardSystem( GetGame() ).Get( GetAllBlackboardDefs().TaggedObjectsList ).Signal( GetAllBlackboardDefs().TaggedObjectsList.taggedObjectsList );
		}
		m_HPListenersList.Remove( evt.listener );
		GameInstance.GetStatPoolsSystem( GetGame() ).RequestUnregisteringListener( evt.listener.m_lsitenTarget.GetEntityID(), gamedataStatPoolType.Health, evt.listener );
		if( evt.isFromListenerEvent )
		{
			LoseTarget( evt.listener.m_lsitenTarget, true );
		}
	}

	private function ClearAllHPListeners()
	{
		var i : Int32;
		for( i = 0; i < m_HPListenersList.Size(); i += 1 )
		{
			GameInstance.GetStatPoolsSystem( GetGame() ).RequestUnregisteringListener( m_HPListenersList[ i ].m_lsitenTarget.GetEntityID(), gamedataStatPoolType.Health, m_HPListenersList[ i ] );
		}
		m_HPListenersList.Clear();
	}

	protected event OnSetJammedEvent( evt : SetJammedEvent )
	{
		if( evt.newJammedState && m_sensorDeviceState != ESensorDeviceStates.JAMMER )
		{
			BreakTargeting();
			BreakBehaviourResolve();
			OnAllValidTargetsDisappears();
			TurnOffSenseComponent();
			ForceStartBehaviorResolve( ESensorDeviceStates.JAMMER );
			RemoveAllTargets();
		}
		else
		{
			TurnOnDevice();
			ForceStartBehaviorResolve( ESensorDeviceStates.IDLE );
		}
	}

	public virtual function SetAsIntrestingTarget( target : weak< GameObject > ) : Bool
	{
		var isIntresting : Bool;
		if( GetDevicePS().IsConnectedToSecuritySystem() && !( GetDevicePS().IsAttitudeChanged() ) )
		{
			isIntresting = GetDevicePS().GetSecuritySystem().ShouldReactToTarget( target.GetEntityID(), GetEntityID() );
			if( !( IsFinal() ) )
			{
			}
			return isIntresting;
		}
		isIntresting = GetAttitudeTowards( this, target ) == EAIAttitude.AIA_Hostile;
		if( !( IsFinal() ) )
		{
		}
		return isIntresting;
	}

	public virtual function OnValidTargetAppears( target : weak< GameObject > ) {}

	public virtual function OnCurrentTargetAppears( target : weak< GameObject > )
	{
		var securityState : ESecuritySystemState;
		if( GetDevicePS().IsControlledByPlayer() )
		{
			return;
		}
		DetermineLightScanRefs( m_lightColors.red );
		if( m_targetForcedFormTagKill || ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsInFollowMode() )
		{
			if( !( IsFinal() ) )
			{
			}
			ChangeTemporaryAttitude();
			StartBehaviourResolve( ESensorDeviceStates.TARGETLOCK );
			StartLockingTarget( 0.0 );
			return;
		}
		if( GetDevicePS().IsConnectedToSecuritySystem() && !( GetDevicePS().IsAttitudeChanged() ) )
		{
			securityState = GetDevicePS().GetSecuritySystem().GetSecurityState();
			if( securityState == ESecuritySystemState.SAFE )
			{
				return;
			}
			if( securityState == ESecuritySystemState.ALERTED )
			{
				StartBehaviourResolve( ESensorDeviceStates.TARGETLOCK );
				SetQuestVisibility( true );
				return;
			}
			if( securityState == ESecuritySystemState.COMBAT )
			{
				StartBehaviourResolve( ESensorDeviceStates.TARGETLOCK );
				StartLockingTarget( 0.0 );
				return;
			}
		}
		else
		{
			StartBehaviourResolve( ESensorDeviceStates.TARGETLOCK );
			StartLockingTarget( GetBehaviourTimeToTakeAction() );
		}
	}

	private function GetBehaviourTimeToTakeAction() : Float
	{
		if( IsTemporaryAttitudeChanged() )
		{
			return GetDevicePS().GetBehaviourtimeToTakeAction() / 2.0;
		}
		else
		{
			return GetDevicePS().GetBehaviourtimeToTakeAction();
		}
	}

	protected function ChangeTemporaryAttitude()
	{
		var puppetAttitudeAgent : AttitudeAgent;
		var groupName : CName;
		if( m_targetForcedFormTagKill || GetDevicePS().IsControlledByPlayer() )
		{
			CacheInitialAttitude();
			puppetAttitudeAgent = GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject().GetAttitudeAgent();
			groupName = puppetAttitudeAgent.GetAttitudeGroup();
			GetAttitudeAgent().SetAttitudeGroup( groupName );
			if( !( IsFinal() ) )
			{
			}
		}
		else
		{
			if( GetDevicePS().IsInFollowMode() )
			{
				GetAttitudeAgent().SetAttitudeTowards( GetForcedTargetObject().GetAttitudeAgent(), EAIAttitude.AIA_Hostile );
			}
		}
		DetermineLightAttitudeRefs();
	}

	private function CacheInitialAttitude()
	{
		if( m_initialAttitude == '' )
		{
			m_initialAttitude = GetAttitudeAgent().GetAttitudeGroup();
			if( !( IsFinal() ) )
			{
			}
		}
	}

	private function ClearInitialAttitude()
	{
		if( !( m_targetForcedFormTagKill ) )
		{
			m_initialAttitude = '';
		}
		else
		{
			if( !( IsFinal() ) )
			{
			}
		}
	}

	public const function IsTemporaryAttitudeChanged() : Bool
	{
		return m_initialAttitude == '';
	}

	private function RevertTemporaryAttitude()
	{
		if( m_initialAttitude != '' )
		{
			if( !( IsFinal() ) )
			{
			}
			GetAttitudeAgent().SetAttitudeGroup( m_initialAttitude );
			DetermineLightAttitudeRefs();
		}
	}

	protected event OnQhackExecuted( evt : QhackExecuted )
	{
		ChangeTemporaryAttitude();
	}

	public virtual function OnValidTargetDisappears( target : weak< GameObject > )
	{
		if( target == m_currentlyFollowedTarget )
		{
			if( m_sensorDeviceState == ESensorDeviceStates.REPRIMAND )
			{
				degbu_SS_inputsSend += 1;
				debug_SS_inputsSendLoseTarget += 1;
				SendDefaultSSNotification( target, true );
			}
			BreakTargeting();
		}
	}

	public virtual function OnAllValidTargetsDisappears()
	{
		RevertTemporaryAttitude();
		SetQuestVisibility( false );
		DetermineLightScanRefs( m_lightColors.yellow );
	}

	protected override function ToggleAreaIndicator( turnOn : Bool )
	{
		super.ToggleAreaIndicator( turnOn );
		if( turnOn && GetDevicePS().IsON() )
		{
			if( !( m_visionConeEffectInstance ) )
			{
				RunVisionConeGameEffect();
			}
			if( m_disableAreaIndicatorDelayActive )
			{
				GameInstance.GetDelaySystem( GetGame() ).CancelDelay( m_disableAreaIndicatorID );
				GameInstance.GetDelaySystem( GetGame() ).CancelCallback( m_disableAreaIndicatorID );
				m_disableAreaIndicatorDelayActive = false;
			}
		}
		else if( !( IsTaggedinFocusMode() ) )
		{
			TerminateGameEffect( m_visionConeEffectInstance );
			ToggleActiveEffect( true );
		}
		else if( GetDevicePS().IsBroken() || !( GetDevicePS().IsON() ) )
		{
			TerminateGameEffect( m_visionConeEffectInstance );
		}
	}

	protected override function SendDisableAreaIndicatorEvent()
	{
		var disableAreaEvent : DisableAreaIndicatorEvent;
		disableAreaEvent = new DisableAreaIndicatorEvent;
		m_disableAreaIndicatorID = GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, disableAreaEvent, 5.0 );
		m_disableAreaIndicatorDelayActive = true;
	}

	protected virtual function StartLockingTarget( lockingTime : Float )
	{
		var evt : TargetLockedEvent;
		evt = new TargetLockedEvent;
		if( !( IsFinal() ) )
		{
		}
		if( lockingTime <= 0.0 )
		{
			OnTargetLocked( evt );
		}
		else
		{
			m_targetingDelayEventID = GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, evt, lockingTime );
			hack_isTargetingDelayEventFilled = true;
		}
	}

	private function BreakTargeting()
	{
		if( hack_isTargetingDelayEventFilled )
		{
			if( !( IsFinal() ) )
			{
			}
			GameInstance.GetDelaySystem( GetGame() ).CancelCallback( m_targetingDelayEventID );
			hack_isTargetingDelayEventFilled = false;
		}
	}

	private function BreakBehaviourResolve()
	{
		if( hack_isResolveDelayEventFilled )
		{
			if( !( IsFinal() ) )
			{
			}
			GameInstance.GetDelaySystem( GetGame() ).CancelDelay( m_currentResolveDelayEventID );
			hack_isResolveDelayEventFilled = false;
		}
	}

	protected event OnTargetLocked( evt : TargetLockedEvent )
	{
		if( !( IsFinal() ) )
		{
		}
		SetQuestVisibility( true );
		if( GetDevicePS().IsConnectedToSecuritySystem() )
		{
			if( !( hack_wasTargetReevaluated ) )
			{
				degbu_SS_inputsSend += 1;
				debug_SS_inputsSendTargetLock += 1;
				GetDevicePS().TriggerSecuritySystemNotification( m_currentlyFollowedTarget, m_currentlyFollowedTarget.GetWorldPosition(), ESecurityNotificationType.COMBAT );
			}
			BreakReprimand();
		}
	}

	private function SetQuestVisibility( isVisible : Bool )
	{
		if( EntityID.IsDefined( GetDevicePS().GetQuestSpotTargetID() ) )
		{
			if( GetDevicePS().GetQuestSpotTargetID() == m_currentlyFollowedTarget.GetEntityID() )
			{
				GetDevicePS().SetQuestTargetSpotted( isVisible );
			}
		}
		GetDevicePS().SetTargetIsLocked( isVisible );
	}

	protected event OnDetectionRiseEvent( evt : DetectionRiseEvent )
	{
		var detection : Float;
		var fakeDetectedEvent : OnDetectedEvent;
		detection = GetSensesComponent().GetDetection( evt.target.GetEntityID() );
		if( evt.isVisible && GetDevicePS().GetBehaviourCanDetectIntruders() )
		{
			if( ( evt.target.IsPlayer() && !( m_isPLAYERSAFETargetLock ) ) && ( GetDetectionFactor() >= 0.0 ) )
			{
				if( !( m_currentlyFollowedTarget ) && !( GetDevicePS().IsInFollowMode() ) )
				{
					m_isPLAYERSAFETargetLock = true;
					if( !( IsFinal() ) )
					{
					}
					if( IsPrevention() )
					{
						return true;
					}
					else
					{
						ForcedLookAtEntityWithoutTargetMODE( evt.target );
						StopSoundEvent( this, m_idleSound );
						m_idleSoundIsPlaying = false;
						PlaySoundEvent( this, m_idleSoundStop );
						PlaySoundEvent( this, 'dev_surveillance_camera_detect' );
					}
					ToggleActiveEffect( false );
					RunGameEffect( m_scanGameEffect, GetDevicePS().GetScanGameEffectRef(), m_scanFXSlotName, GetDeviceFXRecord().ScanGameEffectLength() );
					PlaySoundEvent( this, m_soundDetectionLoop );
					DetermineLightScanRefs( m_lightColors.blue );
					RecognizeTarget( evt.target, true );
					if( detection >= 100.0 )
					{
						fakeDetectedEvent = new OnDetectedEvent;
						fakeDetectedEvent.target = evt.target;
						fakeDetectedEvent.isVisible = evt.isVisible;
						fakeDetectedEvent.shapeId = evt.shapeId;
						fakeDetectedEvent.description = evt.description;
						OnOnDetectedEvent( fakeDetectedEvent );
					}
				}
			}
			else
			{
				if( !( IsFinal() ) )
				{
				}
				if( !( GetDevicePS().IsInTagKillMode() ) )
				{
					RecognizeTarget( evt.target );
				}
			}
		}
	}

	protected event OnOnDetectedEvent( evt : OnDetectedEvent )
	{
		if( evt.isVisible )
		{
			if( evt.target.IsPlayer() )
			{
				m_playerDetected = true;
				GetDevicePS().NotifyAboutSpottingPlayer( true );
			}
			if( evt.target == m_currentlyFollowedTarget )
			{
				if( !( IsFinal() ) )
				{
				}
				m_isPLAYERSAFETargetLock = false;
				TerminateGameEffect( m_scanGameEffect );
				ToggleActiveEffect( true );
				StopSoundEvent( this, m_soundDetectionLoop );
				PlaySoundEvent( this, m_soundDetectionLoopStop );
				SendDefaultSSNotification( evt.target, true );
				OnCurrentTargetAppears( evt.target );
			}
		}
		else
		{
			if( evt.target.IsPlayer() )
			{
				m_playerDetected = false;
			}
		}
	}

	protected event OnOnRemoveDetection( evt : OnRemoveDetection )
	{
		SenseLoseTarget( evt.target );
	}

	protected function SenseLoseTarget( target : GameObject )
	{
		if( target.IsPlayer() )
		{
			m_isPLAYERSAFETargetLock = false;
			GetDevicePS().NotifyAboutSpottingPlayer( false );
			TerminateGameEffect( m_scanGameEffect );
			ToggleActiveEffect( true );
			StopSoundEvent( this, m_soundDetectionLoop );
			PlaySoundEvent( this, m_soundDetectionLoopStop );
			DetermineLightScanRefs( m_lightColors.yellow );
			CancelPLAYERSAFEDelayEvent();
		}
		LoseTarget( target );
	}

	protected event OnLostTargetDelayFalsePositivesDelay( evt : LostTargetDelayFalsePositivesDelay )
	{
		SenseLoseTarget( evt.target );
	}

	protected event OnEnterShapeEvent( evt : EnterShapeEvent )
	{
		var cameraDeadBodyData : CameraDeadBodyData;
		var timeStamp : Float;
		if( GetAttitudeTowards( GetPlayer( GetGame() ) ) == EAIAttitude.AIA_Friendly )
		{
			return false;
		}
		cameraDeadBodyData = new CameraDeadBodyData;
		cameraDeadBodyData.ownerID = GetEntityID();
		cameraDeadBodyData.bodyID = evt.target.GetEntityID();
		if( !( evt.target.IsActive() ) && !( GameSessionDataSystem.CheckDataRequest( GetGame(), EGameSessionDataType.CameraDeadBody, cameraDeadBodyData ) ) )
		{
			GameSessionDataSystem.AddDataEntryRequest( GetGame(), EGameSessionDataType.CameraDeadBody, cameraDeadBodyData );
			timeStamp = EngineTime.ToFloat( GameInstance.GetEngineTime( GetGame() ) );
			if( GetSensesComponent().IsAgentVisible( GetPlayer( GetGame() ) ) && ( ( timeStamp - evt.target.GetReceivedDamageByPlayerLastTimeStamp() ) < 2.79999995 ) )
			{
				GetDevicePS().TriggerSecuritySystemNotification( GetPlayer( GetGame() ), GetPlayer( GetGame() ).GetWorldPosition(), ESecurityNotificationType.COMBAT );
			}
			else
			{
				GetDevicePS().TriggerSecuritySystemNotification( evt.target, evt.target.GetWorldPosition(), ESecurityNotificationType.ALARM );
			}
		}
		if( GetDevicePS().CanTagEnemies() && evt.target.IsActive() )
		{
			GameObject.TagObject( evt.target );
		}
	}

	protected event OnSenseVisibilityEvent( evt : SenseVisibilityEvent )
	{
		if( evt.isVisible && ( evt.target == m_currentlyFollowedTarget ) )
		{
			CancelLosetargetFalsePositiveDelay();
			return true;
		}
		if( ( ( !( evt.isVisible ) && evt.target ) && m_currentlyFollowedTarget ) && ( evt.target == m_currentlyFollowedTarget ) )
		{
			if( IsCurrentTargetOutOfSenseRange( evt.target ) )
			{
				SenseLoseTarget( evt.target );
				return true;
			}
			LoseTargetFalsePositiveDelay( evt.target );
			return true;
		}
	}

	private function IsCurrentTargetOutOfSenseRange( lostTarget : GameObject ) : Bool
	{
		if( Vector4.Distance( lostTarget.GetWorldPosition(), GetWorldPosition() ) >= GetSenseRange() )
		{
			return true;
		}
		return false;
	}

	private function GetSenseRange() : Float
	{
		var i : Int32;
		var senseShapes : array< ISenseShape >;
		var coneShape : SenseCone;
		senseShapes = m_senseComponent.GetSenseShapes();
		for( i = 0; i < senseShapes.Size(); i += 1 )
		{
			coneShape = ( ( SenseCone )( senseShapes[ i ] ) );
		}
		if( coneShape.position1.Z != 0.0 )
		{
			return coneShape.position1.Z;
		}
		return coneShape.position2.Z;
	}

	private function LoseTargetFalsePositiveDelay( target : weak< GameObject > )
	{
		var delayEvt : LostTargetDelayFalsePositivesDelay;
		var presetDB : TweakDBID;
		var dropTime : Float;
		var dropFactor : Float;
		if( hack_isTargetLostBySensesDelEvtFilled )
		{
			return;
		}
		presetDB = m_senseComponent.GetCurrentPreset();
		dropTime = ( ( SensePreset_Record )( TweakDBInterface.GetSensePresetRecord( presetDB ) ) ).DetectionCoolDownTime();
		dropFactor = ( ( SensePreset_Record )( TweakDBInterface.GetSensePresetRecord( presetDB ) ) ).DetectionDropFactor();
		if( dropFactor <= 0.0 )
		{
			return;
		}
		delayEvt = new LostTargetDelayFalsePositivesDelay;
		delayEvt.target = target;
		m_targetLostBySensesDelayEventID = GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, delayEvt, dropTime + 1.0 );
		hack_isTargetLostBySensesDelEvtFilled = true;
	}

	private function GetDetectionFactor() : Float
	{
		var riseFactor : Float;
		var presetDB : TweakDBID;
		presetDB = m_senseComponent.GetCurrentPreset();
		riseFactor = ( ( SensePreset_Record )( TweakDBInterface.GetSensePresetRecord( presetDB ) ) ).DetectionFactor();
		return riseFactor;
	}

	protected event OnSetDetectionMultiplier( evt : SetDetectionMultiplier )
	{
		SetDetectionMultiplier( evt.multiplier );
	}

	public function SetDetectionMultiplier( multiplier : Float )
	{
		if( m_senseComponent.GetDetectionMultiplier( GetEntityID() ) == 0.0 )
		{
			m_senseComponent.SetDetectionMultiplier( GetPlayer( GetGame() ).GetEntityID(), multiplier );
		}
		else
		{
			m_senseComponent.SetDetectionMultiplier( GetPlayer( GetGame() ).GetEntityID(), m_senseComponent.GetDetectionMultiplier( GetEntityID() ) * multiplier );
		}
	}

	private function CancelLosetargetFalsePositiveDelay()
	{
		if( hack_isTargetLostBySensesDelEvtFilled )
		{
			GameInstance.GetDelaySystem( GetGame() ).CancelDelay( m_targetLostBySensesDelayEventID );
			hack_isTargetLostBySensesDelEvtFilled = false;
		}
	}

	private function CancelPLAYERSAFEDelayEvent()
	{
		if( m_isPLAYERSAFETargetLock )
		{
			m_isPLAYERSAFETargetLock = false;
			StartBehaviourResolve( ESensorDeviceStates.IDLE );
		}
	}

	private function ForceCancelAllForcedBehaviours()
	{
		CancelPLAYERSAFEDelayEvent();
		CancelLosetargetFalsePositiveDelay();
		BreakTargeting();
		BreakBehaviourResolve();
	}

	private function RecognizeTarget( newObject : weak< GameObject >, optional questForcedIntresting : Bool )
	{
		var isIntresting : Bool;
		if( !( GetDevicePS().GetBehaviourCanDetectIntruders() ) )
		{
			if( !( IsFinal() ) )
			{
			}
			return;
		}
		if( GetDevicePS().IsControlledByPlayer() )
		{
			if( !( IsFinal() ) )
			{
			}
			return;
		}
		if( !( newObject.GetAttitudeAgent() ) )
		{
			if( !( IsFinal() ) )
			{
			}
			return;
		}
		if( GameInstance.GetStatPoolsSystem( GetGame() ).GetStatPoolValue( newObject.GetEntityID(), gamedataStatPoolType.Health, true ) <= 1.0 )
		{
			if( !( IsFinal() ) )
			{
			}
			return;
		}
		if( ( ( ScriptedPuppet )( newObject ) ) && ScriptedPuppet.IsDefeated( newObject ) )
		{
			if( !( IsFinal() ) )
			{
			}
			return;
		}
		isIntresting = SetAsIntrestingTarget( newObject );
		if( questForcedIntresting || CheckIfTargetIsTaggedByPlayer( newObject ) )
		{
			isIntresting = true;
			if( !( IsFinal() ) )
			{
			}
			SimpleTargetManager.AddTarget( m_targets, newObject, isIntresting, true );
			if( m_currentlyFollowedTarget != GetForcedTargetObject() )
			{
				LookAtStop();
			}
		}
		else
		{
			SimpleTargetManager.AddTarget( m_targets, newObject, isIntresting, true );
		}
		SendDefaultSSNotification( newObject, isIntresting );
		RegisterListenerOnTargetHP( newObject );
		OnValidTargetAppears( newObject );
		if( !( SimpleTargetManager.HasInterestingTargets( m_targets ) ) || !( isIntresting ) )
		{
			if( !( IsFinal() ) )
			{
			}
			return;
		}
		if( ( ( SensorDeviceControllerPS )( GetDevicePS() ) ).IsInFollowMode() && ( m_currentlyFollowedTarget == GetForcedTargetObject() ) )
		{
			if( !( IsFinal() ) )
			{
			}
			return;
		}
		m_currentlyFollowedTarget = SimpleTargetManager.GetFirstInterestingTargetObject( m_targets );
		BreakBehaviourResolve();
		if( !( m_isPLAYERSAFETargetLock ) )
		{
			OnCurrentTargetAppears( newObject );
		}
		else
		{
			if( !( IsFinal() ) )
			{
			}
		}
	}

	public function LoseTarget( lostObject : weak< GameObject >, optional forceRemoveTarget : Bool )
	{
		if( !( lostObject.GetAttitudeAgent() ) )
		{
			return;
		}
		if( ( lostObject == GetForcedTargetObject() ) && GetDevicePS().IsInFollowMode() )
		{
			if( !( IsFinal() ) )
			{
			}
			return;
		}
		if( ( GetDevicePS().IsConnectedToSecuritySystem() && HasSupport() ) && !( forceRemoveTarget ) )
		{
			if( !( SimpleTargetManager.SetTargetVisible( m_targets, lostObject, false ) ) )
			{
				return;
			}
		}
		else
		{
			if( !( SimpleTargetManager.RemoveTarget( m_targets, lostObject ) ) )
			{
				return;
			}
			UnregisterListenerOnTargetHP( this, lostObject );
		}
		if( !( IsFinal() ) )
		{
		}
		OnValidTargetDisappears( lostObject );
		if( ( lostObject != m_currentlyFollowedTarget ) && ( m_currentlyFollowedTarget != NULL ) )
		{
			if( !( IsFinal() ) )
			{
			}
			return;
		}
		if( GetDevicePS().IsInFollowMode() )
		{
			if( !( IsFinal() ) )
			{
			}
			return;
		}
		if( !( IsFinal() ) )
		{
		}
		BreakReprimand();
		if( SimpleTargetManager.HasInterestingTargets( m_targets ) && !( GetDevicePS().IsControlledByPlayer() ) )
		{
			m_currentlyFollowedTarget = SimpleTargetManager.GetFirstInterestingTargetObject( m_targets );
			if( !( IsFinal() ) )
			{
			}
			StartBehaviourResolve( ESensorDeviceStates.TARGETLOCK );
			return;
		}
		if( !( IsFinal() ) )
		{
		}
		OnAllValidTargetsDisappears();
		if( !( HasSupport() ) )
		{
			if( m_currentlyFollowedTarget )
			{
				StartBehaviourResolve( ESensorDeviceStates.TARGETLOSE );
			}
			else
			{
				StartBehaviourResolve( ESensorDeviceStates.IDLE );
			}
		}
		m_currentlyFollowedTarget = NULL;
		CancelLosetargetFalsePositiveDelay();
	}

	protected event OnSecuritySystemEnabled( evt : SecuritySystemEnabled )
	{
		if( m_attitudeAgent )
		{
			m_attitudeAgent.SetAttitudeGroup( GetSecuritySystem().GetSecuritySystemAttitudeGroupName() );
		}
	}

	protected event OnSecuritySystemSupport( evt : SecuritySystemSupport )
	{
		var player : GameObject;
		if( ( GetDevicePS().IsControlledByPlayer() || GetDevicePS().IsSecurityWakeUpBlocked() ) || GetDevicePS().IsAttitudeChanged() )
		{
			return false;
		}
		player = GetPlayer( GetGame() );
		if( evt.supportGranted )
		{
			SetHasSupport( true );
			player = GetPlayer( GetGame() );
			if( SimpleTargetManager.IsTargetAlreadyAdded( m_targets, player ) >= 0 )
			{
				if( SimpleTargetManager.IsTargetVisible( m_targets, player ) )
				{
					RecognizeTarget( player );
				}
			}
			else
			{
				SimpleTargetManager.AddTarget( m_targets, player, true, false );
				ForcedLookAtEntityWithoutTargetMODE( player );
			}
		}
		else
		{
			SetHasSupport( false );
			if( GetCurrentlyFollowedTarget() == NULL )
			{
				LoseTarget( player, true );
			}
		}
	}

	protected event OnSecuritySystemOutput( evt : SecuritySystemOutput )
	{
		HandleSecuritySystemOutputByTask();
	}

	protected event OnSecuritySystemForceAttitudeChange( evt : SecuritySystemForceAttitudeChange )
	{
		if( !( IsTemporaryAttitudeChanged() ) )
		{
			m_attitudeAgent.SetAttitudeGroup( evt.newAttitude );
		}
	}

	private function BlinkSecurityLight( howManyTimes : Int32 ) {}

	protected event OnTargetAssessmentRequest( evt : TargetAssessmentRequest )
	{
		if( ( GetDevicePS().IsControlledByPlayer() || GetDevicePS().IsSecurityWakeUpBlocked() ) || GetDevicePS().IsAttitudeChanged() )
		{
			return false;
		}
		if( !( IsFinal() ) )
		{
		}
		debug_SS_TargetAssessmentRequest += 1;
		SetSensePresetBasedOnSSState();
		DetermineLightAttitudeRefs();
		ReevaluateTargets();
	}

	protected event OnReprimandUpdate( evt : ReprimandUpdate )
	{
		if( evt.reprimandInstructions == EReprimandInstructions.INITIATE_FIRST || evt.reprimandInstructions == EReprimandInstructions.INITIATE_SUCCESSIVE )
		{
			if( !( IsFinal() ) )
			{
			}
			StartReprimand();
		}
		else if( evt.reprimandInstructions == EReprimandInstructions.RELEASE_TO_ANOTHER_ENTITY )
		{
			if( !( IsFinal() ) )
			{
			}
			BreakReprimand();
			StartBehaviourResolve( ESensorDeviceStates.TARGETLOCK );
		}
		else if( evt.reprimandInstructions == EReprimandInstructions.CONCLUDE_SUCCESSFUL )
		{
			if( !( IsFinal() ) )
			{
			}
			BreakReprimand();
			StartBehaviourResolve( ESensorDeviceStates.IDLE );
		}
		else if( evt.reprimandInstructions == EReprimandInstructions.CONCLUDE_FAILED )
		{
			GetDevicePS().TriggerSecuritySystemNotification( ( ( GameObject )( GameInstance.FindEntityByID( GetGame(), evt.target ) ) ), evt.targetPos, ESecurityNotificationType.COMBAT );
		}
	}

	private function StartReprimand()
	{
		StartBehaviourResolve( ESensorDeviceStates.REPRIMAND );
		PlaySoundEvent( this, 'q003_sc_03_ui_deal_virus' );
		StartLockingTarget( 6.0 );
	}

	private function BreakReprimand( optional wasSucesfull : Bool )
	{
		if( m_sensorDeviceState == ESensorDeviceStates.REPRIMAND )
		{
			if( !( IsFinal() ) )
			{
			}
			BreakTargeting();
			m_sensorDeviceState = ESensorDeviceStates.NONE;
			StopSoundEvent( this, 'q003_sc_03_ui_deal_virus' );
		}
	}

	private function SendDefaultSSNotification( target : weak< GameObject >, securityIntresting : Bool )
	{
		if( ( GetDevicePS().IsConnectedToSecuritySystem() && !( m_isPLAYERSAFETargetLock ) ) && !( m_targetForcedFormTagKill ) )
		{
			if( ( !( hack_wasTargetReevaluated ) && securityIntresting ) || ( SimpleTargetManager.IsTargetAlreadyAdded( m_targets, ( ( ScriptedPuppet )( target ) ) ) < 0 ) )
			{
				degbu_SS_inputsSend += 1;
				debug_SS_inputsSendIntresting += 1;
				if( !( IsFinal() ) )
				{
				}
				DetermineLightInfoRefs( m_lightColors.white );
				if( securityIntresting )
				{
					GetDevicePS().TriggerSecuritySystemNotification( target, target.GetWorldPosition(), ESecurityNotificationType.DEFAULT );
				}
			}
		}
	}

	private function SetSensePresetBasedOnSSState()
	{
		if( ( m_defaultSensePreset == T"Senses.BasicTurret" ) || ( m_defaultSensePreset == T"Senses.BasicCamera" ) )
		{
			if( GetDevicePS().GetSecuritySystem().GetSecurityState() == ESecuritySystemState.COMBAT )
			{
				SenseComponent.RequestPresetChange( this, T"Senses.DeviceSecuritySystemCombat", true );
				m_senseComponent.SetDetectionMultiplier( GetPlayer( GetGame() ).GetEntityID(), 100.0 );
			}
			if( GetDevicePS().GetSecuritySystem().GetSecurityState() == ESecuritySystemState.ALERTED )
			{
				m_senseComponent.SetDetectionMultiplier( GetPlayer( GetGame() ).GetEntityID(), 2.0 );
				SenseComponent.RequestPresetChange( this, m_defaultSensePreset, true );
			}
			if( GetDevicePS().GetSecuritySystem().GetSecurityState() == ESecuritySystemState.SAFE )
			{
				m_senseComponent.SetDetectionMultiplier( GetPlayer( GetGame() ).GetEntityID(), 1.0 );
				SenseComponent.RequestPresetChange( this, m_defaultSensePreset, true );
			}
		}
	}

	private function GetForcedTargetObject() : weak< GameObject >
	{
		var entID : EntityID;
		entID = GetDevicePS().GetForcedTargetID();
		return ( ( GameObject )( GameInstance.FindEntityByID( GetGame(), entID ) ) );
	}

	protected event OnStartFollowingForcedTarget( evt : QuestFollowTarget )
	{
		CancelLosetargetFalsePositiveDelay();
		CancelPLAYERSAFEDelayEvent();
		TerminateGameEffect( m_scanGameEffect );
		ToggleActiveEffect( true );
		StopSoundEvent( this, m_soundDetectionLoop );
		PlaySoundEvent( this, m_soundDetectionLoopStop );
		RemoveAllTargets();
		OnAllValidTargetsDisappears();
		if( !( IsFinal() ) )
		{
		}
		if( GetForcedTargetObject() )
		{
			GetSensesComponent().SetDetectionMultiplier( GetForcedTargetObject().GetEntityID(), 100.0 );
			GetSensesComponent().SetDetectionDropFactor( 0.0 );
		}
		RecognizeTarget( GetForcedTargetObject(), true );
	}

	protected event OnStopFollowingForcedTarget( evt : QuestStopFollowingTarget )
	{
		if( !( IsFinal() ) )
		{
		}
		if( EntityID.IsDefined( evt.targetEntityID ) )
		{
			GetSensesComponent().SetDetectionMultiplier( evt.targetEntityID, 1.0 );
			GetSensesComponent().SetDetectionDropFactor( ( ( SensePreset_Record )( TweakDBInterface.GetSensePresetRecord( m_senseComponent.GetCurrentPreset() ) ) ).DetectionDropFactor() );
		}
		LoseTarget( m_currentlyFollowedTarget );
	}

	protected event OnStartQuestLookAtTarget( evt : QuestLookAtTarget )
	{
		CancelLosetargetFalsePositiveDelay();
		CancelPLAYERSAFEDelayEvent();
		TerminateGameEffect( m_scanGameEffect );
		StopSoundEvent( this, m_soundDetectionLoop );
		PlaySoundEvent( this, m_soundDetectionLoopStop );
		RemoveAllTargets();
		OnAllValidTargetsDisappears();
		if( !( IsFinal() ) )
		{
		}
		ForceLookAtQuestTarget();
	}

	protected event OnStopQuestStopLookAtTarget( evt : QuestStopLookAtTarget )
	{
		if( !( IsFinal() ) )
		{
		}
		LoseTarget( m_currentlyFollowedTarget );
	}

	protected event OnQuestSetDetectionToTrue( evt : QuestSetDetectionToTrue )
	{
		if( !( IsFinal() ) )
		{
		}
	}

	protected event OnQuestSetDetectionToFalse( evt : QuestSetDetectionToFalse )
	{
		if( !( IsFinal() ) )
		{
		}
		RemoveAllTargets();
		CancelPLAYERSAFEDelayEvent();
		CancelLosetargetFalsePositiveDelay();
		BreakTargeting();
		BreakBehaviourResolve();
		BreakReprimand();
		OnAllValidTargetsDisappears();
	}

	protected event OnQuestForceScanEffect( evt : QuestForceScanEffect )
	{
		RunGameEffect( m_scanGameEffect, GetDevicePS().GetScanGameEffectRef(), m_scanFXSlotName, GetDeviceFXRecord().ScanGameEffectLength() );
		PlaySoundEvent( this, m_soundDetectionLoop );
	}

	protected event OnQuestForceScanEffectStop( evt : QuestForceScanEffectStop )
	{
		TerminateGameEffect( m_scanGameEffect );
		StopSoundEvent( this, m_soundDetectionLoop );
		PlaySoundEvent( this, m_soundDetectionLoopStop );
	}

	protected event OnQuestForceAttitude( evt : QuestForceAttitude )
	{
		var groupName : CName;
		ClearInitialAttitude();
		groupName = ( ( CName )evt.prop.first );
		m_attitudeAgent.SetAttitudeGroup( groupName );
		if( !( IsFinal() ) )
		{
		}
		GetDevicePS().SetIsAttitudeChanged( true );
		ReevaluateTargets();
		UpdateDeviceState();
	}

	private function StartBehaviourResolve( newState : ESensorDeviceStates )
	{
		var behaviourEvent : ResolveSensorDeviceBehaviour;
		behaviourEvent = new ResolveSensorDeviceBehaviour;
		newState = CanResolveStateChange( newState );
		m_sensorDeviceState = newState;
		OnResolveSensorDeviceBehaviour( behaviourEvent );
	}

	private function ForceStartBehaviorResolve( newState : ESensorDeviceStates )
	{
		var behaviourEvent : ResolveSensorDeviceBehaviour;
		behaviourEvent = new ResolveSensorDeviceBehaviour;
		BreakBehaviourResolve();
		if( !( IsFinal() ) )
		{
		}
		m_sensorDeviceState = newState;
		OnResolveSensorDeviceBehaviour( behaviourEvent );
	}

	private function CanResolveStateChange( newState : ESensorDeviceStates ) : ESensorDeviceStates
	{
		if( GetDevicePS().IsIdleForced() )
		{
			if( !( IsFinal() ) )
			{
			}
			return ESensorDeviceStates.IDLEFORCED;
		}
		else if( m_sensorDeviceState == ESensorDeviceStates.JAMMER )
		{
			if( !( IsFinal() ) )
			{
			}
			return ESensorDeviceStates.JAMMER;
		}
		else if( m_sensorDeviceState == ESensorDeviceStates.REPRIMAND )
		{
			if( !( IsFinal() ) )
			{
			}
			return ESensorDeviceStates.REPRIMAND;
		}
		BreakBehaviourResolve();
		if( !( IsFinal() ) )
		{
		}
		return newState;
	}

	protected event OnResolveSensorDeviceBehaviour( evt : ResolveSensorDeviceBehaviour )
	{
		if( m_sensorDeviceState == ESensorDeviceStates.IDLE || m_sensorDeviceState == ESensorDeviceStates.IDLEFORCED )
		{
			ResolveLogicIDLE();
		}
		if( m_sensorDeviceState == ESensorDeviceStates.TARGETLOSE )
		{
			ResolveLogicLOSETARGET( evt.iteration );
		}
		if( m_sensorDeviceState == ESensorDeviceStates.TARGETLOCK )
		{
			ResolveLogicTARGETLOCK();
		}
		if( m_sensorDeviceState == ESensorDeviceStates.TARGETRECEIVED )
		{
			ResolveLogicTARGETRECEIVED( evt.iteration );
		}
		if( m_sensorDeviceState == ESensorDeviceStates.REPRIMAND )
		{
			ResolveLogicREPRIMEND();
		}
		if( m_sensorDeviceState == ESensorDeviceStates.JAMMER )
		{
			m_currentlyFollowedTarget = GetPlayer( GetGame() );
			ResolveLogicJAMMER();
		}
	}

	private function ResolveLogicIDLE()
	{
		if( GetDevicePS().GetBehaviourCanRotate() )
		{
			ModeSearch( 1.0 );
		}
		else
		{
			ModeIdleNoTarget();
		}
	}

	private function ResolveLogicLOSETARGET( iterator : Int32 )
	{
		var coroutine : ResolveSensorDeviceBehaviour;
		var delayTime : Float;
		var endCoroutine : Bool;
		switch( iterator )
		{
			case 0:
			{
				ModeStopMovementAtTargetPos( m_currentlyFollowedTarget.GetWorldPosition() );
				delayTime = GetDevicePS().GetBehaviourLastTargetLookAtTime();
				break;
			}
			case 1:
			{
				ModeSearch( 1.0 );
				delayTime = GetDevicePS().GetBehaviourLostTargetSearchTime();
				break;
			}
			case 2:
			{
				ModeIdleNoTarget();
				endCoroutine = true;
				break;
			}
			default:
			{
				endCoroutine = true;
			}
		}
		if( !( endCoroutine ) )
		{
			coroutine = new ResolveSensorDeviceBehaviour;
			coroutine.iteration = iterator + 1;
			m_currentResolveDelayEventID = GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, coroutine, delayTime );
			hack_isResolveDelayEventFilled = true;
		}
		else
		{
			StartBehaviourResolve( ESensorDeviceStates.IDLE );
		}
	}

	private function ResolveLogicTARGETLOCK()
	{
		ModeLookAtCurrentTarget();
	}

	private function ResolveLogicJAMMER()
	{
		if( !( m_currentlyFollowedTarget ) )
		{
			return;
		}
		m_animFeatureData.state = ( ( Int32 )( ETargetManagerAnimGraphState.JAMMED ) );
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
		CreateLookAt();
	}

	private function CreateLookAt( optional position : Vector4, optional otherTarget : GameObject )
	{
		var lookAtEntityEventVert : LookAtAddEvent;
		var lookAtEntityEventHor : LookAtAddEvent;
		LookAtStop();
		lookAtEntityEventVert = SetupLookAtProperties( GetDevicePS().GetLookAtPresetVert(), position, otherTarget );
		OverrideLookAtSetupVert( lookAtEntityEventVert );
		lookAtEntityEventHor = SetupLookAtProperties( GetDevicePS().GetLookAtPresetHor(), position, otherTarget );
		OverrideLookAtSetupHor( lookAtEntityEventHor );
		QueueEvent( lookAtEntityEventVert );
		QueueEvent( lookAtEntityEventHor );
		m_currentLookAtEventVert = lookAtEntityEventVert;
		m_currentLookAtEventHor = lookAtEntityEventHor;
	}

	private function SetupLookAtProperties( recordID : TweakDBID, optional position : Vector4, optional otherTarget : GameObject ) : LookAtAddEvent
	{
		var lookAtEntityEvent : LookAtAddEvent;
		var lookatPreset : weak< LookAtPreset_Record >;
		var lookatPointFix : Vector4;
		lookAtEntityEvent = new LookAtAddEvent;
		if( Vector4.IsZero( position ) )
		{
			if( otherTarget )
			{
				SetLookAtPositionProviderOnFollowedTarget( lookAtEntityEvent, otherTarget );
			}
			else
			{
				SetLookAtPositionProviderOnFollowedTarget( lookAtEntityEvent );
			}
		}
		else
		{
			lookatPointFix.Z = 1.0;
			lookAtEntityEvent.SetStaticTarget( position + lookatPointFix );
		}
		lookAtEntityEvent.SetStyle( animLookAtStyle.Normal );
		lookAtEntityEvent.SetLimits( animLookAtLimitDegreesType.None, animLookAtLimitDegreesType.None, animLookAtLimitDistanceType.None, animLookAtLimitDegreesType.None );
		if( !( IsFinal() ) )
		{
			lookAtEntityEvent.SetDebugInfo( "ScriptSensorDevice" );
		}
		lookatPreset = TweakDBInterface.GetLookAtPresetRecord( recordID );
		lookAtEntityEvent.bodyPart = lookatPreset.BodyPart();
		lookAtEntityEvent.request.transitionSpeed = lookatPreset.TransitionSpeed();
		lookAtEntityEvent.request.hasOutTransition = lookatPreset.HasOutTransition();
		lookAtEntityEvent.request.outTransitionSpeed = lookatPreset.OutTransitionSpeed();
		lookAtEntityEvent.request.limits.softLimitDegrees = lookatPreset.SoftLimitDegrees();
		lookAtEntityEvent.request.limits.hardLimitDegrees = lookatPreset.HardLimitDegrees();
		lookAtEntityEvent.request.limits.hardLimitDistance = lookatPreset.HardLimitDistance();
		lookAtEntityEvent.request.limits.backLimitDegrees = lookatPreset.BackLimitDegrees();
		lookAtEntityEvent.request.calculatePositionInParentSpace = lookatPreset.CalculatePositionInParentSpace();
		return lookAtEntityEvent;
	}

	protected virtual function OverrideLookAtSetupVert( out lookAtEntityEvent : LookAtAddEvent ) {}

	protected virtual function OverrideLookAtSetupHor( out lookAtEntityEvent : LookAtAddEvent ) {}

	private function ResolveLogicTARGETRECEIVED( iterator : Int32 )
	{
		var coroutine : ResolveSensorDeviceBehaviour;
		var delayTime : Float;
		switch( iterator )
		{
			case 0:
			{
				delayTime = 3.0;
				break;
			}
			case 1:
			{
				StartBehaviourResolve( ESensorDeviceStates.IDLE );
				return;
			}
			default:
			{
				StartBehaviourResolve( ESensorDeviceStates.IDLE );
				return;
			}
		}
		coroutine = new ResolveSensorDeviceBehaviour;
		coroutine.iteration = iterator + 1;
		m_currentResolveDelayEventID = GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, coroutine, delayTime );
		hack_isResolveDelayEventFilled = true;
	}

	private function ResolveLogicREPRIMEND()
	{
		ModeLookAtCurrentTarget();
	}

	protected virtual function SetLookAtPositionProviderOnFollowedTarget( evt : LookAtAddEvent, optional otherTarget : GameObject )
	{
		if( otherTarget )
		{
			evt.SetEntityTarget( otherTarget, 'Chest', Vector4.EmptyVector() );
		}
		else
		{
			evt.SetEntityTarget( m_currentlyFollowedTarget, 'Chest', Vector4.EmptyVector() );
		}
	}

	private function ModeLookAtCurrentTarget()
	{
		LookAtStop();
		m_animFeatureData.state = ( ( Int32 )( ETargetManagerAnimGraphState.MODELOOKAT ) );
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
		CreateLookAt();
	}

	private function ModeSearch( optional speedMultipler : Float )
	{
		LookAtStop();
		m_animFeatureData.state = ( ( Int32 )( ETargetManagerAnimGraphState.IDLE ) );
		m_animFeatureData.overrideRootRotation = GetDevicePS().GetBehaviourOverrideRootRotation();
		m_animFeatureData.pitchAngle = GetDevicePS().GetBehaviourPitchAngle();
		m_animFeatureData.maxRotationAngle = GetDevicePS().GetBehaviourMaxRotationAngle();
		m_animFeatureData.rotationSpeed = GetDevicePS().GetBehaviourRotationSpeed() * speedMultipler;
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
		if( ( !( m_idleSoundIsPlaying ) && GetDevicePS().IsON() ) && m_playIdleSoundOnIdle )
		{
			PlaySoundEvent( this, m_idleSound );
			m_idleSoundIsPlaying = true;
		}
	}

	private function ModeIdleNoTarget()
	{
		LookAtStop();
		m_animFeatureData.state = ( ( Int32 )( ETargetManagerAnimGraphState.IDLE ) );
		m_animFeatureData.overrideRootRotation = GetDevicePS().GetBehaviourOverrideRootRotation();
		m_animFeatureData.pitchAngle = GetDevicePS().GetBehaviourPitchAngle();
		m_animFeatureData.maxRotationAngle = GetDevicePS().GetBehaviourMaxRotationAngle();
		if( GetDevicePS().GetBehaviourCanRotate() )
		{
			m_animFeatureData.rotationSpeed = GetDevicePS().GetBehaviourRotationSpeed();
			if( ( !( m_idleSoundIsPlaying ) && GetDevicePS().IsON() ) && m_playIdleSoundOnIdle )
			{
				PlaySoundEvent( this, m_idleSound );
				m_idleSoundIsPlaying = true;
			}
		}
		else
		{
			m_animFeatureData.rotationSpeed = 0.0;
		}
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
	}

	private function ModeStopMovementAtTargetPos( targetPosition : Vector4 )
	{
		LookAtStop();
		CreateLookAt( targetPosition );
		m_animFeatureData.state = ( ( Int32 )( ETargetManagerAnimGraphState.MODELOOKAT ) );
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
	}

	private function LookAtStop()
	{
		if( m_currentLookAtEventHor )
		{
			LookAtRemoveEvent.QueueRemoveLookatEvent( this, m_currentLookAtEventHor );
			m_currentLookAtEventHor = NULL;
		}
		if( m_currentLookAtEventVert )
		{
			LookAtRemoveEvent.QueueRemoveLookatEvent( this, m_currentLookAtEventVert );
			m_currentLookAtEventVert = NULL;
		}
	}

	private function OneShotLookAtPosition( targetPos : Vector4, optional forcedLook : Bool )
	{
		if( !( m_currentlyFollowedTarget ) || forcedLook )
		{
			ModeStopMovementAtTargetPos( targetPos );
			StartBehaviourResolve( ESensorDeviceStates.TARGETRECEIVED );
		}
	}

	private function ForcedLookAtEntityWithoutTargetMODE( target : GameObject )
	{
		if( !( m_currentlyFollowedTarget ) )
		{
			CreateLookAt( , target );
			m_animFeatureData.state = ( ( Int32 )( ETargetManagerAnimGraphState.MODELOOKAT ) );
			ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
		}
	}

	protected event OnSetDeviceTagKillMode( evt : SetDeviceTagKillMode )
	{
		AddTaggedListener( this, 'OnKillTaggedTarget' );
	}

	private function AddTaggedListener( object : GameObject, funcName : CName )
	{
		var BBoard : IBlackboard;
		var callback : CallbackHandle;
		BBoard = GameInstance.GetBlackboardSystem( GetGame() ).Get( GetAllBlackboardDefs().TaggedObjectsList );
		callback = BBoard.RegisterListenerVariant( GetAllBlackboardDefs().TaggedObjectsList.taggedObjectsList, object, funcName );
		BBoard.Signal( GetAllBlackboardDefs().TaggedObjectsList.taggedObjectsList );
		m_taggedListenerCallback = callback;
	}

	protected event OnKillTaggedTarget( value : Variant )
	{
		var i : Int32;
		var listOfObjects : array< weak< GameObject > >;
		if( GetDevicePS().IsControlledByPlayer() )
		{
			return false;
		}
		listOfObjects = ( ( array< weak< GameObject > > )value );
		ChangeAttiudetowardsTag( listOfObjects );
		for( i = 0; i < listOfObjects.Size(); i += 1 )
		{
			if( listOfObjects[ i ] == this )
			{
				continue;
			}
			if( listOfObjects[ i ].IsDead() )
			{
				continue;
			}
			if( listOfObjects[ i ].GetAttitudeAgent() )
			{
				RemoveAllTargets();
				OnAllValidTargetsDisappears();
				ForceCancelAllForcedBehaviours();
				RecognizeTarget( listOfObjects[ i ] );
				return false;
			}
		}
	}

	private function CheckIfTargetIsTaggedByPlayer( object : weak< GameObject > ) : Bool
	{
		var BBoard : IBlackboard;
		var listOfObjects : array< weak< GameObject > >;
		if( GetDevicePS().IsInTagKillMode() )
		{
			BBoard = GameInstance.GetBlackboardSystem( GetGame() ).Get( GetAllBlackboardDefs().TaggedObjectsList );
			listOfObjects = ( ( array< weak< GameObject > > )( BBoard.GetVariant( GetAllBlackboardDefs().TaggedObjectsList.taggedObjectsList ) ) );
			if( listOfObjects.FindFirst( object ) > -1 )
			{
				if( !( IsFinal() ) )
				{
				}
				RemoveAllTargets();
				m_targetForcedFormTagKill = true;
				return true;
			}
		}
		return false;
	}

	private function ChangeAttiudetowardsTag( const currentList : ref< array< weak< GameObject > > > )
	{
		var attitudeBetweenGroups : EAIAttitude;
		var i : Int32;
		for( i = m_previoustagKillList.Size() - 1; i >= 0; i -= 1 )
		{
			if( currentList.Contains( m_previoustagKillList[ i ] ) )
			{
				m_previoustagKillList.Erase( i );
			}
		}
		for( i = 0; i < currentList.Size(); i += 1 )
		{
			GetAttitudeAgent().SetAttitudeTowards( currentList[ i ].GetAttitudeAgent(), EAIAttitude.AIA_Hostile );
		}
		for( i = 0; i < m_previoustagKillList.Size(); i += 1 )
		{
			attitudeBetweenGroups = GameInstance.GetAttitudeSystem( GetGame() ).GetAttitudeRelation( GetAttitudeAgent().GetAttitudeGroup(), m_previoustagKillList[ i ].GetAttitudeAgent().GetAttitudeGroup() );
			GetAttitudeAgent().SetAttitudeTowards( m_previoustagKillList[ i ].GetAttitudeAgent(), attitudeBetweenGroups );
		}
		m_previoustagKillList = currentList;
	}

	protected event OnSetDeviceAttitude( evt : SetDeviceAttitude )
	{
		var playerPuppet : PlayerPuppet;
		var current_attitude : EAIAttitude;
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject() ) );
		current_attitude = GetAttitudeTowards( playerPuppet );
		if( current_attitude != evt.Attitude )
		{
			switch( evt.Attitude )
			{
				case EAIAttitude.AIA_Friendly:
					SetDeviceFriendly( evt );
				break;
				case EAIAttitude.AIA_Neutral:
					SetDeviceNeutral( evt );
				break;
				default:
					KeepHostilityTowardsPlayerHostiles( false );
				break;
			}
		}
		super.OnSetDeviceAttitude( evt );
	}

	private function SetDeviceNeutral( evt : SetDeviceAttitude )
	{
		var puppetAttitudeAgent : AttitudeAgent;
		var enableAimAssist : EnableAimAssist;
		SetHasSupport( false );
		if( !( IsSurveillanceCamera() ) )
		{
			SenseComponent.RequestPresetChange( this, T"Senses.BasicTurret", true );
		}
		else
		{
			SenseComponent.RequestPresetChange( this, m_defaultSensePreset, true );
		}
		enableAimAssist = new EnableAimAssist;
		QueueEvent( enableAimAssist );
		SendReprimandInstructionToSecuritySystem();
		RevertTemporaryAttitude();
		puppetAttitudeAgent = GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject().GetAttitudeAgent();
		m_attitudeAgent.SetAttitudeTowards( puppetAttitudeAgent, EAIAttitude.AIA_Neutral );
		m_senseComponent.ReevaluateDetectionOverwrite( evt.GetExecutor() );
		m_senseComponent.RequestRemovingSenseMappin();
		KeepHostilityTowardsPlayerHostiles( false );
		GetDevicePS().SetIsAttitudeChanged( true );
		ReevaluateTargets();
		DetermineLightScanRefs( m_lightColors.red );
		ToggleActiveEffect( true );
		UpdateDeviceState();
		SendReactivateHighlightEvent();
		if( IsTaggedinFocusMode() )
		{
			RunVisionConeGameEffect();
		}
		GetDevicePS().SetBlockSecurityWakeUp( true );
	}

	private function SetDeviceFriendly( evt : SetDeviceAttitude )
	{
		var puppetAttitudeAgent : AttitudeAgent;
		var disableAimAssist : DisableAimAssist;
		SetHasSupport( false );
		if( !( IsSurveillanceCamera() ) )
		{
			SenseComponent.RequestPresetChange( this, T"Senses.FriendlyTurret", true );
		}
		else
		{
			SenseComponent.RequestPresetChange( this, m_defaultSensePreset, true );
		}
		disableAimAssist = new DisableAimAssist;
		QueueEvent( disableAimAssist );
		SendReprimandInstructionToSecuritySystem();
		CacheInitialAttitude();
		puppetAttitudeAgent = GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject().GetAttitudeAgent();
		m_attitudeAgent.SetAttitudeTowards( puppetAttitudeAgent, EAIAttitude.AIA_Friendly );
		GetSensesComponent().SetDetectionOverwrite( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerControlledGameObject().GetEntityID() );
		if( evt.IsCompleted() )
		{
			m_attitudeAgent.SetAttitudeGroup( puppetAttitudeAgent.GetAttitudeGroup() );
		}
		else
		{
			m_attitudeAgent.SetAttitudeGroupUnsavable( puppetAttitudeAgent.GetAttitudeGroup() );
		}
		m_senseComponent.ReevaluateDetectionOverwrite( evt.GetExecutor() );
		m_senseComponent.RequestRemovingSenseMappin();
		if( !( evt.IgnoreHostiles ) )
		{
			SetHostileTowardsPlayerHostiles( true );
		}
		KeepHostilityTowardsPlayerHostiles( !( evt.IgnoreHostiles ) );
		GetDevicePS().SetIsAttitudeChanged( true );
		ReevaluateTargets();
		DetermineLightAttitudeRefs();
		DetermineLightScanRefs( m_lightColors.green );
		ToggleActiveEffect( true );
		UpdateDeviceState();
		SendReactivateHighlightEvent();
		if( IsTaggedinFocusMode() )
		{
			RunVisionConeGameEffect();
		}
		GetDevicePS().SendDeviceNotOperationalEvent();
	}

	private function KeepHostilityTowardsPlayerHostiles( keep : Bool )
	{
		var playerPuppet : PlayerPuppet;
		if( keep == m_keepHostilityTowardsPlayerHostiles )
		{
			return;
		}
		m_keepHostilityTowardsPlayerHostiles = keep;
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject() ) );
		if( keep )
		{
			playerPuppet.RegisterFriendlyDeviceHostileToEnemies( GetEntityID() );
		}
		else
		{
			playerPuppet.UnregisterFriendlyDeviceHostileToEnemies( GetEntityID() );
		}
	}

	protected function SetHostileTowardsPlayerHostiles( optional useTargetingSystem : Bool )
	{
		var player : PlayerPuppet;
		var playerTargets : array< TrackedLocation >;
		var i, size : Int32;
		var searchQuery : TargetSearchQuery;
		var targets : array< TS_TargetPartInfo >;
		var target : GameObject;
		if( useTargetingSystem )
		{
			searchQuery.searchFilter = TSF_And( TSF_Not( TSFMV.Att_Friendly ), TSF_Any( TSFMV.Att_Hostile | TSFMV.Sp_Aggressive ), TSF_All( TSFMV.Obj_Puppet | TSFMV.St_AliveAndActive ) );
			searchQuery.testedSet = TargetingSet.Complete;
			searchQuery.includeSecondaryTargets = false;
			player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject() ) );
			GameInstance.GetTargetingSystem( GetGame() ).GetTargetParts( player, searchQuery, targets );
			size = targets.Size();
			for( i = 0; i < size; i += 1 )
			{
				target = ( ( GameObject )( TS_TargetPartInfo.GetComponent( targets[ i ] ).GetEntity() ) );
				if( target )
				{
					m_attitudeAgent.SetAttitudeTowardsAgentGroup( target.GetAttitudeAgent(), m_attitudeAgent, EAIAttitude.AIA_Hostile );
				}
			}
		}
		playerTargets = player.GetTargetTrackerComponent().GetHostileThreats( false );
		for( i = 0; i < playerTargets.Size(); i += 1 )
		{
			m_attitudeAgent.SetAttitudeTowardsAgentGroup( ( ( GameObject )( playerTargets[ i ].entity ) ).GetAttitudeAgent(), m_attitudeAgent, EAIAttitude.AIA_Hostile );
		}
	}

	public function ScheduleHostileUpdateTowardsPlayerHostiles()
	{
		var evt : HostileUpdateTowardsPlayerHostiles;
		if( !( m_keepHostilityTowardsPlayerHostiles ) )
		{
			return;
		}
		if( m_hostileUpdateTowardsPlayerHostilesDelayed )
		{
			return;
		}
		evt = new HostileUpdateTowardsPlayerHostiles;
		GameInstance.GetDelaySystem( GetGame() ).DelayEvent( this, evt, 0.2 );
		m_hostileUpdateTowardsPlayerHostilesDelayed = true;
	}

	protected event OnHostileUpdateTowardsPlayerHostiles( evt : HostileUpdateTowardsPlayerHostiles )
	{
		if( !( m_keepHostilityTowardsPlayerHostiles ) )
		{
			return false;
		}
		SetHostileTowardsPlayerHostiles();
		ReevaluateTargets();
		m_hostileUpdateTowardsPlayerHostilesDelayed = false;
	}

	protected event OnForcePlayerIgnore( evt : ForceIgnoreTargets )
	{
		ReevaluateTargets();
	}

	protected function SendReprimandInstructionToSecuritySystem()
	{
		var evt : ReprimandAgentDisconnectEvent;
		evt = new ReprimandAgentDisconnectEvent;
		evt.agentID = GetEntityID();
		if( GetDevicePS().IsConnectedToSecuritySystem() )
		{
			GameInstance.GetPersistencySystem( GetGame() ).QueuePSEvent( GetDevicePS().GetSecuritySystem().GetID(), GetDevicePS().GetSecuritySystem().GetClassName(), evt );
		}
	}

	public function ReevaluateTargets()
	{
		var firstObject : weak< GameObject >;
		var i : Int32;
		debug_SS_reevaluatesDone += 1;
		for( i = 0; i < m_targets.Size(); i += 1 )
		{
			if( m_targets[ i ].GetTarget() )
			{
				m_targets[ i ].SetIsInteresting( SetAsIntrestingTarget( m_targets[ i ].GetTarget() ) );
			}
		}
		if( GetDevicePS().IsConnectedToSecuritySystem() )
		{
			hack_wasTargetReevaluated = true;
		}
		firstObject = SimpleTargetManager.GetFirstInterestingTargetObject( m_targets );
		if( firstObject )
		{
			if( firstObject != m_currentlyFollowedTarget )
			{
				LookAtStop();
			}
			RecognizeTarget( firstObject );
		}
		else
		{
			if( m_currentlyFollowedTarget )
			{
				LoseTarget( m_currentlyFollowedTarget );
			}
		}
		hack_wasTargetReevaluated = false;
	}

	public function RemoveAllTargets()
	{
		SimpleTargetManager.RemoveAllTargets( m_targets );
		m_currentlyFollowedTarget = NULL;
		RevertTemporaryAttitude();
		ClearAllHPListeners();
	}

	public const override function GetDefaultHighlight() : FocusForcedHighlightData
	{
		var highlight : FocusForcedHighlightData;
		var outline : EFocusOutlineType;
		if( GetDevicePS().IsDisabled() )
		{
			return NULL;
		}
		if( GetCurrentGameplayRole() == EGameplayRole.None || GetCurrentGameplayRole() == EGameplayRole.Clue )
		{
			return NULL;
		}
		if( m_scanningComponent.IsBraindanceBlocked() || m_scanningComponent.IsPhotoModeBlocked() )
		{
			return NULL;
		}
		outline = GetCurrentOutline();
		highlight = new FocusForcedHighlightData;
		highlight.sourceID = GetEntityID();
		highlight.sourceName = GetClassName();
		highlight.priority = EPriority.Low;
		highlight.outlineType = outline;
		if( outline == EFocusOutlineType.QUEST )
		{
			highlight.highlightType = EFocusForcedHighlightType.QUEST;
		}
		else if( outline == EFocusOutlineType.HOSTILE )
		{
			highlight.highlightType = EFocusForcedHighlightType.HOSTILE;
		}
		else if( outline == EFocusOutlineType.HACKABLE )
		{
			highlight.highlightType = EFocusForcedHighlightType.HACKABLE;
		}
		else if( outline == EFocusOutlineType.FRIENDLY )
		{
			highlight.highlightType = EFocusForcedHighlightType.FRIENDLY;
		}
		else if( outline == EFocusOutlineType.IMPORTANT_INTERACTION )
		{
			highlight.highlightType = EFocusForcedHighlightType.IMPORTANT_INTERACTION;
		}
		else if( outline == EFocusOutlineType.INTERACTION )
		{
			highlight.highlightType = EFocusForcedHighlightType.INTERACTION;
		}
		else if( highlight.outlineType == EFocusOutlineType.NEUTRAL )
		{
			highlight.highlightType = EFocusForcedHighlightType.NEUTRAL;
		}
		else
		{
			highlight = NULL;
		}
		if( highlight != NULL )
		{
			if( IsNetrunner() && highlight.outlineType != EFocusOutlineType.NEUTRAL )
			{
				highlight.patternType = VisionModePatternType.Netrunner;
			}
			else
			{
				highlight.patternType = VisionModePatternType.Default;
			}
		}
		return highlight;
	}

	public const override function GetCurrentOutline() : EFocusOutlineType
	{
		var playerPuppet : PlayerPuppet;
		var attitude : EAIAttitude;
		var oultineType : EFocusOutlineType;
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject() ) );
		attitude = GetAttitudeTowards( playerPuppet );
		if( GetAttitudeTowards( playerPuppet ) == EAIAttitude.AIA_Friendly )
		{
			oultineType = EFocusOutlineType.FRIENDLY;
		}
		else if( GetDevicePS().IsBroken() )
		{
			oultineType = EFocusOutlineType.NEUTRAL;
		}
		else if( attitude == EAIAttitude.AIA_Hostile || ( attitude != EAIAttitude.AIA_Friendly && !( GetDevicePS().IsUserAuthorized( playerPuppet.GetEntityID() ) ) ) )
		{
			oultineType = EFocusOutlineType.HOSTILE;
		}
		else
		{
			oultineType = super.GetCurrentOutline();
		}
		return oultineType;
	}

	protected event OnRevealStateChanged( evt : RevealStateChangedEvent )
	{
		super.OnRevealStateChanged( evt );
		if( evt.state == ERevealState.STARTED )
		{
			ToggleForcedVisibilityInAnimSystem( 'RevealStateChangedEvent', true, 0.0 );
		}
		else if( evt.state == ERevealState.STOPPED )
		{
			ToggleForcedVisibilityInAnimSystem( 'RevealStateChangedEvent', false, evt.transitionTime );
		}
	}

	protected function TCSMeshToggle( isVisible : Bool )
	{
		var i : Int32;
		for( i = 0; i < m_elementsToHideOnTCSRefs.Size(); i += 1 )
		{
			m_elementsToHideOnTCSRefs[ i ].Toggle( isVisible );
		}
	}

	protected event OnTCSTakeOverControlActivate( evt : TCSTakeOverControlActivate )
	{
		var objectUp : Vector4;
		if( !( m_wasVisible ) )
		{
			m_wasVisible = true;
			ResolveGameplayState();
		}
		objectUp = WorldTransform.GetUp( GetWorldTransform() );
		if( objectUp.Z <= 0.0 )
		{
			if( m_cameraComponentInverted )
			{
				m_cameraComponent = m_cameraComponentInverted;
				m_animFeatureData.isCeiling = true;
			}
		}
		super.OnTCSTakeOverControlActivate( evt );
		ToggleAreaIndicator( false );
		TurnOffSenseComponent();
		ForceCancelAllForcedBehaviours();
		LookAtStop();
		m_animFeatureData.state = ( ( Int32 )( ETargetManagerAnimGraphState.MODELOOKAT ) );
		m_animFeatureData.isControlled = GetDevicePS().IsControlledByPlayer();
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
		if( IsTaggedinFocusMode() )
		{
			TerminateGameEffect( m_visionConeEffectInstance );
		}
		TerminateGameEffect( m_scanGameEffect );
		ToggleActiveEffect( false );
		StopSoundEvent( this, m_soundDetectionLoop );
		SyncRotationWithAnimGraph();
		RemoveAllTargets();
		OnAllValidTargetsDisappears();
		TCSMeshToggle( false );
	}

	protected event OnTCSTakeOverControlDeactivate( evt : TCSTakeOverControlDeactivate )
	{
		super.OnTCSTakeOverControlDeactivate( evt );
		m_senseComponent.ToggleComponent( true );
		m_animFeatureData.isControlled = GetDevicePS().IsControlledByPlayer();
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
		StartBehaviourResolve( ESensorDeviceStates.IDLE );
		RevertTemporaryAttitude();
		TCSMeshToggle( true );
		ToggleActiveEffect( true );
		if( IsTaggedinFocusMode() )
		{
			RunVisionConeGameEffect();
		}
		if( EntityID.IsDynamic( GetEntityID() ) )
		{
			PlaySoundEvent( this, m_soundDeviceOFF );
		}
	}

	public function SyncRotationWithAnimGraph()
	{
		var eulerAngle : EulerAngles;
		eulerAngle = GetRotationFromSlotRotation();
		m_playerControlData.m_currentYawModifier = eulerAngle.Yaw;
		m_playerControlData.m_currentPitchModifier = -( eulerAngle.Pitch );
		m_animFeatureData.currentRotation.X = m_playerControlData.m_currentYawModifier;
		m_animFeatureData.currentRotation.Y = m_playerControlData.m_currentPitchModifier;
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
	}

	public function ResetRotation()
	{
		m_animFeatureData.currentRotation.X = 0.0;
		m_animFeatureData.currentRotation.Y = 0.0;
		ApplyAnimFeatureToReplicate( this, m_animFeatureDataName, m_animFeatureData );
	}

	public const function GetRotationFromSlotRotation() : EulerAngles
	{
		var directionTowardsTarget : Vector4;
		var localLookAtDirection : Vector4;
		var forwardLocalToWorldAngle : Float;
		var ForwardEulerToTarget : EulerAngles;
		var slotWorldTransform : WorldTransform;
		m_forwardFaceSlotComponent.GetSlotTransform( 'TargetFacing', slotWorldTransform );
		directionTowardsTarget = WorldTransform.GetForward( slotWorldTransform );
		forwardLocalToWorldAngle = Vector4.Heading( this.GetWorldForward() );
		localLookAtDirection = Vector4.RotByAngleXY( directionTowardsTarget, forwardLocalToWorldAngle );
		ForwardEulerToTarget = Vector4.ToRotation( localLookAtDirection );
		return ForwardEulerToTarget;
	}

	protected event OnTCSInputXYAxisEvent( evt : TCSInputXYAxisEvent )
	{
		super.OnTCSInputXYAxisEvent( evt );
		if( evt.isAnyInput )
		{
			if( !( m_idleSoundIsPlaying ) )
			{
				PlaySoundEvent( this, m_idleSound );
				m_idleSoundIsPlaying = true;
			}
		}
		else
		{
			if( m_idleSoundIsPlaying )
			{
				StopSoundEvent( this, m_idleSound );
				PlaySoundEvent( this, m_idleSoundStop );
				m_idleSoundIsPlaying = false;
			}
		}
	}

	private function ForceLookAtQuestTarget()
	{
		LookAtStop();
		SimpleTargetManager.AddTarget( m_targets, GetForcedTargetObject(), true, true );
		m_currentlyFollowedTarget = SimpleTargetManager.GetFirstInterestingTargetObject( m_targets );
		ModeLookAtCurrentTarget();
	}

	protected function InitializeDeviceFXRecord()
	{
		var fxRecord : DeviceFX_Record;
		if( IsSurveillanceCamera() && !( GetDevicePS().IsConnectedToSecuritySystem() ) )
		{
			return;
		}
		fxRecord = TweakDBInterface.GetDeviceFXRecord( T"DeviceFXPackage.Default" );
		if( fxRecord )
		{
			m_deviceFXRecord = fxRecord;
		}
	}

	protected function InitializeLights()
	{
		GameInstance.GetDelaySystem( GetGame() ).QueueTask( this, NULL, 'InitializeLightsTask', gameScriptTaskExecutionStage.Any );
	}

	protected export function InitializeLightsTask( data : ScriptTaskData )
	{
		DetermineLightAttitudeRefs();
		DetermineLightScanRefs( m_lightColors.yellow );
		DetermineLightInfoRefs( m_lightColors.blue );
	}

	protected function DetermineLightAttitudeRefs()
	{
		var playerPuppet : PlayerPuppet;
		var attitude : EAIAttitude;
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject() ) );
		attitude = GetAttitudeTowards( playerPuppet );
		if( attitude == EAIAttitude.AIA_Hostile )
		{
			gameLightComponent.ChangeLightSettingByRefs( m_lightAttitudeRefs, m_lightColors.red );
		}
		else if( attitude == EAIAttitude.AIA_Friendly || GetDevicePS().IsUserAuthorized( playerPuppet.GetEntityID() ) )
		{
			gameLightComponent.ChangeLightSettingByRefs( m_lightAttitudeRefs, m_lightColors.green );
		}
		else
		{
			gameLightComponent.ChangeLightSettingByRefs( m_lightAttitudeRefs, m_lightColors.yellow );
		}
	}

	protected function RunGameEffect( out effectInstance : EffectInstance, effectRef : EffectRef, slotName : CName, range : Float )
	{
		TerminateGameEffect( effectInstance );
		effectInstance = GameInstance.GetGameEffectSystem( GetGame() ).CreateEffect( effectRef, this );
		EffectData.SetVector( effectInstance.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.position, GetWorldPosition() );
		EffectData.SetVector( effectInstance.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.forward, GetWorldForward() );
		EffectData.SetFloat( effectInstance.GetSharedData(), GetAllBlackboardDefs().EffectSharedData.range, range );
		effectInstance.AttachToSlot( this, slotName, GetAllBlackboardDefs().EffectSharedData.position, GetAllBlackboardDefs().EffectSharedData.forward );
		effectInstance.Run();
	}

	protected function TerminateGameEffect( out effectInstance : EffectInstance )
	{
		if( effectInstance )
		{
			effectInstance.Terminate();
			effectInstance = NULL;
		}
	}

	protected function DetermineLightScanRefs( desiredColor : ScriptLightSettings )
	{
		var playerPuppet : PlayerPuppet;
		var attitude : EAIAttitude;
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject() ) );
		attitude = GetAttitudeTowards( playerPuppet );
		if( attitude == EAIAttitude.AIA_Hostile )
		{
			gameLightComponent.ChangeLightSettingByRefs( m_lightScanRefs, desiredColor, 0.5 );
		}
		else if( attitude == EAIAttitude.AIA_Friendly || GetDevicePS().IsUserAuthorized( playerPuppet.GetEntityID() ) )
		{
			gameLightComponent.ChangeLightSettingByRefs( m_lightScanRefs, m_lightColors.green, 0.5 );
		}
		else
		{
			gameLightComponent.ChangeLightSettingByRefs( m_lightScanRefs, desiredColor, 0.5 );
		}
	}

	protected function DetermineLightInfoRefs( desiredColor : ScriptLightSettings )
	{
		if( GetDevicePS().IsConnectedToSecuritySystem() )
		{
			gameLightComponent.ChangeLightSettingByRefs( m_lightInfoRefs, desiredColor, 0.2, 'glitch', true );
		}
	}

	protected function ToggleActiveEffect( active : Bool )
	{
		var playerPuppet : PlayerPuppet;
		var attitude : EAIAttitude;
		if( IsSurveillanceCamera() && !( GetDevicePS().IsConnectedToSecuritySystem() ) )
		{
			return;
		}
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject() ) );
		attitude = GetAttitudeTowards( playerPuppet );
		if( ( active && !( GetDevicePS().IsControlledByPlayer() ) ) && GetDevicePS().IsON() )
		{
			if( attitude == EAIAttitude.AIA_Friendly )
			{
				TerminateGameEffect( m_idleGameEffectInstance );
				if( !( m_visionConeEffectInstance ) )
				{
					RunGameEffect( m_idleGameEffectInstance, GetDevicePS().GetIdleFriendlyRef(), m_scanFXSlotName, GetDeviceFXRecord().IdleEffectLength() );
				}
				GameObjectEffectHelper.StopEffectEvent( this, 'active' );
				GameObjectEffectHelper.StartEffectEvent( this, 'friendly' );
			}
			else
			{
				TerminateGameEffect( m_idleGameEffectInstance );
				if( !( m_visionConeEffectInstance ) )
				{
					RunGameEffect( m_idleGameEffectInstance, GetDevicePS().GetIdleActiveRef(), m_scanFXSlotName, GetDeviceFXRecord().IdleEffectLength() );
				}
				GameObjectEffectHelper.StartEffectEvent( this, 'active' );
				GameObjectEffectHelper.StopEffectEvent( this, 'friendly' );
			}
		}
		else
		{
			TerminateGameEffect( m_idleGameEffectInstance );
			GameObjectEffectHelper.StopEffectEvent( this, 'active' );
			GameObjectEffectHelper.StopEffectEvent( this, 'friendly' );
		}
	}

	protected event OnReactoToPreventionSystem( evt : ReactoToPreventionSystem )
	{
		if( !( evt.wakeUp ) )
		{
			m_senseComponent.RemoveSenseMappin();
		}
		ForceReEvaluateGameplayRole();
	}

	protected function HasEntityPlayerAttitudeGroup() : Bool
	{
		return GetPlayer( GetGame() ).GetAttitudeAgent().GetAttitudeGroup() == GetAttitudeAgent().GetAttitudeGroup();
	}

	protected event OnProgramSetDeviceAttitude( evt : ProgramSetDeviceAttitude )
	{
		if( evt.IsStarted() )
		{
			CacheInitialAttitude();
		}
		else
		{
			RevertTemporaryAttitude();
			ClearInitialAttitude();
		}
	}

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

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

	protected event OnNetworkLinkQuickhackEvent( evt : NetworkLinkQuickhackEvent )
	{
		var ps : SensorDeviceControllerPS;
		ps = GetDevicePS();
		if( !( ps ) )
		{
			return false;
		}
		ps.SetNetrunnerID( evt.netrunnerID );
		ps.SetNetrunnerProxyID( evt.proxyID );
		ps.SetNetrunnerTargetID( evt.targetID );
		ps.DrawBetweenEntities( true, false, GetFxResourceByKey( 'pingNetworkLink' ), evt.to, evt.from, false, false, false, false );
		ToggleForcedVisibilityInAnimSystem( 'pingNetworkLink', true, 0.0, evt.from );
	}

	public function RemoveLinkedStatusEffects() : Bool
	{
		var targetPuppet : weak< ScriptedPuppet >;
		var linkedStatusEffect : LinkedStatusEffect;
		var ps : SensorDeviceControllerPS;
		ps = GetDevicePS();
		if( !( ps ) )
		{
			return false;
		}
		linkedStatusEffect = ps.GetLinkedStatusEffect();
		if( EntityID.IsDefined( linkedStatusEffect.targetID ) )
		{
			targetPuppet = ( ( weak< weak< ScriptedPuppet > > )( GameInstance.FindEntityByID( GetGame(), linkedStatusEffect.targetID ) ) );
			if( targetPuppet )
			{
				targetPuppet.RemoveLinkedStatusEffectsFromTarget( GetEntityID() );
				ps.ClearLinkedStatusEffect();
			}
		}
		RemoveLink();
		return true;
	}

	public function RemoveLinkedStatusEffectsFromTarget( sourceID : EntityID ) : Bool
	{
		var linkedStatusEffect : LinkedStatusEffect;
		var ps : SensorDeviceControllerPS;
		var i : Int32;
		ps = GetDevicePS();
		if( !( ps ) )
		{
			return false;
		}
		linkedStatusEffect = ps.GetLinkedStatusEffect();
		if( linkedStatusEffect.netrunnerIDs.Contains( sourceID ) && ( linkedStatusEffect.targetID == GetEntityID() ) )
		{
			if( linkedStatusEffect.netrunnerIDs.Size() == 1 )
			{
				for( i = 0; i < linkedStatusEffect.statusEffectList.Size(); i += 1 )
				{
					StatusEffectHelper.RemoveStatusEffect( this, linkedStatusEffect.statusEffectList[ i ] );
				}
				ps.ClearLinkedStatusEffect();
				StatusEffectHelper.RemoveStatusEffect( this, T"AIQuickHackStatusEffect.BeingHacked" );
			}
			else
			{
				linkedStatusEffect.netrunnerIDs.Remove( sourceID );
				AIActionHelper.UpdateLinkedStatusEffects( this, linkedStatusEffect );
				ps.SetLinkedStatusEffect( linkedStatusEffect );
			}
		}
		return true;
	}

	public function RemoveLink()
	{
		var netrunnerID : EntityID;
		var proxyID : EntityID;
		var targetID : EntityID;
		var netrunner : GameObject;
		var target : GameObject;
		var attackAttemptEvent : AIAttackAttemptEvent;
		var ps : SensorDeviceControllerPS;
		ps = GetDevicePS();
		if( !( ps ) )
		{
			return;
		}
		netrunnerID = ps.GetNetrunnerID();
		if( !( EntityID.IsDefined( netrunnerID ) ) )
		{
			return;
		}
		GameInstance.GetStatPoolsSystem( GetGame() ).RequestRemovingStatPool( netrunnerID, gamedataStatPoolType.QuickHackUpload );
		targetID = ps.GetNetrunnerTargetID();
		if( !( EntityID.IsDefined( targetID ) ) )
		{
			return;
		}
		proxyID = ps.GetNetrunnerProxyID();
		if( EntityID.IsDefined( proxyID ) )
		{
			ps.DrawBetweenEntities( false, true, GetFxResourceByKey( 'pingNetworkLink' ), netrunnerID, proxyID, false, false );
			ps.DrawBetweenEntities( false, true, GetFxResourceByKey( 'pingNetworkLink' ), proxyID, targetID, false, false );
			ToggleForcedVisibilityInAnimSystem( 'pingNetworkLink', false, 0.0, netrunnerID );
			ToggleForcedVisibilityInAnimSystem( 'pingNetworkLink', false, 0.0, proxyID );
		}
		else
		{
			ps.DrawBetweenEntities( false, true, GetFxResourceByKey( 'pingNetworkLink' ), netrunnerID, targetID, false, false );
			ToggleForcedVisibilityInAnimSystem( 'pingNetworkLink', false, 0.0, netrunnerID );
		}
		netrunner = ( ( GameObject )( GameInstance.FindEntityByID( GetGame(), netrunnerID ) ) );
		target = ( ( GameObject )( GameInstance.FindEntityByID( GetGame(), targetID ) ) );
		attackAttemptEvent = new AIAttackAttemptEvent;
		attackAttemptEvent.instigator = netrunner;
		attackAttemptEvent.continuousMode = gameEContinuousMode.Stop;
		if( target )
		{
			attackAttemptEvent.target = target;
			target.QueueEvent( attackAttemptEvent );
			if( netrunner )
			{
				netrunner.QueueEvent( attackAttemptEvent );
			}
			StatusEffectHelper.RemoveStatusEffect( target, T"AIQuickHackStatusEffect.BeingHacked" );
		}
		else if( netrunner )
		{
			attackAttemptEvent.target = netrunner;
			netrunner.QueueEvent( attackAttemptEvent );
		}
	}

	public const function GetTargets() : array< Target >
	{
		return m_targets;
	}

	public function SetSenseObjectType( type : gamedataSenseObjectType )
	{
		var objectTypeEvent : VisibleObjectTypeEvent;
		if( GetSensesComponent() )
		{
			GetSensesComponent().SetVisibleObjectType( type );
			GetSensesComponent().SetSensorObjectType( type );
		}
		if( GetVisibleObjectComponent() )
		{
			objectTypeEvent = new VisibleObjectTypeEvent;
			objectTypeEvent.type = type;
			QueueEvent( objectTypeEvent );
		}
	}

	private function RunVisionConeGameEffect()
	{
		var playerPuppet : PlayerPuppet;
		var attitude : EAIAttitude;
		if( IsSurveillanceCamera() && !( GetDevicePS().IsConnectedToSecuritySystem() ) )
		{
			return;
		}
		playerPuppet = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( GetGame() ).GetLocalPlayerMainGameObject() ) );
		attitude = GetAttitudeTowards( playerPuppet );
		if( m_visionConeEffectInstance )
		{
			TerminateGameEffect( m_visionConeEffectInstance );
		}
		if( attitude == EAIAttitude.AIA_Friendly || ( GetDevicePS().IsDeviceSecured() && GetDevicePS().IsUserAuthorized( playerPuppet.GetEntityID() ) ) )
		{
			TerminateGameEffect( m_idleGameEffectInstance );
			RunGameEffect( m_visionConeEffectInstance, GetDevicePS().GetVisionConeFriendlyEffectRef(), m_scanFXSlotName, GetDeviceFXRecord().VisionConeEffectLength() );
		}
		else
		{
			TerminateGameEffect( m_idleGameEffectInstance );
			RunGameEffect( m_visionConeEffectInstance, GetDevicePS().GetVisionConeEffectRef(), m_scanFXSlotName, GetDeviceFXRecord().VisionConeEffectLength() );
		}
	}

}

