abstract class BraindanceControlsTransition extends DefaultTransition
{

	protected const function SetBraindaneVisionModeBB( const scriptInterface : StateGameScriptInterface, newMode : braindanceVisionMode )
	{
		var BraindanceBB : IBlackboard;
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		BraindanceBB.SetInt( GetAllBlackboardDefs().Braindance.activeBraindanceVisionMode, ( ( Int32 )( newMode ) ), true );
	}

	protected const function SetLastBraindanceVisionMode( const scriptInterface : StateGameScriptInterface, newMode : braindanceVisionMode )
	{
		var BraindanceBB : IBlackboard;
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		BraindanceBB.SetInt( GetAllBlackboardDefs().Braindance.lastBraindanceVisionMode, ( ( Int32 )( newMode ) ), true );
	}

	protected const function SetBraindanceVisionFact( const scriptInterface : StateGameScriptInterface, newMode : braindanceVisionMode )
	{
		scriptInterface.GetQuestsSystem().SetFact( 'braindanceVisionMode', ( ( Int32 )( newMode ) ) );
	}

	protected const function SetCachedPlaySpeedPermVariable( scriptInterface : StateGameScriptInterface, stateContext : StateContext )
	{
		stateContext.SetPermanentIntParameter( 'cachedPlaySpeed', ( ( Int32 )( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() ) ), true );
	}

	protected const function SetPlaybackSpeedInBlackboard( const scriptInterface : StateGameScriptInterface, speed : scnPlaySpeed )
	{
		var BraindanceBB : IBlackboard;
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		BraindanceBB.SetVariant( GetAllBlackboardDefs().Braindance.PlaybackSpeed, speed, true );
	}

	protected const function SetPlaybackDirectionInBlackboard( const scriptInterface : StateGameScriptInterface, direction : scnPlayDirection )
	{
		var BraindanceBB : IBlackboard;
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		BraindanceBB.SetVariant( GetAllBlackboardDefs().Braindance.PlaybackDirection, direction, true );
	}

	protected const function IsCachedPlaySpeedSet( const stateContext : StateContext ) : Bool
	{
		var result : StateResultInt;
		result = stateContext.GetPermanentIntParameter( 'cachedPlaySpeed' );
		return result.valid;
	}

	protected const function GetCachedPlaySpeedPermVariable( const stateContext : StateContext ) : scnPlaySpeed
	{
		var result : StateResultInt;
		result = stateContext.GetPermanentIntParameter( 'cachedPlaySpeed' );
		return ( ( scnPlaySpeed )( result.value ) );
	}

	protected const function CanBraindanceEnterLayer( const scriptInterface : StateGameScriptInterface, layer : braindanceVisionMode ) : Bool
	{
		switch( layer )
		{
			case braindanceVisionMode.Default:
				return true;
			case braindanceVisionMode.Audio:
				return scriptInterface.GetQuestsSystem().GetFact( 'braindaneAudioLayerAvailable' ) > 0;
			case braindanceVisionMode.Thermal:
				return scriptInterface.GetQuestsSystem().GetFact( 'braindaneThermalLayerAvailable' ) > 0;
			default:
				return false;
		}
	}

	protected const function GetCurrentBraindanceVisionMode( const scriptInterface : StateGameScriptInterface ) : braindanceVisionMode
	{
		var BraindanceBB : IBlackboard;
		var mode : Int32;
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		mode = BraindanceBB.GetInt( GetAllBlackboardDefs().Braindance.activeBraindanceVisionMode );
		return ( ( braindanceVisionMode )( mode ) );
	}

	protected const function GetLastBraindanceVisionMode( const scriptInterface : StateGameScriptInterface ) : braindanceVisionMode
	{
		var BraindanceBB : IBlackboard;
		var mode : Int32;
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		mode = BraindanceBB.GetInt( GetAllBlackboardDefs().Braindance.lastBraindanceVisionMode );
		return ( ( braindanceVisionMode )( mode ) );
	}

	protected const function SetBraindanceVisionMode( const scriptInterface : StateGameScriptInterface, newMode : braindanceVisionMode )
	{
		SetBraindaneVisionModeBB( scriptInterface, newMode );
		SetBraindanceVisionFact( scriptInterface, newMode );
	}

	protected const function SendAudioEvents( const scriptInterface : StateGameScriptInterface, BdStart : Bool )
	{
		var AudioSys : AudioSystem;
		var eventName : CName;
		AudioSys = scriptInterface.GetAudioSystem();
		eventName = ( ( BdStart ) ? ( 'g_sc_bd_rewind_forward' ) : ( 'g_sc_bd_rewind_forward_end' ) );
		AudioSys.Play( eventName );
		eventName = ( ( BdStart ) ? ( 'g_sc_bd_rewind_backward' ) : ( 'g_sc_bd_rewind_backward_end' ) );
		AudioSys.Play( eventName );
	}

	protected const function CycleBraindanceVisionMode( const scriptInterface : StateGameScriptInterface )
	{
		var cycleMode : Int32;
		var i : Int32;
		cycleMode = ( ( Int32 )( GetCurrentBraindanceVisionMode( scriptInterface ) ) );
		for( i = 0; i < EnumGetMax( 'braindanceVisionMode' ); i += 1 )
		{
			cycleMode -= 1;
			if( cycleMode < 0 )
			{
				cycleMode = ( ( Int32 )( EnumGetMax( 'braindanceVisionMode' ) ) );
			}
			if( CanBraindanceEnterLayer( scriptInterface, ( ( braindanceVisionMode )( cycleMode ) ) ) )
			{
				SetBraindanceVisionMode( scriptInterface, ( ( braindanceVisionMode )( cycleMode ) ) );
				break;
			}
		}
	}

