enum ECarryState
{
	None = 0,
	Pickup = 1,
	Carry = 2,
	Drop = 3,
	Release = 4,
	Dispose = 5,
	Jump = 6,
	Aim = 7,
	Throw = 8,
}

abstract class CarriedObjectTransition extends DefaultTransition
{

	protected function CanEquipFirearm( owner : GameObject, stateContext : StateContext, scriptInterface : StateGameScriptInterface ) : Bool
	{
		var equipmentSystem : EquipmentSystem;
		var weaponID : ItemID;
		var playerData : EquipmentSystemPlayerData;
		var itemType : gamedataItemType;
		itemType = gamedataItemType.Invalid;
		equipmentSystem = ( ( EquipmentSystem )( GameInstance.GetScriptableSystemsContainer( owner.GetGame() ).Get( 'EquipmentSystem' ) ) );
		if( !( equipmentSystem ) )
		{
			return false;
		}
		if( IsInEmptyHandsState( stateContext ) )
		{
			return false;
		}
		playerData = equipmentSystem.GetPlayerData( owner );
		weaponID = playerData.GetLastUsedOrFirstAvailableOneHandedRangedWeapon();
		if( ItemID.IsValid( weaponID ) )
		{
			itemType = RPGManager.GetItemType( weaponID );
			if( itemType == gamedataItemType.Wea_Handgun || itemType == gamedataItemType.Wea_Revolver )
			{
				return true;
			}
		}
		return false;
	}

	protected function IsPlayerCombatAllowed( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'NoCombat' ) )
		{
			return false;
		}
		if( IsInTier2Locomotion( scriptInterface ) )
		{
			return false;
		}
		return true;
	}

	protected function SetFastModeParameter( stateContext : StateContext, fastMode : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'carriedObjectFastMode', fastMode, true );
	}

	protected const function GetFastModeParameter( stateContext : StateContext ) : Bool
	{
		var fastModeResult : StateResultBool;
		fastModeResult = stateContext.GetPermanentBoolParameter( 'carriedObjectFastMode' );
		if( fastModeResult.valid )
		{
			return fastModeResult.value;
		}
		return false;
	}

	protected function SetIsFriendlyCarryParameter( stateContext : StateContext, isFriendlyCarry : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'carriedObjectIsFriendlyCarry', isFriendlyCarry, true );
	}

	protected const function GetIsFriendlyCarryParameter( stateContext : StateContext ) : Bool
	{
		var isFriendlyCarryResult : StateResultBool;
		isFriendlyCarryResult = stateContext.GetPermanentBoolParameter( 'carriedObjectIsFriendlyCarry' );
		if( isFriendlyCarryResult.valid )
		{
			return isFriendlyCarryResult.value;
		}
		return false;
	}

	public static function HasRightHandWeaponActiveInSlot( owner : GameObject ) : Bool
	{
		var weaponItem : ItemID;
		if( owner )
		{
			weaponItem = GameInstance.GetTransactionSystem( owner.GetGame() ).GetActiveItemInSlot( owner, T"AttachmentSlots.WeaponRight" );
			if( ItemID.IsValid( weaponItem ) )
			{
				return true;
			}
		}
		return false;
	}

}

abstract class CarriedObjectDecisions extends CarriedObjectTransition
{

	public const function ToRelease( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return !( scriptInterface.owner.IsAttached() );
	}

	public const function ToForceDropBody( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var shouldDropBody : StateResultBool;
		var player : PlayerPuppet;
		shouldDropBody = stateContext.GetTemporaryBoolParameter( 'bodyCarryInteractionForceDrop' );
		if( shouldDropBody.valid )
		{
			return shouldDropBody.value;
		}
		player = GetPlayerPuppet( scriptInterface );
		if( player.IsDead() )
		{
			return true;
		}
		if( ( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Vitals ) == ( ( Int32 )( gamePSMVitals.Dead ) ) ) || ( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Vitals ) == ( ( Int32 )( gamePSMVitals.Resurrecting ) ) ) )
		{
			return true;
		}
		if( scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Fall ) == ( ( Int32 )( gamePSMFallStates.FastFall ) ) )
		{
			return true;
		}
		if( ( StatusEffectSystem.ObjectHasStatusEffectOfType( scriptInterface.executionOwner, gamedataStatusEffectType.Knockdown ) || StatusEffectSystem.ObjectHasStatusEffectOfType( scriptInterface.executionOwner, gamedataStatusEffectType.VehicleKnockdown ) ) && !( StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'BodyCarryingNoDrop' ) ) )
		{
			return true;
		}
		if( ( !( scriptInterface.HasStatFlag( gamedataStatType.CanShootWhileCarryingBody ) ) && !( IsInUpperBodyState( stateContext, 'forceEmptyHands' ) ) ) && ( scriptInterface.GetActionValue( 'RangedAttack' ) > 0.0 ) )
		{
			return IsPlayerAllowedToDropBody( stateContext, scriptInterface );
		}
		if( IsInHighLevelState( stateContext, 'swimming' ) )
		{
			return true;
		}
		if( IsForceBodyDropRequested( stateContext, scriptInterface ) )
		{
			return true;
		}
		return false;
	}

	protected const function IsPlayerAllowedToDropBody( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'BodyCarryingNoDrop' ) && !( IsBodyDropForced( stateContext, scriptInterface ) ) )
		{
			return false;
		}
		if( IsInInputContextState( stateContext, 'interactionContext' ) || IsInInputContextState( stateContext, 'uiRadialContext' ) )
		{
			return false;
		}
		return true;
	}

	protected const function IsBodyDropForced( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'BodyCarryingForceDrop' ) )
		{
			return true;
		}
		return false;
	}

	private const function IsForceBodyDropRequested( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var isForceDropBody : StateResultBool;
		isForceDropBody = stateContext.GetTemporaryBoolParameter( 'forceDropBody' );
		if( isForceDropBody.valid && isForceDropBody.value )
		{
			return true;
		}
		return false;
	}

}

abstract class CarriedObjectEvents extends CarriedObjectTransition
{
	var m_animFeature : AnimFeature_Mounting;
	var m_animCarryFeature : AnimFeature_Carry;
	var m_leftHandFeature : AnimFeature_LeftHandAnimation;
	var m_AnimWrapperWeightSetterStrong : AnimWrapperWeightSetter;
	var m_AnimWrapperWeightSetterFriendly : AnimWrapperWeightSetter;
	var m_styleName : CName;
	default m_styleName = 'CarriedObject.Style';
	var m_forceStyleName : CName;
	default m_forceStyleName = 'CarriedObject.ForcedStyle';
	var m_isFriendlyCarry : Bool;
	var m_forcedCarryStyle : gamePSMBodyCarryingStyle;

