enum EDeathType
{
	Ground = 0,
	Air = 1,
	Swimming = 2,
}

abstract class HighLevelTransition extends DefaultTransition
{

	public function BlockMovement( const scriptInterface : StateGameScriptInterface, val : Bool )
	{
		if( val == true )
		{
			StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoMovement" );
		}
		else
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoMovement" );
		}
	}

	public function ForceEmptyHands( stateContext : StateContext, val : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'ForceEmptyHands', val, true );
	}

	public function IsForceEmptyHands( stateContext : StateContext ) : Bool
	{
		return stateContext.GetBoolParameter( 'ForceEmptyHands', true );
	}

	public function ForceTemporaryUnequip( stateContext : StateContext, val : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'forcedTemporaryUnequip', val, true );
	}

	public function ForceSafeState( stateContext : StateContext )
	{
		stateContext.SetPermanentBoolParameter( 'ForceSafeState', true, true );
	}

	public function ForceReadyState( stateContext : StateContext )
	{
		stateContext.SetPermanentBoolParameter( 'ForceReadyState', true, true );
	}

	public function ForceExitToStand( stateContext : StateContext )
	{
		if( stateContext.GetConditionBool( 'CrouchToggled' ) )
		{
			stateContext.SetConditionBoolParameter( 'CrouchToggled', false, true );
		}
	}

	public function ResetForceWalkSpeed( stateContext : StateContext )
	{
		stateContext.SetPermanentFloatParameter( 'ForceWalkSpeed', -1.0, true );
	}

	public function SetTier2LocomotionSlow( scriptInterface : StateGameScriptInterface )
	{
		if( !( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Tier2LocomotionSlow" ) ) )
		{
			StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Tier2LocomotionSlow" );
		}
	}

	public function SetTier2Locomotion( scriptInterface : StateGameScriptInterface )
	{
		if( !( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Tier2Locomotion" ) ) )
		{
			StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Tier2Locomotion" );
		}
	}

	public function SetTier2LocomotionFast( scriptInterface : StateGameScriptInterface )
	{
		if( !( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Tier2LocomotionFast" ) ) )
		{
			StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Tier2LocomotionFast" );
		}
	}

	public function RemoveTier2LocomotionSlow( scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Tier2LocomotionSlow" );
	}

	public function RemoveTier2Locomotion( scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Tier2Locomotion" );
	}

	public function RemoveTier2LocomotionFast( scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.Tier2LocomotionFast" );
	}

	public function RemoveAllTierLocomotions( scriptInterface : StateGameScriptInterface )
	{
		RemoveTier2LocomotionSlow( scriptInterface );
		RemoveTier2Locomotion( scriptInterface );
		RemoveTier2LocomotionFast( scriptInterface );
	}

	public function ActivateTier3Locomotion( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var player : PlayerPuppet;
		var swapEvent : PSMAddOnDemandStateMachine;
		swapEvent = new PSMAddOnDemandStateMachine;
		player = GetPlayerPuppet( scriptInterface );
		swapEvent.stateMachineName = 'LocomotionTier3';
		player.QueueEvent( swapEvent );
	}

	public function ActivateTier4Locomotion( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var player : PlayerPuppet;
		var swapEvent : PSMAddOnDemandStateMachine;
		swapEvent = new PSMAddOnDemandStateMachine;
		player = GetPlayerPuppet( scriptInterface );
		swapEvent.stateMachineName = 'LocomotionTier4';
		player.QueueEvent( swapEvent );
	}

	public function ActivateTier5Locomotion( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var player : PlayerPuppet;
		var swapEvent : PSMAddOnDemandStateMachine;
		swapEvent = new PSMAddOnDemandStateMachine;
		player = GetPlayerPuppet( scriptInterface );
		swapEvent.stateMachineName = 'LocomotionTier5';
		player.QueueEvent( swapEvent );
	}

	public function ActivateWorkspotLocomotion( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var player : PlayerPuppet;
		var swapEvent : PSMAddOnDemandStateMachine;
		swapEvent = new PSMAddOnDemandStateMachine;
		player = GetPlayerPuppet( scriptInterface );
		swapEvent.stateMachineName = 'LocomotionWorkspot';
		player.QueueEvent( swapEvent );
	}

	public function ForceDefaultLocomotion( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var player : PlayerPuppet;
		var swapEvent : PSMAddOnDemandStateMachine;
		swapEvent = new PSMAddOnDemandStateMachine;
		player = GetPlayerPuppet( scriptInterface );
		swapEvent.stateMachineName = 'Locomotion';
		swapEvent.tryHotSwap = true;
		player.QueueEvent( swapEvent );
	}

	protected function GetCurrentHealthPerc( scriptInterface : StateGameScriptInterface ) : Float
	{
		var health : Float;
		var gameInstance : GameInstance;
		var ownerID : StatsObjectID;
		ownerID = scriptInterface.ownerEntityID;
		gameInstance = scriptInterface.owner.GetGame();
		health = GameInstance.GetStatPoolsSystem( gameInstance ).GetStatPoolValue( ownerID, gamedataStatPoolType.Health );
		return health;
	}

	protected function SetPlayerVitalsAnimFeatureData( stateContext : StateContext, scriptInterface : StateGameScriptInterface, val : Int32, stateDuration : Float )
	{
		var animFeature : AnimFeature_PlayerVitals;
		animFeature = new AnimFeature_PlayerVitals;
		animFeature.state = val;
		animFeature.stateDuration = stateDuration;
		scriptInterface.SetAnimationParameterFeature( 'PlayerVitals', animFeature );
	}

	protected const function GetDeathType( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : EDeathType
	{
		var deathType : EDeathType;
		if( scriptInterface.IsFalling() )
		{
			deathType = EDeathType.Air;
		}
		else if( stateContext.IsStateMachineActive( 'LocomotionSwimming' ) )
		{
			deathType = EDeathType.Swimming;
		}
		else
		{
			deathType = EDeathType.Ground;
		}
		return deathType;
	}

	protected final function SetDeathCameraParameters( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var param : StateResultCName;
		param = GetStaticCNameParameter( "onEnterCameraParamsName" );
		if( param.valid )
		{
			stateContext.SetPermanentCNameParameter( 'LocomotionCameraParams', param.value, true );
			if( stateContext.IsStateMachineActive( 'Vehicle' ) )
			{
				stateContext.SetPermanentCNameParameter( 'VehicleCameraParams', param.value, true );
			}
			UpdateCameraParams( stateContext, scriptInterface );
		}
	}

	protected const function IsDeathMenuBlocked( scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GameInstance.GetQuestsSystem( scriptInterface.owner.GetGame() ).GetFact( 'block_death_menu' ) == 1;
	}

	protected function StartDeathEffects( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		EvaluateSettingCustomDeathAnimation( stateContext, scriptInterface );
		RemoveAllBreathingEffects( scriptInterface );
		ForceTemporaryUnequip( stateContext, true );
		SetIsResurrectionAllowedBasedOnState( stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.SceneTier1 ) ) );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vitals, ( ( Int32 )( gamePSMVitals.Dead ) ) );
		SetPlayerVitalsAnimFeatureData( stateContext, scriptInterface, 1, TDB.GetFloat( T"player.deathMenu.delayToDisplay", 3.0 ) );
		scriptInterface.GetAudioSystem().Play( 'global_death_enter' );
		scriptInterface.GetAudioSystem().Play( 'ui_death' );
	}

	protected function SetIsResurrectionAllowedBasedOnState( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var locomotionState : gamePSMDetailedLocomotionStates;
		var wasPlayerForceKilled : Bool;
		if( scriptInterface.GetStatsSystem().GetStatValue( scriptInterface.ownerEntityID, gamedataStatType.ForcePreventResurrect ) == 0.0 )
		{
			if( HasSecondHeart( scriptInterface ) )
			{
				locomotionState = ( ( gamePSMDetailedLocomotionStates )( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.LocomotionDetailed ) ) );
				wasPlayerForceKilled = StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.owner, T"BaseStatusEffect.ForceKill" );
				if( locomotionState != gamePSMDetailedLocomotionStates.DeathLand && !( wasPlayerForceKilled ) )
				{
					stateContext.SetPermanentBoolParameter( 'isResurrectionAllowed', true, true );
					return;
				}
			}
		}
		stateContext.SetPermanentBoolParameter( 'isResurrectionAllowed', false, true );
		if( !( IsDeathMenuBlocked( scriptInterface ) ) )
		{
			SetBlackboardBoolVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.DisplayDeathMenu, true );
		}
		scriptInterface.GetStatPoolsSystem().RequestSettingStatPoolValueIgnoreChangeMode( scriptInterface.ownerEntityID, gamedataStatPoolType.Health, 0.0, NULL );
	}

	protected function SetPlayerDeathAnimFeatureData( stateContext : StateContext, scriptInterface : StateGameScriptInterface, val : Int32 )
	{
		var animFeature : AnimFeature_PlayerDeathAnimation;
		animFeature = new AnimFeature_PlayerDeathAnimation;
		animFeature.animation = val;
		scriptInterface.SetAnimationParameterFeature( 'DeathAnimation', animFeature );
	}

	protected function EvaluateSettingCustomDeathAnimation( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var setAnimInt : Int32;
		if( GetStaticIntParameterDefault( "DEBUG_forceSetDeathAnimation", -1 ) > 0 )
		{
			setAnimInt = GetStaticIntParameterDefault( "DEBUG_forceSetDeathAnimation", -1 );
		}
		else
		{
			if( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.NetwatcherGeneral" ) )
			{
				setAnimInt = 1;
			}
			else
			{
				setAnimInt = 0;
			}
		}
		SetPlayerDeathAnimFeatureData( stateContext, scriptInterface, setAnimInt );
	}

	protected const function IsResurrectionAllowed( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return stateContext.GetBoolParameter( 'isResurrectionAllowed', true );
	}

	protected const function CanPlayerSwim( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface, depthThresholdAndTolerance : Float ) : Bool
	{
		var deepEnough : Bool;
		var playerFeetPosition : Vector4;
		var depthRaycastDestination : Vector4;
		var waterLevel : Float;
		if( stateContext.IsStateMachineActive( 'Vehicle' ) )
		{
			return false;
		}
		if( stateContext.IsStateMachineActive( 'LocomotionTakedown' ) )
		{
			return false;
		}
		playerFeetPosition = GetPlayerPosition( scriptInterface );
		depthRaycastDestination = playerFeetPosition;
		depthRaycastDestination.Z = depthRaycastDestination.Z - 2.0;
		deepEnough = false;
		if( scriptInterface.GetWaterLevel( playerFeetPosition, depthRaycastDestination, waterLevel ) )
		{
			deepEnough = ( playerFeetPosition.Z - waterLevel ) <= depthThresholdAndTolerance;
		}
		return deepEnough;
	}

	public virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var glpSys : GameplayLogicPackageSystem;
		var glpID : TweakDBID;
		if( GetGLP( glpID ) )
		{
			glpSys = scriptInterface.GetGameplayLogicPackageSystem();
			if( glpSys )
			{
				glpSys.ApplyPackage( scriptInterface.executionOwner, scriptInterface.executionOwner, glpID );
			}
		}
	}

	public export virtual function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var glpSys : GameplayLogicPackageSystem;
		var glpID : TweakDBID;
		if( GetGLP( glpID ) )
		{
			glpSys = scriptInterface.GetGameplayLogicPackageSystem();
			if( glpSys )
			{
				glpSys.RemovePackage( scriptInterface.executionOwner, glpID );
			}
		}
	}

	private final function GetGLP( out glpID : TweakDBID ) : Bool
	{
		glpID = TDBID.Create( GetStaticStringParameterDefault( "gameplayLogicPackageID", "" ) );
		return TDBID.IsValid( glpID );
	}

	protected const final function HasSecondHeart( scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.GetStatsSystem().GetStatValue( scriptInterface.ownerEntityID, gamedataStatType.HasSecondHeart ) > 0.0;
	}

}

