abstract class CombatGadgetTransitions extends DefaultTransition
{

	protected function SetLeftHandAnimationAnimFeature( scriptInterface : StateGameScriptInterface, newState : Bool )
	{
		var animFeature : AnimFeature_LeftHandAnimation;
		animFeature = new AnimFeature_LeftHandAnimation;
		animFeature.lockLeftHandAnimation = newState;
		scriptInterface.SetAnimationParameterFeature( 'LeftHandAnimation', animFeature, scriptInterface.executionOwner );
	}

	protected function SetCombatGadgetAnimFeature( scriptInterface : StateGameScriptInterface, isQuickthrow : Bool, isChargedThrow : Bool )
	{
		var feature : AnimFeature_CombatGadget;
		feature = new AnimFeature_CombatGadget;
		feature.isQuickthrow = isQuickthrow;
		feature.isChargedThrow = isChargedThrow;
		scriptInterface.SetAnimationParameterFeature( 'CombatGadget', feature, scriptInterface.executionOwner );
	}

	protected function SetBlackbordThrowUnequip( scriptInterface : StateGameScriptInterface, newThrowUnequip : Bool )
	{
		SetBlackboardBoolVariable( scriptInterface, GetAllBlackboardDefs().CombatGadget.throwUnequip, newThrowUnequip );
	}

	protected const function SetThrowableAnimFeatureOnGrenade( scriptInterface : StateGameScriptInterface, newState : Int32, target : weak< GameObject > )
	{
		var feature : AnimFeature_Throwable;
		feature = new AnimFeature_Throwable;
		feature.state = newState;
		scriptInterface.SetAnimationParameterFeature( 'CombatGadget', feature, target );
	}

	protected const function SetThrowableAnimFeatureOnGrenade( scriptInterface : StateGameScriptInterface, newState : Int32, isQuickthrow : Bool )
	{
		var feature : AnimFeature_Throwable;
		var target : ItemObject;
		var transactionSystem : TransactionSystem;
		var slot : String;
		feature = new AnimFeature_Throwable;
		transactionSystem = scriptInterface.GetTransactionSystem();
		slot = ( ( isQuickthrow ) ? ( "AttachmentSlots.WeaponLeft" ) : ( "AttachmentSlots.WeaponRight" ) );
		target = transactionSystem.GetItemInSlot( ( ( PlayerPuppet )( scriptInterface.executionOwner ) ), TDBID.Create( slot ) );
		feature.state = newState;
		scriptInterface.SetAnimationParameterFeature( 'CombatGadget', feature, target );
	}

	protected const function ClearLastUsedAnimWrapperInfo( scriptInterface : StateGameScriptInterface )
	{
		var blackboardSystem : BlackboardSystem;
		var blackboard : IBlackboard;
		var lastUsed : ItemID;
		blackboardSystem = scriptInterface.GetBlackboardSystem();
		blackboard = blackboardSystem.GetLocalInstanced( scriptInterface.executionOwnerEntityID, GetAllBlackboardDefs().PlayerStateMachine );
		lastUsed = ( ( ItemID )( blackboard.GetVariant( GetAllBlackboardDefs().PlayerStateMachine.LastCombatGadgetUsed ) ) );
		if( ItemID.IsValid( lastUsed ) )
		{
			SendAnimWrapperInfo( scriptInterface, lastUsed, true );
		}
	}

