abstract class ZoomTransitionHelper
{

	public constexpr static function GetReevaluateZoomName() : CName
	{
		return 'ReevaluateZoom';
	}

}

abstract class ZoomTransition extends DefaultTransition
{

	public const function IsControllingDevice( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface, optional excludeSniperNest : Bool ) : Bool
	{
		var isControllingDevice : Bool;
		var isValidDevice : Bool;
		isControllingDevice = scriptInterface.localBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsControllingDevice );
		isValidDevice = true;
		if( excludeSniperNest )
		{
			isValidDevice = !( IsControllingSniperNestDevice( scriptInterface ) );
		}
		return isControllingDevice && isValidDevice;
	}

	public const function IsControllingSniperNestDevice( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var blackboard : IBlackboard;
		blackboard = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().SniperNestDeviceBlackboard );
		return blackboard.GetBool( GetAllBlackboardDefs().SniperNestDeviceBlackboard.IsInTheSniperNest );
	}

	public const function IsGenericDeviceOrFocusActive( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return IsControllingDevice( stateContext, scriptInterface, true ) || IsInVisionModeActiveState( stateContext, scriptInterface );
	}

	public const function IsGenericDeviceAndFocusInactive( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( !( IsControllingDevice( stateContext, scriptInterface, true ) ) && !( IsInVisionModeActiveState( stateContext, scriptInterface ) ) )
		{
			return true;
		}
		return false;
	}

	public const function IsConsideredAiming( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsInVisionModeActiveState( stateContext, scriptInterface ) )
		{
			return false;
		}
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		if( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.UpperBody ) == ( ( Int32 )( gamePSMUpperBodyStates.Aim ) ) )
		{
			return true;
		}
		if( stateContext.GetStateMachineCurrentState( 'LeftHandCyberware' ) == 'leftHandCyberwareCharge' )
		{
			return true;
		}
		if( IsControllingSniperNestDevice( scriptInterface ) && ( scriptInterface.GetActionValue( 'CameraAim' ) != 0.0 ) )
		{
			return true;
		}
		return false;
	}

	public const virtual function ShouldPlayZoomExitSound() : Bool
	{
		return true;
	}

	public const virtual function ShouldPlayZoomStepSound() : Bool
	{
		return true;
	}

	protected function ShouldPlayZoomFX( stateContext : StateContext, scriptInterface : StateGameScriptInterface ) : Bool
	{
		var stateName : CName;
		stateName = GetStateName();
		if( scriptInterface.GetTimeSystem().IsTimeDilationActive() )
		{
			return false;
		}
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		if( stateContext.GetBoolParameter( 'ReevaluateAiming', false ) )
		{
			return false;
		}
		if( IsControllingDevice( stateContext, scriptInterface, true ) || IsInVisionModeActiveState( stateContext, scriptInterface ) )
		{
			return true;
		}
		if( stateName == 'zoomLevelBase' || stateName == 'zoomLevelAim' )
		{
			return false;
		}
		return true;
	}

	protected function StartZoomEffect( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var blackboard : worldEffectBlackboard;
		var clampedValue : Float;
		if( !( ShouldPlayZoomFX( stateContext, scriptInterface ) ) )
		{
			return;
		}
		clampedValue = GetCurrentZoomLevel( stateContext ) / 8.0;
		blackboard = new worldEffectBlackboard;
		blackboard.SetValue( 'zoomLevel', clampedValue );
		StartEffect( scriptInterface, 'zoom', blackboard );
	}

	protected function PlayFocusModeZoomEnterSound( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( !( ShouldPlayZoomFX( stateContext, scriptInterface ) ) )
		{
			return;
		}
		if( !( GetActiveWeapon( scriptInterface ) ) )
		{
			PlaySound( 'ui_focus_mode_zooming_in_enter', scriptInterface );
			StartZoomEffect( stateContext, scriptInterface );
		}
	}

	protected function PlayZoomEndVisualEffect( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( !( ShouldPlayZoomFX( stateContext, scriptInterface ) ) )
		{
			return;
		}
		StartEffect( scriptInterface, 'zoom_end' );
	}

	protected function SetCurrentZoomLevel( stateContext : StateContext, zoomLevel : Int32 )
	{
		var value : Float;
		value = GetZoomValueFromLevel( stateContext, zoomLevel );
		stateContext.SetPermanentFloatParameter( 'zoomLevel', value, true );
	}

	protected function SetPreviousZoomLevel( stateContext : StateContext, value : Float )
	{
		stateContext.SetPermanentFloatParameter( 'previousZoomLevel', value, true );
	}

	protected function SetBlendTime( stateContext : StateContext, value : Float )
	{
		stateContext.SetPermanentFloatParameter( 'blendTime', value, true );
	}

	protected function SetZoomLevelNumber( stateContext : StateContext, value : Int32 )
	{
		stateContext.SetPermanentIntParameter( 'zoomLvlNumber', value, true );
	}

	protected function SetShouldUseWeaponZoomData( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var flag : Bool;
		var isPlayerInFPP : Bool;
		isPlayerInFPP = !( scriptInterface.localBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.IsDriverCombatInTPP ) ) || !( stateContext.IsStateMachineActive( 'Vehicle' ) );
		if( isPlayerInFPP && ( ( GetActiveWeapon( scriptInterface ) && !( IsInVisionModeActiveState( stateContext, scriptInterface ) ) ) && !( stateContext.IsStateActive( 'Weapon', 'safe' ) ) ) )
		{
			flag = true;
		}
		else
		{
			flag = false;
		}
		stateContext.SetPermanentBoolParameter( 'shouldUseWeaponZoomStats', flag, true );
	}

	protected function ResetShouldUseWeaponZoomData( stateContext : StateContext )
	{
		stateContext.SetPermanentBoolParameter( 'shouldUseWeaponZoomStats', false, true );
	}

	public const virtual function GetActualZoomValue( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Float
	{
		return GetCurrentZoomLevel( stateContext );
	}

	protected const function GetCurrentZoomLevel( const stateContext : StateContext ) : Float
	{
		return stateContext.GetFloatParameter( 'zoomLevel', true );
	}

	protected function GetPreviousZoomLevel( stateContext : StateContext ) : Float
	{
		return stateContext.GetFloatParameter( 'previousZoomLevel', true );
	}

	protected const function GetNextZoomLevel( const stateContext : StateContext ) : Float
	{
		var zoomLevelNumber : Int32;
		zoomLevelNumber = GetZoomLevelNumber( stateContext );
		return GetZoomValueFromLevel( stateContext, zoomLevelNumber + 1 );
	}

	protected function GetBlendTime( stateContext : StateContext ) : Float
	{
		return stateContext.GetFloatParameter( 'blendTime', true );
	}

	protected const function GetZoomLevelNumber( const stateContext : StateContext ) : Int32
	{
		return stateContext.GetIntParameter( 'zoomLvlNumber', true );
	}

	protected function ResetAimType( stateContext : StateContext )
	{
		stateContext.SetPermanentIntParameter( 'AimType', ( ( Int32 )( aimTypeEnum.Invalid ) ), true );
	}

	protected function GetShouldUseWeaponZoomData( stateContext : StateContext ) : Bool
	{
		return stateContext.GetBoolParameter( 'shouldUseWeaponZoomStats', true );
	}

	protected const function GetZoomValueFromLevel( stateContext : StateContext, index : Int32 ) : Float
	{
		var zoomLevels : array< Float >;
		zoomLevels = GetZoomLevelsArray( stateContext );
		if( ( index < 0 ) || ( index >= zoomLevels.Size() ) )
		{
			return -1.0;
		}
		return zoomLevels[ index ];
	}

	protected const function GetZoomLevelsArray( stateContext : StateContext ) : array< Float >
	{
		if( stateContext.GetStateMachineCurrentState( 'LeftHandCyberware' ) == 'leftHandCyberwareCharge' )
		{
			return GetStaticFloatArrayParameter( "zoomLevelsCw" );
		}
		else
		{
			return GetStaticFloatArrayParameter( "zoomLevels" );
		}
	}

	protected function SendZoomAnimFeatureData( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var animFeatureData : AnimFeature_Zoom;
		var weapon : WeaponObject;
		var stats : StatsSystem;
		weapon = GetActiveWeapon( scriptInterface );
		stats = scriptInterface.GetStatsSystem();
		animFeatureData = new AnimFeature_Zoom;
		animFeatureData.finalZoomLevel = GetCurrentZoomLevel( stateContext );
		if( weapon )
		{
			animFeatureData.weaponZoomLevel = stats.GetStatValue( weapon.GetEntityID(), gamedataStatType.ZoomLevel );
			animFeatureData.weaponScopeFov = stats.GetStatValue( weapon.GetEntityID(), gamedataStatType.ScopeFOV );
			animFeatureData.weaponAimFOV = stats.GetStatValue( weapon.GetEntityID(), gamedataStatType.AimFOV );
		}
		animFeatureData.worldFOV = GameInstance.GetCameraSystem( scriptInterface.owner.GetGame() ).GetActiveCameraFOV();
		animFeatureData.zoomLevelNum = GetZoomLevelNumber( stateContext );
		animFeatureData.noWeaponAimInTime = GetStaticFloatParameterDefault( "noWeaponAimInTime", 0.2 );
		animFeatureData.noWeaponAimOutTime = GetStaticFloatParameterDefault( "noWeaponAimOutTime", 0.2 );
		animFeatureData.shouldUseWeaponZoomStats = GetShouldUseWeaponZoomData( stateContext );
		animFeatureData.focusModeActive = IsInVisionModeActiveState( stateContext, scriptInterface ) || stateContext.IsStateActive( 'UpperBody', 'temporaryUnequip' );
		scriptInterface.SetAnimationParameterFeature( 'ZoomAnimData', animFeatureData );
	}

}