class ExplorationDecisions extends HighLevelTransition
{

	protected constexpr const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return true;
	}

}

class ExplorationEvents extends HighLevelTransition
{

	public function OnEnterFromSwimming( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		StopStatPoolDecayAndRegenerate( scriptInterface, gamedataStatPoolType.Oxygen );
		DisableCameraBobbing( stateContext, scriptInterface, false );
		OnEnter( stateContext, scriptInterface );
	}

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var animFeature : AnimFeature_SceneSystem;
		PlayerPuppet.ReevaluateAllBreathingEffects( ( ( PlayerPuppet )( scriptInterface.owner ) ) );
		BlockMovement( scriptInterface, false );
		ResetForceFlags( stateContext );
		ResetForceWalkSpeed( stateContext );
		RemoveAllTierLocomotions( scriptInterface );
		ForceDefaultLocomotion( stateContext, scriptInterface );
		GameObject.PlaySoundEvent( scriptInterface.owner, 'ST_Health_Status_Hi_Set_State' );
		ClearSceneGameplayOverrides( scriptInterface );
		animFeature = new AnimFeature_SceneSystem;
		animFeature.tier = 0;
		scriptInterface.SetAnimationParameterFeature( 'Scene', animFeature );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.SceneTier1 ) ) );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vitals, ( ( Int32 )( gamePSMVitals.Alive ) ) );
		SetPlayerVitalsAnimFeatureData( stateContext, scriptInterface, 0, 0.0 );
		SetPlayerDeathAnimFeatureData( stateContext, scriptInterface, 0 );
		scriptInterface.GetAudioSystem().Play( 'global_death_exit' );
		super.OnEnter( stateContext, scriptInterface );
	}

	protected function ClearSceneGameplayOverrides( scriptInterface : StateGameScriptInterface )
	{
		var animFeature : AnimFeature_SceneGameplayOverrides;
		animFeature = new AnimFeature_SceneGameplayOverrides;
		scriptInterface.localBlackboard.SetBool( GetAllBlackboardDefs().PlayerStateMachine.SceneAimForced, false );
		scriptInterface.localBlackboard.SetBool( GetAllBlackboardDefs().PlayerStateMachine.SceneSafeForced, false );
		animFeature.aimForced = false;
		animFeature.safeForced = false;
		animFeature.isAimOutTimeOverridden = false;
		animFeature.aimOutTimeOverride = 0.0;
		scriptInterface.SetAnimationParameterFeature( 'SceneGameplayOverrides', animFeature );
	}

	protected export function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface ) {}
}