	protected const function SendAnimWrapperInfo( scriptInterface : StateGameScriptInterface, item : ItemID, clearWrapperInfo : Bool, optional delay : Float )
	{
		var animWrapperEvent : FillAnimWrapperInfoBasedOnEquippedItem;
		animWrapperEvent = new FillAnimWrapperInfoBasedOnEquippedItem;
		animWrapperEvent.itemID = item;
		animWrapperEvent.itemType = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) ).ItemType().Name();
		animWrapperEvent.itemName = StringToName( TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) ).FriendlyName() );
		animWrapperEvent.clearWrapperInfo = clearWrapperInfo;
		if( delay > 0.0 )
		{
			scriptInterface.GetDelaySystem().DelayEvent( scriptInterface.executionOwner, animWrapperEvent, delay, true );
		}
		else
		{
			scriptInterface.executionOwner.QueueEventForEntityID( scriptInterface.executionOwnerEntityID, animWrapperEvent );
		}
	}

	protected const function SaveLastUsedCombatGadget( scriptInterface : StateGameScriptInterface, item : ItemID )
	{
		var blackboardSystem : BlackboardSystem;
		var blackboard : IBlackboard;
		blackboardSystem = scriptInterface.GetBlackboardSystem();
		blackboard = blackboardSystem.GetLocalInstanced( scriptInterface.executionOwnerEntityID, GetAllBlackboardDefs().PlayerStateMachine );
		blackboard.SetVariant( GetAllBlackboardDefs().PlayerStateMachine.LastCombatGadgetUsed, item );
	}

	protected const function GetLockHoldCondition( const stateContext : StateContext ) : Bool
	{
		var result : StateResultBool;
		result = stateContext.GetConditionBoolParameter( 'lockHold' );
		return result.valid && result.value;
	}

	protected const function GetSlotTDBID( const stateContext : StateContext ) : TweakDBID
	{
		if( stateContext.GetBoolParameter( 'rightHandThrow', true ) )
		{
			return T"AttachmentSlots.WeaponRight";
		}
		else
		{
			return T"AttachmentSlots.WeaponLeft";
		}
	}

	protected const function RemoveGrenadeFromRightHand( scriptInterface : StateGameScriptInterface )
	{
		var transactionSystem : TransactionSystem;
		var item : weak< ItemObject >;
		transactionSystem = scriptInterface.GetTransactionSystem();
		item = transactionSystem.GetItemInSlot( ( ( PlayerPuppet )( scriptInterface.executionOwner ) ), T"AttachmentSlots.WeaponRight" );
		if( ( ( BaseGrenade )( item ) ) != NULL )
		{
			transactionSystem.RemoveItemFromSlot( ( ( PlayerPuppet )( scriptInterface.executionOwner ) ), T"AttachmentSlots.WeaponRight", false );
		}
		else if( ( ( ThrowableKnifeNPC )( item ) ) != NULL )
		{
			transactionSystem.RemoveItemFromSlot( ( ( PlayerPuppet )( scriptInterface.executionOwner ) ), T"AttachmentSlots.WeaponRight", false );
		}
	}

	protected const function GetRotateAngle( isQuickthrow : Bool ) : Float
	{
		if( isQuickthrow )
		{
			return GetStaticFloatParameterDefault( "quickThrowAngle", 1.0 );
		}
		else
		{
			return GetStaticFloatParameterDefault( "regularThrowAngle", 1.0 );
		}
	}

	protected const function Throw( scriptInterface : StateGameScriptInterface, stateContext : StateContext, isQuickthrow : Bool, optional inLocalAimForward : Vector4, optional inLocalAimPosition : Vector4 )
	{
		var launchEvent : gameprojectileSetUpAndLaunchEvent;
		var transactionSystem : TransactionSystem;
		var targetingSystem : TargetingSystem;
		var item : ItemObject;
		var blackboardSystem : BlackboardSystem;
		var blackboard : IBlackboard;
		var playerPuppet : PlayerPuppet;
		var logicalPositionProvider : IPositionProvider;
		var logicalOrientationProvider : IOrientationProvider;
		var orientationEntitySpace : Quaternion;
		transactionSystem = scriptInterface.GetTransactionSystem();
		if( !( CheckItemCategoryInQuickWheel( scriptInterface, gamedataItemCategory.Gadget ) ) )
		{
			return;
		}
		blackboardSystem = scriptInterface.GetBlackboardSystem();
		blackboard = blackboardSystem.Get( GetAllBlackboardDefs().UI_QuickSlotsData );
		blackboard.SetBool( GetAllBlackboardDefs().UI_QuickSlotsData.dpadHintRefresh, true );
		blackboard.SignalBool( GetAllBlackboardDefs().UI_QuickSlotsData.dpadHintRefresh );
		playerPuppet = ( ( PlayerPuppet )( scriptInterface.executionOwner ) );
		item = transactionSystem.GetItemInSlot( playerPuppet, GetSlotTDBID( stateContext ) );
		GameInstance.GetTelemetrySystem( playerPuppet.GetGame() ).LogCombatGadgetUsed( playerPuppet, item.GetItemID() );
		if( ( ( BaseGrenade )( item ) ) != NULL )
		{
			transactionSystem.RemoveItemFromSlot( playerPuppet, GetSlotTDBID( stateContext ), item.IsClientSideOnlyGadget(), false, true );
		}
		if( item && !( item.IsClientSideOnlyGadget() ) )
		{
			launchEvent = new gameprojectileSetUpAndLaunchEvent;
			SetItemIDWrapperPermanentParameter( stateContext, 'grenade', item.GetItemID() );
			Quaternion.SetIdentity( orientationEntitySpace );
			Quaternion.SetXRot( orientationEntitySpace, GetRotateAngle( isQuickthrow ) );
			if( Vector4.IsZero( inLocalAimPosition ) || Vector4.IsZero( inLocalAimForward ) )
			{
				targetingSystem = GameInstance.GetTargetingSystem( playerPuppet.GetGame() );
				logicalPositionProvider = targetingSystem.GetDefaultCrosshairPositionProvider( playerPuppet );
				logicalOrientationProvider = targetingSystem.GetDefaultCrosshairOrientationProvider( playerPuppet, orientationEntitySpace );
			}
			else
			{
				logicalPositionProvider = IPositionProvider.CreateEntityPositionProvider( playerPuppet, Vector4.Vector4To3( inLocalAimPosition ) );
				inLocalAimForward = Quaternion.Transform( orientationEntitySpace, inLocalAimForward );
				orientationEntitySpace = Quaternion.BuildFromDirectionVector( inLocalAimForward );
				logicalOrientationProvider = IOrientationProvider.CreateEntityOrientationProvider( NULL, '', playerPuppet, orientationEntitySpace );
			}
			launchEvent.launchParams.logicalPositionProvider = logicalPositionProvider;
			launchEvent.launchParams.logicalOrientationProvider = logicalOrientationProvider;
			launchEvent.launchParams.visualPositionProvider = IPositionProvider.CreateEntityPositionProvider( item );
			launchEvent.launchParams.visualOrientationProvider = IOrientationProvider.CreateEntityOrientationProvider( NULL, '', item );
			launchEvent.launchParams.ownerVelocityProvider = MoveComponentVelocityProvider.CreateMoveComponentVelocityProvider( playerPuppet );
			launchEvent.lerpMultiplier = 15.0;
			launchEvent.trajectoryParams = CreateTrajectoryParams( item, isQuickthrow );
			launchEvent.owner = playerPuppet;
			item.QueueEvent( launchEvent );
		}
	}

	protected const function NotifyAutocraftSystem( const scriptInterface : StateGameScriptInterface )
	{
		var autocraftSystem : AutocraftSystem;
		var autocraftItemUsedRequest : RegisterItemUsedRequest;
		autocraftSystem = ( ( AutocraftSystem )( scriptInterface.GetScriptableSystem( 'AutocraftSystem' ) ) );
		autocraftItemUsedRequest = new RegisterItemUsedRequest;
		autocraftItemUsedRequest.itemUsed = EquipmentSystem.GetData( scriptInterface.executionOwner ).GetActiveGadget();
		autocraftSystem.QueueRequest( autocraftItemUsedRequest );
	}

	protected const function CreateTrajectoryParams( item : ItemObject, isQuickthrow : Bool ) : gameprojectileTrajectoryParams
	{
		var initialVelocity : Float;
		var accelerationZ : Float;
		var grenadeItem : BaseGrenade;
		var grenadeItemCopy : ThrowableKnifeNPC;
		grenadeItem = ( ( BaseGrenade )( item ) );
		if( !( grenadeItem ) )
		{
			grenadeItemCopy = ( ( ThrowableKnifeNPC )( item ) );
			initialVelocity = grenadeItemCopy.GetInitialVelocity( isQuickthrow );
			accelerationZ = grenadeItemCopy.GetAccelerationZ();
		}
		else
		{
			initialVelocity = grenadeItem.GetInitialVelocity( isQuickthrow );
			accelerationZ = grenadeItem.GetAccelerationZ();
		}
		return ParabolicTrajectoryParams.GetAccelVelParabolicParams( Vector4( 0.0, 0.0, accelerationZ, 0.0 ), initialVelocity, 20.0 );
	}

	protected const function CheckVehicleStatesForUnequipRequest( const stateContext : StateContext ) : Bool
	{
		return stateContext.IsStateMachineActive( 'Vehicle' ) && !( stateContext.IsStateActive( 'Vehicle', 'combat' ) );
	}

	protected function SetItemInLeftHand( scriptInterface : StateGameScriptInterface, newState : Bool )
	{
		var animFeature : AnimFeature_LeftHandItem;
		animFeature = new AnimFeature_LeftHandItem;
		animFeature.itemInLeftHand = newState;
		scriptInterface.SetAnimationParameterFeature( 'LeftHandItem', animFeature, scriptInterface.executionOwner );
	}

	protected function SetLeftHandItemHandlingItemState( scriptInterface : StateGameScriptInterface, newState : Int32 )
	{
		var leftHandItemHandling : AnimFeature_EquipUnequipItem;
		leftHandItemHandling = new AnimFeature_EquipUnequipItem;
		leftHandItemHandling.itemState = newState;
		if( newState > 0 )
		{
			leftHandItemHandling.itemType = 5;
		}
		else
		{
			leftHandItemHandling.itemType = 0;
		}
		scriptInterface.SetAnimationParameterFeature( 'leftHandItemHandling', leftHandItemHandling, scriptInterface.executionOwner );
	}

	protected const function ShouldForceUnequipGrenade( const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var takedownState : Int32;
		var isInTakedown : Bool;
		takedownState = scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Takedown );
		isInTakedown = ( ( takedownState == ( ( Int32 )( gamePSMTakedown.Grapple ) ) ) || ( takedownState == ( ( Int32 )( gamePSMTakedown.Leap ) ) ) ) || ( takedownState == ( ( Int32 )( gamePSMTakedown.Takedown ) ) );
		return ( isInTakedown || !( IsUsingLeftHandAllowed( scriptInterface ) ) ) || ( scriptInterface.GetWorkspotSystem().IsActorInWorkspot( scriptInterface.executionOwner ) && !( scriptInterface.localBlackboard.GetBool( GetAllBlackboardDefs().PlayerStateMachine.MountedToVehicle ) ) );
	}

	protected const function RemoveGrenadeFromInventory( const scriptInterface : StateGameScriptInterface )
	{
		var grenadeThrowCost : Float;
		if( scriptInterface.GetStatusEffectSystem().HasStatusEffect( scriptInterface.executionOwner.GetEntityID(), T"BaseStatusEffect.Tech_Left_Perk_3_2_Buff" ) )
		{
			grenadeThrowCost = 0.0;
		}
		else
		{
			grenadeThrowCost = ( ( Float )( GetPlayer( scriptInterface.GetGame() ).GetGrenadeThrowCost() ) );
		}
		scriptInterface.GetStatPoolsSystem().RequestChangingStatPoolValue( scriptInterface.executionOwner.GetEntityID(), gamedataStatPoolType.GrenadesCharges, -( grenadeThrowCost ), NULL, false, false );
		ConsumablesChargesHelper.HotkeyRefresh( scriptInterface.GetGame() );
	}

	protected const function GetCancelGrenadeAction( const stateContext : StateContext ) : Bool
	{
		var cancelAction : StateResultBool;
		cancelAction = stateContext.GetTemporaryBoolParameter( 'CancelGrenadeAction' );
		return cancelAction.valid && cancelAction.value;
	}

	protected const function CheckEquipDurationCondition( scriptInterface : StateGameScriptInterface, stateContext : StateContext ) : Bool
	{
		var inStateTime : Float;
		var unequip : Float;
		var equip : Float;
		inStateTime = GetInStateTime();
		unequip = stateContext.GetFloatParameter( 'rhUnequipDuration', true );
		equip = GetStaticFloatParameterDefault( "equipDuration", 1.0 );
		if( unequip < equip )
		{
			unequip = equip;
		}
		unequip += 0.2;
		return ( inStateTime >= equip ) && ( inStateTime >= unequip );
	}

}