class ZoomDecisionsTransition extends ZoomTransition
{

	public const virtual function ToNextZoomLevel( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var currentZoomLevel, kiroshiMaxZoomLevel : Float;
		if( scriptInterface.IsActionJustPressed( 'ZoomIn' ) )
		{
			currentZoomLevel = GetCurrentZoomLevel( stateContext );
			kiroshiMaxZoomLevel = GameInstance.GetStatsSystem( scriptInterface.owner.GetGame() ).GetStatValue( scriptInterface.owner.GetEntityID(), gamedataStatType.KiroshiMaxZoomLevel );
			if( IsControllingSniperNestDevice( scriptInterface ) )
			{
				if( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Vision ) != ( ( Int32 )( gamePSMVision.Focus ) ) )
				{
					return false;
				}
			}
			else if( currentZoomLevel >= kiroshiMaxZoomLevel )
			{
				return false;
			}
			if( !( IsControllingDevice( stateContext, scriptInterface ) ) )
			{
				if( !( scriptInterface.HasStatFlag( gamedataStatType.CanUseZoom ) ) )
				{
					return false;
				}
				if( IsAimingBlockedForTime( stateContext, scriptInterface ) )
				{
					return false;
				}
				if( IsWeaponStateBlockingAiming( scriptInterface ) )
				{
					return false;
				}
				if( scriptInterface.IsActionJustPressed( 'DriverCombatControllerActivateVisionHold' ) )
				{
					if( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Vision ) != ( ( Int32 )( gamePSMVision.Focus ) ) )
					{
						return false;
					}
				}
				if( ( currentZoomLevel != 1.0 ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'NoZooming' ) )
				{
					return false;
				}
			}
			else
			{
				if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
				{
					return false;
				}
			}
			return true;
		}
		return false;
	}

	public const virtual function ToPreviousZoomLevel( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( scriptInterface.IsActionJustPressed( 'ZoomOut' ) )
		{
			if( !( IsControllingDevice( stateContext, scriptInterface ) ) )
			{
				if( !( scriptInterface.HasStatFlag( gamedataStatType.CanUseZoom ) ) )
				{
					return false;
				}
			}
			if( IsControllingSniperNestDevice( scriptInterface ) )
			{
				return false;
			}
			if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
			{
				return false;
			}
			return true;
		}
		return false;
	}

	public const virtual function ToBaseZoom( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var cycleBlock : StateResultBool;
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		if( IsAimingBlockedForTime( stateContext, scriptInterface ) && stateContext.GetStateMachineCurrentState( 'LeftHandCyberware' ) != 'leftHandCyberwareCharge' )
		{
			return true;
		}
		if( scriptInterface.localBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.SceneAimForced ) )
		{
			return false;
		}
		if( IsWeaponStateBlockingAiming( scriptInterface ) )
		{
			return true;
		}
		if( IsRightHandInUnequippingState( stateContext ) || IsLeftHandInUnequippingState( stateContext ) )
		{
			return true;
		}
		cycleBlock = stateContext.GetConditionBoolParameter( 'cycleRoundBlockZoom' );
		if( cycleBlock.valid && cycleBlock.value )
		{
			return true;
		}
		if( IsGenericDeviceAndFocusInactive( stateContext, scriptInterface ) && !( IsConsideredAiming( stateContext, scriptInterface ) ) )
		{
			return true;
		}
		if( stateContext.GetBoolParameter( 'ReevaluateAiming', false ) )
		{
			return true;
		}
		return false;
	}

}