class SwimmingDecisions extends HighLevelTransition
{

	protected export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return CanPlayerSwim( stateContext, scriptInterface, GetStaticFloatParameterDefault( "depthTreshold", 1.20000005 ) + GetStaticFloatParameterDefault( "tolerance", 0.1 ) );
	}

	protected const function ToExploration( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var findSeabedResult : TraceResult;
		var foundWater : Bool;
		var tooShallow : Bool;
		var validFloorPosition : Bool;
		var depthTreshold : Float;
		var tolerance : Float;
		var maxDepth : Float;
		var waterLevel : Float;
		var playerDistanceFromFloor : Float;
		var playerFeetPosition : Vector4;
		var findWaterDestination : Vector4;
		var findSeabedSource : Vector4;
		var findSeabedDestination : Vector4;
		if( GetBlackboardIntVariable( scriptInterface.executionOwner, GetAllBlackboardDefs().PlayerStateMachine.Swimming ) == ( ( Int32 )( gamePSMSwimming.Climbing ) ) )
		{
			return true;
		}
		maxDepth = 100.0;
		playerFeetPosition = GetPlayerPosition( scriptInterface );
		findWaterDestination = playerFeetPosition;
		findWaterDestination.Z = findWaterDestination.Z + maxDepth;
		foundWater = scriptInterface.GetWaterLevel( playerFeetPosition, findWaterDestination, waterLevel );
		if( foundWater )
		{
			depthTreshold = GetStaticFloatParameterDefault( "depthTreshold", -1.20000005 );
			tolerance = GetStaticFloatParameterDefault( "tolerance", -0.1 );
			findSeabedSource = playerFeetPosition;
			findSeabedSource.Z = waterLevel;
			findSeabedDestination = playerFeetPosition;
			findSeabedDestination.Z = findSeabedDestination.Z + ( depthTreshold + tolerance );
			findSeabedResult = scriptInterface.RaycastWithASingleGroup( findSeabedSource, findSeabedDestination, 'PlayerBlocker' );
			if( TraceResult.IsValid( findSeabedResult ) )
			{
				playerDistanceFromFloor = playerFeetPosition.Z - findSeabedResult.position.Z;
				validFloorPosition = ( playerDistanceFromFloor > 0.0 ) && ( playerDistanceFromFloor < AbsF( tolerance ) );
				tooShallow = validFloorPosition && ( ( findSeabedResult.position.Z - waterLevel ) > ( depthTreshold - tolerance ) );
			}
		}
		return !( foundWater ) || tooShallow;
	}

	protected const function ToDeath( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var gi : GameInstance;
		var player : PlayerPuppet;
		var playerID : StatsObjectID;
		var isDead : Bool;
		player = GetPlayerPuppet( scriptInterface );
		playerID = player.GetEntityID();
		gi = scriptInterface.owner.GetGame();
		isDead = GameInstance.GetStatPoolsSystem( gi ).HasStatPoolValueReachedMin( playerID, gamedataStatPoolType.Health );
		if( isDead )
		{
			return true;
		}
		return false;
	}

}