class CombatGadgetStartDecisions extends DefaultTransition
{

	protected export const function ToCombatGadgetInactive( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return ( ( PlayerPuppet )( scriptInterface.GetPlayerSystem().GetLocalPlayerMainGameObject() ) ).GetGrenadeCharges() > 0;
	}

	protected export const function ToCombatGadgetUnequip( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return ( ( PlayerPuppet )( scriptInterface.GetPlayerSystem().GetLocalPlayerMainGameObject() ) ).GetGrenadeCharges() <= 0;
	}

}

class CombatGadgetStartEvents extends DefaultTransition
{
}

class CombatGadgetInactiveDecisions extends CombatGadgetTransitions
{

	protected export const function ToCombatGadgetQuickThrow( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return ( ( scriptInterface.GetActionValue( 'UseCombatGadget' ) == 0.0 ) && stateContext.GetStateMachineCurrentState( 'UpperBody' ) != 'useConsumable' ) && !( IsInWeaponReloadState( scriptInterface ) );
	}

	protected export const function ToCombatGadgetEquip( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return scriptInterface.IsActionJustHeld( 'UseCombatGadget' ) || stateContext.GetBoolParameter( 'cgCached', true );
	}

}

class CombatGadgetInactiveEvents extends CombatGadgetTransitions
{