	protected virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var mountEvent : MountingRequest;
		var mountingInfo : MountingInfo;
		var slotId : MountingSlotId;
		var isNPCMounted : Bool;
		mountingInfo = scriptInterface.GetMountingFacility().GetMountingInfoSingleWithObjects( scriptInterface.owner );
		isNPCMounted = EntityID.IsDefined( mountingInfo.childId );
		if( !( isNPCMounted ) && !( IsBodyDisposalOngoing( stateContext, scriptInterface ) ) )
		{
			mountEvent = new MountingRequest;
			slotId.id = 'leftShoulder';
			mountingInfo.childId = scriptInterface.ownerEntityID;
			mountingInfo.parentId = scriptInterface.executionOwnerEntityID;
			mountingInfo.slotId = slotId;
			mountEvent.lowLevelMountingInfo = mountingInfo;
			scriptInterface.GetMountingFacility().Mount( mountEvent );
			( ( NPCPuppet )( scriptInterface.owner ) ).MountingStartDisableComponents();
		}
		m_animFeature = new AnimFeature_Mounting;
		m_animFeature.mountingState = 2;
		UpdateCarryStylePickUpAndDropParams( stateContext, scriptInterface, false );
		m_forcedCarryStyle = gamePSMBodyCarryingStyle.Any;
		CalculateForcedCarryStyleAndIsFriendlyCarry( stateContext, scriptInterface );
		if( ( ( gamePuppet )( scriptInterface.owner ) ) )
		{
			UpdateCarryStylePickUpAndDropParams( stateContext, scriptInterface, m_isFriendlyCarry );
		}
		scriptInterface.SetAnimationParameterFeature( 'Mounting', m_animFeature, scriptInterface.executionOwner );
		scriptInterface.SetAnimationParameterFeature( 'Mounting', m_animFeature );
		( ( NPCPuppet )( scriptInterface.owner ) ).MountingStartDisableComponents();
	}

	protected virtual function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface ) {}

	protected virtual function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		CleanUpCarryStateMachine( ECarryState.None, stateContext, scriptInterface );
	}

	protected function IsBodyDisposalOngoing( stateContext : StateContext, scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.localBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.CarryingDisposal );
	}

	protected function UpdateCarryStylePickUpAndDropParams( stateContext : StateContext, scriptInterface : StateGameScriptInterface, isFriendly : Bool )
	{
		if( GetStyle( stateContext ) == gamePSMBodyCarryingStyle.WoundedSoldier )
		{
			ApplyWoundedSoldierCarryGameplayRestrictions( stateContext, scriptInterface );
		}
		else if( isFriendly )
		{
			UpdateGameplayRestrictions( stateContext, scriptInterface );
			stateContext.SetConditionBoolParameter( 'CarriedObjectPlayPickUp', false, true );
			SetBodyCarryFriendlyCameraContext( stateContext, scriptInterface, true );
			ApplyFriendlyCarryGameplayRestrictions( stateContext, scriptInterface );
		}
		else
		{
			UpdateGameplayRestrictions( stateContext, scriptInterface );
			stateContext.SetConditionBoolParameter( 'CarriedObjectPlayPickUp', true, true );
		}
	}

	protected function SetAnimFeature_Carry( state : ECarryState, instant : Bool, stateContext : StateContext, scriptInterface : StateGameScriptInterface, optional setExecutionOwnerOnly : Bool )
	{
		var lockLeftHand : Bool;
		var isMultiplayer : Bool;
		m_animCarryFeature = new AnimFeature_Carry;
		m_animCarryFeature.state = ( ( Int32 )( state ) );
		m_animCarryFeature.pickupAnimation = GetPickupAnimationParameter( stateContext );
		m_animCarryFeature.fastMode = GetFastModeParameter( stateContext );
		m_animCarryFeature.useBothHands = false;
		m_animCarryFeature.instant = instant;
		m_animCarryFeature.isCarryActive = true;
		m_animCarryFeature.isFriendlyCarry = m_isFriendlyCarry;
		m_animCarryFeature.wasThrown = GetWasThrownParameter( stateContext );
		if( GetStyle( stateContext ) == gamePSMBodyCarryingStyle.WoundedSoldier )
		{
			m_animCarryFeature.useBothHands = false;
		}
		else if( state != ECarryState.None && state != ECarryState.Release )
		{
			if( GetStyle( stateContext ) == gamePSMBodyCarryingStyle.Strong && state == ECarryState.Carry )
			{
				isMultiplayer = GameInstance.GetRuntimeInfo( scriptInterface.executionOwner.GetGame() ).IsMultiplayer();
				if( isMultiplayer )
				{
					m_animCarryFeature.useBothHands = !( HasRightHandWeaponActiveInSlot( scriptInterface.executionOwner ) );
				}
				else if( !( isMultiplayer ) && scriptInterface.HasStatFlag( gamedataStatType.CanShootWhileCarryingBody ) )
				{
					m_animCarryFeature.useBothHands = !( CanEquipFirearm( scriptInterface.executionOwner, stateContext, scriptInterface ) );
				}
				else
				{
					m_animCarryFeature.useBothHands = true;
				}
			}
			else
			{
				m_animCarryFeature.useBothHands = true;
			}
		}
		scriptInterface.SetAnimationParameterFeature( 'Carry', m_animCarryFeature, scriptInterface.executionOwner );
		if( !( setExecutionOwnerOnly ) )
		{
			scriptInterface.SetAnimationParameterFeature( 'Carry', m_animCarryFeature, scriptInterface.owner );
		}
		lockLeftHand = !( m_animCarryFeature.useBothHands );
		SetAnimFeature_LeftHandAnimation( scriptInterface, lockLeftHand );
	}

	protected function SetBodyPickUpCameraContext( stateContext : StateContext, scriptInterface : StateGameScriptInterface, value : Bool, optional skipCameraContextUpdate : Bool )
	{
		SetCameraContext( stateContext, scriptInterface, 'setBodyPickUpContext', value, skipCameraContextUpdate );
	}

	protected function SetBodyCarryCameraContext( stateContext : StateContext, scriptInterface : StateGameScriptInterface, value : Bool, optional skipCameraContextUpdate : Bool )
	{
		SetCameraContext( stateContext, scriptInterface, 'setBodyCarryContext', value, skipCameraContextUpdate );
	}

	protected function SetBodyCarryFriendlyCameraContext( stateContext : StateContext, scriptInterface : StateGameScriptInterface, value : Bool, optional skipCameraContextUpdate : Bool )
	{
		SetCameraContext( stateContext, scriptInterface, 'setBodyCarryFriendlyContext', value, skipCameraContextUpdate );
	}

	protected function SetBodyCarryWoundedSoldierCameraContext( stateContext : StateContext, scriptInterface : StateGameScriptInterface, value : Bool, optional skipCameraContextUpdate : Bool )
	{
		SetCameraContext( stateContext, scriptInterface, 'setBodyCarryWoundedSoldierContext', value, skipCameraContextUpdate );
		if( !( value ) )
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingWoundedSoldier" );
			GameInstance.GetAudioSystem( scriptInterface.executionOwner.GetGame() ).RemoveTriggerEffect( 'BlackWall_Somi_Ability' );
		}
	}

	protected function SetCameraContext( stateContext : StateContext, scriptInterface : StateGameScriptInterface, varName : CName, value : Bool, skipCameraContextUpdate : Bool )
	{
		var oldValue : Bool;
		if( skipCameraContextUpdate )
		{
			stateContext.SetPermanentBoolParameter( varName, value, true );
		}
		else
		{
			oldValue = stateContext.GetBoolParameter( varName, true );
			stateContext.SetPermanentBoolParameter( varName, value, true );
			if( oldValue != value )
			{
				UpdateCameraParams( stateContext, scriptInterface );
			}
		}
	}

	protected function SetStyle( style : gamePSMBodyCarryingStyle, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		stateContext.SetPermanentIntParameter( m_styleName, ( ( Int32 )( style ) ), true );
		EnableAnimSet( style == gamePSMBodyCarryingStyle.Strong, 'carry_strong', scriptInterface );
		EnableAnimSet( style == gamePSMBodyCarryingStyle.Friendly, 'carry_friendly', scriptInterface );
		EnableAnimSet( style == gamePSMBodyCarryingStyle.WoundedSoldier, 'carry_woundedSoldier', scriptInterface );
	}

	protected function SetForcedStyle( style : gamePSMBodyCarryingStyle, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		stateContext.SetPermanentIntParameter( m_forceStyleName, ( ( Int32 )( style ) ), true );
		SetStyle( style, stateContext, scriptInterface );
	}

	protected function ClearForcedStyle( stateContext : StateContext )
	{
		stateContext.RemovePermanentIntParameter( m_forceStyleName );
	}

	protected function ClearStyleParameters( stateContext : StateContext )
	{
		stateContext.RemovePermanentIntParameter( m_forceStyleName );
		stateContext.RemovePermanentIntParameter( m_styleName );
	}

	protected function SetAnimFeature_LeftHandAnimation( scriptInterface : StateGameScriptInterface, lockLeftHand : Bool )
	{
		m_leftHandFeature = new AnimFeature_LeftHandAnimation;
		m_leftHandFeature.lockLeftHandAnimation = lockLeftHand;
		scriptInterface.SetAnimationParameterFeature( 'LeftHandAnimation', m_leftHandFeature, scriptInterface.executionOwner );
	}

	protected const function GetStyle( const stateContext : StateContext ) : gamePSMBodyCarryingStyle
	{
		return ( ( gamePSMBodyCarryingStyle )( stateContext.GetIntParameter( m_styleName, true ) ) );
	}

	private function EnableAnimSet( enable : Bool, animSet : CName, scriptInterface : StateGameScriptInterface )
	{
		var ev : AnimWrapperWeightSetter;
		ev = new AnimWrapperWeightSetter;
		ev.key = animSet;
		ev.value = ( ( enable ) ? ( 1.0 ) : ( 0.0 ) );
		scriptInterface.owner.QueueEvent( ev );
		scriptInterface.executionOwner.QueueEvent( ev );
	}

	protected function SetObjectInvulnerable( object : GameObject, enable : Bool )
	{
		if( enable && !( StatusEffectSystem.ObjectHasStatusEffect( object, T"BaseStatusEffect.Invulnerable" ) ) )
		{
			StatusEffectHelper.ApplyStatusEffect( object, T"BaseStatusEffect.Invulnerable" );
		}
		else
		{
			StatusEffectHelper.RemoveStatusEffect( object, T"BaseStatusEffect.Invulnerable" );
		}
	}

	protected function CleanUpCarryStateMachine( state : ECarryState, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var unmountingRequest : UnmountingRequest;
		var mountingInfo : MountingInfo;
		var broadcaster : StimBroadcasterComponent;
		var setPositionEvent : SetBodyPositionEvent;
		var mountEventData : MountEventData;
		var setAnimFeatureOnExecutionOwnerOnly : Bool;
		var isSceneDropAnimation : StateResultBool;
		var player : GameObject;
		player = scriptInterface.executionOwner;
		isSceneDropAnimation = stateContext.GetTemporaryBoolParameter( 'bodyCarrySceneDropAnimation' );
		unmountingRequest = new UnmountingRequest;
		mountingInfo.childId = scriptInterface.ownerEntityID;
		mountingInfo.parentId = scriptInterface.executionOwnerEntityID;
		unmountingRequest.lowLevelMountingInfo = mountingInfo;
		if( isSceneDropAnimation.valid && isSceneDropAnimation.value )
		{
			mountEventData = new MountEventData;
			mountEventData.removePitchRollRotationOnDismount = false;
			unmountingRequest.mountData = mountEventData;
		}
		scriptInterface.GetMountingFacility().Unmount( unmountingRequest );
		setAnimFeatureOnExecutionOwnerOnly = StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.owner, T"BaseStatusEffect.ThrownNPC" );
		SetAnimFeature_Carry( state, false, stateContext, scriptInterface, setAnimFeatureOnExecutionOwnerOnly );
		GameInstance.GetDelaySystem( player.GetGame() ).DelayEvent( player, new ClearAnimFeatureCarryEvent, 0.30000001, true );
		stateContext.RemovePermanentBoolParameter( 'checkCanShootWhileCarryingBodyStatFlag' );
		stateContext.SetPermanentCNameParameter( 'ETakedownActionType', '', true );
		SetAnimFeature_LeftHandAnimation( scriptInterface, false );
		ResetMountingAnimFeature( stateContext, scriptInterface );
		if( !( StatusEffectSystem.ObjectHasStatusEffectOfType( scriptInterface.executionOwner, gamedataStatusEffectType.VehicleKnockdown ) ) )
		{
			stateContext.SetPermanentBoolParameter( 'forcedTemporaryUnequip', false, true );
		}
		SetBlackboardBoolVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Carrying, false );
		GetPlayer( scriptInterface.owner.GetGame() ).QueueEvent( new DropBodyBreathingEvent );
		( ( NPCPuppet )( scriptInterface.owner ) ).MountingEndEnableComponents();
		( ( NPCPuppet )( scriptInterface.owner ) ).SetDisableRagdoll( false );
		RemoveGameplayRestrictions( stateContext, scriptInterface );
		SetBodyPickUpCameraContext( stateContext, scriptInterface, false, true );
		SetBodyCarryCameraContext( stateContext, scriptInterface, false, true );
		SetBodyCarryFriendlyCameraContext( stateContext, scriptInterface, false, true );
		SetBodyCarryWoundedSoldierCameraContext( stateContext, scriptInterface, false, true );
		UpdateCameraParams( stateContext, scriptInterface );
		SetObjectInvulnerable( scriptInterface.owner, false );
		broadcaster = player.GetStimBroadcasterComponent();
		if( broadcaster )
		{
			broadcaster.RemoveActiveStimuliByName( player, gamedataStimType.CarryBody );
		}
		( ( NPCPuppet )( scriptInterface.owner ) ).GetVisibleObjectComponent().Toggle( true );
		setPositionEvent = new SetBodyPositionEvent;
		setPositionEvent.bodyPosition = scriptInterface.owner.GetWorldPosition();
		scriptInterface.owner.QueueEvent( setPositionEvent );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.BodyCarrying, ( ( Int32 )( gamePSMBodyCarrying.Default ) ) );
		SetBlackboardBoolVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CanThrowCarriedNPC, false );
		ClearStyleParameters( stateContext );
	}

	protected function ResetMountingAnimFeature( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		m_animFeature = new AnimFeature_Mounting;
		m_animFeature.mountingState = 0;
		scriptInterface.SetAnimationParameterFeature( 'Mounting', m_animFeature, scriptInterface.executionOwner );
		scriptInterface.SetAnimationParameterFeature( 'Mounting', m_animFeature );
	}

	protected function ApplyInitGameplayRestrictions( scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoJump" );
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingActionRestriction" );
	}

	protected function EvaluateAutomaticLootPickupFromMountedPuppet( scriptInterface : StateGameScriptInterface )
	{
		if( ( ( NPCPuppet )( scriptInterface.owner ) ).HasQuestItems() && !( RPGManager.IsInventoryEmpty( scriptInterface.owner ) ) )
		{
			scriptInterface.GetTransactionSystem().TransferAllItems( ( ( weak< weak< NPCPuppet > > )( scriptInterface.owner ) ), scriptInterface.executionOwner );
		}
	}

	protected function ApplyFriendlyCarryGameplayRestrictions( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingFriendly" );
	}

	protected function ApplyWoundedSoldierCarryGameplayRestrictions( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingWoundedSoldier" );
	}

	protected function UpdateGameplayRestrictions( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( scriptInterface.HasStatFlag( gamedataStatType.CanSprintWhileCarryingBody ) && !( m_isFriendlyCarry ) )
		{
			StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingCanSprint" );
		}
		else
		{
			if( PlayerDevelopmentSystem.GetData( scriptInterface.executionOwner ).IsNewPerkBoughtAnyLevel( gamedataNewPerkType.Body_Master_Perk_5 ) )
			{
				if( StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'BodyCarryingGeneric' ) )
				{
					StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingGeneric" );
					SetBlackboardBoolVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CanThrowCarriedNPC, true );
				}
				StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingBodyMasterPerk5" );
			}
			else
			{
				if( StatusEffectSystem.ObjectHasStatusEffectWithTag( scriptInterface.executionOwner, 'BodyCarryingBodyMasterPerk5' ) )
				{
					StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingBodyMasterPerk5" );
					SetBlackboardBoolVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CanThrowCarriedNPC, false );
				}
				StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingGeneric" );
			}
		}
	}

	protected function RemoveGameplayRestrictions( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingFriendly" );
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingNoDrop" );
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingGeneric" );
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingBodyMasterPerk5" );
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingCanSprint" );
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingActionRestriction" );
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoJump" );
		if( GetStyle( stateContext ) == gamePSMBodyCarryingStyle.WoundedSoldier )
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.BodyCarryingWoundedSoldier" );
		}
	}

	protected function DisableAndResetRagdoll( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		scriptInterface.owner.QueueEvent( CreateDisableRagdollEvent( 'DisableAndResetRagdollScriptFunc' ) );
		( ( NPCPuppet )( scriptInterface.owner ) ).SetDisableRagdoll( true );
	}

	protected function EvaluateWeaponUnequipping( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( IsHeavyWeaponEquipped( scriptInterface ) )
		{
			SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.UnequipWeapon );
		}
		else
		{
			stateContext.SetPermanentBoolParameter( 'forcedTemporaryUnequip', true, true );
		}
	}

	protected function EnableRagdoll( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		( ( NPCPuppet )( scriptInterface.owner ) ).SetDisableRagdoll( false, true );
		scriptInterface.owner.QueueEvent( CreateForceRagdollNoPowerPoseEvent( 'CarriedObject' ) );
	}

	protected function EnableRagdollUncontrolledMovement( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var evt : UncontrolledMovementStartEvent;
		( ( NPCPuppet )( scriptInterface.owner ) ).SetDisableRagdoll( false, true );
		evt = new UncontrolledMovementStartEvent;
		evt.ragdollNoGroundThreshold = -1.0;
		evt.ragdollOnCollision = true;
		evt.calculateEarlyPositionGroundHeight = true;
		evt.DebugSetSourceName( 'CarriedObjectUncontrolledMovement' );
		scriptInterface.owner.QueueEvent( evt );
	}

	protected function SetPickupAnimationParameter( stateContext : StateContext, pickupAnimation : Int32 )
	{
		stateContext.SetPermanentIntParameter( 'carriedObjectPickupAnimation', pickupAnimation, true );
	}

	protected const function GetPickupAnimationParameter( stateContext : StateContext ) : Int32
	{
		var pickupAnimationResult : StateResultInt;
		pickupAnimationResult = stateContext.GetPermanentIntParameter( 'carriedObjectPickupAnimation' );
		if( pickupAnimationResult.valid )
		{
			return pickupAnimationResult.value;
		}
		return 0;
	}

	protected function SetWasThrownParameter( stateContext : StateContext, wasThrown : Bool )
	{
		stateContext.SetPermanentBoolParameter( 'carriedObjectWasThrown', wasThrown, true );
	}

	protected const function GetWasThrownParameter( stateContext : StateContext ) : Bool
	{
		var wasThrownResult : StateResultBool;
		wasThrownResult = stateContext.GetPermanentBoolParameter( 'carriedObjectWasThrown' );
		if( wasThrownResult.valid )
		{
			return wasThrownResult.value;
		}
		return false;
	}

	protected function CalculateForcedCarryStyleAndIsFriendlyCarry( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var attitude : EAIAttitude;
		var puppet : gamePuppet;
		var workspotSystem : WorkspotGameSystem;
		m_isFriendlyCarry = false;
		puppet = ( ( gamePuppet )( scriptInterface.owner ) );
		if( puppet )
		{
			workspotSystem = scriptInterface.GetWorkspotSystem();
			if( workspotSystem && !( IsBodyDisposalOngoing( stateContext, scriptInterface ) ) )
			{
				workspotSystem.StopNpcInWorkspot( puppet );
			}
			m_forcedCarryStyle = ( ( gamePSMBodyCarryingStyle )( puppet.GetBlackboard().GetInt( GetAllBlackboardDefs().Puppet.ForcedCarryStyle ) ) );
			attitude = GameObject.GetAttitudeBetween( scriptInterface.owner, scriptInterface.executionOwner );
			if( m_forcedCarryStyle == gamePSMBodyCarryingStyle.Friendly || ( attitude == EAIAttitude.AIA_Friendly && m_forcedCarryStyle == gamePSMBodyCarryingStyle.Any ) )
			{
				m_isFriendlyCarry = true;
			}
		}
		SetIsFriendlyCarryParameter( stateContext, m_isFriendlyCarry );
	}

}