class SwimmingEvents extends HighLevelTransition
{

	public function OnEnterFromSceneTierII( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		stateContext.SetPermanentBoolParameter( 'enteredWaterFromSceneTierII', true, true );
		OnEnter( stateContext, scriptInterface );
	}

	public function OnEnterFromSceneTierIV( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var animFeature : AnimFeature_SceneSystem;
		var playerPuppet : PlayerPuppet;
		stateContext.SetPermanentBoolParameter( 'enteredWaterFromSceneTierIV', true, true );
		PlayerPuppet.ReevaluateAllBreathingEffects( ( ( PlayerPuppet )( scriptInterface.owner ) ) );
		BlockMovement( scriptInterface, false );
		ResetForceFlags( stateContext );
		ResetForceWalkSpeed( stateContext );
		RemoveAllTierLocomotions( scriptInterface );
		GameObject.PlaySoundEvent( scriptInterface.owner, 'ST_Health_Status_Hi_Set_State' );
		ClearSceneGameplayOverrides( scriptInterface );
		animFeature = new AnimFeature_SceneSystem;
		animFeature.tier = 0;
		scriptInterface.SetAnimationParameterFeature( 'Scene', animFeature );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.SceneTier1 ) ) );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vitals, ( ( Int32 )( gamePSMVitals.Alive ) ) );
		SetPlayerVitalsAnimFeatureData( stateContext, scriptInterface, 0, 0.0 );
		SetPlayerDeathAnimFeatureData( stateContext, scriptInterface, 0 );
		scriptInterface.GetAudioSystem().Play( 'global_death_exit' );
		playerPuppet = ( ( PlayerPuppet )( ( ( PlayerPuppet )( scriptInterface.owner ) ) ) );
		if( playerPuppet )
		{
			playerPuppet.GetFPPCameraComponent().SceneDisableBlendingToStaticPosition();
		}
		OnEnter( stateContext, scriptInterface );
	}

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var swapEvent : PSMAddOnDemandStateMachine;
		swapEvent = new PSMAddOnDemandStateMachine;
		swapEvent.stateMachineName = 'LocomotionSwimming';
		swapEvent.tryHotSwap = true;
		scriptInterface.owner.QueueEvent( swapEvent );
		PlaySound( 'lcm_falling_wind_loop_end', scriptInterface );
		DisableCameraBobbing( stateContext, scriptInterface, true );
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.VehicleNoInteraction" );
		super.OnEnter( stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.Swimming ) ) );
		ForceDisableToggleWalk( stateContext );
		scriptInterface.GetSpatialQueriesSystem().GetPlayerObstacleSystem().SetIsSwimming( true, scriptInterface.owner );
	}

	protected function ClearSceneGameplayOverrides( scriptInterface : StateGameScriptInterface )
	{
		var animFeature : AnimFeature_SceneGameplayOverrides;
		animFeature = new AnimFeature_SceneGameplayOverrides;
		scriptInterface.localBlackboard.SetBool( GetAllBlackboardDefs().PlayerStateMachine.SceneAimForced, false );
		scriptInterface.localBlackboard.SetBool( GetAllBlackboardDefs().PlayerStateMachine.SceneSafeForced, false );
		animFeature.aimForced = false;
		animFeature.safeForced = false;
		animFeature.isAimOutTimeOverridden = false;
		animFeature.aimOutTimeOverride = 0.0;
		scriptInterface.SetAnimationParameterFeature( 'SceneGameplayOverrides', animFeature );
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( stateContext.GetBoolParameter( 'enteredWaterFromSceneTierII', true ) )
		{
			stateContext.RemovePermanentBoolParameter( 'enteredWaterFromSceneTierII' );
			stateContext.SetTemporaryBoolParameter( 'requestReEnteringScene', true, true );
		}
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.VehicleNoInteraction" );
		scriptInterface.GetSpatialQueriesSystem().GetPlayerObstacleSystem().SetIsSwimming( false, scriptInterface.owner );
		super.OnExit( stateContext, scriptInterface );
	}

}

class AiControlledDecisions extends HighLevelTransition
{

	public export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var isPlayerControlled : StateResultBool;
		var aiComponent : AIComponent;
		var playerPuppet : PlayerPuppet;
		playerPuppet = GetPlayerPuppet( scriptInterface );
		aiComponent = playerPuppet.GetAIControllerComponent();
		if( aiComponent == NULL )
		{
			return false;
		}
		isPlayerControlled = stateContext.GetTemporaryBoolParameter( 'playerControlled' );
		return isPlayerControlled.valid && !( isPlayerControlled.value );
	}

	public const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var isPlayerControlled : StateResultBool;
		isPlayerControlled = stateContext.GetTemporaryBoolParameter( 'playerControlled' );
		return isPlayerControlled.valid && isPlayerControlled.value;
	}

}

class AiControlledEvents extends HighLevelTransition
{

	public override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		ForceIdle( stateContext );
		super.OnEnter( stateContext, scriptInterface );
		ForceDisableToggleWalk( stateContext );
	}

}