class ZoomEventsTransition extends ZoomTransition
{

	public virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var zoomLevelNumber : Int32;
		zoomLevelNumber = GetStaticIntParameterDefault( "zoomLevelNumber", 1 );
		if( IsControllingSniperNestDevice( scriptInterface ) && ( scriptInterface.GetActionValue( 'CameraAim' ) != 0.0 ) )
		{
			zoomLevelNumber = 6;
			PlaySound( 'w_gun_sniper_tech_rasetsu_aim_enter', scriptInterface );
		}
		SetPreviousZoomLevel( stateContext, GetCurrentZoomLevel( stateContext ) );
		SetCurrentZoomLevel( stateContext, zoomLevelNumber );
		SetZoomLevelNumber( stateContext, zoomLevelNumber );
		SetBlackboardFloatVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.ZoomLevel, GetCurrentZoomLevel( stateContext ) );
		SendZoomAnimFeatureData( stateContext, scriptInterface );
		if( !( IsInVisionModeActiveState( stateContext, scriptInterface ) ) && !( IsControllingSniperNestDevice( scriptInterface ) ) )
		{
			if( zoomLevelNumber > 1 )
			{
				PlaySound( 'ST_Focus_Mode_On_Set_State', scriptInterface );
			}
			else
			{
				PlaySound( 'ST_Focus_Mode_Off_Set_State', scriptInterface );
			}
		}
	}

	public virtual function OnExitToZoomLevelBase( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( IsControllingSniperNestDevice( scriptInterface ) )
		{
			PlaySound( 'w_gun_sniper_tech_rasetsu_aim_enter', scriptInterface );
		}
		else if( ShouldPlayZoomExitSound() && scriptInterface.HasStatFlag( gamedataStatType.CanUseZoom ) )
		{
			PlaySound( 'ui_focus_mode_zooming_in_exit', scriptInterface );
		}
		BreakEffectLoop( scriptInterface, 'zoom' );
		PlayZoomEndVisualEffect( stateContext, scriptInterface );
		stateContext.SetPermanentIntParameter( 'AimType', ( ( Int32 )( aimTypeEnum.AimOut ) ), true );
		SendZoomAnimFeatureData( stateContext, scriptInterface );
	}

	public virtual function OnExitToNextZoomLevel( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( ShouldPlayZoomStepSound() )
		{
			PlaySound( 'ui_focus_mode_zooming_in_step_change', scriptInterface );
		}
		BreakEffectLoop( scriptInterface, 'zoom' );
	}

	public virtual function OnExitToPreviousZoomLevel( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( ShouldPlayZoomStepSound() )
		{
			PlaySound( 'ui_focus_mode_zooming_in_step_change', scriptInterface );
		}
		BreakEffectLoop( scriptInterface, 'zoom' );
	}

}