class CanTransitionToThrowDecisions extends CarriedObjectDecisions
{
	protected var m_throwNPCActionReleasedName : CName;
	private var m_throwNPCActionReleasedTime : Float;
	private var m_canThrow : Bool;
	private var m_canThrowInitialized : Bool;

	protected export function OnAttach( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface )
	{
		scriptInterface.executionOwner.RegisterInputListener( this, 'ThrowNPC' );
		scriptInterface.executionOwner.RegisterInputListener( this, 'ThrowNPCAlt' );
	}

	protected export function OnDetach( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface )
	{
		scriptInterface.executionOwner.UnregisterInputListener( this );
	}

	protected event OnAction( action : ListenerAction, consumer : ListenerActionConsumer )
	{
		if( ListenerAction.IsButtonJustReleased( action ) )
		{
			m_throwNPCActionReleasedName = ListenerAction.GetName( action );
			m_throwNPCActionReleasedTime = EngineTime.ToFloat( GameInstance.GetSimTime( GetGameInstance() ) );
		}
	}

	protected function ValidThrowNPCActionReleased( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var playerObject : GameObject;
		var ignoreThrowNPCAction : Bool;
		if( m_throwNPCActionReleasedName == '' )
		{
			return false;
		}
		if( ( m_throwNPCActionReleasedTime + 0.5 ) < EngineTime.ToFloat( GameInstance.GetSimTime( scriptInterface.owner.GetGame() ) ) )
		{
			ignoreThrowNPCAction = true;
		}
		else if( m_throwNPCActionReleasedName == 'ThrowNPCAlt' )
		{
			if( ( !( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.owner, T"BaseStatusEffect.ThrownNPC" ) ) && !( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.BerserkPlayerBuff" ) ) ) && !( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.executionOwner, T"BaseStatusEffect.AdvancedBerserkPlayerBuff" ) ) )
			{
				playerObject = scriptInterface.executionOwner;
				if( GameInstance.GetTransactionSystem( playerObject.GetGame() ).GetItemInSlot( playerObject, T"AttachmentSlots.WeaponRight" ) )
				{
					ignoreThrowNPCAction = true;
				}
				else if( scriptInterface.HasStatFlag( gamedataStatType.CanShootWhileCarryingBody ) )
				{
					ignoreThrowNPCAction = CanEquipFirearm( playerObject, stateContext, scriptInterface );
				}
			}
		}
		if( ignoreThrowNPCAction )
		{
			m_throwNPCActionReleasedName = '';
			return false;
		}
		return true;
	}

	protected function UpdateCanThrow( const canThrow : Bool, const scriptInterface : StateGameScriptInterface )
	{
		if( m_canThrowInitialized && m_canThrow == canThrow )
		{
			return;
		}
		SetBlackboardBoolVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CanThrowCarriedNPC, canThrow );
		m_canThrow = canThrow;
		m_canThrowInitialized = true;
	}

}

class PickUpDecisions extends CanTransitionToThrowDecisions
{