class DeathEvents extends HighLevelTransition
{
	protected var isDyingEffectPlaying : Bool;

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( GetBlackboardIntVariable( scriptInterface.executionOwner, GetAllBlackboardDefs().PlayerStateMachine.Vitals ) != ( ( Int32 )( gamePSMVitals.Dead ) ) )
		{
			StartDeathEffects( stateContext, scriptInterface );
		}
		if( ( !( IsDeathMenuBlocked( scriptInterface ) ) && !( StatusEffectSystem.ObjectHasStatusEffect( ( ( PlayerPuppet )( scriptInterface.executionOwner ) ), T"BaseStatusEffect.CerberusGrabAttackEffect01" ) ) ) && !( StatusEffectSystem.ObjectHasStatusEffect( ( ( PlayerPuppet )( scriptInterface.executionOwner ) ), T"BaseStatusEffect.CerberusGrabAttackEffectBack" ) ) )
		{
			StartEffect( scriptInterface, 'dying' );
			isDyingEffectPlaying = true;
		}
		super.OnEnter( stateContext, scriptInterface );
		ForceDisableToggleWalk( stateContext );
	}

	protected export override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( isDyingEffectPlaying )
		{
			StopEffect( scriptInterface, 'dying' );
			isDyingEffectPlaying = false;
		}
		super.OnExit( stateContext, scriptInterface );
	}

}

class DeathDecisions extends HighLevelTransition
{

	protected export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var player : PlayerPuppet;
		player = ( ( PlayerPuppet )( scriptInterface.executionOwner ) );
		if( player.GetPuppetPS().GetIsDead() )
		{
			return true;
		}
		if( scriptInterface.GetStatPoolsSystem().HasStatPoolValueReachedMin( scriptInterface.ownerEntityID, gamedataStatPoolType.Health ) )
		{
			return true;
		}
		if( HasSecondHeart( scriptInterface ) && scriptInterface.GetStatPoolsSystem().IsStatPoolAdded( scriptInterface.ownerEntityID, gamedataStatPoolType.Health ) )
		{
			if( GameInstance.GetGodModeSystem( scriptInterface.GetGame() ).HasGodMode( scriptInterface.ownerEntityID, gameGodModeType.Invulnerable ) )
			{
				return false;
			}
			return scriptInterface.GetStatPoolsSystem().GetStatPoolValue( scriptInterface.ownerEntityID, gamedataStatPoolType.Health, true ) <= 1.10000002;
		}
		return false;
	}

}

class DeathDecisionsWithResurrection extends HighLevelTransition
{

	protected export const function ToResurrect( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( IsResurrectionAllowed( stateContext, scriptInterface ) )
		{
			if( GetInStateTime() >= GetStaticFloatParameterDefault( "stateDuration", 3.0 ) )
			{
				return true;
			}
		}
		return false;
	}

}

class GroundDeathDecisions extends DeathDecisionsWithResurrection
{

	protected export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetDeathType( stateContext, scriptInterface ) == EDeathType.Ground;
	}

}

class GroundDeathEvents extends DeathEvents
{

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		BlockMovement( scriptInterface, true );
		SetDeathCameraParameters( stateContext, scriptInterface );
		super.OnEnter( stateContext, scriptInterface );
	}

}

class AirDeathDecisions extends DeathDecisionsWithResurrection
{

	protected const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetDeathType( stateContext, scriptInterface ) == EDeathType.Air;
	}

	protected const function ToSwimmingDeath( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return CanPlayerSwim( stateContext, scriptInterface, GetStaticFloatParameterDefault( "depthTreshold", 1.20000005 ) + GetStaticFloatParameterDefault( "tolerance", 0.1 ) );
	}

}

class AirDeathEvents extends DeathEvents
{
}

class SwimmingDeathDecisions extends DeathDecisionsWithResurrection
{

	protected const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetDeathType( stateContext, scriptInterface ) == EDeathType.Swimming;
	}

}

class SwimmingDeathEvents extends DeathEvents
{

	protected function SetSwimming( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var swapEvent : PSMAddOnDemandStateMachine;
		swapEvent = new PSMAddOnDemandStateMachine;
		swapEvent.stateMachineName = 'LocomotionSwimming';
		swapEvent.tryHotSwap = true;
		scriptInterface.owner.QueueEvent( swapEvent );
	}

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		EvaluateSettingCustomDeathAnimation( stateContext, scriptInterface );
		ForceFreeze( stateContext );
		if( !( stateContext.IsStateMachineActive( 'LocomotionSwimming' ) ) )
		{
			SetSwimming( stateContext, scriptInterface );
		}
		super.OnEnter( stateContext, scriptInterface );
	}

}

class ResurrectDecisions extends HighLevelTransition
{

	protected const function ToExploration( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( StatusEffectHelper.GetStatusEffectByID( scriptInterface.owner, T"BaseStatusEffect.SecondHeart" ).GetRemainingDuration() <= 0.0 )
		{
			return true;
		}
		return false;
	}

	protected const function ToDeath( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var state : gamePSMLandingState;
		state = ( ( gamePSMLandingState )( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Landing ) ) );
		return state == gamePSMLandingState.DeathLand || state == gamePSMLandingState.VeryHardLand;
	}

}