class ZoomBlockedDecisions extends ZoomDecisionsTransition
{

	public export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( ( stateContext.IsStateMachineActive( 'Vehicle' ) && ( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Vehicle ) != ( ( Int32 )( gamePSMVehicle.DriverCombat ) ) ) ) && ( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.HighLevel ) != ( ( Int32 )( gamePSMHighLevel.SceneTier3 ) ) ) )
		{
			if( !( IsGenericDeviceOrFocusActive( stateContext, scriptInterface ) ) && !( IsInUpperBodyState( stateContext, 'aimingState' ) ) )
			{
				return true;
			}
			if( stateContext.GetStateMachineCurrentState( 'Vehicle' ) == 'exiting' )
			{
				return true;
			}
		}
		return false;
	}

	public export const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return !( EnterCondition( stateContext, scriptInterface ) );
	}

}

class ZoomBlockedEvents extends ZoomEventsTransition
{
	var previousCameraPerspective : vehicleCameraPerspective;
	var previousCameraPerspectiveValid : Bool;

	public export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( stateContext.IsStateMachineActive( 'Vehicle' ) )
		{
			if( previousCameraPerspectiveValid && previousCameraPerspective != vehicleCameraPerspective.FPP )
			{
				RequestVehicleCameraPerspective( scriptInterface, previousCameraPerspective );
				SetZoomStateAnimFeature( scriptInterface, false );
			}
		}
		SetBlendTime( stateContext, GetStaticFloatParameterDefault( "blendTime", 0.2 ) );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.MaxZoomLevel, GetZoomLevelNumber( stateContext ) );
		super.OnEnter( stateContext, scriptInterface );
		StopEffect( scriptInterface, 'zoom' );
	}

	protected function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var isInDriverCombat : Bool;
		isInDriverCombat = scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Vehicle ) == ( ( Int32 )( gamePSMVehicle.DriverCombat ) );
		if( stateContext.IsStateMachineActive( 'Vehicle' ) && !( isInDriverCombat ) )
		{
			previousCameraPerspective = GetMountedVehicle( scriptInterface.executionOwner ).GetCameraManager().GetActivePerspective();
			previousCameraPerspectiveValid = true;
		}
		else
		{
			previousCameraPerspectiveValid = false;
		}
	}

	public export override function OnExitToZoomLevelBase( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExit( stateContext, scriptInterface );
	}

}