	public const function ToCarry( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var toCarryStateDuration : Float;
		if( ShouldThrow( scriptInterface ) )
		{
			return false;
		}
		if( GetFastModeParameter( stateContext ) )
		{
			toCarryStateDuration = GetStaticFloatParameterDefault( "toCarryStateDurationFastMode", 1.0 );
		}
		else
		{
			toCarryStateDuration = GetStaticFloatParameterDefault( "toCarryStateDuration", 1.0 );
		}
		return !( stateContext.GetConditionBool( 'CarriedObjectPlayPickUp' ) ) || ( GetInStateTime() > toCarryStateDuration );
	}

	public function ToAim( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( !( ShouldThrow( scriptInterface ) ) )
		{
			return false;
		}
		if( ValidThrowNPCActionReleased( stateContext, scriptInterface ) || !( IsPlayerCombatAllowed( scriptInterface ) ) )
		{
			return false;
		}
		if( GetInStateTime() < GetStaticFloatParameterDefault( "toAimStateDuration", 1.0 ) )
		{
			return false;
		}
		return true;
	}

	public function ToThrow( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( !( ShouldThrow( scriptInterface ) ) )
		{
			return false;
		}
		if( !( ValidThrowNPCActionReleased( stateContext, scriptInterface ) ) && IsPlayerCombatAllowed( scriptInterface ) )
		{
			return false;
		}
		if( GetInStateTime() < GetStaticFloatParameterDefault( "toThrowStateDuration", 1.0 ) )
		{
			return false;
		}
		return true;
	}