class ResurrectEvents extends HighLevelTransition
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.owner, T"BaseStatusEffect.SecondHeart" );
		ForceFreeze( stateContext );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.SceneTier1 ) ) );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Vitals, ( ( Int32 )( gamePSMVitals.Resurrecting ) ) );
		SetPlayerVitalsAnimFeatureData( stateContext, scriptInterface, 2, 2.0 );
		scriptInterface.PushAnimationEvent( 'PlayerResurrect' );
		super.OnEnter( stateContext, scriptInterface );
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var playerPuppet : PlayerPuppet;
		SendResurrectEvent( scriptInterface );
		ForceTemporaryUnequip( stateContext, false );
		scriptInterface.PushAnimationEvent( 'PlayerResurrected' );
		playerPuppet = ( ( PlayerPuppet )( scriptInterface.executionOwner ) );
		if( playerPuppet.IsControlledByLocalPeer() )
		{
			GameInstance.GetDebugVisualizerSystem( scriptInterface.GetGame() ).ClearAll();
		}
		if( GetDeathType( stateContext, scriptInterface ) == EDeathType.Swimming )
		{
			StopStatPoolDecayAndRegenerate( scriptInterface, gamedataStatPoolType.Oxygen );
		}
		super.OnExit( stateContext, scriptInterface );
	}

	private function SendResurrectEvent( scriptInterface : StateGameScriptInterface )
	{
		var player : PlayerPuppet;
		var resurrectEvent : ResurrectEvent;
		player = ( ( PlayerPuppet )( scriptInterface.executionOwner ) );
		resurrectEvent = new ResurrectEvent;
		player.QueueEvent( resurrectEvent );
	}

}

class InspectionDecisions extends HighLevelTransition
{

	protected export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var inspectionComponent : InspectionComponent;
		inspectionComponent = ( ( PlayerPuppet )( scriptInterface.owner ) ).GetInspectionComponent();
		if( inspectionComponent )
		{
			return inspectionComponent.GetIsPlayerInspecting();
		}
		return false;
	}

	protected const function ToExploration( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( scriptInterface.IsActionJustPressed( 'InspectionClose' ) )
		{
			return true;
		}
		return !( ( ( PlayerPuppet )( scriptInterface.owner ) ).GetInspectionComponent().GetIsPlayerInspecting() );
	}

}

class InspectionEvents extends HighLevelTransition
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		ForceEmptyHands( stateContext, true );
		ForceIdle( stateContext );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.SceneTier1 ) ) );
		super.OnEnter( stateContext, scriptInterface );
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var evt : InspectionEvent;
		evt = new InspectionEvent;
		evt.enabled = false;
		( ( PlayerPuppet )( scriptInterface.owner ) ).QueueEvent( evt );
		super.OnExit( stateContext, scriptInterface );
	}

}

class MinigameDecisions extends HighLevelTransition
{

	protected export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return IsInMinigame( scriptInterface ) && IsInLocomotionState( stateContext, 'workspot' );
	}

	protected const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return !( IsInMinigame( scriptInterface ) );
	}

}

class MinigameEvents extends HighLevelTransition
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		ForceEmptyHands( stateContext, true );
		ForceFreeze( stateContext );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.Default ) ) );
		super.OnEnter( stateContext, scriptInterface );
	}

}

class SceneTierInitialDecisions extends SceneTierAbstract
{

	protected export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( ( ( ( Int32 )( GetCurrentSceneTier( stateContext ) ) ) > ( ( Int32 )( GameplayTier.Tier1_FullGameplay ) ) ) || stateContext.GetBoolParameter( 'requestReEnteringScene', true ) )
		{
			if( stateContext.GetBoolParameter( 'enteredWaterFromSceneTierII', true ) || stateContext.IsStateMachineActive( 'LocomotionTakedown' ) )
			{
				return false;
			}
			return true;
		}
		return false;
	}

}

class SceneTierInitialEvents extends SceneTierAbstract
{
}

abstract class SceneTierAbstract extends HighLevelTransition
{

	protected const function GetCurrentSceneTier( const stateContext : StateContext ) : GameplayTier
	{
		const var sceneTier : SceneTierData;
		var requestedSceneTier : GameplayTier;
		requestedSceneTier = GameplayTier.Undefined;
		sceneTier = GetCurrentSceneTierData( stateContext );
		if( sceneTier )
		{
			requestedSceneTier = sceneTier.tier;
		}
		return ( ( GameplayTier )( requestedSceneTier ) );
	}

	protected const virtual function SceneTierToEnter() : GameplayTier
	{
		return GameplayTier.Undefined;
	}

}

abstract class SceneTierAbstractDecisions extends SceneTierAbstract
{

	protected export const function ToExploration( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( GetCurrentSceneTier( stateContext ) == GameplayTier.Tier1_FullGameplay )
		{
			return true;
		}
		return false;
	}

}

abstract class SceneTierAbstractEvents extends SceneTierAbstract
{

	public override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var animFeature : AnimFeature_SceneSystem;
		const var sceneTier : SceneTierData;
		animFeature = new AnimFeature_SceneSystem;
		animFeature.tier = ( ( Int32 )( SceneTierToEnter() ) );
		scriptInterface.SetAnimationParameterFeature( 'Scene', animFeature );
		ResetForceFlags( stateContext );
		sceneTier = GetCurrentSceneTierData( stateContext );
		if( sceneTier )
		{
			if( IsClient() )
			{
				stateContext.SetPermanentBoolParameter( 'EmptyHandsForcedByTierChange', sceneTier.emptyHands, true );
			}
			ForceEmptyHands( stateContext, sceneTier.emptyHands );
		}
		ForceDisableToggleWalk( stateContext );
		ForceDefaultLocomotion( stateContext, scriptInterface );
		UpdateCameraParams( stateContext, scriptInterface );
		super.OnEnter( stateContext, scriptInterface );
	}

	protected export virtual function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		const var sceneTier : SceneTierData;
		var currentHighLevelState : Int32;
		var desiredHighLevelState : Int32;
		SetAudioParameter( 'g_player_health', GetCurrentHealthPerc( scriptInterface ), scriptInterface );
		sceneTier = GetCurrentSceneTierData( stateContext );
		if( sceneTier )
		{
			if( sceneTier.emptyHands != IsForceEmptyHands( stateContext ) )
			{
				if( IsClient() )
				{
					stateContext.SetPermanentBoolParameter( 'EmptyHandsForcedByTierChange', sceneTier.emptyHands, true );
				}
				ForceEmptyHands( stateContext, sceneTier.emptyHands );
			}
			currentHighLevelState = scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.HighLevel );
			desiredHighLevelState = ( ( Int32 )( SceneTierToEnter() ) );
			if( currentHighLevelState != desiredHighLevelState )
			{
				SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, desiredHighLevelState );
			}
		}
	}

}