class ZoomLevelBaseDecisions extends ZoomDecisionsTransition
{

	protected export const function ToZoomLevelAim( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( ToNextZoomLevel( stateContext, scriptInterface ) )
		{
			if( IsControllingSniperNestDevice( scriptInterface ) )
			{
				return false;
			}
			if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
			{
				return false;
			}
			return true;
		}
		if( IsConsideredAiming( stateContext, scriptInterface ) )
		{
			return true;
		}
		return false;
	}

}

class ZoomLevelBaseEvents extends ZoomEventsTransition
{

	public export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetBlendTime( stateContext, GetStaticFloatParameterDefault( "blendTime", 0.2 ) );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.MaxZoomLevel, GetZoomLevelNumber( stateContext ) );
		super.OnEnter( stateContext, scriptInterface );
		StopEffect( scriptInterface, 'zoom' );
	}

	protected export function OnExitToZoomLevelAim( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		stateContext.SetPermanentIntParameter( 'AimType', ( ( Int32 )( aimTypeEnum.AimIn ) ), true );
	}

}

class ZoomLevelAimDecisions extends ZoomDecisionsTransition
{

	public export const override function ToBaseZoom( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		if( super.ToBaseZoom( stateContext, scriptInterface ) )
		{
			return true;
		}
		if( IsGenericDeviceOrFocusActive( stateContext, scriptInterface ) && ToPreviousZoomLevel( stateContext, scriptInterface ) )
		{
			return true;
		}
		return false;
	}