	protected export virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var activeGadget : ItemID;
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CombatGadget, ( ( Int32 )( gamePSMCombatGadget.Default ) ) );
		SetLeftHandItemHandlingItemState( scriptInterface, 2 );
		activeGadget = EquipmentSystem.GetData( scriptInterface.executionOwner ).GetActiveGadget();
		ClearLastUsedAnimWrapperInfo( scriptInterface );
		SendAnimWrapperInfo( scriptInterface, activeGadget, false );
		SaveLastUsedCombatGadget( scriptInterface, activeGadget );
		SetCombatGadgetAnimFeature( scriptInterface, false, false );
		SetLeftHandAnimationAnimFeature( scriptInterface, true );
		stateContext.SetTemporaryBoolParameter( 'InterruptSprint', true, true );
	}

}

class CombatGadgetEquipDecisions extends CombatGadgetTransitions
{

	protected constexpr export const function ToCombatGadgetQuickThrow( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return false;
	}

	protected export const function ToCombatGadgetCharge( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var isKereznikowActive : Bool;
		isKereznikowActive = scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.Locomotion ) == ( ( Int32 )( gamePSMLocomotionStates.Kereznikov ) );
		return ( CheckItemCategoryInQuickWheel( scriptInterface, gamedataItemCategory.Gadget ) && !( stateContext.GetBoolParameter( 'CancelAction', true ) ) ) && !( isKereznikowActive );
	}

	protected const function ToCombatGadgetWaitForUnequip( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		if( scriptInterface.IsActionJustPressed( 'Reload' ) || ( scriptInterface.IsActionJustPressed( 'SwitchItem' ) && !( IsInInputContextState( stateContext, 'aimingContext' ) ) ) )
		{
			return true;
		}
		if( ( ( ( ( ( ( ( stateContext.IsStateActive( 'Locomotion', 'superheroFall' ) || stateContext.IsStateActive( 'Locomotion', 'vault' ) ) || IsInLadderState( stateContext ) ) || stateContext.IsStateActive( 'Vehicle', 'exitingCombat' ) ) || CheckVehicleStatesForUnequipRequest( stateContext ) ) || GetCancelGrenadeAction( stateContext ) ) || IsInSafeZone( scriptInterface ) ) || IsInSafeSceneTier( scriptInterface ) ) || stateContext.GetBoolParameter( 'CancelAction', true ) )
		{
			return true;
		}
		else
		{
			return scriptInterface.localBlackboard.GetInt( GetAllBlackboardDefs().PlayerStateMachine.CombatGadget ) == ( ( Int32 )( gamePSMCombatGadget.WaitForUnequip ) );
		}
	}

	protected const function ToCombatGadgetUnequip( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return ( ( ( stateContext.IsStateActive( 'Locomotion', 'climb' ) || stateContext.IsStateActive( 'HighLevel', 'swimming' ) ) || CheckVehicleStatesForUnequipRequest( stateContext ) ) || StatusEffectSystem.ObjectHasStatusEffectOfType( scriptInterface.executionOwner, gamedataStatusEffectType.Knockdown ) ) || IsPlayerInAnyMenu( scriptInterface );
	}

}