class SceneTierIIDecisions extends SceneTierAbstractDecisions
{

	protected const override function SceneTierToEnter() : GameplayTier
	{
		return GameplayTier.Tier2_StagedGameplay;
	}

	protected export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetCurrentSceneTier( stateContext ) == GameplayTier.Tier2_StagedGameplay;
	}

}

class SceneTierIIEvents extends SceneTierAbstractEvents
{
	var m_cachedSpeedValue : Float;
	var m_maxSpeedStat : gameStatModifierData;
	var m_currentSpeedMovementPreset : Tier2WalkType;
	var m_currentSpeedValue : Float;
	var m_currentLocomotionState : CName;

	protected const override function SceneTierToEnter() : GameplayTier
	{
		return GameplayTier.Tier2_StagedGameplay;
	}

	protected const function GetSceneTier2Data( const stateContext : StateContext ) : SceneTier2Data
	{
		var tier2Data : SceneTier2Data;
		tier2Data = ( ( SceneTier2Data )( GetCurrentSceneTierData( stateContext ) ) );
		return tier2Data;
	}

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var statSystem : StatsSystem;
		var ownerID : StatsObjectID;
		ownerID = scriptInterface.executionOwnerEntityID;
		super.OnEnter( stateContext, scriptInterface );
		SetTier2Locomotion( scriptInterface );
		ForceSafeState( stateContext );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.SceneTier2 ) ) );
		m_cachedSpeedValue = UpdateSpeedValue( stateContext, scriptInterface );
		m_maxSpeedStat = RPGManager.CreateStatModifier( gamedataStatType.MaxSpeed, gameStatModifierType.Additive, m_cachedSpeedValue );
		statSystem = scriptInterface.GetStatsSystem();
		statSystem.AddModifier( ownerID, m_maxSpeedStat );
	}

	protected export override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var ownerID : StatsObjectID;
		ownerID = scriptInterface.executionOwnerEntityID;
		super.OnExit( stateContext, scriptInterface );
		scriptInterface.GetStatsSystem().RemoveModifier( ownerID, m_maxSpeedStat );
		RemoveAllTierLocomotions( scriptInterface );
	}

	protected export override function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnUpdate( timeDelta, stateContext, scriptInterface );
		UpdateLocomotionStatsBasedOnMovementType( stateContext, scriptInterface );
		if( scriptInterface.IsActionJustPressed( 'MeleeAttack' ) )
		{
			QueueActionBlocked( scriptInterface );
		}
	}

	protected function UpdateLocomotionStatsBasedOnMovementType( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var statSystem : StatsSystem;
		var ownerID : StatsObjectID;
		var speedValue : Float;
		statSystem = scriptInterface.GetStatsSystem();
		ownerID = scriptInterface.executionOwnerEntityID;
		speedValue = UpdateSpeedValue( stateContext, scriptInterface );
		if( speedValue != m_cachedSpeedValue )
		{
			m_cachedSpeedValue = speedValue;
			scriptInterface.GetStatsSystem().RemoveModifier( ownerID, m_maxSpeedStat );
			m_maxSpeedStat = RPGManager.CreateStatModifier( gamedataStatType.MaxSpeed, gameStatModifierType.Additive, m_cachedSpeedValue );
			statSystem.AddModifier( ownerID, m_maxSpeedStat );
		}
	}

	protected function UpdateSpeedValue( stateContext : StateContext, scriptInterface : StateGameScriptInterface ) : Float
	{
		var speedValue : Float;
		var currentMovementPreset : Tier2WalkType;
		var currentLocomotionState : CName;
		currentMovementPreset = GetCurrentTier2MovementPreset( stateContext );
		currentLocomotionState = stateContext.GetStateMachineCurrentState( 'Locomotion' );
		if( currentMovementPreset == m_currentSpeedMovementPreset && currentLocomotionState == m_currentLocomotionState )
		{
			return m_currentSpeedValue;
		}
		switch( currentMovementPreset )
		{
			case Tier2WalkType.Slow:
				RemoveTier2Locomotion( scriptInterface );
			RemoveTier2LocomotionFast( scriptInterface );
			SetTier2LocomotionSlow( scriptInterface );
			UpdateMaxSpeedBasedOnPlayerState( currentLocomotionState, currentMovementPreset, speedValue );
			break;
			case Tier2WalkType.Normal:
				RemoveTier2LocomotionSlow( scriptInterface );
			RemoveTier2LocomotionFast( scriptInterface );
			SetTier2Locomotion( scriptInterface );
			UpdateMaxSpeedBasedOnPlayerState( currentLocomotionState, currentMovementPreset, speedValue );
			break;
			case Tier2WalkType.Fast:
				RemoveTier2LocomotionSlow( scriptInterface );
			RemoveTier2Locomotion( scriptInterface );
			SetTier2LocomotionFast( scriptInterface );
			UpdateMaxSpeedBasedOnPlayerState( currentLocomotionState, currentMovementPreset, speedValue );
			break;
			default:
				RemoveAllTierLocomotions( scriptInterface );
			SetTier2Locomotion( scriptInterface );
			speedValue = 0.0;
			break;
		}
		m_currentSpeedValue = speedValue;
		m_currentSpeedMovementPreset = currentMovementPreset;
		m_currentLocomotionState = currentLocomotionState;
		return speedValue;
	}

	protected function UpdateMaxSpeedBasedOnPlayerState( locomotionStateName : CName, movementPreset : Tier2WalkType, out speedValue : Float )
	{
		switch( movementPreset )
		{
			case Tier2WalkType.Slow:
				if( locomotionStateName == 'stand' )
				{
					speedValue = GetStaticFloatParameterDefault( "slowWalkSpeed", -1.29999995 );
				}
				else if( locomotionStateName == 'sprint' )
				{
					speedValue = GetStaticFloatParameterDefault( "slowJogSpeed", -2.5 );
				}
				else if( locomotionStateName == 'crouch' )
				{
					speedValue = GetStaticFloatParameterDefault( "slowCrouchSpeed", 0.0 );
				}
			break;
			case Tier2WalkType.Normal:
				if( locomotionStateName == 'stand' )
				{
					speedValue = GetStaticFloatParameterDefault( "normalWalkSpeed", 0.0 );
				}
				else if( locomotionStateName == 'sprint' )
				{
					speedValue = GetStaticFloatParameterDefault( "normalJogSpeed", 0.0 );
				}
				else if( locomotionStateName == 'crouch' )
				{
					speedValue = GetStaticFloatParameterDefault( "normalCrouchSpeed", 0.0 );
				}
			break;
			case Tier2WalkType.Fast:
				if( locomotionStateName == 'stand' )
				{
					speedValue = GetStaticFloatParameterDefault( "fastWalkSpeed", 0.0 );
				}
				else if( locomotionStateName == 'sprint' )
				{
					speedValue = GetStaticFloatParameterDefault( "fastJogSpeed", 0.0 );
				}
				else if( locomotionStateName == 'crouch' )
				{
					speedValue = GetStaticFloatParameterDefault( "fastCrouchSpeed", 0.0 );
				}
			break;
			default:
				speedValue = 0.0;
			break;
		}
	}

	protected const function GetCurrentTier2MovementPreset( stateContext : StateContext ) : Tier2WalkType
	{
		const var sceneTier2Data : SceneTier2Data;
		sceneTier2Data = GetSceneTier2Data( stateContext );
		return sceneTier2Data.walkType;
	}

	private function QueueActionBlocked( scriptInterface : StateGameScriptInterface )
	{
		var notificationEvent : UIInGameNotificationEvent;
		notificationEvent = new UIInGameNotificationEvent;
		notificationEvent.m_notificationType = UIInGameNotificationType.ActionRestriction;
		scriptInterface.GetUISystem().QueueEvent( notificationEvent );
	}

}