	protected const function TogglePausePlayForward( scriptInterface : StateGameScriptInterface, stateContext : StateContext )
	{
		var playSpeed : scnPlaySpeed;
		var playDirection : scnPlayDirection;
		if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Pause )
		{
			playSpeed = scnPlaySpeed.Normal;
			playDirection = scnPlayDirection.Forward;
			scriptInterface.GetAudioSystem().Play( 'g_sc_bd_rewind_play' );
			GetSceneSystemInterface( scriptInterface ).SetRewindableSectionPlayDirection( playDirection );
			GetSceneSystemInterface( scriptInterface ).SetRewindableSectionPlaySpeed( playSpeed );
			SetPlaybackDirectionInBlackboard( scriptInterface, playDirection );
		}
		else
		{
			playSpeed = scnPlaySpeed.Pause;
			scriptInterface.GetAudioSystem().Play( 'g_sc_bd_rewind_pause' );
			GetSceneSystemInterface( scriptInterface ).SetRewindableSectionPlaySpeed( playSpeed );
		}
		SetPlaybackSpeedInBlackboard( scriptInterface, playSpeed );
	}

	protected const function ForceBraindancePause( scriptInterface : StateGameScriptInterface, stateContext : StateContext )
	{
		if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() != scnPlaySpeed.Pause )
		{
			scriptInterface.GetAudioSystem().Play( 'g_sc_bd_rewind_pause_forced' );
			GetSceneSystemInterface( scriptInterface ).SetRewindableSectionPlaySpeed( scnPlaySpeed.Pause );
			SetPlaybackSpeedInBlackboard( scriptInterface, scnPlaySpeed.Pause );
		}
	}

	protected const function CyclePlaySpeed( const scriptInterface : StateGameScriptInterface, direction : scnPlayDirection )
	{
		var currentPlayDirection : scnPlayDirection;
		var currentPlaySpeed : scnPlaySpeed;
		var newPlayDirection : scnPlayDirection;
		var newPlaySpeed : scnPlaySpeed;
		var multiplier : Int32;
		currentPlayDirection = GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlayDirection();
		currentPlaySpeed = GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed();
		newPlayDirection = currentPlayDirection;
		if( currentPlaySpeed == scnPlaySpeed.Fast && currentPlayDirection == direction )
		{
			return;
		}
		if( currentPlaySpeed == scnPlaySpeed.Pause && direction != currentPlayDirection )
		{
			newPlayDirection = ( ( scnPlayDirection )( ( ( ( Int32 )( currentPlayDirection ) ) + 1 ) % 2 ) );
			GetSceneSystemInterface( scriptInterface ).SetRewindableSectionPlayDirection( newPlayDirection );
			SetPlaybackDirectionInBlackboard( scriptInterface, newPlayDirection );
		}
		if( currentPlaySpeed == scnPlaySpeed.Slow && direction != currentPlayDirection )
		{
			newPlayDirection = ( ( scnPlayDirection )( ( ( ( Int32 )( currentPlayDirection ) ) + 1 ) % 2 ) );
			GetSceneSystemInterface( scriptInterface ).SetRewindableSectionPlayDirection( newPlayDirection );
			SetPlaybackDirectionInBlackboard( scriptInterface, newPlayDirection );
			return;
		}
		multiplier = ( ( direction == newPlayDirection ) ? ( 1 ) : ( -1 ) );
		newPlaySpeed = ( ( scnPlaySpeed )( Clamp( ( ( Int32 )( currentPlaySpeed ) ) + multiplier, 0, ( ( Int32 )( EnumGetMax( 'scnPlaySpeed' ) ) ) ) ) );
		GetSceneSystemInterface( scriptInterface ).SetRewindableSectionPlaySpeed( newPlaySpeed );
		SetPlaybackSpeedInBlackboard( scriptInterface, newPlaySpeed );
	}

	protected const function SetPlaySpeedAndDirection( const scriptInterface : StateGameScriptInterface, direction : scnPlayDirection, speed : scnPlaySpeed )
	{
		GetSceneSystemInterface( scriptInterface ).SetRewindableSectionPlayDirection( direction );
		GetSceneSystemInterface( scriptInterface ).SetRewindableSectionPlaySpeed( speed );
		SetPlaybackDirectionInBlackboard( scriptInterface, direction );
		SetPlaybackSpeedInBlackboard( scriptInterface, speed );
	}

	protected const function GetDistanceFromBraindanceTPPCameraToFPPCamera( const scriptInterface : StateGameScriptInterface ) : Float
	{
		var player : PlayerPuppet;
		var distance : Float;
		distance = 0.0;
		player = ( ( PlayerPuppet )( scriptInterface.executionOwner ) );
		if( player != NULL )
		{
			distance = Vector4.Distance( player.GetWorldPosition(), WorldPosition.ToVector4( GetSceneSystemInterface( scriptInterface ).GetSceneSystemCameraLastCameraPosition() ) );
		}
		return distance;
	}

	protected const function CheckTargetThirdPersonPositionCollisions( const scriptInterface : StateGameScriptInterface, fppPosition : Vector4, fppOrientationEuler : EulerAngles, angle : Float, distance : Float, radius : Float, out outPosition : Vector4 ) : Float
	{
		var raycastDirection : Vector4;
		var collisionDistance : Float;
		var foundCollision : TraceResult;
		var targetPosition : Vector4;
		var targetOrientationQuat : Quaternion;
		var targetOrientationEuler : EulerAngles;
		targetOrientationEuler.Pitch = 0.0;
		targetOrientationEuler.Yaw = fppOrientationEuler.Yaw + angle;
		targetOrientationEuler.Roll = 0.0;
		targetOrientationQuat = EulerAngles.ToQuat( targetOrientationEuler );
		targetPosition = fppPosition - ( Quaternion.GetForward( targetOrientationQuat ) * distance );
		raycastDirection = targetPosition - fppPosition;
		collisionDistance = distance;
		Vector4.Normalize( raycastDirection );
		outPosition = targetPosition;
		foundCollision = scriptInterface.RaycastWithASingleGroup( fppPosition, targetPosition, 'PlayerBlocker' );
		if( TraceResult.IsValid( foundCollision ) )
		{
			collisionDistance = Vector4.Length( fppPosition - ( ( Vector4 )( foundCollision.position ) ) ) - radius;
			outPosition = ( ( Vector4 )( foundCollision.position ) ) - ( raycastDirection * radius );
		}
		return collisionDistance;
	}

	protected const function OnBraindancePerspectiveChangedFromFirstPersonToThirdPerson( const scriptInterface : StateGameScriptInterface )
	{
		var player : PlayerPuppet;
		var fppPosition : Vector4;
		var fppOrientationQuat : Quaternion;
		var fppOrientationEuler : EulerAngles;
		var targetDist : Float;
		var targetPosition : Vector4;
		var targetDirection : Vector4;
		var targetOrientationQuat : Quaternion;
		var targetOrientationEuler : EulerAngles;
		var heightOffset : Float;
		var distanceOffset : Float;
		var collisionRadius : Float;
		var targetPosBack : Vector4;
		var targetDistBack : Float;
		var targetPosLeft : Vector4;
		var targetDistLeft : Float;
		var targetPosRight : Vector4;
		var targetDistRight : Float;
		var groundRaycastBeginPoint : Vector4;
		var groundRaycastEndPoint : Vector4;
		var foundGround : TraceResult;
		player = ( ( PlayerPuppet )( scriptInterface.GetPlayerSystem().GetLocalPlayerControlledGameObject() ) );
		player.GetFPPCameraComponent().ResetPitch();
		fppPosition = WorldPosition.ToVector4( GetSceneSystemInterface( scriptInterface ).GetSceneSystemCameraLastCameraPosition() );
		fppOrientationQuat = GetSceneSystemInterface( scriptInterface ).GetSceneSystemCameraLastCameraOrientation();
		fppOrientationEuler = Quaternion.ToEulerAngles( fppOrientationQuat );
		heightOffset = GetStaticFloatParameterDefault( "tppInitialHeightOffset", 1.0 );
		distanceOffset = GetStaticFloatParameterDefault( "tppInitialDistance", 1.0 );
		collisionRadius = GetStaticFloatParameterDefault( "tppCollisionRadius", 0.40000001 );
		targetDistBack = CheckTargetThirdPersonPositionCollisions( scriptInterface, fppPosition, fppOrientationEuler, 0.0, distanceOffset, collisionRadius, targetPosBack );
		targetPosition = targetPosBack;
		targetDist = targetDistBack;
		if( targetDist < distanceOffset )
		{
			targetDistLeft = CheckTargetThirdPersonPositionCollisions( scriptInterface, fppPosition, fppOrientationEuler, -90.0, distanceOffset, collisionRadius, targetPosLeft );
			if( ( targetDistLeft > 0.0 ) && ( targetDistLeft > targetDist ) )
			{
				targetPosition = targetPosLeft;
				targetDist = targetDistLeft;
			}
			targetDistRight = CheckTargetThirdPersonPositionCollisions( scriptInterface, fppPosition, fppOrientationEuler, 90.0, distanceOffset, collisionRadius, targetPosRight );
			if( ( targetDistRight > 0.0 ) && ( targetDistRight > targetDist ) )
			{
				targetPosition = targetPosRight;
				targetDist = targetDistRight;
			}
		}
		targetDirection = fppPosition - targetPosition;
		targetDirection.Z = 0.0;
		Vector4.Normalize( targetDirection );
		targetOrientationQuat = Quaternion.BuildFromDirectionVector( targetDirection );
		targetOrientationEuler = Quaternion.ToEulerAngles( targetOrientationQuat );
		groundRaycastBeginPoint = targetPosition;
		groundRaycastBeginPoint.Z += collisionRadius;
		groundRaycastEndPoint = targetPosition;
		groundRaycastEndPoint.Z -= ( heightOffset + collisionRadius );
		foundGround = scriptInterface.RaycastWithASingleGroup( groundRaycastBeginPoint, groundRaycastEndPoint, 'PlayerBlocker' );
		if( TraceResult.IsValid( foundGround ) )
		{
			targetPosition = ( ( Vector4 )( foundGround.position ) );
			targetPosition.Z += collisionRadius;
		}
		else
		{
			targetPosition.Z -= heightOffset;
		}
		GameInstance.GetTeleportationFacility( scriptInterface.executionOwner.GetGame() ).Teleport( player, targetPosition, targetOrientationEuler );
	}

	protected const function EnableBraindanceLocomoition( const scriptInterface : StateGameScriptInterface )
	{
		var player : PlayerPuppet;
		var swapEvent : PSMAddOnDemandStateMachine;
		swapEvent = new PSMAddOnDemandStateMachine;
		player = GetPlayerPuppet( scriptInterface );
		swapEvent.stateMachineName = 'LocomotionBraindance';
		player.QueueEvent( swapEvent );
	}

	protected const function ToggleCameraControlEnabled( const scriptInterface : StateGameScriptInterface, stateContext : StateContext, out blendTime : Float )
	{
		var newState : Bool;
		var distance : Float;
		var minBlendTime : Float;
		var maxBlendTime : Float;
		var distanceToBlendRatio : Float;
		var BraindanceBB : IBlackboard;
		var uiBB : IBlackboard;
		var message : SimpleScreenMessage;
		minBlendTime = 0.5;
		maxBlendTime = 2.0;
		distanceToBlendRatio = 15.0;
		newState = !( GetSceneSystemInterface( scriptInterface ).GetSceneSystemCameraControlEnabled() );
		stateContext.SetPermanentBoolParameter( 'forceVM', !( newState ), true );
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		BraindanceBB.SetBool( GetAllBlackboardDefs().Braindance.IsFPP, newState, false );
		uiBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_Notifications );
		uiBB.SetVariant( GetAllBlackboardDefs().UI_Notifications.WarningMessage, message );
		if( newState )
		{
			distance = GetDistanceFromBraindanceTPPCameraToFPPCamera( scriptInterface );
			blendTime = MinF( minBlendTime + ( distance / distanceToBlendRatio ), maxBlendTime );
			RemoveBraindanceRestriction( scriptInterface );
			ApplyNoMovementRestriction( scriptInterface );
			GetSceneSystemInterface( scriptInterface ).SetSceneSystemCameraControlEnabled( newState, blendTime );
			SetLastBraindanceVisionMode( scriptInterface, GetCurrentBraindanceVisionMode( scriptInterface ) );
			SetBraindanceVisionMode( scriptInterface, braindanceVisionMode.Default );
			stateContext.SetPermanentBoolParameter( 'forceDisableVision', true, true );
			SetBraindanceUiGameContext( scriptInterface, UIGameContext.BraindancePlayback );
		}
		else
		{
			blendTime = minBlendTime;
			EnableBraindanceLocomoition( scriptInterface );
			RemoveNoMovementRestriction( scriptInterface );
			ApplyBraindanceRestriction( scriptInterface );
			OnBraindancePerspectiveChangedFromFirstPersonToThirdPerson( scriptInterface );
			GetSceneSystemInterface( scriptInterface ).SetSceneSystemCameraControlEnabled( newState, minBlendTime );
			if( GetLastBraindanceVisionMode( scriptInterface ) != braindanceVisionMode.Default )
			{
				SetBraindanceVisionMode( scriptInterface, GetLastBraindanceVisionMode( scriptInterface ) );
			}
			SetBraindanceUiGameContext( scriptInterface, UIGameContext.BraindanceEditor );
		}
	}

	protected const function SetCameraControl( const scriptInterface : StateGameScriptInterface, stateContext : StateContext, setState : Bool, out blendTime : Float )
	{
		var currentState : Bool;
		var minBlendTime : Float;
		var BraindanceBB : IBlackboard;
		var uiBB : IBlackboard;
		var message : SimpleScreenMessage;
		minBlendTime = 0.5;
		currentState = GetSceneSystemInterface( scriptInterface ).GetSceneSystemCameraControlEnabled();
		if( setState == currentState )
		{
			return;
		}
		stateContext.SetPermanentBoolParameter( 'forceVM', !( setState ), true );
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		BraindanceBB.SetBool( GetAllBlackboardDefs().Braindance.IsFPP, setState, false );
		uiBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_Notifications );
		uiBB.SetVariant( GetAllBlackboardDefs().UI_Notifications.WarningMessage, message );
		if( setState )
		{
			blendTime = 0.0;
			RemoveBraindanceRestriction( scriptInterface );
			ApplyNoMovementRestriction( scriptInterface );
			GetSceneSystemInterface( scriptInterface ).SetSceneSystemCameraControlEnabled( setState, blendTime );
			SetLastBraindanceVisionMode( scriptInterface, GetCurrentBraindanceVisionMode( scriptInterface ) );
			SetBraindanceVisionMode( scriptInterface, braindanceVisionMode.Default );
			stateContext.SetPermanentBoolParameter( 'forceDisableVision', true, true );
			SetBraindanceUiGameContext( scriptInterface, UIGameContext.BraindancePlayback );
		}
		else
		{
			blendTime = minBlendTime;
			EnableBraindanceLocomoition( scriptInterface );
			RemoveNoMovementRestriction( scriptInterface );
			ApplyBraindanceRestriction( scriptInterface );
			OnBraindancePerspectiveChangedFromFirstPersonToThirdPerson( scriptInterface );
			GetSceneSystemInterface( scriptInterface ).SetSceneSystemCameraControlEnabled( setState, minBlendTime );
			if( GetLastBraindanceVisionMode( scriptInterface ) != braindanceVisionMode.Default )
			{
				SetBraindanceVisionMode( scriptInterface, GetLastBraindanceVisionMode( scriptInterface ) );
			}
			SetBraindanceUiGameContext( scriptInterface, UIGameContext.BraindanceEditor );
		}
	}

	protected const function SetBraindanceState( const scriptInterface : StateGameScriptInterface, stateContext : StateContext, newState : Bool, out blendTime : Float )
	{
		var distance : Float;
		var minBlendTime : Float;
		var maxBlendTime : Float;
		var distanceToBlendRatio : Float;
		var BraindanceBB : IBlackboard;
		var uiBB : IBlackboard;
		var message : SimpleScreenMessage;
		minBlendTime = 0.5;
		maxBlendTime = 2.0;
		distanceToBlendRatio = 15.0;
		if( !( newState ) == GetSceneSystemInterface( scriptInterface ).GetSceneSystemCameraControlEnabled() )
		{
			return;
		}
		stateContext.SetPermanentBoolParameter( 'forceVM', newState, true );
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		BraindanceBB.SetBool( GetAllBlackboardDefs().Braindance.IsFPP, !( newState ), false );
		uiBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_Notifications );
		uiBB.SetVariant( GetAllBlackboardDefs().UI_Notifications.WarningMessage, message );
		if( !( newState ) )
		{
			distance = GetDistanceFromBraindanceTPPCameraToFPPCamera( scriptInterface );
			blendTime = MinF( minBlendTime + ( distance / distanceToBlendRatio ), maxBlendTime );
			RemoveBraindanceRestriction( scriptInterface );
			ApplyNoMovementRestriction( scriptInterface );
			GetSceneSystemInterface( scriptInterface ).SetSceneSystemCameraControlEnabled( !( newState ), blendTime );
			SetLastBraindanceVisionMode( scriptInterface, GetCurrentBraindanceVisionMode( scriptInterface ) );
			SetBraindanceVisionMode( scriptInterface, braindanceVisionMode.Default );
			stateContext.SetPermanentBoolParameter( 'forceDisableVision', true, true );
			SetBraindanceUiGameContext( scriptInterface, UIGameContext.BraindancePlayback );
		}
		else
		{
			blendTime = minBlendTime;
			EnableBraindanceLocomoition( scriptInterface );
			RemoveNoMovementRestriction( scriptInterface );
			ApplyBraindanceRestriction( scriptInterface );
			OnBraindancePerspectiveChangedFromFirstPersonToThirdPerson( scriptInterface );
			GetSceneSystemInterface( scriptInterface ).SetSceneSystemCameraControlEnabled( !( newState ), minBlendTime );
			if( GetLastBraindanceVisionMode( scriptInterface ) != braindanceVisionMode.Default )
			{
				SetBraindanceVisionMode( scriptInterface, GetLastBraindanceVisionMode( scriptInterface ) );
			}
			SetBraindanceUiGameContext( scriptInterface, UIGameContext.BraindanceEditor );
		}
	}

	protected const function SetBraindanceUiGameContext( const scriptInterface : StateGameScriptInterface, uiContext : UIGameContext )
	{
		var uiSystem : UISystem;
		uiSystem = scriptInterface.GetUISystem();
		switch( uiContext )
		{
			case UIGameContext.BraindanceEditor:
				uiSystem.PushGameContext( UIGameContext.BraindanceEditor );
			break;
			case UIGameContext.BraindancePlayback:
				uiSystem.PopGameContext( UIGameContext.BraindanceEditor );
			break;
			default:
				break;
		}
	}

	protected const function RemoveUiGameContext( const scriptInterface : StateGameScriptInterface )
	{
		var uiSystem : UISystem;
		uiSystem = scriptInterface.GetUISystem();
		uiSystem.PopGameContext( UIGameContext.Scanning );
		uiSystem.PopGameContext( UIGameContext.BraindanceEditor );
		uiSystem.PopGameContext( UIGameContext.BraindancePlayback );
	}

	protected const function GetBraindancePauseInput( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.IsActionJustPressed( 'Pause' );
	}

	protected const function GetPlayForwardInput( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.IsActionJustPressed( 'PlayForward' );
	}

	protected const function CheckPlayForwardInput( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.GetActionValue( 'PlayForward' ) > 0.0;
	}

	protected const function GetPlayBackwardInput( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.IsActionJustPressed( 'PlayBackward' );
	}

	protected const function CheckPlayBackwardInput( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.GetActionValue( 'PlayBackward' ) > 0.0;
	}

	protected const function GetRestartInput( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.IsActionJustHeld( 'Restart' );
	}

	protected const function GetSwitchLayerInput( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.IsActionJustPressed( 'SwitchLayer' );
	}

	protected const function GetBdCameraToggleInput( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.IsActionJustPressed( 'BdCameraToggle' );
	}

	protected const function IsPerspectiveTransitionOn( const BlockPerspectiveSwitchTimer : Float ) : Bool
	{
		return BlockPerspectiveSwitchTimer > 0.0;
	}

	protected const function UpdatePerspectiveTransitionTimer( out BlockPerspectiveSwitchTimer : Float, timeDelta : Float )
	{
		if( BlockPerspectiveSwitchTimer > 0.0 )
		{
			BlockPerspectiveSwitchTimer -= timeDelta;
		}
	}

	protected const function PrintDebugInfo( const scriptInterface : StateGameScriptInterface )
	{
	}

	protected const function GetBraindanceInputMask( const scriptInterface : StateGameScriptInterface ) : SBraindanceInputMask
	{
		return GetBraindanceSystem( scriptInterface ).GetInputMask();
	}

	protected const function SendAudioEventForBraindance( enable : Bool, const scriptInterface : StateGameScriptInterface )
	{
		var audioEvent : AudioEvent;
		audioEvent = new AudioEvent;
		audioEvent.eventName = ( ( enable ) ? ( 'enableFootsteps' ) : ( 'disableFootsteps' ) );
		scriptInterface.executionOwner.QueueEvent( audioEvent );
	}

	protected const function IsProgressAtBeggining( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetSceneSystemInterface( scriptInterface ).GetRewindableSectionProgress() == 0.0;
	}

	protected const function IsProgressAtEnd( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetSceneSystemInterface( scriptInterface ).GetRewindableSectionProgress() == 1.0;
	}

	protected const function GetChangeBraindanceStateRequest( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetBraindanceSystem( scriptInterface ).GetRequstCameraToggle();
	}

	protected const function GetPauseBraindanceRequest( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetBraindanceSystem( scriptInterface ).GetPauseBraindanceRequest();
	}

	protected const function GetRequestedEditorState( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetBraindanceSystem( scriptInterface ).GetRequestEditorState();
	}

	protected const function SendClearBraindanceStateRequest( const scriptInterface : StateGameScriptInterface )
	{
		var request : ClearBraindanceStateRequest;
		request = new ClearBraindanceStateRequest;
		GetBraindanceSystem( scriptInterface ).QueueRequest( request );
	}

	protected const function SendClearBraindancePauseRequest( const scriptInterface : StateGameScriptInterface )
	{
		var request : ClearBraindancePauseRequest;
		request = new ClearBraindancePauseRequest;
		GetBraindanceSystem( scriptInterface ).QueueRequest( request );
	}

	protected const function IsResetting( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetSceneSystemInterface( scriptInterface ).IsRewindableSectionResetting();
	}

	protected const function IsInEditorMode( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return !( GetSceneSystemInterface( scriptInterface ).GetSceneSystemCameraControlEnabled() );
	}

	protected const function StartGlitchFx( const scriptInterface : StateGameScriptInterface, optional fxState : Bool )
	{
		var effectName : CName;
		if( fxState )
		{
			return;
		}
		effectName = ( ( !( IsInEditorMode( scriptInterface ) ) ) ? ( 'transition_glitch_loop_braindance' ) : ( 'transition_glitch_loop' ) );
		GameObjectEffectHelper.StopEffectEvent( scriptInterface.executionOwner, effectName );
		effectName = ( ( IsInEditorMode( scriptInterface ) ) ? ( 'transition_glitch_loop_braindance' ) : ( 'transition_glitch_loop' ) );
		GameObjectEffectHelper.StartEffectEvent( scriptInterface.executionOwner, effectName );
	}

	protected const function StopGlitchFx( const scriptInterface : StateGameScriptInterface )
	{
		var effectName : CName;
		effectName = ( ( IsInEditorMode( scriptInterface ) ) ? ( 'transition_glitch_loop_braindance' ) : ( 'transition_glitch_loop' ) );
		GameObjectEffectHelper.StopEffectEvent( scriptInterface.executionOwner, effectName );
	}

	protected const function SetEndRecordingNotificationState( newState : Bool, const scriptInterface : StateGameScriptInterface )
	{
		var simpleScreenMessage : SimpleScreenMessage;
		simpleScreenMessage.isShown = newState;
		simpleScreenMessage.duration = 0.0;
		simpleScreenMessage.message = "LocKey#52608";
		simpleScreenMessage.isInstant = true;
		scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_Notifications ).SetVariant( GetAllBlackboardDefs().UI_Notifications.WarningMessage, simpleScreenMessage, true );
	}

	protected const function ApplyBraindanceRestriction( const scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Braindance" );
	}

	protected const function RemoveBraindanceRestriction( const scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Braindance" );
	}

	protected const function ApplyNoMovementRestriction( const scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoMovement" );
	}

	protected const function RemoveNoMovementRestriction( const scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoMovement" );
	}

	protected const function ApplyNoHubRestrictionOnLocalPlayer( const scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.GetPlayerSystem().GetLocalPlayerMainGameObject(), T"GameplayRestriction.BlockAllHubMenu" );
	}

	protected const function RemoveNoHubRestrictionFromLocalPlayer( const scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.GetPlayerSystem().GetLocalPlayerMainGameObject(), T"GameplayRestriction.BlockAllHubMenu" );
	}

}