class CombatGadgetEquipEvents extends CombatGadgetTransitions
{

	protected export virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetBlackbordThrowUnequip( scriptInterface, false );
		scriptInterface.TEMP_WeaponStopFiring();
		scriptInterface.PushAnimationEvent( 'CombatGadgetEquip' );
		stateContext.RemovePermanentBoolParameter( 'cgCached' );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CombatGadget, ( ( Int32 )( gamePSMCombatGadget.Equipped ) ) );
	}

	protected export function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( GetInStateTime() >= 0.1 )
		{
			SetItemInLeftHand( scriptInterface, true );
		}
	}

}

class CombatGadgetQuickThrowDecisions extends CombatGadgetTransitions
{

	protected const function ToCombatGadgetUnequip( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetInStateTime() >= GetStaticFloatParameterDefault( "postThrowDelay", 0.5 );
	}

}

class CombatGadgetQuickThrowEvents extends CombatGadgetTransitions
{
	var m_grenadeThrown : Bool;
	var m_event : Bool;

	protected virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var broadcaster : StimBroadcasterComponent;
		broadcaster = scriptInterface.executionOwner.GetStimBroadcasterComponent();
		if( broadcaster )
		{
			broadcaster.TriggerSingleBroadcast( scriptInterface.executionOwner, gamedataStimType.IllegalAction );
		}
		SetCombatGadgetAnimFeature( scriptInterface, true, false );
		SetBlackbordThrowUnequip( scriptInterface, true );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CombatGadget, ( ( Int32 )( gamePSMCombatGadget.QuickThrow ) ) );
		PlayRumble( scriptInterface, "medium_pulse" );
		stateContext.SetTemporaryBoolParameter( 'InterruptAiming', true, true );
		if( stateContext.IsStateActive( 'UpperBody', 'aimingState' ) && stateContext.IsStateActive( 'CoverAction', 'activateCover' ) )
		{
			stateContext.SetPermanentBoolParameter( 'QuickthrowHoldPeek', true, true );
		}
		m_grenadeThrown = false;
		m_event = false;
	}

	protected function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( ( GetInStateTime() >= 0.05 ) && !( m_event ) )
		{
			scriptInterface.PushAnimationEvent( 'CombatGadgetQuickThrow' );
			SetThrowableAnimFeatureOnGrenade( scriptInterface, 2, true );
			m_event = true;
		}
		if( ( GetInStateTime() >= GetStaticFloatParameterDefault( "releaseTime", 0.2 ) ) && !( m_grenadeThrown ) )
		{
			m_grenadeThrown = true;
			Throw( scriptInterface, stateContext, true );
			RemoveGrenadeFromInventory( scriptInterface );
		}
	}

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