class SceneTierIIIDecisions extends SceneTierAbstractDecisions
{

	protected const override function SceneTierToEnter() : GameplayTier
	{
		return GameplayTier.Tier3_LimitedGameplay;
	}

	protected export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetCurrentSceneTier( stateContext ) == GameplayTier.Tier3_LimitedGameplay;
	}

}

class SceneTierIIIEvents extends SceneTierAbstractEvents
{

	protected const override function SceneTierToEnter() : GameplayTier
	{
		return GameplayTier.Tier3_LimitedGameplay;
	}

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnEnter( stateContext, scriptInterface );
		ActivateTier3Locomotion( stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.SceneTier3 ) ) );
	}

	protected export override function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnUpdate( timeDelta, stateContext, scriptInterface );
	}

}

class SceneTierIVDecisions extends SceneTierAbstractDecisions
{

	protected const override function SceneTierToEnter() : GameplayTier
	{
		return GameplayTier.Tier4_FPPCinematic;
	}

	protected export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetCurrentSceneTier( stateContext ) == GameplayTier.Tier4_FPPCinematic;
	}

	protected export const function ToSwimming( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( GetCurrentSceneTier( stateContext ) == GameplayTier.Tier1_FullGameplay )
		{
			return CanPlayerSwim( stateContext, scriptInterface, GetStaticFloatParameterDefault( "depthTreshold", 1.20000005 ) + GetStaticFloatParameterDefault( "tolerance", 0.1 ) );
		}
		return false;
	}

}

class SceneTierIVEvents extends SceneTierAbstractEvents
{

	protected const override function SceneTierToEnter() : GameplayTier
	{
		return GameplayTier.Tier4_FPPCinematic;
	}

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnEnter( stateContext, scriptInterface );
		ActivateTier4Locomotion( stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.SceneTier4 ) ) );
	}

}

class SceneTierVDecisions extends SceneTierAbstractDecisions
{

	protected const override function SceneTierToEnter() : GameplayTier
	{
		return GameplayTier.Tier5_Cinematic;
	}

	protected export const function EnterCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetCurrentSceneTier( stateContext ) == GameplayTier.Tier5_Cinematic;
	}

}

class SceneTierVEvents extends SceneTierAbstractEvents
{

	protected const override function SceneTierToEnter() : GameplayTier
	{
		return GameplayTier.Tier5_Cinematic;
	}

	protected export override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnEnter( stateContext, scriptInterface );
		if( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.BreathingLow" ) )
		{
			RemoveAllBreathingEffects( scriptInterface );
		}
		ActivateTier5Locomotion( stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.HighLevel, ( ( Int32 )( gamePSMHighLevel.SceneTier5 ) ) );
	}

}