	private const function ShouldThrow( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( !( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.owner, T"BaseStatusEffect.ThrownNPC" ) ) )
		{
			return false;
		}
		return true;
	}

}

class PickUpEvents extends CarriedObjectEvents
{
	const var m_stateMachineInstanceData : StateMachineInstanceData;
	var m_noCameraControlApplied : Bool;
	var m_noMovementApplied : Bool;

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var canUseFireArms : Bool;
		var fastMode : Bool;
		var broadcaster : StimBroadcasterComponent;
		var carriedObjectData : CarriedObjectData;
		var setPositionEvent : SetBodyPositionEvent;
		var body : EntityID;
		carriedObjectData = ( ( CarriedObjectData )( m_stateMachineInstanceData.initData ) );
		body = scriptInterface.ownerEntityID;
		super.OnEnter( stateContext, scriptInterface );
		SetBlackboardBoolVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.Carrying, true );
		if( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.owner, T"BaseStatusEffect.ThrownNPC" ) )
		{
			SetPickupAnimationParameter( stateContext, 5 );
			m_noCameraControlApplied = StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoCameraControl" );
			m_noMovementApplied = StatusEffectHelper.ApplyStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoMovement" );
		}
		else
		{
			switch( GetTakedownAction( stateContext ) )
			{
				case ETakedownActionType.Takedown:
					SetPickupAnimationParameter( stateContext, 1 );
				break;
				case ETakedownActionType.TakedownNonLethal:
					SetPickupAnimationParameter( stateContext, 2 );
				break;
				case ETakedownActionType.AerialTakedown:
					SetPickupAnimationParameter( stateContext, 3 );
				break;
				default:
					SetPickupAnimationParameter( stateContext, 0 );
				if( PlayerDevelopmentSystem.GetData( scriptInterface.executionOwner ).IsNewPerkBoughtAnyLevel( gamedataNewPerkType.Body_Master_Perk_5 ) )
				{
					fastMode = true;
				}
				break;
			}
		}
		if( IsPickUpFromVehicleTrunk( scriptInterface ) )
		{
			SetPickupAnimationParameter( stateContext, 4 );
			fastMode = false;
		}
		if( m_isFriendlyCarry )
		{
			fastMode = false;
		}
		SetFastModeParameter( stateContext, fastMode );
		SetWasThrownParameter( stateContext, false );
		SetAnimFeature_Carry( ECarryState.Pickup, carriedObjectData.instant, stateContext, scriptInterface );
		canUseFireArms = scriptInterface.HasStatFlag( gamedataStatType.CanShootWhileCarryingBody );
		if( GameInstance.GetRuntimeInfo( scriptInterface.executionOwner.GetGame() ).IsMultiplayer() )
		{
			canUseFireArms = true;
		}
		ClearForcedStyle( stateContext );
		if( m_forcedCarryStyle != gamePSMBodyCarryingStyle.Any )
		{
			SetForcedStyle( m_forcedCarryStyle, stateContext, scriptInterface );
		}
		else if( m_isFriendlyCarry )
		{
			SetStyle( gamePSMBodyCarryingStyle.Friendly, stateContext, scriptInterface );
		}
		else if( canUseFireArms )
		{
			SetStyle( gamePSMBodyCarryingStyle.Strong, stateContext, scriptInterface );
		}
		else
		{
			SetStyle( gamePSMBodyCarryingStyle.Default, stateContext, scriptInterface );
		}
		if( GetStyle( stateContext ) != gamePSMBodyCarryingStyle.Friendly )
		{
			SetBodyPickUpCameraContext( stateContext, scriptInterface, true );
		}
		DisableAndResetRagdoll( stateContext, scriptInterface );
		EvaluateWeaponUnequipping( stateContext, scriptInterface );
		GetPlayer( scriptInterface.owner.GetGame() ).QueueEvent( new PickUpBodyBreathingEvent );
		broadcaster = scriptInterface.executionOwner.GetStimBroadcasterComponent();
		if( broadcaster )
		{
			broadcaster.AddActiveStimuli( scriptInterface.executionOwner, gamedataStimType.CarryBody, -1.0 );
		}
		( ( NPCPuppet )( scriptInterface.owner ) ).GetVisibleObjectComponent().Toggle( false );
		setPositionEvent = new SetBodyPositionEvent;
		setPositionEvent.bodyPosition = scriptInterface.owner.GetWorldPosition();
		setPositionEvent.pickedUp = true;
		setPositionEvent.bodyPositionID = body;
		scriptInterface.owner.QueueEvent( setPositionEvent );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.BodyCarrying, ( ( Int32 )( gamePSMBodyCarrying.PickUp ) ) );
		ApplyInitGameplayRestrictions( scriptInterface );
		ScriptedPuppet.EvaluateApplyingStatusEffectsFromMountedObjectToPlayer( scriptInterface.owner, scriptInterface.executionOwner );
		EvaluateAutomaticLootPickupFromMountedPuppet( scriptInterface );
		SetObjectInvulnerable( scriptInterface.owner, true );
		SetObjectInvulnerable( scriptInterface.executionOwner, true );
	}

	protected function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( m_noCameraControlApplied && ( GetInStateTime() > GetStaticFloatParameterDefault( "toAimNoCameraControlTime", 1.0 ) ) )
		{
			RestoreCameraControl( stateContext, scriptInterface );
		}
		if( m_noMovementApplied && ( GetInStateTime() > GetStaticFloatParameterDefault( "toAimNoMovementTime", 1.0 ) ) )
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoMovement" );
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoJump" );
			m_noMovementApplied = false;
		}
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExitCommon( stateContext, scriptInterface );
		super.OnExit( stateContext, scriptInterface );
	}

	protected override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExitCommon( stateContext, scriptInterface );
		super.OnForcedExit( stateContext, scriptInterface );
	}

	private function OnExitCommon( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetObjectInvulnerable( scriptInterface.executionOwner, false );
		if( m_noCameraControlApplied )
		{
			RestoreCameraControl( stateContext, scriptInterface );
		}
		if( m_noMovementApplied )
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoMovement" );
			m_noMovementApplied = false;
		}
	}

	private function RestoreCameraControl( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoCameraControl" );
		m_noCameraControlApplied = false;
		SetBodyPickUpCameraContext( stateContext, scriptInterface, false );
		SetBodyCarryCameraContext( stateContext, scriptInterface, true );
		SetBlackboardBoolVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CanThrowCarriedNPC, true );
	}

	private function IsPickUpFromVehicleTrunk( scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( StatusEffectSystem.ObjectHasStatusEffect( scriptInterface.owner, T"BaseStatusEffect.VehicleTrunkBodyPickup" ) )
		{
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.owner, T"BaseStatusEffect.VehicleTrunkBodyPickup" );
			return true;
		}
		else
		{
			return false;
		}
	}

}