	public export const function ToScanZoomLevel( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var adsZoomIndex : StateResultInt;
		if( IsControllingSniperNestDevice( scriptInterface ) )
		{
			return false;
		}
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		adsZoomIndex = stateContext.GetConditionIntParameter( 'adsZoomIndex' );
		if( !( adsZoomIndex.valid ) )
		{
			return ToNextZoomLevel( stateContext, scriptInterface );
		}
		else if( ( adsZoomIndex.value == 2 ) || ( adsZoomIndex.value == 1 ) )
		{
			return ToNextZoomLevel( stateContext, scriptInterface );
		}
		return false;
	}

	public export const function ToZoomLevel3( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var adsZoomIndex : StateResultInt;
		if( IsControllingSniperNestDevice( scriptInterface ) )
		{
			return false;
		}
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		adsZoomIndex = stateContext.GetConditionIntParameter( 'adsZoomIndex' );
		if( !( adsZoomIndex.valid ) )
		{
			return false;
		}
		else if( adsZoomIndex.value == 3 )
		{
			return ToNextZoomLevel( stateContext, scriptInterface );
		}
		else if( adsZoomIndex.value == 4 )
		{
			return ToPreviousZoomLevel( stateContext, scriptInterface );
		}
		return false;
	}

	public export const function ToZoomLevel4( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var adsZoomIndex : StateResultInt;
		if( IsControllingSniperNestDevice( scriptInterface ) )
		{
			return false;
		}
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		adsZoomIndex = stateContext.GetConditionIntParameter( 'adsZoomIndex' );
		if( !( adsZoomIndex.valid ) )
		{
			return false;
		}
		else if( adsZoomIndex.value == 4 )
		{
			return ToNextZoomLevel( stateContext, scriptInterface );
		}
		else if( adsZoomIndex.value > 4 )
		{
			return ToPreviousZoomLevel( stateContext, scriptInterface );
		}
		return false;
	}

	public const override function GetActualZoomValue( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Float
	{
		var weapon : WeaponObject;
		var stats : StatsSystem;
		weapon = GetActiveWeapon( scriptInterface );
		if( weapon )
		{
			stats = scriptInterface.GetStatsSystem();
			if( stats )
			{
				return stats.GetStatValue( weapon.GetEntityID(), gamedataStatType.ZoomLevel );
			}
		}
		return GetCurrentZoomLevel( stateContext );
	}

}

class ZoomLevelAimEvents extends ZoomEventsTransition
{
	var isAmingWithWeapon : Bool;

	public export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var prevZoomLevel : Float;
		isAmingWithWeapon = GetActiveWeapon( scriptInterface );
		if( !( IsControllingDevice( stateContext, scriptInterface, true ) ) && stateContext.IsStateMachineActive( 'Vehicle' ) )
		{
			SetZoomStateAnimFeature( scriptInterface, true );
		}
		SetShouldUseWeaponZoomData( stateContext, scriptInterface );
		super.OnEnter( stateContext, scriptInterface );
		prevZoomLevel = GetPreviousZoomLevel( stateContext );
		if( prevZoomLevel > 1.0 )
		{
			PlaySound( 'ui_focus_mode_zooming_in_step_change', scriptInterface );
		}
		else
		{
			PlayFocusModeZoomEnterSound( stateContext, scriptInterface );
		}
		ReevaluateADSZoomIndex( stateContext, scriptInterface );
	}

