class AICoverHelper
{

	public static function CoverExposureMethodNameToEnum( exposureMethodName : CName ) : AICoverExposureMethod
	{
		switch( exposureMethodName )
		{
			case 'Standing_Step_Left':
				return AICoverExposureMethod.Standing_Step_Left;
			case 'Standing_Step_Right':
				return AICoverExposureMethod.Standing_Step_Right;
			case 'Standing_Lean_Left':
				return AICoverExposureMethod.Standing_Lean_Left;
			case 'Standing_Lean_Right':
				return AICoverExposureMethod.Standing_Lean_Right;
			case 'Standing_Blind_Left':
				return AICoverExposureMethod.Standing_Blind_Left;
			case 'Standing_Blind_Right':
				return AICoverExposureMethod.Standing_Blind_Right;
			case 'Crouching_Step_Left':
				return AICoverExposureMethod.Crouching_Step_Left;
			case 'Crouching_Step_Right':
				return AICoverExposureMethod.Crouching_Step_Right;
			case 'Crouching_Lean_Left':
				return AICoverExposureMethod.Crouching_Lean_Left;
			case 'Crouching_Lean_Right':
				return AICoverExposureMethod.Crouching_Lean_Right;
			case 'Crouching_Blind_Left':
				return AICoverExposureMethod.Crouching_Blind_Left;
			case 'Crouching_Blind_Right':
				return AICoverExposureMethod.Crouching_Blind_Right;
			case 'Crouching_Blind_Top':
				return AICoverExposureMethod.Crouching_Blind_Top;
			case 'Lean_Over':
				return AICoverExposureMethod.Lean_Over;
			case 'Stand_Up':
				return AICoverExposureMethod.Stand_Up;
			default:
				break;
		}
		return AICoverExposureMethod.Count;
	}

	public static function CoverHeightNameToEnum( coverHeight : CName ) : gameCoverHeight
	{
		switch( coverHeight )
		{
			case 'Low':
				return gameCoverHeight.Low;
			case 'High':
				return gameCoverHeight.High;
			case 'Invalid':
				return gameCoverHeight.Invalid;
			default:
				break;
		}
		return gameCoverHeight.Invalid;
	}

	public static function CoverActionNameToEnum( actionName : CName ) : EAICoverAction
	{
		switch( actionName )
		{
			case 'StepOut':
				return EAICoverAction.StepOut;
			case 'LeanOut':
				return EAICoverAction.LeanOut;
			case 'StepUp':
				return EAICoverAction.StepUp;
			case 'LeanOver':
				return EAICoverAction.LeanOver;
			case 'Undefined':
				return EAICoverAction.Undefined;
			default:
				break;
		}
		return EAICoverAction.Undefined;
	}