class CarryDecisions extends CanTransitionToThrowDecisions
{

	protected const function ToDrop( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( !( IsDoorInteractionActive( scriptInterface ) ) )
		{
			if( !( scriptInterface.executionOwner.PlayerLastUsedKBM() ) )
			{
				if( scriptInterface.IsActionJustHeld( 'DropCarriedObject' ) )
				{
					return IsPlayerAllowedToDropBody( stateContext, scriptInterface );
				}
			}
			else if( scriptInterface.IsActionJustReleased( 'DropCarriedObject' ) )
			{
				return IsPlayerAllowedToDropBody( stateContext, scriptInterface );
			}
		}
		if( IsBodyDropForced( stateContext, scriptInterface ) )
		{
			return true;
		}
		return false;
	}

	protected const function ToDispose( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.localBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.CarryingDisposal );
	}

	protected function ToThrow( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var canThrow : Bool;
		var player : PlayerPuppet;
		var statsSystem : StatsSystem;
		player = GetPlayerPuppet( scriptInterface );
		if( !( player ) )
		{
			return false;
		}
		statsSystem = GameInstance.GetStatsSystem( player.GetGame() );
		canThrow = true;
		if( !( PlayerDevelopmentSystem.GetData( player ).IsNewPerkBoughtAnyLevel( gamedataNewPerkType.Body_Master_Perk_5 ) ) )
		{
			canThrow = false;
		}
		else if( player.IsAimingAtFriendly() )
		{
			canThrow = false;
		}
		else if( !( IsPlayerCombatAllowed( scriptInterface ) ) )
		{
			canThrow = false;
		}
		else if( GetIsFriendlyCarryParameter( stateContext ) )
		{
			canThrow = false;
		}
		else if( statsSystem.GetStatValue( scriptInterface.ownerEntityID, gamedataStatType.NPCThrowImmunity ) > 0.0 )
		{
			canThrow = false;
		}
		UpdateCanThrow( canThrow, scriptInterface );
		if( !( canThrow ) )
		{
			return false;
		}
		if( !( ValidThrowNPCActionReleased( stateContext, scriptInterface ) ) )
		{
			return false;
		}
		m_throwNPCActionReleasedName = '';
		return true;
	}

}

class CarryEvents extends CarriedObjectEvents
{
	var m_knockdownImmunityModifier : gameStatModifierData;

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnEnter( stateContext, scriptInterface );
		SetBodyPickUpCameraContext( stateContext, scriptInterface, false );
		if( GameInstance.GetRuntimeInfo( scriptInterface.executionOwner.GetGame() ).IsMultiplayer() || ( CanEquipFirearm( scriptInterface.executionOwner, stateContext, scriptInterface ) && GetStyle( stateContext ) == gamePSMBodyCarryingStyle.Strong ) )
		{
			stateContext.SetPermanentBoolParameter( 'forcedTemporaryUnequip', false, true );
		}
		if( GetStyle( stateContext ) == gamePSMBodyCarryingStyle.WoundedSoldier )
		{
			SetBodyCarryWoundedSoldierCameraContext( stateContext, scriptInterface, true );
		}
		else if( !( m_isFriendlyCarry ) )
		{
			SetBodyCarryCameraContext( stateContext, scriptInterface, true );
			StatusEffectHelper.RemoveStatusEffect( scriptInterface.executionOwner, T"GameplayRestriction.NoJump" );
		}
		if( m_isFriendlyCarry )
		{
			AddKnockdownModifier( scriptInterface );
		}
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.BodyCarrying, ( ( Int32 )( gamePSMBodyCarrying.Carry ) ) );
		SetAnimFeature_Carry( ECarryState.Carry, false, stateContext, scriptInterface );
		if( PlayerDevelopmentSystem.GetData( scriptInterface.executionOwner ).IsNewPerkBoughtAnyLevel( gamedataNewPerkType.Body_Master_Perk_5 ) )
		{
			SetBlackboardBoolVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CanThrowCarriedNPC, true );
		}
	}

	protected function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var linearVelocity : Vector4;
		linearVelocity = GetLinearVelocity( scriptInterface );
		SyncJump( stateContext, scriptInterface );
		m_animFeature.parentSpeed = Vector4.Length( linearVelocity );
		m_animFeature.parentHorizontalSpeed = Vector4.Length( Vector4( linearVelocity.X, linearVelocity.Y, 0.0, 0.0 ) );
		scriptInterface.SetAnimationParameterFeature( 'Mounting', m_animFeature );
		RefreshCarryState( stateContext, scriptInterface );
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExitCommon( stateContext, scriptInterface );
		super.OnExit( stateContext, scriptInterface );
	}

	protected override function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		OnExitCommon( stateContext, scriptInterface );
		super.OnForcedExit( stateContext, scriptInterface );
	}

	private function OnExitCommon( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		RemoveKnockdownModifier( scriptInterface );
	}

	private function RefreshCarryState( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( ( !( m_isFriendlyCarry ) && scriptInterface.HasStatFlag( gamedataStatType.CanShootWhileCarryingBody ) ) && !( stateContext.GetBoolParameter( 'checkCanShootWhileCarryingBodyStatFlag', true ) ) )
		{
			if( GetStyle( stateContext ) == gamePSMBodyCarryingStyle.WoundedSoldier )
			{
				stateContext.SetPermanentBoolParameter( 'forcedTemporaryUnequip', false, true );
				SetAnimFeature_Carry( ECarryState.Carry, false, stateContext, scriptInterface );
			}
			else
			{
				UpdateGameplayRestrictions( stateContext, scriptInterface );
				if( CanEquipFirearm( scriptInterface.executionOwner, stateContext, scriptInterface ) )
				{
					if( GetStyle( stateContext ) != gamePSMBodyCarryingStyle.Strong )
					{
						SetStyle( gamePSMBodyCarryingStyle.Strong, stateContext, scriptInterface );
					}
					stateContext.SetPermanentBoolParameter( 'forcedTemporaryUnequip', false, true );
					SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.RequestLastUsedOrFirstAvailableOneHandedRangedWeapon );
					SetAnimFeature_Carry( ECarryState.Carry, false, stateContext, scriptInterface );
					stateContext.SetPermanentBoolParameter( 'checkCanShootWhileCarryingBodyStatFlag', true, true );
				}
			}
		}
	}

	private function SyncJump( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( IsInLocomotionState( stateContext, 'jump' ) && !( stateContext.GetBoolParameter( 'playerJumped', true ) ) )
		{
			stateContext.SetPermanentBoolParameter( 'playerJumped', true, true );
			UpdatePuppetCarryState( ECarryState.Jump, stateContext, scriptInterface );
		}
		else if( scriptInterface.IsOnGround() && stateContext.GetBoolParameter( 'playerJumped', true ) )
		{
			UpdatePuppetCarryState( ECarryState.Carry, stateContext, scriptInterface );
			stateContext.RemovePermanentBoolParameter( 'playerJumped' );
		}
	}

	private function UpdatePuppetCarryState( state : ECarryState, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		m_animCarryFeature = new AnimFeature_Carry;
		m_animCarryFeature.state = ( ( Int32 )( state ) );
		m_animCarryFeature.pickupAnimation = GetPickupAnimationParameter( stateContext );
		m_animCarryFeature.fastMode = GetFastModeParameter( stateContext );
		m_animCarryFeature.isCarryActive = true;
		m_animCarryFeature.isFriendlyCarry = m_isFriendlyCarry;
		m_animCarryFeature.wasThrown = GetWasThrownParameter( stateContext );
		scriptInterface.SetAnimationParameterFeature( 'Carry', m_animCarryFeature, scriptInterface.owner );
	}

	private function AddKnockdownModifier( scriptInterface : StateGameScriptInterface )
	{
		var statSys : StatsSystem;
		statSys = scriptInterface.GetStatsSystem();
		m_knockdownImmunityModifier = RPGManager.CreateStatModifier( gamedataStatType.KnockdownImmunity, gameStatModifierType.Additive, 1.0 );
		statSys.AddModifier( scriptInterface.executionOwnerEntityID, m_knockdownImmunityModifier );
	}

	private function RemoveKnockdownModifier( scriptInterface : StateGameScriptInterface )
	{
		var statSys : StatsSystem;
		statSys = scriptInterface.GetStatsSystem();
		if( m_knockdownImmunityModifier )
		{
			statSys.RemoveModifier( scriptInterface.executionOwnerEntityID, m_knockdownImmunityModifier );
			m_knockdownImmunityModifier = NULL;
		}
	}

}