class CombatGadgetChargedThrowDecisions extends CombatGadgetTransitions
{

	protected export const function ToCombatGadgetWaitForUnequip( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetInStateTime() >= GetStaticFloatParameterDefault( "releaseTime", 0.2 );
	}

}

class CombatGadgetChargedThrowEvents extends CombatGadgetTransitions
{
	var m_grenadeThrown : Bool;
	var m_localAimForward : Vector4;
	var m_localAimPosition : Vector4;

	protected export virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var targetingSystem : TargetingSystem;
		var aimPosition : Vector4;
		var aimForward : Vector4;
		var ownerWorldTransform : WorldTransform;
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CombatGadget, ( ( Int32 )( gamePSMCombatGadget.Throwing ) ) );
		SetBlackbordThrowUnequip( scriptInterface, true );
		SetItemInLeftHand( scriptInterface, false );
		SetCombatGadgetAnimFeature( scriptInterface, false, true );
		scriptInterface.PushAnimationEvent( 'CombatGadgetChargedThrow' );
		SetThrowableAnimFeatureOnGrenade( scriptInterface, 2, false );
		m_grenadeThrown = false;
		PlayRumble( scriptInterface, "heavy_pulse" );
		targetingSystem = scriptInterface.GetTargetingSystem();
		targetingSystem.GetDefaultCrosshairData( scriptInterface.executionOwner, aimPosition, aimForward );
		ownerWorldTransform = scriptInterface.executionOwner.GetWorldTransform();
		m_localAimForward = WorldTransform.TransformInvPoint( ownerWorldTransform, scriptInterface.executionOwner.GetWorldPosition() + aimForward );
		m_localAimPosition = WorldTransform.TransformInvPoint( ownerWorldTransform, aimPosition );
	}

	protected export function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		if( ( GetInStateTime() >= GetStaticFloatParameterDefault( "releaseTime", 0.2 ) ) && !( m_grenadeThrown ) )
		{
			m_grenadeThrown = true;
			Throw( scriptInterface, stateContext, false, m_localAimForward, m_localAimPosition );
			RemoveGrenadeFromInventory( scriptInterface );
		}
	}

}

class CombatGadgetChargeDecisions extends CombatGadgetTransitions
{

	protected export const function ToCombatGadgetChargedThrow( stateContext : StateContext, scriptInterface : StateGameScriptInterface ) : Bool
	{
		return ( ( ( ( ( ( scriptInterface.GetActionValue( 'UseCombatGadget' ) == 0.0 ) && ( scriptInterface.GetActionValue( 'VisionHold' ) == 0.0 ) ) && !( IsRightHandInUnequippingState( stateContext ) ) ) && IsLeftHandInEquippedState( stateContext ) ) && CheckEquipDurationCondition( scriptInterface, stateContext ) ) && !( IsInFocusMode( scriptInterface ) ) ) && !( IsPlayerInAnyMenu( scriptInterface ) );
	}

	protected export const function ToCombatGadgetWaitForUnequip( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var locomotionState : CName;
		locomotionState = stateContext.GetStateMachineCurrentState( 'Locomotion' );
		if( ( ( ( ( ( ( ( ( ( ( locomotionState == 'superheroFall' || locomotionState == 'ladder' ) || locomotionState == 'ladderSprint' ) || locomotionState == 'ladderSlide' ) || CheckVehicleStatesForUnequipRequest( stateContext ) ) || GetCancelGrenadeAction( stateContext ) ) || IsInSafeZone( scriptInterface ) ) || IsSafeStateForced( stateContext, scriptInterface ) ) || ( scriptInterface.GetActionValue( 'VisionHold' ) != 0.0 ) ) || IsInFocusMode( scriptInterface ) ) || ShouldForceUnequipGrenade( scriptInterface ) ) || IsInSafeSceneTier( scriptInterface ) )
		{
			return true;
		}
		return false;
	}

	protected export const function ToCombatGadgetUnequip( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		var locomotionState : CName;
		locomotionState = stateContext.GetStateMachineCurrentState( 'Locomotion' );
		if( ( ( ( ( ( ( locomotionState == 'climb' || stateContext.IsStateActive( 'HighLevel', 'swimming' ) ) || CheckVehicleStatesForUnequipRequest( stateContext ) ) || StatusEffectSystem.ObjectHasStatusEffectOfType( scriptInterface.executionOwner, gamedataStatusEffectType.Knockdown ) ) || IsPlayerInAnyMenu( scriptInterface ) ) || scriptInterface.IsActionJustReleased( 'OpenPauseMenu' ) ) || scriptInterface.executionOwner.GetTakeOverControlSystem().IsDeviceControlled() ) || locomotionState == 'vehicleKnockdown' )
		{
			return true;
		}
		return false;
	}