class ControlsInactiveDecisions extends BraindanceControlsTransition
{

	protected export const function ToControlsActive( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetSceneSystemInterface( scriptInterface ).IsRewindableSectionActive();
	}

}

class ControlsInactiveEvents extends BraindanceControlsTransition
{

	protected export function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var BraindanceBB : IBlackboard;
		var SectionTime : Float;
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		BraindanceBB.SetBool( GetAllBlackboardDefs().Braindance.IsActive, true, false );
		BraindanceBB.SetBool( GetAllBlackboardDefs().Braindance.EnableExit, false, true );
		GetSceneSystemInterface( scriptInterface ).SetSceneSystemCameraControlEnabled( true );
		stateContext.SetPermanentBoolParameter( 'lockVM', true, true );
		SectionTime = GetSceneSystemInterface( scriptInterface ).GetRewindableSectionDurationInSec();
		BraindanceBB.SetFloat( GetAllBlackboardDefs().Braindance.SectionTime, SectionTime, false );
		SendAudioEventForBraindance( false, scriptInterface );
		SetLastBraindanceVisionMode( scriptInterface, braindanceVisionMode.Default );
		SetBraindanceVisionMode( scriptInterface, braindanceVisionMode.Default );
		SetPlaybackSpeedInBlackboard( scriptInterface, scnPlaySpeed.Normal );
		SetPlaybackDirectionInBlackboard( scriptInterface, scnPlayDirection.Forward );
		ApplyNoMovementRestriction( scriptInterface );
		ApplyNoHubRestrictionOnLocalPlayer( scriptInterface );
		SendAudioEvents( scriptInterface, true );
	}

	protected export function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		stateContext.RemovePermanentBoolParameter( 'lockVM' );
	}

	protected export function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var BraindanceBB : IBlackboard;
		var uiBB : IBlackboard;
		var message : SimpleScreenMessage;
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		BraindanceBB.SetBool( GetAllBlackboardDefs().Braindance.IsActive, false, true );
		uiBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_Notifications );
		uiBB.SetVariant( GetAllBlackboardDefs().UI_Notifications.WarningMessage, message );
		GetSceneSystemInterface( scriptInterface ).SetSceneSystemCameraControlEnabled( true );
		stateContext.RemovePermanentBoolParameter( 'lockVM' );
		stateContext.RemovePermanentBoolParameter( 'forceVM' );
		stateContext.SetPermanentBoolParameter( 'forceDisableVision', true, true );
		SendAudioEventForBraindance( true, scriptInterface );
		RemoveBraindanceRestriction( scriptInterface );
		RemoveNoMovementRestriction( scriptInterface );
		RemoveNoHubRestrictionFromLocalPlayer( scriptInterface );
		RemoveUiGameContext( scriptInterface );
	}

}