class DropDecisions extends CarriedObjectDecisions
{

	public const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetInStateTime() > GetStaticFloatParameterDefault( "stateDuration", 1.5 );
	}

}

class DropEvents extends CarriedObjectEvents
{
	var m_ragdollReenabled : Bool;

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnEnter( stateContext, scriptInterface );
		m_ragdollReenabled = false;
		stateContext.SetPermanentBoolParameter( 'forcedTemporaryUnequip', true, true );
		SetAnimFeature_Carry( ECarryState.Drop, false, stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.BodyCarrying, ( ( Int32 )( gamePSMBodyCarrying.Drop ) ) );
		scriptInterface.owner.QueueEvent( new RagdollRequestCollectAnimPoseEvent );
		EnableRagdollUncontrolledMovement( stateContext, scriptInterface );
	}

	protected function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( !( m_ragdollReenabled ) )
		{
			if( GetInStateTime() > GetStaticFloatParameterDefault( "ragdollActivateTime", 1.0 ) )
			{
				EnableRagdoll( stateContext, scriptInterface );
				m_ragdollReenabled = true;
			}
			else if( IsInLocomotionState( stateContext, 'crouch' ) && ( GetInStateTime() > GetStaticFloatParameterDefault( "ragdollActivateTimeCrouch", 1.0 ) ) )
			{
				EnableRagdoll( stateContext, scriptInterface );
				m_ragdollReenabled = true;
			}
		}
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( !( m_ragdollReenabled ) )
		{
			EnableRagdoll( stateContext, scriptInterface );
			m_ragdollReenabled = true;
		}
	}

}

class DisposeDecisions extends CarriedObjectDecisions
{

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

}

class DisposeEvents extends CarriedObjectEvents
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.BodyCarrying, ( ( Int32 )( gamePSMBodyCarrying.Dispose ) ) );
		super.OnEnter( stateContext, scriptInterface );
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		( ( NPCPuppet )( scriptInterface.owner ) ).GetVisibleObjectComponent().Toggle( false );
	}

}

class ForceDropBodyEvents extends CarriedObjectEvents
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var isSceneDropAnimation : StateResultBool;
		StatusEffectHelper.RemoveStatusEffect( scriptInterface.owner, T"BaseStatusEffect.ThrownNPC" );
		CalculateForcedCarryStyleAndIsFriendlyCarry( stateContext, scriptInterface );
		isSceneDropAnimation = stateContext.GetTemporaryBoolParameter( 'bodyCarrySceneDropAnimation' );
		if( !( isSceneDropAnimation.valid ) || ( isSceneDropAnimation.valid && !( isSceneDropAnimation.value ) ) )
		{
			EnableRagdoll( stateContext, scriptInterface );
		}
		CleanUpCarryStateMachine( ECarryState.Release, stateContext, scriptInterface );
	}

}

class AimDecisions extends CanTransitionToThrowDecisions
{

	protected function ToThrow( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var player : PlayerPuppet;
		player = GetPlayerPuppet( scriptInterface );
		if( !( player ) )
		{
			return false;
		}
		if( player.IsAimingAtFriendly() )
		{
			UpdateCanThrow( false, scriptInterface );
			return false;
		}
		UpdateCanThrow( true, scriptInterface );
		if( !( ValidThrowNPCActionReleased( stateContext, scriptInterface ) ) && IsPlayerCombatAllowed( scriptInterface ) )
		{
			return false;
		}
		return true;
	}

}

class AimEvents extends CarriedObjectEvents
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		super.OnEnter( stateContext, scriptInterface );
		SetAnimFeature_Carry( ECarryState.Aim, false, stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.BodyCarrying, ( ( Int32 )( gamePSMBodyCarrying.Aim ) ) );
	}

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

}

class ThrowDecisions extends CarriedObjectDecisions
{

	public const function ExitCondition( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetInStateTime() > GetStaticFloatParameterDefault( "stateDuration", 1.5 );
	}

}