	protected export const function ToCombatGadgetEquip( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetCancelChargeButtonInput( scriptInterface );
	}

}

class CombatGadgetChargeEvents extends CombatGadgetTransitions
{
	var initiated : Bool;
	var itemSwitched : Bool;

	protected export virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var broadcaster : StimBroadcasterComponent;
		broadcaster = scriptInterface.executionOwner.GetStimBroadcasterComponent();
		if( broadcaster )
		{
			broadcaster.AddActiveStimuli( scriptInterface.executionOwner, gamedataStimType.IllegalInteraction, -1.0 );
		}
		DisableCameraBobbing( stateContext, scriptInterface, true );
		ShowInputHint( scriptInterface, 'CancelChargingCG', 'Locomotion', "LocKey#49906" );
		initiated = false;
		itemSwitched = false;
		stateContext.SetPermanentBoolParameter( 'rightHandThrow', true, true );
		SetCombatGadgetAnimFeature( scriptInterface, false, true );
		if( IsRightHandInEquippedState( stateContext ) )
		{
			stateContext.SetPermanentBoolParameter( 'forceTempUnequipWeapon', true, true );
		}
	}

	protected export function OnUpdate( timeDelta : Float, stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var puppet : PlayerPuppet;
		var transactionSystem : TransactionSystem;
		var itemObject : ItemObject;
		var setupEvent : gameprojectileSetUpEvent;
		if( ( !( initiated ) && IsRightHandInUnequippedState( stateContext ) ) && !( itemSwitched ) )
		{
			SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CombatGadget, ( ( Int32 )( gamePSMCombatGadget.Charging ) ) );
			scriptInterface.PushAnimationEvent( 'CombatGadgetCharge' );
			scriptInterface.TEMP_WeaponStopFiring();
			puppet = ( ( PlayerPuppet )( scriptInterface.executionOwner ) );
			transactionSystem = scriptInterface.GetTransactionSystem();
			itemObject = transactionSystem.GetItemInSlot( puppet, T"AttachmentSlots.WeaponLeft" );
			if( itemObject )
			{
				transactionSystem.ChangeItemToSlot( scriptInterface.executionOwner, T"AttachmentSlots.WeaponRight", itemObject.GetItemID() );
				initiated = true;
			}
		}
		if( initiated && !( itemSwitched ) )
		{
			itemObject = transactionSystem.GetItemInSlot( puppet, T"AttachmentSlots.WeaponRight" );
			if( itemObject )
			{
				setupEvent = new gameprojectileSetUpEvent;
				setupEvent.owner = puppet;
				setupEvent.trajectoryParams = CreateTrajectoryParams( itemObject, false );
				itemObject.QueueEvent( setupEvent );
				SetThrowableAnimFeatureOnGrenade( scriptInterface, 1, itemObject );
				itemSwitched = true;
			}
		}
		if( CheckEquipDurationCondition( scriptInterface, stateContext ) )
		{
			TogglePreview( true, scriptInterface, stateContext );
		}
	}

	protected export function OnExitToCombatGadgetChargedThrow( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		scriptInterface.TEMP_WeaponStopFiring();
		TogglePreview( false, scriptInterface, stateContext );
		RemoveActiveStimuli( scriptInterface.executionOwner );
		DisableCameraBobbing( stateContext, scriptInterface, false );
		RemoveInputHint( scriptInterface, 'CancelChargingCG', 'Locomotion' );
	}

	protected function OnExitToCombatGadgetWaitForUnequip( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		scriptInterface.TEMP_WeaponStopFiring();
		TogglePreview( false, scriptInterface, stateContext );
		RemoveActiveStimuli( scriptInterface.executionOwner );
		DisableCameraBobbing( stateContext, scriptInterface, false );
		RemoveInputHint( scriptInterface, 'CancelChargingCG', 'Locomotion' );
	}

	protected function OnExitToCombatGadgetUnequip( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		scriptInterface.TEMP_WeaponStopFiring();
		TogglePreview( false, scriptInterface, stateContext );
		RemoveActiveStimuli( scriptInterface.executionOwner );
		DisableCameraBobbing( stateContext, scriptInterface, false );
		RemoveInputHint( scriptInterface, 'CancelChargingCG', 'Locomotion' );
	}

	protected function OnExitToCombatGadgetEquip( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		scriptInterface.TEMP_WeaponStopFiring();
		scriptInterface.PushAnimationEvent( 'CombatGadgetStopCharge' );
		stateContext.SetPermanentBoolParameter( 'CancelAction', true, true );
		TogglePreview( false, scriptInterface, stateContext );
		RemoveActiveStimuli( scriptInterface.executionOwner );
		DisableCameraBobbing( stateContext, scriptInterface, false );
		RemoveInputHint( scriptInterface, 'CancelChargingCG', 'Locomotion' );
	}

	protected function TogglePreview( on : Bool, scriptInterface : StateGameScriptInterface, stateContext : StateContext )
	{
		var transactionSystem : TransactionSystem;
		var itemObject : ItemObject;
		var showPreviewEvent : gameprojectileProjectilePreviewEvent;
		if( !( scriptInterface.executionOwner.IsControlledByLocalPeer() ) )
		{
			return;
		}
		stateContext.SetPermanentBoolParameter( 'CombatGadgetPreviewShown', on, true );
		transactionSystem = scriptInterface.GetTransactionSystem();
		itemObject = transactionSystem.GetItemInSlot( ( ( PlayerPuppet )( scriptInterface.executionOwner ) ), GetSlotTDBID( stateContext ) );
		if( itemObject )
		{
			showPreviewEvent = new gameprojectileProjectilePreviewEvent;
			showPreviewEvent.previewActive = on;
			itemObject.QueueEvent( showPreviewEvent );
		}
	}

	private function RemoveActiveStimuli( owner : GameObject )
	{
		var broadcaster : StimBroadcasterComponent;
		broadcaster = owner.GetStimBroadcasterComponent();
		if( broadcaster )
		{
			broadcaster.RemoveActiveStimuliByName( owner, gamedataStimType.IllegalInteraction );
		}
	}

}