	public static function GetCoverBlackboard( puppet : ScriptedPuppet ) : IBlackboard
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard();
	}

	public static function GetCoverManager( puppet : ScriptedPuppet ) : CoverManager
	{
		return GameInstance.GetCoverManager( puppet.GetGame() );
	}

	public static function GetCurrentCoverStance( puppet : ScriptedPuppet ) : CName
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().GetName( GetAllBlackboardDefs().AICover.currentCoverStance );
	}

	public static function GetCurrentCoverStance( puppet : ScriptedPuppet, out coverStance : gameCoverHeight )
	{
		var coverStanceName : CName;
		coverStanceName = puppet.GetAIControllerComponent().GetCoverBlackboard().GetName( GetAllBlackboardDefs().AICover.currentCoverStance );
		coverStance = CoverHeightNameToEnum( coverStanceName );
	}

	public static function SetCurrentCoverStance( puppet : ScriptedPuppet, value : gameCoverHeight )
	{
		puppet.GetAIControllerComponent().GetCoverBlackboard().SetName( GetAllBlackboardDefs().AICover.currentCoverStance, EnumValueToName( 'gameCoverHeight', ( ( Int32 )( value ) ) ) );
	}

	public static function SetCurrentCoverStance( puppet : ScriptedPuppet, value : CName )
	{
		puppet.GetAIControllerComponent().GetCoverBlackboard().SetName( GetAllBlackboardDefs().AICover.currentCoverStance, value );
	}

	public static function GetDesiredCoverStance( puppet : ScriptedPuppet ) : CName
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().GetName( GetAllBlackboardDefs().AICover.desiredCoverStance );
	}

	public static function GetDesiredCoverStance( puppet : ScriptedPuppet, out coverStance : gameCoverHeight )
	{
		var coverStanceName : CName;
		coverStanceName = puppet.GetAIControllerComponent().GetCoverBlackboard().GetName( GetAllBlackboardDefs().AICover.desiredCoverStance );
		coverStance = CoverHeightNameToEnum( coverStanceName );
	}

	public static function SetDesiredCoverStance( puppet : ScriptedPuppet, value : CName )
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().SetName( GetAllBlackboardDefs().AICover.desiredCoverStance, value );
	}

	public static function SetDesiredCoverStance( puppet : ScriptedPuppet, value : gameCoverHeight )
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().SetName( GetAllBlackboardDefs().AICover.desiredCoverStance, EnumValueToName( 'gameCoverHeight', ( ( Int32 )( value ) ) ) );
	}

	public static function GetCoverExposureMethod( puppet : ScriptedPuppet ) : CName
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().GetName( GetAllBlackboardDefs().AICover.exposureMethod );
	}

	public static function GetFallbackCoverExposureMethod( puppet : ScriptedPuppet, out method : AICoverExposureMethod )
	{
		var methodName : CName;
		methodName = puppet.GetAIControllerComponent().GetCoverBlackboard().GetName( GetAllBlackboardDefs().AICover.fallbackExposureMethod );
		method = ( ( AICoverExposureMethod )( ( ( Int32 )( EnumValueFromName( 'AICoverExposureMethod', methodName ) ) ) ) );
	}

	public static function GetCoverExposureMethod( puppet : ScriptedPuppet, out method : AICoverExposureMethod )
	{
		var methodName : CName;
		methodName = puppet.GetAIControllerComponent().GetCoverBlackboard().GetName( GetAllBlackboardDefs().AICover.exposureMethod );
		method = ( ( AICoverExposureMethod )( ( ( Int32 )( EnumValueFromName( 'AICoverExposureMethod', methodName ) ) ) ) );
	}

	public static function HasAnyCoverLastAvailableExposureMethod( puppet : ScriptedPuppet ) : Bool
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().GetUint( GetAllBlackboardDefs().AICover.lastAvailableMethods ) != ( ( Uint32 )( 0 ) );
	}

	public static function GetRandomCoverLastAvailableExposureMethod( puppet : ScriptedPuppet, out method : AICoverExposureMethod )
	{
		var lastAvailableMethods : Uint32;
		var randomOffset : Uint32;
		var i : Int32;
		var tmp : Uint32;
		lastAvailableMethods = puppet.GetAIControllerComponent().GetCoverBlackboard().GetUint( GetAllBlackboardDefs().AICover.lastAvailableMethods );
		method = AICoverExposureMethod.Count;
		if( lastAvailableMethods != ( ( Uint32 )( 0 ) ) )
		{
			randomOffset = ( ( Uint32 )( RandRange( 0, ( ( Int32 )( AICoverExposureMethod.Count ) ) ) ) );
			for( i = 0; i < ( ( Int32 )( AICoverExposureMethod.Count ) ); i += 1 )
			{
				tmp = ( ( ( Uint32 )( i ) ) + randomOffset ) % ( ( Uint32 )( AICoverExposureMethod.Count ) );
				if( lastAvailableMethods & ( ( Uint32 )( PowF( 2.0, ( ( Float )( tmp ) ) ) ) ) )
				{
					method = ( ( AICoverExposureMethod )( tmp ) );
				}
			}
		}
	}

	public static function SetCoverExposureMethod( puppet : ScriptedPuppet, value : CName )
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().SetName( GetAllBlackboardDefs().AICover.exposureMethod, value );
	}

	public static function SetCoverExposureMethod( puppet : ScriptedPuppet, value : AICoverExposureMethod )
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().SetName( GetAllBlackboardDefs().AICover.exposureMethod, EnumValueToName( 'AICoverExposureMethod', ( ( Int32 )( value ) ) ) );
	}

	public static function SetFallbackCoverExposureMethod( puppet : ScriptedPuppet, value : AICoverExposureMethod )
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().SetName( GetAllBlackboardDefs().AICover.fallbackExposureMethod, EnumValueToName( 'AICoverExposureMethod', ( ( Int32 )( value ) ) ) );
	}

	public static function SetCoverLastAvailableExposureMethod( puppet : ScriptedPuppet, optional exposureMethods : array< AICoverExposureMethod > )
	{
		var methodsMask : Uint32;
		var i : Int32;
		methodsMask = ( ( Uint32 )( 0 ) );
		for( i = 0; i < exposureMethods.Size(); i += 1 )
		{
			methodsMask = methodsMask | ( ( Uint32 )( PowF( 2.0, ( ( Float )( ( ( Int32 )( exposureMethods[ i ] ) ) ) ) ) ) );
		}
		methodsMask = methodsMask & ~( ( ( Uint32 )( PowF( 2.0, ( ( Float )( ( ( Uint32 )( AICoverExposureMethod.Standing_Step_Left ) ) ) ) ) ) ) );
		methodsMask = methodsMask & ~( ( ( Uint32 )( PowF( 2.0, ( ( Float )( ( ( Uint32 )( AICoverExposureMethod.Standing_Step_Right ) ) ) ) ) ) ) );
		methodsMask = methodsMask & ~( ( ( Uint32 )( PowF( 2.0, ( ( Float )( ( ( Uint32 )( AICoverExposureMethod.Crouching_Step_Left ) ) ) ) ) ) ) );
		methodsMask = methodsMask & ~( ( ( Uint32 )( PowF( 2.0, ( ( Float )( ( ( Uint32 )( AICoverExposureMethod.Crouching_Step_Right ) ) ) ) ) ) ) );
		puppet.GetAIControllerComponent().GetCoverBlackboard().SetUint( GetAllBlackboardDefs().AICover.lastAvailableMethods, methodsMask );
	}

	public static function GetCoverNPCCurrentlyExposed( puppet : ScriptedPuppet ) : Bool
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().GetBool( GetAllBlackboardDefs().AICover.currentlyExposed );
	}

	public static function SetCoverNPCCurrentlyExposed( puppet : ScriptedPuppet, value : Bool )
	{
		return puppet.GetAIControllerComponent().GetCoverBlackboard().SetBool( GetAllBlackboardDefs().AICover.currentlyExposed, value );
	}

	public static function IsCurrentlyInCover( puppet : ScriptedPuppet ) : Bool
	{
		var cm : CoverManager;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return false;
		}
		return cm.IsCoverRegular( cm.GetCurrentCover( puppet ) );
	}

	public static function IsCurrentlyInShootingSpot( puppet : ScriptedPuppet ) : Bool
	{
		var cm : CoverManager;
		var id : Uint64;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return false;
		}
		id = cm.GetCurrentCover( puppet );
		if( id > ( ( Uint64 )( 0 ) ) )
		{
			return !( cm.IsCoverRegular( id ) );
		}
		return false;
	}

	public static function IsCurrentlyInSmartObject( puppet : ScriptedPuppet ) : Bool
	{
		var cm : CoverManager;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return false;
		}
		return cm.GetCurrentCover( puppet ) > ( ( Uint64 )( 0 ) );
	}

	public static function GetCurrentCover( puppet : ScriptedPuppet ) : Uint64
	{
		var cm : CoverManager;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return ( ( Uint64 )( 0 ) );
		}
		return cm.GetCurrentCover( puppet );
	}

	public static function IsStandingExposureMethod( exposureMethodName : CName ) : Bool
	{
		switch( exposureMethodName )
		{
			case 'Lean_Over':
				return false;
			case 'Crouching_Step_Left':
				return false;
			case 'Crouching_Step_Right':
				return false;
			case 'Crouching_Lean_Left':
				return false;
			case 'Crouching_Lean_Right':
				return false;
			case 'Crouching_Blind_Left':
				return false;
			case 'Crouching_Blind_Right':
				return false;
			case 'Crouching_Blind_Top':
				return false;
			default:
				return true;
		}
	}

	public static function IsUnsafeExposureMethod( exposureMethodName : CName ) : Bool
	{
		switch( exposureMethodName )
		{
			case 'Standing_Step_Left':
				return false;
			case 'Standing_Step_Right':
				return false;
			case 'Crouching_Step_Left':
				return false;
			case 'Crouching_Step_Right':
				return false;
			case 'Stand_Up':
				return false;
			default:
				return true;
		}
	}

	public static function FillEmptyCoverExposureMethodArray() : array< AICoverExposureMethod >
	{
		var allExposureMethods : array< AICoverExposureMethod >;
		allExposureMethods.Resize( 15 );
		allExposureMethods[ 0 ] = AICoverExposureMethod.Standing_Step_Left;
		allExposureMethods[ 1 ] = AICoverExposureMethod.Standing_Step_Right;
		allExposureMethods[ 2 ] = AICoverExposureMethod.Standing_Lean_Left;
		allExposureMethods[ 3 ] = AICoverExposureMethod.Standing_Lean_Right;
		allExposureMethods[ 4 ] = AICoverExposureMethod.Crouching_Step_Left;
		allExposureMethods[ 5 ] = AICoverExposureMethod.Crouching_Step_Right;
		allExposureMethods[ 6 ] = AICoverExposureMethod.Crouching_Lean_Left;
		allExposureMethods[ 7 ] = AICoverExposureMethod.Crouching_Lean_Right;
		allExposureMethods[ 8 ] = AICoverExposureMethod.Lean_Over;
		allExposureMethods[ 9 ] = AICoverExposureMethod.Stand_Up;
		allExposureMethods[ 10 ] = AICoverExposureMethod.Standing_Blind_Left;
		allExposureMethods[ 11 ] = AICoverExposureMethod.Standing_Blind_Right;
		allExposureMethods[ 12 ] = AICoverExposureMethod.Crouching_Blind_Left;
		allExposureMethods[ 13 ] = AICoverExposureMethod.Crouching_Blind_Right;
		allExposureMethods[ 14 ] = AICoverExposureMethod.Crouching_Blind_Top;
		return allExposureMethods;
	}

	public static function FillEmptyCoverExposureMethodNameArray() : array< CName >
	{
		var allExposureMethods : array< CName >;
		allExposureMethods.Resize( 15 );
		allExposureMethods[ 0 ] = 'Standing_Step_Left';
		allExposureMethods[ 1 ] = 'Standing_Step_Right';
		allExposureMethods[ 2 ] = 'Standing_Lean_Left';
		allExposureMethods[ 3 ] = 'Standing_Lean_Right';
		allExposureMethods[ 4 ] = 'Crouching_Step_Left';
		allExposureMethods[ 5 ] = 'Crouching_Step_Right';
		allExposureMethods[ 6 ] = 'Crouching_Lean_Left';
		allExposureMethods[ 7 ] = 'Crouching_Lean_Right';
		allExposureMethods[ 8 ] = 'Lean_Over';
		allExposureMethods[ 9 ] = 'Stand_Up';
		allExposureMethods[ 10 ] = 'Standing_Blind_Left';
		allExposureMethods[ 11 ] = 'Standing_Blind_Right';
		allExposureMethods[ 12 ] = 'Crouching_Blind_Left';
		allExposureMethods[ 13 ] = 'Crouching_Blind_Right';
		allExposureMethods[ 14 ] = 'Crouching_Blind_Top';
		return allExposureMethods;
	}

	public static function UnregisterLastCover( puppet : ScriptedPuppet )
	{
		var cm : CoverManager;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return;
		}
		cm.UnregisterCoverOccupant( puppet );
	}

	public static function RegisterNewCover( puppet : ScriptedPuppet, coverId : Uint64 )
	{
		var cm : CoverManager;
		if( coverId == ( ( Uint64 )( 0 ) ) )
		{
			if( coverId == ( ( Uint64 )( 0 ) ) )
			{
				return;
			}
			;
		}
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return;
		}
		cm.RegisterCoverOccupant( coverId, puppet );
	}

	public static function GetAbsAngleFromCoverToTargetPosition( puppet : weak< ScriptedPuppet >, coverID : Uint64, targetPosition : Vector4 ) : Float
	{
		var vecToTarget : Vector4;
		var absAngleToTarget : Float;
		vecToTarget = targetPosition - GameInstance.GetCoverManager( puppet.GetGame() ).GetCoverPosition( coverID );
		absAngleToTarget = AbsF( Vector4.GetAngleDegAroundAxis( vecToTarget, GameInstance.GetCoverManager( puppet.GetGame() ).GetCoverWorldForward( coverID ), GameInstance.GetCoverManager( puppet.GetGame() ).GetCoverWorldUp( coverID ) ) );
		return absAngleToTarget;
	}

	public static function GetAbsAngleFromCoverToCombatTarget( puppet : ScriptedPuppet, targetPosition : Vector4, coverID : Uint64 ) : Float
	{
		var cm : CoverManager;
		var vecToTarget : Vector4;
		var absAngleToTarget : Float;
		if( Vector4.IsZero( targetPosition ) || ( coverID == ( ( Uint64 )( 0 ) ) ) )
		{
			return -1.0;
		}
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return -1.0;
		}
		vecToTarget = targetPosition - cm.GetCoverPosition( coverID );
		absAngleToTarget = AbsF( Vector4.GetAngleDegAroundAxis( vecToTarget, cm.GetCoverWorldForward( coverID ), cm.GetCoverWorldUp( coverID ) ) );
		return absAngleToTarget;
	}

	public static function GetAbsAngleFromCoverToMovementTarget( puppet : ScriptedPuppet, movementTargetPos : Vector4, coverID : Uint64 ) : Float
	{
		var cm : CoverManager;
		var vecToTarget : Vector4;
		var absAngleToTarget : Float;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return -1.0;
		}
		vecToTarget = movementTargetPos - cm.GetCoverPosition( coverID );
		absAngleToTarget = AbsF( Vector4.GetAngleDegAroundAxis( vecToTarget, cm.GetCoverWorldForward( coverID ), cm.GetCoverWorldUp( coverID ) ) );
		return absAngleToTarget;
	}

	public static function GetCoverHeight( puppet : ScriptedPuppet, coverID : Uint64 ) : gameCoverHeight
	{
		var cm : CoverManager;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return gameCoverHeight.Invalid;
		}
		return cm.GetCoverHeight( coverID );
	}

	public static function GetCoverType( puppet : ScriptedPuppet, coverID : Uint64, out shootingSpot : Bool ) : gameCoverHeight
	{
		var cm : CoverManager;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return gameCoverHeight.Invalid;
		}
		if( cm.IsShootingSpot( coverID ) )
		{
			shootingSpot = true;
		}
		return cm.GetCoverHeight( coverID );
	}

	public static function NotifyGotDamageInCover( puppet : ScriptedPuppet, coverID : Uint64, damageTime : EngineTime, executingCoverAction : Bool )
	{
		var cm : CoverManager;
		var statesComponent : NPCStatesComponent;
		var isShooting : Bool;
		statesComponent = puppet.GetStatesComponent();
		isShooting = false;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return;
		}
		if( statesComponent )
		{
			isShooting = statesComponent.GetCurrentUpperBodyState() == gamedataNPCUpperBodyState.Shoot;
		}
		return cm.NotifyGotDamageInCover( coverID, damageTime, executingCoverAction, isShooting );
	}

	public static function GetCoverRemainingHealthPerc( puppet : weak< ScriptedPuppet >, coverID : Uint64 ) : Float
	{
		var cm : CoverManager;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return -1.0;
		}
		return cm.GetCoverRemainingHealthPercentage( coverID );
	}

	public static function HasCoverExposureMethods( const puppetOwner : weak< ScriptedPuppet >, const coverID : Uint64, const target : weak< GameObject >, const exposureMethods : ref< array< AICoverExposureMethod > > ) : Bool
	{
		var usableExposureSpots : array< gameAvailableExposureMethodResult >;
		var i, j : Int32;
		if( exposureMethods.Size() == 0 )
		{
			return true;
		}
		usableExposureSpots = GameInstance.GetCoverManager( puppetOwner.GetGame() ).GetUsableExposureSpotsForCover( coverID, target );
		for( i = 0; i < usableExposureSpots.Size(); i += 1 )
		{
			for( j = 0; j < exposureMethods.Size(); j += 1 )
			{
				if( ( usableExposureSpots[ i ].distanceToTarget == 0.0 ) && usableExposureSpots[ i ].method == exposureMethods[ j ] )
				{
					break;
				}
			}
			if( j >= exposureMethods.Size() )
			{
				return false;
			}
		}
		return true;
	}

	public static function HasCoverExposureMethods( const ownerPuppet : weak< ScriptedPuppet >, const coverID : Uint64, const target : weak< GameObject >, const exposureMethods : ref< array< CName > > ) : Bool
	{
		var methods : array< AICoverExposureMethod >;
		var i : Int32;
		for( i = 0; i < exposureMethods.Size(); i += 1 )
		{
			methods.PushBack( CoverExposureMethodNameToEnum( exposureMethods[ i ] ) );
		}
		return HasCoverExposureMethods( ownerPuppet, coverID, target, methods );
	}

	public static function GetAvailableExposureSpots( puppet : weak< ScriptedPuppet >, coverID : Uint64, const target : weak< GameObject >, requestedExposureMethods : array< AICoverExposureMethod >, lineOfSightTolerance : Float, optional exposureMethodPriority : array< weak< AIExposureMethodType_Record > > ) : array< AICoverExposureMethod >
	{
		var validExposureSpots : array< gameAvailableExposureMethodResult >;
		var availableExposureMethods : array< AICoverExposureMethod >;
		var cm : CoverManager;
		var i, j : Int32;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return availableExposureMethods;
		}
		if( requestedExposureMethods.Size() == 0 )
		{
			requestedExposureMethods = AICoverHelper.FillEmptyCoverExposureMethodArray();
		}
		validExposureSpots = cm.GetUsableExposureSpotsForCover( coverID, target );
		for( i = 0; i < validExposureSpots.Size(); i += 1 )
		{
			for( j = 0; j < requestedExposureMethods.Size(); j += 1 )
			{
				if( ( validExposureSpots[ i ].distanceToTarget <= lineOfSightTolerance ) && validExposureSpots[ i ].method == requestedExposureMethods[ j ] )
				{
					availableExposureMethods.PushBack( requestedExposureMethods[ j ] );
				}
			}
		}
		return availableExposureMethods;
	}

	public static function GetAvailableExposureSpots( puppet : weak< ScriptedPuppet >, coverID : Uint64, const target : weak< GameObject >, record : weak< AISubActionCover_Record >, lineOfSightTolerance : Float, optional exposureMethodPriority : array< weak< AIExposureMethodType_Record > > ) : array< AICoverExposureMethod >
	{
		var allAvailableExposureMethods : array< AICoverExposureMethod >;
		return GetAvailableExposureSpots( puppet, coverID, target, record, lineOfSightTolerance, exposureMethodPriority, allAvailableExposureMethods );
	}

	public static function GetAvailableExposureSpots( puppet : weak< ScriptedPuppet >, coverID : Uint64, const target : weak< GameObject >, record : weak< AISubActionCover_Record >, lineOfSightTolerance : Float, optional exposureMethodPriority : array< weak< AIExposureMethodType_Record > >, allAvailableExposureMethods : ref< array< AICoverExposureMethod > > ) : array< AICoverExposureMethod >
	{
		var validExposureSpots : array< gameAvailableExposureMethodResult >;
		var noCollisionExposureMethods : array< AICoverExposureMethod >;
		var requestedExposureMethods : array< AICoverExposureMethod >;
		var coverExposureMethods : array< CName >;
		var coverCommandParams : weak< CoverCommandParams >;
		var cm : CoverManager;
		var i, j : Int32;
		var tmpVariant : Variant;
		var blackboard : IBlackboard;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return allAvailableExposureMethods;
		}
		blackboard = puppet.GetAIControllerComponent().GetCoverBlackboard();
		tmpVariant = blackboard.GetVariant( GetAllBlackboardDefs().AICover.commandExposureMethods );
		if( tmpVariant.IsValid() )
		{
			coverCommandParams = ( ( weak< weak< CoverCommandParams > > )tmpVariant );
		}
		coverCommandParams = ( ( weak< weak< CoverCommandParams > > )( blackboard.GetVariant( GetAllBlackboardDefs().AICover.commandExposureMethods ) ) );
		if( coverCommandParams )
		{
			requestedExposureMethods = coverCommandParams.exposureMethods;
		}
		else
		{
			coverExposureMethods = record.CoverExposureMethods();
			requestedExposureMethods.Resize( coverExposureMethods.Size() );
			for( i = 0; i < coverExposureMethods.Size(); i += 1 )
			{
				requestedExposureMethods[ i ] = AICoverHelper.CoverExposureMethodNameToEnum( coverExposureMethods[ i ] );
			}
		}
		if( requestedExposureMethods.Size() == 0 )
		{
			requestedExposureMethods = AICoverHelper.FillEmptyCoverExposureMethodArray();
		}
		validExposureSpots = cm.GetUsableExposureSpotsForCover( coverID, target );
		for( i = 0; i < validExposureSpots.Size(); i += 1 )
		{
			for( j = 0; j < requestedExposureMethods.Size(); j += 1 )
			{
				if( ( validExposureSpots[ i ].distanceToTarget <= lineOfSightTolerance ) && validExposureSpots[ i ].method == requestedExposureMethods[ j ] )
				{
					if( validExposureSpots[ i ].distanceToTarget == 0.0 )
					{
						noCollisionExposureMethods.PushBack( requestedExposureMethods[ j ] );
						continue;
					}
					if( noCollisionExposureMethods.Size() == 0 )
					{
						allAvailableExposureMethods.PushBack( requestedExposureMethods[ j ] );
					}
				}
			}
		}
		if( noCollisionExposureMethods.Size() > 0 )
		{
			allAvailableExposureMethods = noCollisionExposureMethods;
			return ReturnHighestPriorityMethods( puppet, record, noCollisionExposureMethods );
		}
		return ReturnHighestPriorityMethods( puppet, record, allAvailableExposureMethods );
	}

	public static function CalculateCoverExposureMethod( puppet : weak< ScriptedPuppet >, const target : weak< GameObject >, coverID : Uint64, record : weak< AISubActionCover_Record >, lineOfSightTolerance : Float, const trackedLocation : ref< TrackedLocation >, exposureMethods : ref< array< AICoverExposureMethod > > ) : AICoverExposureMethod
	{
		var lastExposureMethod : AICoverExposureMethod;
		var exposureMethod : AICoverExposureMethod;
		var tmpMethods : array< AICoverExposureMethod >;
		GetCoverExposureMethod( puppet, lastExposureMethod );
		tmpMethods = GetAvailableExposureSpots( puppet, coverID, target, record, lineOfSightTolerance, , exposureMethods );
		if( tmpMethods.Size() == 0 )
		{
			return AICoverExposureMethod.Count;
		}
		if( tmpMethods.Size() > 1 )
		{
			tmpMethods.Remove( lastExposureMethod );
		}
		exposureMethod = tmpMethods[ RandRange( 0, tmpMethods.Size() ) ];
		return exposureMethod;
	}

	public static function ReturnHighestPriorityMethods( puppet : ScriptedPuppet, record : weak< AISubActionCover_Record >, const exposureMethods : ref< array< AICoverExposureMethod > > ) : array< AICoverExposureMethod >
	{
		var presence : array< Int32 >;
		var priority : array< Int32 >;
		var candidates : array< AICoverExposureMethod >;
		var exposureMethodPriority : array< weak< AIExposureMethodType_Record > >;
		var hitReactionComponent : HitReactionComponent;
		var previousHitDelay : Float;
		var i, j : Int32;
		hitReactionComponent = puppet.GetHitReactionComponent();
		previousHitDelay = EngineTime.ToFloat( GameInstance.GetSimTime( puppet.GetGame() ) ) - hitReactionComponent.GetLastHitTimeStamp();
		if( ( hitReactionComponent && ( record.PrioritizeBlindFireAfterHit() > 0.0 ) ) && ( previousHitDelay < record.PrioritizeBlindFireAfterHit() ) )
		{
			exposureMethodPriority.Resize( 1 );
			exposureMethodPriority[ 0 ] = TweakDBInterface.GetAIExposureMethodTypeRecord( T"AIExposureMethodType.BlindFire" );
		}
		else
		{
			record.ExposureMethodPriority( exposureMethodPriority );
		}
		for( i = 0; i < exposureMethodPriority.Size(); i += 1 )
		{
			priority = exposureMethodPriority[ i ].Priority();
			presence.Clear();
			presence.Resize( 15 );
			for( j = 0; j < exposureMethods.Size(); j += 1 )
			{
				presence[ ( ( Int32 )( exposureMethods[ j ] ) ) ] = 1;
			}
			for( j = 0; j < priority.Size(); j += 1 )
			{
				if( presence[ priority[ j ] ] == 1 )
				{
					candidates.PushBack( ( ( AICoverExposureMethod )( priority[ j ] ) ) );
				}
			}
			if( candidates.Size() > 0 )
			{
				return candidates;
			}
		}
		return exposureMethods;
	}

	public static function GetCoverStanceFromExposureSpot( puppet : ScriptedPuppet, exposureSpot : AICoverExposureMethod ) : gameCoverHeight
	{
		switch( exposureSpot )
		{
			case AICoverExposureMethod.Standing_Step_Left:
				return gameCoverHeight.High;
			case AICoverExposureMethod.Standing_Step_Right:
				return gameCoverHeight.High;
			case AICoverExposureMethod.Standing_Lean_Left:
				return gameCoverHeight.High;
			case AICoverExposureMethod.Standing_Lean_Right:
				return gameCoverHeight.High;
			case AICoverExposureMethod.Crouching_Step_Left:
				return gameCoverHeight.Low;
			case AICoverExposureMethod.Crouching_Step_Right:
				return gameCoverHeight.Low;
			case AICoverExposureMethod.Crouching_Lean_Left:
				return gameCoverHeight.Low;
			case AICoverExposureMethod.Crouching_Lean_Right:
				return gameCoverHeight.Low;
			case AICoverExposureMethod.Lean_Over:
				return gameCoverHeight.Low;
			case AICoverExposureMethod.Stand_Up:
				return gameCoverHeight.Low;
			case AICoverExposureMethod.Standing_Blind_Left:
				return gameCoverHeight.High;
			case AICoverExposureMethod.Standing_Blind_Right:
				return gameCoverHeight.High;
			case AICoverExposureMethod.Crouching_Blind_Left:
				return gameCoverHeight.Low;
			case AICoverExposureMethod.Crouching_Blind_Right:
				return gameCoverHeight.Low;
			case AICoverExposureMethod.Crouching_Blind_Top:
				return gameCoverHeight.Low;
			default:
				return CoverHeightNameToEnum( GetCurrentCoverStance( puppet ) );
		}
	}

	public static function LeaveCoverImmediately( puppet : ScriptedPuppet ) : Bool
	{
		var cm : CoverManager;
		cm = GetCoverManager( puppet );
		if( !( cm ) )
		{
			return false;
		}
		cm.LeaveCoverImmediately( puppet );
		return true;
	}

	public static function GetCurrentCoverId( puppet : ScriptedPuppet ) : Uint64
	{
		var cm : CoverManager;
		if( !( puppet ) )
		{
			return ( ( Uint64 )( 0 ) );
		}
		cm = GameInstance.GetCoverManager( puppet.GetGame() );
		if( !( cm ) )
		{
			return ( ( Uint64 )( 0 ) );
		}
		return cm.GetCurrentCover( puppet );
	}

}