class ThrowEvents extends CarriedObjectEvents
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var thrownNPC : NPCPuppet;
		thrownNPC = ( ( NPCPuppet )( scriptInterface.owner ) );
		super.OnEnter( stateContext, scriptInterface );
		if( !( thrownNPC.IsDead() ) )
		{
			thrownNPC.Kill( scriptInterface.executionOwner, true, true );
			StatusEffectHelper.ApplyStatusEffect( thrownNPC, T"BaseStatusEffect.ForceKillFromRagdoll" );
		}
		SetWasThrownParameter( stateContext, true );
		if( !( StatusEffectSystem.ObjectHasStatusEffect( thrownNPC, T"BaseStatusEffect.ThrownNPC" ) ) )
		{
			StatusEffectHelper.ApplyStatusEffect( thrownNPC, T"BaseStatusEffect.ThrownNPC" );
		}
		SetAnimFeature_Carry( ECarryState.Throw, false, stateContext, scriptInterface );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.BodyCarrying, ( ( Int32 )( gamePSMBodyCarrying.Throw ) ) );
		EnableRagdollUncontrolledMovement( stateContext, scriptInterface );
		scriptInterface.owner.QueueEvent( new RagdollRequestCollectAnimPoseEvent );
	}

	protected override function OnExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var thrownNPC : NPCPuppet;
		var player : PlayerPuppet;
		var cameraWorldTransform : Transform;
		var cameraEulerAngles : EulerAngles;
		var ragdollImpulse : Float;
		var ragdollImpulseScale : Float;
		var ragdollMaxImpulsePitch : Float;
		var ragdollMinImpulsePitch : Float;
		var targetSearchQuery : TargetSearchQuery;
		var targetSearchFilter : TargetSearchFilter;
		var targetObject : GameObject;
		var targetLateralSpeed : Float;
		var maxAutoTargetAngle : Float;
		var minAutoTargetAngle : Float;
		var throwDirectionForward : Vector4;
		var throwDirectionRight : Vector4;
		var throwAdjustmentAngleXY : Float;
		var nearbyCrowdNPCs : array< weak< Entity > >;
		thrownNPC = ( ( NPCPuppet )( scriptInterface.owner ) );
		cameraWorldTransform = scriptInterface.GetCameraWorldTransform();
		throwDirectionForward = Transform.GetForward( cameraWorldTransform );
		throwDirectionRight = Transform.GetRight( cameraWorldTransform );
		if( IsPlayerCombatAllowed( scriptInterface ) )
		{
			player = GetPlayerPuppet( scriptInterface );
			if( !( player ) || player.GetAimAssistLevel() != EAimAssistLevel.Off )
			{
				minAutoTargetAngle = GetStaticFloatParameterDefault( "minAutoTargetAngle", 10.0 );
				targetSearchFilter = TSF_And( TSF_All( ( TSFMV.Obj_Puppet | TSFMV.Sp_Aggressive ) | TSFMV.St_Alive ), TSF_Not( TSFMV.Obj_Player ) );
				targetSearchQuery.searchFilter = targetSearchFilter;
				targetObject = GetTargetObject( scriptInterface, targetSearchQuery, -1.0, false, minAutoTargetAngle );
				if( !( targetObject ) )
				{
					targetSearchFilter = TSF_And( TSF_All( ( TSFMV.Obj_Puppet | TSFMV.Att_Hostile ) | TSFMV.St_Alive ), TSF_Not( TSFMV.Obj_Player ) );
					targetSearchQuery.searchFilter = targetSearchFilter;
					targetObject = GetTargetObject( scriptInterface, targetSearchQuery, -1.0, false, minAutoTargetAngle );
				}
				if( targetObject )
				{
					targetLateralSpeed = AbsF( Vector4.Dot( ( ( gamePuppet )( targetObject ) ).GetVelocity(), player.GetWorldRight() ) );
					if( targetLateralSpeed <= GetStaticFloatParameterDefault( "maxAutoTargetLateralSpeed", 1.0 ) )
					{
						throwAdjustmentAngleXY = Vector4.GetAngleDegAroundAxis( throwDirectionForward, targetObject.GetWorldPosition() - scriptInterface.executionOwner.GetWorldPosition(), GetUpVector() );
						maxAutoTargetAngle = GetStaticFloatParameterDefault( "maxAutoTargetAngle", 3.0 );
						if( AbsF( throwAdjustmentAngleXY ) > maxAutoTargetAngle )
						{
							throwAdjustmentAngleXY = throwAdjustmentAngleXY * ClampF( ( minAutoTargetAngle - AbsF( throwAdjustmentAngleXY ) ) / ( minAutoTargetAngle - maxAutoTargetAngle ), 0.0, 1.0 );
						}
						throwDirectionForward = Vector4.RotByAngleXY( throwDirectionForward, -( throwAdjustmentAngleXY ) );
						throwDirectionRight = Vector4.RotByAngleXY( throwDirectionRight, -( throwAdjustmentAngleXY ) );
					}
				}
			}
			cameraEulerAngles = Transform.ToEulerAngles( cameraWorldTransform );
			ragdollMaxImpulsePitch = GetStaticFloatParameterDefault( "ragdollMaxImpulsePitch", 90.0 );
			ragdollMinImpulsePitch = GetStaticFloatParameterDefault( "ragdollMinImpulsePitch", 90.0 );
			ragdollImpulseScale = ClampF( cameraEulerAngles.Pitch, ragdollMaxImpulsePitch, ragdollMinImpulsePitch );
			ragdollImpulseScale = ( ragdollImpulseScale - ragdollMaxImpulsePitch ) / ( ragdollMinImpulsePitch - ragdollMaxImpulsePitch );
			ragdollImpulse = LerpF( ragdollImpulseScale, GetStaticFloatParameterDefault( "ragdollMaxImpulse", 100.0 ), GetStaticFloatParameterDefault( "ragdollMinImpulse", 100.0 ) );
		}
		else
		{
			ragdollImpulse = 30.0;
			StatusEffectHelper.RemoveStatusEffect( thrownNPC, T"BaseStatusEffect.ThrownNPC" );
		}
		thrownNPC.SetDisableRagdoll( false, true );
		thrownNPC.QueueEvent( CreateForceRagdollNoPowerPoseEvent( 'CarriedObect_Throw' ) );
		GameInstance.GetDelaySystem( thrownNPC.GetGame() ).DelayEvent( thrownNPC, CreateRagdollApplyImpulseEvent( thrownNPC.GetWorldPosition(), throwDirectionForward * ragdollImpulse, 10000.0 ), 0.1, false );
		nearbyCrowdNPCs = ComputeNearbyCrowdNPCs( player, thrownNPC, throwDirectionForward, throwDirectionRight );
		thrownNPC.OnNPCThrown( nearbyCrowdNPCs );
	}

	private function ComputeNearbyCrowdNPCs( player : PlayerPuppet, thrownNPC : NPCPuppet, throwDirectionForward : Vector4, throwDirectionRight : Vector4 ) : array< weak< Entity > >
	{
		var c_nearbyCrowdNPCQueryBoxDepth : Float;
		var c_nearbyCrowdNPCQueryBoxWidth : Float;
		var c_nearbyCrowdNPCQueryBoxBottom : Float;
		var c_nearbyCrowdNPCQueryBoxTop : Float;
		var c_nearbyCrowdNPCMaxDistance : Float;
		var trafficEntitiesQueryBoxPoints : array< Vector4 >;
		var trafficEntities : array< weak< Entity > >;
		c_nearbyCrowdNPCQueryBoxDepth = 25.0;
		c_nearbyCrowdNPCQueryBoxWidth = 4.0;
		c_nearbyCrowdNPCQueryBoxBottom = -0.25;
		c_nearbyCrowdNPCQueryBoxTop = 2.0;
		c_nearbyCrowdNPCMaxDistance = 2.0;
		trafficEntitiesQueryBoxPoints.PushBack( player.GetWorldPosition() + Vector4( 0.0, 0.0, c_nearbyCrowdNPCQueryBoxBottom, 0.0 ) );
		trafficEntitiesQueryBoxPoints.PushBack( ( player.GetWorldPosition() + ( throwDirectionForward * c_nearbyCrowdNPCQueryBoxDepth ) ) + Vector4( 0.0, 0.0, c_nearbyCrowdNPCQueryBoxTop, 0.0 ) );
		trafficEntitiesQueryBoxPoints.PushBack( player.GetWorldPosition() + ( throwDirectionRight * ( c_nearbyCrowdNPCQueryBoxWidth * 0.5 ) ) );
		trafficEntitiesQueryBoxPoints.PushBack( player.GetWorldPosition() - ( throwDirectionRight * ( c_nearbyCrowdNPCQueryBoxWidth * 0.5 ) ) );
		GameInstance.GetTrafficSystem( player.GetGame() ).FindEntitiesNearPlane( thrownNPC, trafficEntitiesQueryBoxPoints, player.GetWorldPosition(), throwDirectionRight, c_nearbyCrowdNPCMaxDistance, 25, trafficEntities );
		return trafficEntities;
	}

}

class ReleaseEvents extends CarriedObjectEvents
{

	protected override function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		CalculateForcedCarryStyleAndIsFriendlyCarry( stateContext, scriptInterface );
		CleanUpCarryStateMachine( ECarryState.Release, stateContext, scriptInterface );
	}

}