class CombatGadgetWaitForUnequipDecisions extends CombatGadgetTransitions
{

	protected export const function ToCombatGadgetUnequip( const stateContext : StateContext, const scriptInterface : StateGameScriptInterface ) : Bool
	{
		return GetInStateTime() >= GetStaticFloatParameterDefault( "UnequipDuration", 0.2 );
	}

}

class CombatGadgetWaitForUnequipEvents extends CombatGadgetTransitions
{

	protected export virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CombatGadget, ( ( Int32 )( gamePSMCombatGadget.WaitForUnequip ) ) );
		scriptInterface.PushAnimationEvent( 'CombatGadgetUnequip' );
		SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.UnequipGadget );
		if( !( stateContext.GetBoolParameter( 'rightHandThrow', true ) ) )
		{
			SetLeftHandAnimationAnimFeature( scriptInterface, false );
		}
	}

	protected function OnForcedExit( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		SetLeftHandAnimationAnimFeature( scriptInterface, false );
		SetItemInLeftHand( scriptInterface, false );
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CombatGadget, ( ( Int32 )( gamePSMCombatGadget.Default ) ) );
		SetLeftHandItemHandlingItemState( scriptInterface, 0 );
		stateContext.RemovePermanentBoolParameter( 'CancelAction' );
		stateContext.RemovePermanentBoolParameter( 'forceTempUnequipWeapon' );
		stateContext.RemovePermanentBoolParameter( 'rightHandThrow' );
		stateContext.RemovePermanentBoolParameter( 'lockHold' );
		ClearItemIDWrapperPermanentParameter( stateContext, 'grenade' );
	}

}

class CombatGadgetUnequipEvents extends CombatGadgetTransitions
{

	protected export virtual function OnEnter( stateContext : StateContext, scriptInterface : StateGameScriptInterface )
	{
		var psmRemove : PSMRemoveOnDemandStateMachine;
		var psmIdent : StateMachineIdentifier;
		psmRemove = new PSMRemoveOnDemandStateMachine;
		SetBlackboardIntVariable( scriptInterface, GetAllBlackboardDefs().PlayerStateMachine.CombatGadget, ( ( Int32 )( gamePSMCombatGadget.Default ) ) );
		SetLeftHandAnimationAnimFeature( scriptInterface, false );
		SetCombatGadgetAnimFeature( scriptInterface, false, false );
		SetItemInLeftHand( scriptInterface, false );
		SetLeftHandItemHandlingItemState( scriptInterface, 0 );
		SendEquipmentSystemWeaponManipulationRequest( scriptInterface, EquipmentManipulationAction.UnequipGadget );
		if( stateContext.GetBoolParameter( 'rightHandThrow', true ) )
		{
			RemoveGrenadeFromRightHand( scriptInterface );
		}
		stateContext.RemoveConditionBoolParameter( 'lockHold' );
		stateContext.RemovePermanentBoolParameter( 'CancelAction' );
		stateContext.RemovePermanentBoolParameter( 'forceTempUnequipWeapon' );
		stateContext.RemovePermanentBoolParameter( 'rightHandThrow' );
		psmIdent.definitionName = 'CombatGadget';
		psmRemove.stateMachineIdentifier = psmIdent;
		scriptInterface.executionOwner.QueueEvent( psmRemove );
		ClearItemIDWrapperPermanentParameter( stateContext, 'grenade' );
	}

}