class ControlsActiveDecisions extends BraindanceControlsTransition
{

	protected export const function ToControlsInactive( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return !( GetSceneSystemInterface( scriptInterface ).IsRewindableSectionActive() );
	}

}

class ControlsActiveEvents extends BraindanceControlsTransition
{
	var BraindanceBB : weak< IBlackboard >;
	var BlockPerspectiveSwitchTimer : Float;
	var fxActive : Bool;
	var rewindFxActive : Bool;
	var holdDuration : Float;
	var cachedState : scnPlaySpeed;
	var cacheSet : Bool;
	var forwardInput : Bool;
	var backwardInput : Bool;
	var forwardInputLocked : Bool;
	var backwardInputLocked : Bool;
	var activeDirection : scnPlayDirection;
	var rewindRunning : Bool;
	var contextsSetup : Bool;
	var pauseLock : Bool;
	var endRecordingMessageSet : Bool;

	protected export function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var currentState : Bool;
		currentState = GetSceneSystemInterface( scriptInterface ).GetSceneSystemCameraControlEnabled();
		BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		BraindanceBB.SetBool( GetAllBlackboardDefs().Braindance.IsFPP, currentState, true );
		SetPlaybackSpeedInBlackboard( scriptInterface, GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() );
		SetPlaybackDirectionInBlackboard( scriptInterface, GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlayDirection() );
		ApplyNoMovementRestriction( scriptInterface );
		SendAudioEvents( scriptInterface, true );
		fxActive = false;
		rewindFxActive = false;
		BlockPerspectiveSwitchTimer = -1.0;
		holdDuration = 0.0;
		forwardInput = false;
		backwardInput = false;
		contextsSetup = false;
		pauseLock = false;
		endRecordingMessageSet = false;
	}

	protected export function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var inputMask : SBraindanceInputMask;
		var fadeInDelayFinished : Bool;
		inputMask = GetBraindanceInputMask( scriptInterface );
		if( !( contextsSetup ) )
		{
			scriptInterface.GetUISystem().PushGameContext( UIGameContext.BraindancePlayback );
			contextsSetup = true;
		}
		if( !( BraindanceBB ) )
		{
			BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		}
		UpdatePerspectiveTransitionTimer( BlockPerspectiveSwitchTimer, timeDelta );
		if( IsResetting( scriptInterface ) )
		{
			return;
		}
		fadeInDelayFinished = GetInStateTime() > 1.0;
		forwardInput = CheckPlayForwardInput( scriptInterface );
		backwardInput = CheckPlayBackwardInput( scriptInterface );
		if( ( forwardInput || backwardInput ) && fadeInDelayFinished )
		{
			if( !( cacheSet ) )
			{
				cachedState = ( ( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Pause ) ? ( scnPlaySpeed.Pause ) : ( scnPlaySpeed.Normal ) );
				cacheSet = true;
			}
			if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlayDirection() == scnPlayDirection.Forward && !( forwardInput ) )
			{
				backwardInputLocked = false;
			}
			if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlayDirection() == scnPlayDirection.Backward && !( backwardInput ) )
			{
				forwardInputLocked = false;
			}
			if( ( forwardInput && inputMask.playForwardAction ) && !( forwardInputLocked ) )
			{
				forwardInputLocked = true;
				activeDirection = scnPlayDirection.Forward;
				holdDuration = 0.0;
				scriptInterface.GetAudioSystem().Play( 'g_sc_bd_rewind_resume' );
			}
			if( ( backwardInput && inputMask.playBackwardAction ) && !( backwardInputLocked ) )
			{
				backwardInputLocked = true;
				activeDirection = scnPlayDirection.Backward;
				holdDuration = 0.0;
				scriptInterface.GetAudioSystem().Play( 'g_sc_bd_rewind_resume' );
			}
			if( ( ( ( activeDirection == scnPlayDirection.Forward && inputMask.playForwardAction ) && forwardInput ) && !( IsProgressAtEnd( scriptInterface ) ) ) && !( pauseLock ) )
			{
				holdDuration += timeDelta;
				if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Pause )
				{
					SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Forward, scnPlaySpeed.Normal );
					holdDuration = 0.0;
				}
				else if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Normal && cachedState == scnPlaySpeed.Normal )
				{
					SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Forward, scnPlaySpeed.Fast );
					holdDuration = 0.0;
				}
				else if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Normal && ( holdDuration > 2.0 ) )
				{
					SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Forward, scnPlaySpeed.Fast );
					holdDuration = 0.0;
				}
				else if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Fast && ( holdDuration > 2.0 ) )
				{
					SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Forward, scnPlaySpeed.VeryFast );
					holdDuration = 0.0;
				}
				else if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlayDirection() == scnPlayDirection.Backward )
				{
					SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Forward, scnPlaySpeed.Normal );
					holdDuration = 0.0;
					StopGlitchFx( scriptInterface );
					rewindFxActive = false;
				}
			}
			else if( ( ( ( activeDirection == scnPlayDirection.Backward && inputMask.playBackwardAction ) && backwardInput ) && !( IsProgressAtBeggining( scriptInterface ) ) ) && !( pauseLock ) )
			{
				holdDuration += timeDelta;
				if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Pause )
				{
					SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Backward, scnPlaySpeed.Normal );
					holdDuration = 0.0;
				}
				else if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Normal && ( holdDuration < 2.0 ) )
				{
					SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Backward, scnPlaySpeed.Normal );
				}
				else if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Normal && ( holdDuration > 2.0 ) )
				{
					SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Backward, scnPlaySpeed.Fast );
					holdDuration = 0.0;
				}
				else if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Fast && ( holdDuration > 2.0 ) )
				{
					SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Backward, scnPlaySpeed.VeryFast );
					holdDuration = 0.0;
				}
				else if( GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlayDirection() == scnPlayDirection.Forward )
				{
					SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Forward, scnPlaySpeed.Normal );
					holdDuration = 0.0;
				}
			}
			forwardInputLocked = forwardInput;
			backwardInputLocked = backwardInput;
			ProcessGlitchFX( scriptInterface );
		}
		else if( cacheSet )
		{
			if( inputMask.playForwardAction || inputMask.playBackwardAction )
			{
				SetPlaySpeedAndDirection( scriptInterface, scnPlayDirection.Forward, cachedState );
			}
			holdDuration = 0.0;
			cacheSet = false;
			forwardInputLocked = false;
			backwardInputLocked = false;
			if( rewindFxActive )
			{
				StopGlitchFx( scriptInterface );
				rewindFxActive = false;
			}
		}
		if( ( GetBraindancePauseInput( scriptInterface ) && inputMask.pauseAction ) && fadeInDelayFinished )
		{
			TogglePausePlayForward( scriptInterface, stateContext );
			pauseLock = GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed() == scnPlaySpeed.Pause;
			if( rewindFxActive )
			{
				StopGlitchFx( scriptInterface );
				rewindFxActive = false;
			}
		}
		if( pauseLock )
		{
			pauseLock = ( ( activeDirection == scnPlayDirection.Forward ) ? ( forwardInput ) : ( backwardInput ) );
		}
		if( ( ( GetSwitchLayerInput( scriptInterface ) && !( GetSceneSystemInterface( scriptInterface ).GetSceneSystemCameraControlEnabled() ) ) && inputMask.switchLayerAction ) && fadeInDelayFinished )
		{
			CycleBraindanceVisionMode( scriptInterface );
		}
		if( GetChangeBraindanceStateRequest( scriptInterface ) && !( IsPerspectiveTransitionOn( BlockPerspectiveSwitchTimer ) ) )
		{
			SetBraindanceState( scriptInterface, stateContext, GetRequestedEditorState( scriptInterface ), BlockPerspectiveSwitchTimer );
			SendClearBraindanceStateRequest( scriptInterface );
		}
		if( GetPauseBraindanceRequest( scriptInterface ) )
		{
			ForceBraindancePause( scriptInterface, stateContext );
			cachedState = scnPlaySpeed.Pause;
			SendClearBraindancePauseRequest( scriptInterface );
			StopGlitchFx( scriptInterface );
			rewindFxActive = false;
			forwardInputLocked = false;
			backwardInputLocked = false;
		}
		if( ( ( GetBdCameraToggleInput( scriptInterface ) && fadeInDelayFinished ) && !( IsPerspectiveTransitionOn( BlockPerspectiveSwitchTimer ) ) ) && inputMask.cameraToggleAction )
		{
			ToggleCameraControlEnabled( scriptInterface, stateContext, BlockPerspectiveSwitchTimer );
			StopGlitchFx( scriptInterface );
			rewindFxActive = false;
		}
		if( ( GetRestartInput( scriptInterface ) && inputMask.restartAction ) && fadeInDelayFinished )
		{
			scriptInterface.GetAudioSystem().Play( 'g_sc_bd_rewind_restart' );
			GetSceneSystemInterface( scriptInterface ).ResetRewindableSection( 100.0, scnPlayDirection.Forward, scnPlaySpeed.Normal );
			StartGlitchFx( scriptInterface );
			fxActive = true;
			GameInstance.GetTelemetrySystem( scriptInterface.executionOwner.GetGame() ).LogBraindanceReset();
		}
		if( fxActive && !( IsResetting( scriptInterface ) ) )
		{
			StopGlitchFx( scriptInterface );
			fxActive = false;
		}
		if( IsProgressAtBeggining( scriptInterface ) || IsProgressAtEnd( scriptInterface ) )
		{
			StopGlitchFx( scriptInterface );
			rewindFxActive = false;
		}
		if( !( endRecordingMessageSet ) && IsProgressAtEnd( scriptInterface ) )
		{
			SetEndRecordingNotificationState( true, scriptInterface );
			endRecordingMessageSet = true;
		}
		else if( endRecordingMessageSet && !( IsProgressAtEnd( scriptInterface ) ) )
		{
			SetEndRecordingNotificationState( false, scriptInterface );
			endRecordingMessageSet = false;
		}
		BraindanceBB.SetFloat( GetAllBlackboardDefs().Braindance.Progress, GetSceneSystemInterface( scriptInterface ).GetRewindableSectionProgress(), true );
	}

	protected function ProcessGlitchFX( const scriptInterface : StateGameScriptInterface )
	{
		var speed : scnPlaySpeed;
		var direction : scnPlayDirection;
		speed = GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlaySpeed();
		direction = GetSceneSystemInterface( scriptInterface ).GetRewindableSectionPlayDirection();
		if( rewindFxActive || speed == scnPlaySpeed.Pause )
		{
			return;
		}
		if( direction == scnPlayDirection.Backward || ( direction == scnPlayDirection.Forward && speed != scnPlaySpeed.Normal ) )
		{
			StartGlitchFx( scriptInterface, rewindFxActive );
			rewindFxActive = true;
		}
	}

	protected export function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		stateContext.RemovePermanentBoolParameter( 'lockVM' );
		stateContext.RemovePermanentBoolParameter( 'forceVM' );
		StopGlitchFx( scriptInterface );
		SendAudioEvents( scriptInterface, false );
		if( endRecordingMessageSet )
		{
			SetEndRecordingNotificationState( false, scriptInterface );
			endRecordingMessageSet = false;
		}
	}

	protected export function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( !( BraindanceBB ) )
		{
			BraindanceBB = scriptInterface.GetBlackboardSystem().Get( GetAllBlackboardDefs().Braindance );
		}
		BraindanceBB.SetBool( GetAllBlackboardDefs().Braindance.IsActive, false, true );
		GetSceneSystemInterface( scriptInterface ).SetSceneSystemCameraControlEnabled( true );
		stateContext.RemovePermanentBoolParameter( 'lockVM' );
		stateContext.RemovePermanentBoolParameter( 'forceVM' );
		stateContext.SetPermanentBoolParameter( 'forceDisableVision', true, true );
		SendAudioEventForBraindance( true, scriptInterface );
		StopGlitchFx( scriptInterface );
		RemoveBraindanceRestriction( scriptInterface );
		RemoveNoMovementRestriction( scriptInterface );
		RemoveNoHubRestrictionFromLocalPlayer( scriptInterface );
		RemoveUiGameContext( scriptInterface );
		SendAudioEvents( scriptInterface, false );
		if( endRecordingMessageSet )
		{
			SetEndRecordingNotificationState( false, scriptInterface );
			endRecordingMessageSet = false;
		}
	}

}