	protected function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		ResetShouldUseWeaponZoomData( stateContext );
		SendZoomAnimFeatureData( stateContext, scriptInterface );
	}

	protected export function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( stateContext.GetBoolParameter( ZoomTransitionHelper.GetReevaluateZoomName(), false ) )
		{
			stateContext.SetTemporaryBoolParameter( 'ReevaluateZoom', false, true );
			SetShouldUseWeaponZoomData( stateContext, scriptInterface );
			SendZoomAnimFeatureData( stateContext, scriptInterface );
		}
	}

	public export override function OnExitToZoomLevelBase( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnExitToZoomLevelBase( stateContext, scriptInterface );
	}

	public const override function ShouldPlayZoomExitSound() : Bool
	{
		return !( isAmingWithWeapon );
	}

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

	private function ReevaluateADSZoomIndex( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var actualZoom : Float;
		var zoomLevels : array< Float >;
		var i : Int32;
		var adsZoomIndex : Int32;
		actualZoom = GetActualZoomValue( stateContext, scriptInterface );
		zoomLevels = GetZoomLevelsArray( stateContext );
		for( i = 0; i < zoomLevels.Size(); i += 1 )
		{
			if( zoomLevels[ i ] > actualZoom )
			{
				break;
			}
		}
		adsZoomIndex = i;
		stateContext.SetConditionIntParameter( 'adsZoomIndex', adsZoomIndex, true );
	}

	public const override function GetActualZoomValue( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Float
	{
		var weapon : WeaponObject;
		var stats : StatsSystem;
		weapon = GetActiveWeapon( scriptInterface );
		if( weapon )
		{
			stats = scriptInterface.GetStatsSystem();
			if( stats )
			{
				return stats.GetStatValue( weapon.GetEntityID(), gamedataStatType.ZoomLevel );
			}
		}
		return GetCurrentZoomLevel( stateContext );
	}

}

class ZoomLevelScanDecisions extends ZoomDecisionsTransition
{

	public const override function ToBaseZoom( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		if( scriptInterface.IsActionJustPressed( 'RangedAttack' ) )
		{
			return true;
		}
		if( super.ToBaseZoom( stateContext, scriptInterface ) )
		{
			return true;
		}
		return false;
	}

	protected const function ToZoomLevelAim( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var adsZoomIndex : StateResultInt;
		adsZoomIndex = stateContext.GetConditionIntParameter( 'adsZoomIndex' );
		if( IsControllingSniperNestDevice( scriptInterface ) )
		{
			return false;
		}
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		if( !( adsZoomIndex.valid ) )
		{
			return false;
		}
		else if( ( adsZoomIndex.value == 2 ) || ( adsZoomIndex.value == 1 ) )
		{
			return ToPreviousZoomLevel( stateContext, scriptInterface );
		}
		else if( adsZoomIndex.value == 3 )
		{
			return ToNextZoomLevel( stateContext, scriptInterface );
		}
		return false;
	}

}

class ZoomLevelScanEvents extends ZoomEventsTransition
{

	public override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_step_change', scriptInterface );
		StartZoomEffect( stateContext, scriptInterface );
		super.OnEnter( stateContext, scriptInterface );
	}

	protected function OnExitToZoomLevelAim( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlayZoomEndVisualEffect( stateContext, scriptInterface );
	}

}

class ZoomLevel3Decisions extends ZoomDecisionsTransition
{

	public const override function ToBaseZoom( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		if( scriptInterface.IsActionJustPressed( 'RangedAttack' ) )
		{
			return true;
		}
		if( super.ToBaseZoom( stateContext, scriptInterface ) )
		{
			return true;
		}
		return false;
	}

	protected const function ToZoomLevelAim( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var adsZoomIndex : StateResultInt;
		adsZoomIndex = stateContext.GetConditionIntParameter( 'adsZoomIndex' );
		if( IsControllingDevice( stateContext, scriptInterface ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'DeviceControlZoomLock' ) )
		{
			return false;
		}
		if( !( adsZoomIndex.valid ) )
		{
			return false;
		}
		else if( adsZoomIndex.value == 3 )
		{
			return ToPreviousZoomLevel( stateContext, scriptInterface );
		}
		else if( adsZoomIndex.value == 4 )
		{
			return ToNextZoomLevel( stateContext, scriptInterface );
		}
		return false;
	}

}

class ZoomLevel3Events extends ZoomEventsTransition
{

	public override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_step_change', scriptInterface );
		StartZoomEffect( stateContext, scriptInterface );
		super.OnEnter( stateContext, scriptInterface );
	}

}

class ZoomLevel4Decisions extends ZoomDecisionsTransition
{

	protected const function ToZoomLevelAim( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var adsZoomIndex : StateResultInt;
		adsZoomIndex = stateContext.GetConditionIntParameter( 'adsZoomIndex' );
		if( !( adsZoomIndex.valid ) )
		{
			return false;
		}
		else if( adsZoomIndex.value == 4 )
		{
			return ToPreviousZoomLevel( stateContext, scriptInterface );
		}
		else if( adsZoomIndex.value > 5 )
		{
			return ToNextZoomLevel( stateContext, scriptInterface );
		}
		return false;
	}

	public const override function ToBaseZoom( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( scriptInterface.IsActionJustPressed( 'RangedAttack' ) )
		{
			return true;
		}
		if( super.ToBaseZoom( stateContext, scriptInterface ) )
		{
			return true;
		}
		return false;
	}

}

class ZoomLevel4Events extends ZoomEventsTransition
{

	public override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_step_change', scriptInterface );
		StartZoomEffect( stateContext, scriptInterface );
		super.OnEnter( stateContext, scriptInterface );
	}

	public function OnExitToZoomLevelAim( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_exit', scriptInterface );
		StartZoomEffect( stateContext, scriptInterface );
	}

	public function OnExitToBaseZoom( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_exit', scriptInterface );
	}

}

class ZoomLevel5Decisions extends ZoomDecisionsTransition
{

	protected const function ToZoomLevelAim( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var adsZoomIndex : StateResultInt;
		adsZoomIndex = stateContext.GetConditionIntParameter( 'adsZoomIndex' );
		if( !( adsZoomIndex.valid ) )
		{
			return false;
		}
		else if( adsZoomIndex.value == 5 )
		{
			return ToPreviousZoomLevel( stateContext, scriptInterface );
		}
		else if( adsZoomIndex.value > 6 )
		{
			return ToNextZoomLevel( stateContext, scriptInterface );
		}
		return false;
	}

	public const override function ToBaseZoom( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( scriptInterface.IsActionJustPressed( 'RangedAttack' ) )
		{
			return true;
		}
		if( super.ToBaseZoom( stateContext, scriptInterface ) )
		{
			return true;
		}
		return false;
	}

}

class ZoomLevel5Events extends ZoomEventsTransition
{

	public override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_step_change', scriptInterface );
		StartZoomEffect( stateContext, scriptInterface );
		super.OnEnter( stateContext, scriptInterface );
	}

	public function OnExitToZoomLevelAim( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_exit', scriptInterface );
		StartZoomEffect( stateContext, scriptInterface );
	}

	public function OnExitToBaseZoom( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_exit', scriptInterface );
	}

}

class ZoomLevel6Decisions extends ZoomDecisionsTransition
{

	protected const function ToZoomLevelAim( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var adsZoomIndex : StateResultInt;
		adsZoomIndex = stateContext.GetConditionIntParameter( 'adsZoomIndex' );
		if( !( adsZoomIndex.valid ) )
		{
			return false;
		}
		else if( adsZoomIndex.value == 6 )
		{
			return ToPreviousZoomLevel( stateContext, scriptInterface );
		}
		else if( adsZoomIndex.value > 6 )
		{
			return ToNextZoomLevel( stateContext, scriptInterface );
		}
		return false;
	}

	public const override function ToBaseZoom( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( scriptInterface.IsActionJustPressed( 'RangedAttack' ) )
		{
			return true;
		}
		if( super.ToBaseZoom( stateContext, scriptInterface ) )
		{
			return true;
		}
		return false;
	}

}

class ZoomLevel6Events extends ZoomEventsTransition
{

	public override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_step_change', scriptInterface );
		StartZoomEffect( stateContext, scriptInterface );
		super.OnEnter( stateContext, scriptInterface );
	}

	public function OnExitToZoomLevelAim( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_exit', scriptInterface );
		StartZoomEffect( stateContext, scriptInterface );
	}

	public function OnExitToBaseZoom( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		PlaySound( 'ui_focus_mode_zooming_in_exit', scriptInterface );
	}

}

enum aimTypeEnum
{
	AimIn = 0,
	AimOut = 1,
	Invalid = 2,
}

