import class gameuiBaseMenuGameController extends inkGameController
{
	protected import function GetPuppet( sceneName : CName ) : gamePuppet;
	protected import function SpawnMenuInstanceEvent( eventName : CName );
	protected import function SpawnMenuInstanceDataEvent( eventName : CName, userData : IScriptable );
}

class DeathMenuDelayEvent extends Event
{
}

class ResetItemAppearanceInSlotDelayEvent extends Event
{
	var slotID : TweakDBID;
}

class SetZoomLevelEvent extends Event
{
	var m_value : Int32;

	public function SetZoom( zoomValue : Int32 )
	{
		m_value = zoomValue;
	}

}

class DelayedRegisterToGlobalInputCallbackEvent extends Event
{
}

class DelayedHandleQuickLoadEvent extends Event
{
}

class inGameMenuAnimContainer
{
	var m_animProxy : inkAnimProxy;
}

import class gameuiInGameMenuGameController extends gameuiBaseMenuGameController
{
	private var m_quickSaveInProgress : Bool;
	private var m_wasHoldingMapHotKey : Bool;
	private var m_controllerDisconnected : Bool;
	default m_controllerDisconnected = false;
	private var m_showDeathScreenBBID : CallbackHandle;
	private var m_breachingNetworkBBID : CallbackHandle;
	private var m_triggerMenuEventBBID : CallbackHandle;
	private var m_openStorageBBID : CallbackHandle;
	private var m_controllerDisconnectedBBID : CallbackHandle;
	private var m_bbOnEquipmentChangedID : CallbackHandle;
	private var m_inputSchemesBBID : CallbackHandle;
	private var m_inventoryListener : AttachmentSlotsScriptListener;
	private var m_animContainer : inGameMenuAnimContainer;
	private var m_lastInGameNotificationType : UIInGameNotificationType;
	private var m_loadSaveDelayID : DelayID;
	private var m_player : weak< GameObject >;

	protected event OnInitialize()
	{
		RegisterGlobalBlackboards();
		GetSystemRequestsHandler().RegisterToCallback( 'OnSavingComplete', this, 'OnSavingComplete' );
		m_animContainer = new inGameMenuAnimContainer;
	}

	protected event OnDelayedRegisterToGlobalInputCallbackEvent( evt : DelayedRegisterToGlobalInputCallbackEvent )
	{
		RegisterToGlobalInputCallback( 'OnPostOnRelease', this, 'OnHandleMenuInput' );
	}

	protected event OnUninitialize()
	{
		GetSystemRequestsHandler().UnregisterFromCallback( 'OnSavingComplete', this, 'OnSavingComplete' );
		UnregisterFromGlobalInputCallback( 'OnPostOnRelease', this, 'OnHandleMenuInput' );
		UnregisterGlobalBlackboards();
	}

	private function RegisterGlobalBlackboards()
	{
		var m_equipmentBlackboard : IBlackboard;
		var m_networkBlackboard : IBlackboard;
		var m_menuEventBlackboard : IBlackboard;
		var m_storageBlackboard : IBlackboard;
		var m_uiDataBlackboard : IBlackboard;
		var m_inputSchemesBlackboard : IBlackboard;
		m_equipmentBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_Equipment );
		if( m_equipmentBlackboard )
		{
			m_bbOnEquipmentChangedID = m_equipmentBlackboard.RegisterListenerVariant( GetAllBlackboardDefs().UI_Equipment.lastModifiedArea, this, 'OnEquipmentChanged' );
		}
		m_networkBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().NetworkBlackboard );
		if( m_networkBlackboard )
		{
			m_breachingNetworkBBID = m_networkBlackboard.RegisterDelayedListenerString( GetAllBlackboardDefs().NetworkBlackboard.NetworkName, this, 'OnBreachingNetwork' );
		}
		m_menuEventBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().MenuEventBlackboard );
		if( m_menuEventBlackboard )
		{
			m_triggerMenuEventBBID = m_menuEventBlackboard.RegisterDelayedListenerName( GetAllBlackboardDefs().MenuEventBlackboard.MenuEventToTrigger, this, 'OnTriggerMenuEvent' );
		}
		m_storageBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().StorageBlackboard );
		if( m_storageBlackboard )
		{
			m_openStorageBBID = m_storageBlackboard.RegisterDelayedListenerVariant( GetAllBlackboardDefs().StorageBlackboard.StorageData, this, 'OnOpenStorage' );
		}
		m_uiDataBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().UIGameData );
		if( m_uiDataBlackboard )
		{
			m_controllerDisconnectedBBID = m_uiDataBlackboard.RegisterListenerBool( GetAllBlackboardDefs().UIGameData.Controller_Disconnected, this, 'OnDisconnectController' );
		}
		m_inputSchemesBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().InputSchemes );
		if( m_inputSchemesBlackboard )
		{
			m_inputSchemesBBID = m_inputSchemesBlackboard.RegisterListenerUint( GetAllBlackboardDefs().InputSchemes.Scheme, this, 'OnInputSchemeChanged' );
		}
	}

	private function UnregisterGlobalBlackboards()
	{
		var m_equipmentBlackboard : IBlackboard;
		var m_networkBlackboard : IBlackboard;
		var m_menuEventBlackboard : IBlackboard;
		var m_storageBlackboard : IBlackboard;
		var m_uiDataBlackboard : IBlackboard;
		var m_inputSchemesBlackboard : IBlackboard;
		m_equipmentBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().UI_Equipment );
		if( m_equipmentBlackboard )
		{
			m_equipmentBlackboard.UnregisterListenerVariant( GetAllBlackboardDefs().UI_Equipment.lastModifiedArea, m_bbOnEquipmentChangedID );
		}
		m_networkBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().NetworkBlackboard );
		if( m_networkBlackboard )
		{
			m_networkBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().NetworkBlackboard.NetworkName, m_breachingNetworkBBID );
		}
		m_menuEventBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().MenuEventBlackboard );
		if( m_menuEventBlackboard )
		{
			m_menuEventBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().MenuEventBlackboard.MenuEventToTrigger, m_triggerMenuEventBBID );
		}
		m_storageBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().StorageBlackboard );
		if( m_storageBlackboard )
		{
			m_storageBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().StorageBlackboard.StorageData, m_openStorageBBID );
		}
		m_uiDataBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().StorageBlackboard );
		if( m_uiDataBlackboard )
		{
			m_uiDataBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().UIGameData.Controller_Disconnected, m_controllerDisconnectedBBID );
		}
		m_inputSchemesBlackboard = GetBlackboardSystem().Get( GetAllBlackboardDefs().InputSchemes );
		if( m_inputSchemesBlackboard )
		{
			m_inputSchemesBlackboard.UnregisterDelayedListener( GetAllBlackboardDefs().InputSchemes.Scheme, m_inputSchemesBBID );
		}
	}

	protected event OnPlayerAttach( playerPuppet : GameObject )
	{
		var delayEvt : DelayedRegisterToGlobalInputCallbackEvent;
		RegisterInputListenersForPlayer( playerPuppet );
		RegisterPSMListeners( playerPuppet );
		delayEvt = new DelayedRegisterToGlobalInputCallbackEvent;
		QueueEvent( delayEvt );
		m_player = playerPuppet;
	}

	protected event OnPlayerDetach( playerPuppet : GameObject )
	{
		UnregisterInputListenersForPlayer( playerPuppet );
		UnregisterPSMListeners( playerPuppet );
		UnregisterInventoryListener();
	}

	protected function RegisterPSMListeners( playerPuppet : GameObject )
	{
		var playerSMDef : PlayerStateMachineDef;
		var deathBlackboard : IBlackboard;
		playerSMDef = GetAllBlackboardDefs().PlayerStateMachine;
		if( playerSMDef )
		{
			deathBlackboard = GetPSMBlackboard( playerPuppet );
			if( deathBlackboard )
			{
				m_showDeathScreenBBID = deathBlackboard.RegisterListenerBool( playerSMDef.DisplayDeathMenu, this, 'OnDisplayDeathMenu' );
			}
		}
	}

	protected function UnregisterPSMListeners( playerPuppet : GameObject )
	{
		var playerSMDef : PlayerStateMachineDef;
		var deathBlackboard : IBlackboard;
		playerSMDef = GetAllBlackboardDefs().PlayerStateMachine;
		if( playerSMDef )
		{
			deathBlackboard = GetPSMBlackboard( playerPuppet );
			if( deathBlackboard )
			{
				deathBlackboard.UnregisterDelayedListener( playerSMDef.DisplayDeathMenu, m_showDeathScreenBBID );
			}
		}
	}

	private function RegisterInputListenersForPlayer( playerPuppet : GameObject )
	{
		if( playerPuppet.IsControlledByLocalPeer() )
		{
			playerPuppet.RegisterInputListener( this, 'OpenPauseMenu' );
			playerPuppet.RegisterInputListener( this, 'OpenMapMenu' );
			playerPuppet.RegisterInputListener( this, 'OpenCraftingMenu' );
			playerPuppet.RegisterInputListener( this, 'OpenJournalMenu' );
			playerPuppet.RegisterInputListener( this, 'OpenPerksMenu' );
			playerPuppet.RegisterInputListener( this, 'OpenInventoryMenu' );
			playerPuppet.RegisterInputListener( this, 'OpenHubMenu' );
			playerPuppet.RegisterInputListener( this, 'QuickSave' );
			playerPuppet.RegisterInputListener( this, 'QuickLoad' );
			playerPuppet.RegisterInputListener( this, 'FastForward_Hold' );
		}
	}

	private function RegisterInventoryListener()
	{
		var puppetListener : ItemInPaperdollSlotCallback;
		var puppet : gamePuppet;
		puppet = GetPuppet( 'inventory' );
		puppetListener = new ItemInPaperdollSlotCallback;
		puppetListener.SetPuppetRef( puppet );
		m_inventoryListener = GameInstance.GetTransactionSystem( puppet.GetGame() ).RegisterAttachmentSlotListener( puppet, puppetListener );
	}

	private function UnregisterInventoryListener()
	{
		var puppet : gamePuppet;
		puppet = GetPuppet( 'inventory' );
		GameInstance.GetTransactionSystem( puppet.GetGame() ).UnregisterAttachmentSlotListener( puppet, m_inventoryListener );
		m_inventoryListener = NULL;
	}

	private function UnregisterInputListenersForPlayer( playerPuppet : GameObject )
	{
		if( playerPuppet.IsControlledByLocalPeer() )
		{
			playerPuppet.UnregisterInputListener( this );
		}
	}

	protected event OnAction( action : ListenerAction, consumer : ListenerActionConsumer )
	{
		var isPlayerLastUsedKBM : Bool;
		var gameInstance : GameInstance;
		var questsSystem : QuestsSystem;
		var isDuringNonUICutscene : Bool;
		gameInstance = GetPlayerControlledObject().GetGame();
		questsSystem = GameInstance.GetQuestsSystem( gameInstance );
		isDuringNonUICutscene = questsSystem.GetFact( 'q301_02a_stadium_stopUIInCutscene' );
		if( m_controllerDisconnected || isDuringNonUICutscene )
		{
			return false;
		}
		if( ListenerAction.GetType( action ) == gameinputActionType.BUTTON_PRESSED )
		{
			if( ListenerAction.GetName( action ) == 'QuickSave' )
			{
				HandleQuickSave();
			}
		}
		if( ListenerAction.GetType( action ) == gameinputActionType.BUTTON_RELEASED )
		{
			if( ListenerAction.GetName( action ) == 'OpenPauseMenu' )
			{
				SpawnMenuInstanceEvent( 'OnOpenPauseMenu' );
				ListenerActionConsumer.Consume( consumer );
			}
			else if( ListenerAction.GetName( action ) == 'OpenHubMenu' )
			{
				SpawnMenuInstanceEvent( ( ( GetFact( m_player.GetGame(), 'radial_hub_menu_enabled' ) > 0 ) ? ( 'OnOpenRadialHubMenu' ) : ( 'OnOpenHubMenu' ) ) );
			}
			else if( ListenerAction.GetName( action ) == 'QuickLoad' )
			{
				DelayedHandleQuickLoad();
			}
		}
		if( ListenerAction.GetType( action ) == gameinputActionType.BUTTON_HOLD_COMPLETE && ListenerAction.GetName( action ) == 'OpenMapMenu' )
		{
			m_wasHoldingMapHotKey = true;
		}
		isPlayerLastUsedKBM = GetPlayerControlledObject().PlayerLastUsedKBM();
		if( ( ListenerAction.GetType( action ) == gameinputActionType.BUTTON_HOLD_COMPLETE && !( isPlayerLastUsedKBM ) ) || ( ListenerAction.GetType( action ) == gameinputActionType.BUTTON_RELEASED && isPlayerLastUsedKBM ) )
		{
			if( ( ( ListenerAction.GetName( action ) == 'OpenMapMenu' || ListenerAction.GetName( action ) == 'OpenJournalMenu' ) || ListenerAction.GetName( action ) == 'OpenPerksMenu' ) || ListenerAction.GetName( action ) == 'OpenInventoryMenu' )
			{
				OpenShortcutMenu( ListenerAction.GetName( action ) );
			}
			else if( ListenerAction.GetName( action ) == 'OpenCraftingMenu' )
			{
				TryOpenCraftingMenu( ListenerAction.GetName( action ) );
			}
		}
	}

	protected event OnHandleMenuInput( evt : inkPointerEvent )
	{
		if( evt.IsAction( 'back' ) )
		{
			SpawnMenuInstanceEvent( 'OnBack' );
		}
		if( evt.IsAction( 'toggle_menu' ) && !( StatusEffectSystem.ObjectHasStatusEffectWithTag( GetPlayerControlledObject(), 'LockInHubMenu' ) ) )
		{
			SpawnMenuInstanceEvent( 'OnCloseHubMenuRequest' );
		}
		if( HubMenuUtility.IsPlayerHardwareDisabled( m_player ) && !( evt.IsAction( 'toggle_journal' ) ) )
		{
			return false;
		}
		if( evt.IsAction( 'toggle_inventory' ) )
		{
			SpawnMenuInstanceEvent( 'OnHotkeySwitchToInventory' );
		}
		if( evt.IsAction( 'toggle_perks' ) )
		{
			SpawnMenuInstanceEvent( 'OnHotkeySwitchToPerks' );
		}
		if( evt.IsAction( 'toggle_journal' ) && ( !( evt.IsHandled() ) || !( evt.IsConsumed() ) ) )
		{
			SpawnMenuInstanceEvent( 'OnHotkeySwitchToJournal' );
			evt.Handle();
			evt.Consume();
		}
		if( evt.IsAction( 'toggle_map' ) && ( !( evt.IsHandled() ) || !( evt.IsConsumed() ) ) )
		{
			if( m_wasHoldingMapHotKey == false )
			{
				SpawnMenuInstanceEvent( 'OnHotkeySwitchToMap' );
			}
			m_wasHoldingMapHotKey = false;
		}
		if( evt.IsAction( 'toggle_crafting' ) )
		{
			SpawnMenuInstanceEvent( 'OnHotkeySwitchToCrafting' );
		}
	}

	protected event OnRequestHubMenu( evt : StartHubMenuEvent )
	{
		var eventName : CName;
		eventName = ( ( GetFact( m_player.GetGame(), 'radial_hub_menu_enabled' ) > 0 ) ? ( 'OnOpenRadialHubMenu_InitData' ) : ( 'OnOpenHubMenu_InitData' ) );
		SpawnMenuInstanceDataEvent( eventName, evt.m_initData );
	}

	protected event OnForceCloseHubMenuEvent( evt : ForceCloseHubMenuEvent )
	{
		SpawnMenuInstanceEvent( 'OnCloseHubMenuRequest' );
	}

	protected event OnBreachingNetwork( value : String )
	{
		if( IsStringValid( value ) )
		{
			SpawnMenuInstanceEvent( 'OnNetworkBreachBegin' );
		}
		else
		{
			SpawnMenuInstanceEvent( 'OnNetworkBreachEnd' );
		}
	}

	protected event OnOpenStorage( value : Variant )
	{
		SpawnMenuInstanceEvent( 'OnShowStorageMenu' );
	}

	protected event OnDisconnectController( value : Bool )
	{
		m_controllerDisconnected = value;
	}

	protected event OnTriggerMenuEvent( value : CName )
	{
		SpawnMenuInstanceEvent( value );
	}

	protected event OnOpenWardrobe( value : Variant )
	{
		SpawnMenuInstanceEvent( 'OnOpenWardrobeMenu' );
	}

	protected event OnTimeSkipFinishEvent( evt : TimeSkipFinishEvent )
	{
		SpawnMenuInstanceEvent( 'OnTimeSkipPopupClosed' );
	}

	protected event OnDisplayDeathMenu( value : Bool )
	{
		var evt : DeathMenuDelayEvent;
		var delay : Float;
		var playerControlledObject : GameObject;
		var wasPlayerForceKilled : Bool;
		if( !( value ) )
		{
			return false;
		}
		if( IsMultiplayer() )
		{
			return false;
		}
		playerControlledObject = GetPlayerControlledObject();
		wasPlayerForceKilled = StatusEffectSystem.ObjectHasStatusEffect( playerControlledObject, T"BaseStatusEffect.ForceKill" );
		delay = ( ( wasPlayerForceKilled ) ? ( TDB.GetFloat( T"player.deathMenu.delayToDisplayKillTrigger", 3.0 ) ) : ( TDB.GetFloat( T"player.deathMenu.delayToDisplay", 3.0 ) ) );
		evt = new DeathMenuDelayEvent;
		GameInstance.GetDelaySystem( playerControlledObject.GetGame() ).DelayEvent( playerControlledObject, evt, delay );
	}

	protected event OnDeathScreenDelayEvent( evt : DeathMenuDelayEvent )
	{
		SpawnMenuInstanceEvent( 'OnShowDeathMenu' );
	}

	protected event OnResetItemAppearanceInSlotDelayEvent( evt : ResetItemAppearanceInSlotDelayEvent )
	{
		var puppet : gamePuppet;
		var transactionSystem : TransactionSystem;
		var itemID : ItemID;
		puppet = GetPuppet( 'inventory' );
		transactionSystem = GameInstance.GetTransactionSystem( puppet.GetGame() );
		itemID = transactionSystem.GetItemInSlot( puppet, evt.slotID ).GetItemID();
		if( ItemID.IsValid( itemID ) )
		{
			transactionSystem.ResetItemAppearance( puppet, itemID );
		}
	}

	protected event OnArcadeMinigameEvent( value : String )
	{
		if( IsStringValid( value ) )
		{
			SpawnMenuInstanceEvent( 'OnArcadeMinigameBegin' );
		}
		else
		{
			SpawnMenuInstanceEvent( 'OnArcadeMinigameEnd' );
		}
	}

	protected event OnPuppetReady( sceneName : CName, puppet : gamePuppet )
	{
		var equipData : EquipmentSystemPlayerData;
		var transactionSystem : TransactionSystem;
		var item : ItemID;
		var equipAreas : array< SEquipArea >;
		var i : Int32;
		var gender : CName;
		var head : ItemID;
		var placementSlot : TweakDBID;
		var itemData : weak< gameItemData >;
		RegisterInventoryListener();
		transactionSystem = GameInstance.GetTransactionSystem( puppet.GetGame() );
		equipData = EquipmentSystem.GetData( GetPlayer( puppet.GetGame() ) );
		if( equipData )
		{
			equipAreas = equipData.GetPaperDollEquipAreas();
		}
		for( i = 0; i < equipAreas.Size(); i += 1 )
		{
			item = equipData.GetVisualItemInSlot( equipAreas[ i ].areaType );
			placementSlot = EquipmentSystem.GetPlacementSlot( item );
			if( equipAreas[ i ].areaType == gamedataEquipmentArea.RightArm )
			{
				item = ItemID.FromTDBID( ItemID.GetTDBID( equipData.GetActiveItem( equipAreas[ i ].areaType ) ) );
				transactionSystem.GiveItem( puppet, item, 1 );
				transactionSystem.AddItemToSlot( puppet, EquipmentSystem.GetPlacementSlot( item ), item );
			}
			else
			{
				if( !( equipData ) || !( equipData.IsSlotHidden( equipAreas[ i ].areaType ) ) )
				{
					if( EquipmentSystem.IsClothing( item ) )
					{
						transactionSystem.GivePreviewItemByItemID( puppet, item );
					}
					else
					{
						itemData = transactionSystem.GetItemData( GetPlayerControlledObject(), item );
						transactionSystem.GivePreviewItemByItemData( puppet, itemData );
					}
					transactionSystem.AddItemToSlot( puppet, placementSlot, transactionSystem.CreatePreviewItemID( item ) );
				}
			}
		}
		gender = puppet.GetResolvedGenderName();
		if( gender == 'Male' )
		{
			head = ItemID.FromTDBID( T"Items.PlayerMaTppHead" );
		}
		else if( gender == 'Female' )
		{
			head = ItemID.FromTDBID( T"Items.PlayerWaTppHead" );
		}
		transactionSystem.GiveItem( puppet, head, 1 );
		transactionSystem.AddItemToSlot( puppet, EquipmentSystem.GetPlacementSlot( head ), head );
	}

	protected event OnEquipmentChanged( value : Variant )
	{
		var paperdollData : SPaperdollEquipData;
		var transactionSystem : TransactionSystem;
		var affectedItemID, previewItemID : ItemID;
		var affectedItemData : weak< gameItemData >;
		var puppet : gamePuppet;
		var itemToRemove : ItemID;
		var itemObjectToRemove : ItemObject;
		var appearanceReset : Bool;
		var equipData : EquipmentSystemPlayerData;
		var sceneName : CName;
		var equipArea : gamedataEquipmentArea;
		var oldFistItems : array< weak< gameItemData > >;
		var i : Int32;
		sceneName = 'inventory';
		puppet = GetPuppet( sceneName );
		if( puppet )
		{
			transactionSystem = GameInstance.GetTransactionSystem( puppet.GetGame() );
			paperdollData = ( ( SPaperdollEquipData )value );
			if( paperdollData.equipArea.areaType == gamedataEquipmentArea.ArmsCW && ( equipData.GetVisualItemInSlot( gamedataEquipmentArea.RightArm ) == ItemID.None() ) )
			{
				previewItemID = ItemID.CreateQuery( TweakDBInterface.GetWeaponItemRecord( ItemID.GetTDBID( EquipmentSystem.GetData( GetPlayer( puppet.GetGame() ) ).GetActiveMeleeWare() ) ).HolsteredItem().GetID() );
				transactionSystem.GiveItem( puppet, previewItemID, 1 );
				transactionSystem.AddItemToSlot( puppet, EquipmentSystem.GetPlacementSlot( previewItemID ), previewItemID );
				return false;
			}
			if( paperdollData.equipArea.areaType == gamedataEquipmentArea.ArmsCW || ( paperdollData.equipArea.areaType == gamedataEquipmentArea.Weapon && ( paperdollData.slotIndex != paperdollData.equipArea.activeIndex ) ) )
			{
				return false;
			}
			itemObjectToRemove = transactionSystem.GetItemInSlot( puppet, paperdollData.placementSlot );
			if( itemObjectToRemove )
			{
				itemToRemove = itemObjectToRemove.GetItemID();
			}
			equipData = EquipmentSystem.GetData( GetPlayer( puppet.GetGame() ) );
			affectedItemID = equipData.GetVisualItemInSlot( paperdollData.equipArea.areaType );
			previewItemID = transactionSystem.CreatePreviewItemID( affectedItemID );
			equipArea = EquipmentSystem.GetEquipAreaType( previewItemID );
			if( ( !( paperdollData.equipped ) && ( itemToRemove != ItemID.None() ) ) && EquipmentSystem.GetEquipAreaType( itemToRemove ) != paperdollData.equipArea.areaType )
			{
				return false;
			}
			if( transactionSystem.HasTag( GetPlayer( puppet.GetGame() ), 'UnequipHolsteredArms', previewItemID ) )
			{
				return false;
			}
			SetAnimWrapperBasedOnItemFriendlyName( puppet, previewItemID, ( ( paperdollData.equipped ) ? ( 1.0 ) : ( 0.0 ) ) );
			if( paperdollData.equipped )
			{
				paperdollData.placementSlot = EquipmentSystem.GetPlacementSlot( previewItemID );
				if( paperdollData.equipArea.areaType == gamedataEquipmentArea.RightArm )
				{
					transactionSystem.GetItemListByTag( puppet, 'base_fists', oldFistItems );
					for( i = 0; i < oldFistItems.Size(); i = i + 1 )
					{
						transactionSystem.RemoveItem( puppet, oldFistItems[ i ].GetID(), oldFistItems[ i ].GetQuantity() );
					}
					transactionSystem.GiveItem( puppet, previewItemID, 1 );
					transactionSystem.AddItemToSlot( puppet, paperdollData.placementSlot, previewItemID );
				}
				else
				{
					if( ItemID.IsValid( itemToRemove ) )
					{
						if( previewItemID != itemToRemove )
						{
							transactionSystem.RemoveItemFromSlot( puppet, paperdollData.placementSlot, true );
							transactionSystem.RemoveItem( puppet, itemToRemove, 1 );
						}
						else if( equipData && !( equipData.IsSlotHidden( equipArea ) ) )
						{
							transactionSystem.ResetItemAppearance( puppet, itemToRemove );
							appearanceReset = true;
						}
					}
					if( !( appearanceReset ) )
					{
						if( ItemID.IsValid( previewItemID ) )
						{
							if( !( transactionSystem.HasItem( puppet, previewItemID ) ) )
							{
								affectedItemData = transactionSystem.GetItemData( GetPlayerControlledObject(), affectedItemID );
								if( affectedItemData )
								{
									transactionSystem.GivePreviewItemByItemData( puppet, affectedItemData );
								}
								else
								{
									transactionSystem.GivePreviewItemByItemID( puppet, previewItemID );
								}
							}
							if( equipData.ShouldSlotBeHidden( equipArea ) )
							{
								transactionSystem.AddItemToSlot( puppet, paperdollData.placementSlot, previewItemID, , , , , , 'empty_appearance_default' );
							}
							else
							{
								transactionSystem.AddItemToSlot( puppet, paperdollData.placementSlot, previewItemID );
							}
						}
					}
				}
			}
			else
			{
				if( paperdollData.equipArea.areaType == gamedataEquipmentArea.RightArm )
				{
					return false;
				}
				if( ( ( equipData && equipData.IsSlotHidden( equipArea ) ) || !( equipData.IsSlotOverriden( equipArea ) ) ) || equipData.IsVisualSetUnequipInTransition() )
				{
					transactionSystem.RemoveItemFromSlot( puppet, paperdollData.placementSlot, true );
					transactionSystem.RemoveItem( puppet, transactionSystem.CreatePreviewItemID( itemToRemove ), 1 );
				}
			}
		}
	}

	public static function SetAnimWrapperBasedOnItemFriendlyName( puppet : gamePuppet, itemID : ItemID, value : Float )
	{
		var itemRecord : Item_Record;
		if( !( puppet ) || !( ItemID.IsValid( itemID ) ) )
		{
			return;
		}
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) );
		if( !( itemRecord ) )
		{
			return;
		}
		AnimationControllerComponent.SetAnimWrapperWeight( puppet, StringToName( itemRecord.FriendlyName() ), value );
	}

	private function OpenShortcutMenu( const actionName : CName )
	{
		var initData : HubMenuInitData;
		var eventName : CName;
		initData = new HubMenuInitData;
		if( HubMenuUtility.IsPlayerHardwareDisabled( m_player ) && actionName != 'OpenJournalMenu' )
		{
			return;
		}
		switch( actionName )
		{
			case 'OpenMapMenu':
				initData.m_menuName = 'world_map';
			break;
			case 'OpenJournalMenu':
				initData.m_menuName = 'quest_log';
			break;
			case 'OpenPerksMenu':
				initData.m_menuName = 'new_perks';
			break;
			case 'OpenCraftingMenu':
				initData.m_menuName = 'crafting_main';
			break;
			case 'OpenInventoryMenu':
				initData.m_menuName = 'inventory_screen';
			break;
		}
		initData.m_combatRestriction = IsPlayerInCombat();
		eventName = ( ( GetFact( m_player.GetGame(), 'radial_hub_menu_enabled' ) > 0 ) ? ( 'OnOpenRadialHubMenu_InitData' ) : ( 'OnOpenHubMenu_InitData' ) );
		SpawnMenuInstanceDataEvent( eventName, initData );
	}

	protected event OnSavingComplete( success : Bool, locks : array< gameSaveLock > )
	{
		var notificationEvent : UIInGameNotificationEvent;
		if( !( success ) && m_quickSaveInProgress )
		{
			notificationEvent = UIInGameNotificationEvent.CreateSavingLockedEvent( locks );
			SendNotification( notificationEvent );
		}
		m_quickSaveInProgress = false;
	}

	private function HandleQuickSave()
	{
		var locks : array< gameSaveLock >;
		var notificationEvent : UIInGameNotificationEvent;
		if( m_quickSaveInProgress )
		{
			return;
		}
		if( GameInstance.IsSavingLocked( GetPlayerControlledObject().GetGame(), locks ) )
		{
			notificationEvent = UIInGameNotificationEvent.CreateSavingLockedEvent( locks );
			SendNotification( notificationEvent );
			return;
		}
		GetSystemRequestsHandler().QuickSave();
		m_quickSaveInProgress = true;
	}

	private function SendNotification( notificationEvent : UIInGameNotificationEvent )
	{
		if( notificationEvent.m_notificationType != m_lastInGameNotificationType || !( m_animContainer.m_animProxy.IsPlaying() ) )
		{
			GameInstance.GetUISystem( GetPlayerControlledObject().GetGame() ).QueueEvent( new UIInGameNotificationRemoveEvent );
		}
		notificationEvent.m_animContainer = m_animContainer;
		m_lastInGameNotificationType = notificationEvent.m_notificationType;
		GameInstance.GetUISystem( GetPlayerControlledObject().GetGame() ).QueueEvent( notificationEvent );
	}

	protected event OnQuickLoadSavesReady( saves : array< String > )
	{
		var savesCount : Int32;
		savesCount = saves.Size();
		if( savesCount > 0 )
		{
			GameInstance.GetTelemetrySystem( GetPlayerControlledObject().GetGame() ).LogLastCheckpointLoaded();
			GetSystemRequestsHandler().LoadLastCheckpoint( true );
		}
	}

	private function DelayedHandleQuickLoad()
	{
		var evt : DelayedHandleQuickLoadEvent;
		var playerControlledObject : GameObject;
		playerControlledObject = GetPlayerControlledObject();
		evt = new DelayedHandleQuickLoadEvent;
		m_loadSaveDelayID = GameInstance.GetDelaySystem( playerControlledObject.GetGame() ).DelayEvent( playerControlledObject, evt, 0.30000001 );
	}

	protected event OnHandleQuickLoad( evt : DelayedHandleQuickLoadEvent )
	{
		var handler : weak< inkISystemRequestsHandler >;
		handler = GetSystemRequestsHandler();
		handler.RegisterToCallback( 'OnSavesForLoadReady', this, 'OnQuickLoadSavesReady' );
		handler.RequestSavesForLoad();
	}

	protected event OnUiStateChangedSuccessfully( previousStateName : CName, currentStateName : CName )
	{
		var playerControlledObject : GameObject;
		var invalidDelayID : DelayID;
		if( currentStateName == 'inkInGameMenuState' )
		{
			playerControlledObject = GetPlayerControlledObject();
			invalidDelayID = GetInvalidDelayID();
			if( m_loadSaveDelayID != invalidDelayID )
			{
				GameInstance.GetDelaySystem( playerControlledObject.GetGame() ).CancelDelay( m_loadSaveDelayID );
				m_loadSaveDelayID = invalidDelayID;
			}
		}
	}

	private function IsPlayerInCombat() : Bool
	{
		return GetPSMBlackboard( GetPlayerControlledObject() ).GetInt( GetAllBlackboardDefs().PlayerStateMachine.Combat ) == ( ( Int32 )( gamePSMCombat.InCombat ) );
	}

	private function TryOpenCraftingMenu( const actionName : CName )
	{
		var notificationEvent : UIInGameNotificationEvent;
		if( HubMenuUtility.IsCraftingAvailable( ( ( weak< weak< PlayerPuppet > > )( m_player ) ) ) )
		{
			OpenShortcutMenu( actionName );
		}
		else
		{
			notificationEvent = new UIInGameNotificationEvent;
			notificationEvent.m_notificationType = UIInGameNotificationType.CombatRestriction;
			SendNotification( notificationEvent );
		}
	}

	protected event OnInputSchemeChanged( value : Uint32 )
	{
		var request : RefreshInputHintEvent;
		request = new RefreshInputHintEvent;
		GameInstance.GetUISystem( m_player.GetGame() ).QueueEvent( request );
	}

}

struct SPaperdollEquipData
{
	var equipArea : SEquipArea;
	var slotIndex : Int32;
	var placementSlot : TweakDBID;
	var equipped : Bool;
}

class ItemInPaperdollSlotCallback extends AttachmentSlotsScriptCallback
{
	protected var m_paperdollPuppet : weak< gamePuppet >;

	public function SetPuppetRef( puppet : gamePuppet )
	{
		m_paperdollPuppet = puppet;
	}

	public export override function OnItemEquipped( slot : TweakDBID, item : ItemID )
	{
		ResetInnerChest( slot, item );
	}

	public export override function OnItemUnequipped( slot : TweakDBID, item : ItemID )
	{
		ResetInnerChest( slot, item );
	}

	private function ResetInnerChest( slot : TweakDBID, item : ItemID )
	{
		var transactionSystem : TransactionSystem;
		var otherItem : ItemID;
		transactionSystem = GameInstance.GetTransactionSystem( m_paperdollPuppet.GetGame() );
		if( ( ( slot == T"AttachmentSlots.Torso" ) && transactionSystem.MatchVisualTagByItemID( item, m_paperdollPuppet, 'hide_T1part' ) ) && !( transactionSystem.IsSlotEmpty( m_paperdollPuppet, T"AttachmentSlots.Chest" ) ) )
		{
			otherItem = transactionSystem.GetItemInSlot( m_paperdollPuppet, T"AttachmentSlots.Chest" ).GetItemID();
			if( ItemID.IsValid( otherItem ) )
			{
				transactionSystem.ResetItemAppearance( m_paperdollPuppet, otherItem );
			}
		}
		else if( ( slot == T"AttachmentSlots.Chest" ) && !( transactionSystem.IsSlotEmpty( m_paperdollPuppet, T"AttachmentSlots.Torso" ) ) )
		{
			otherItem = transactionSystem.GetItemInSlot( m_paperdollPuppet, T"AttachmentSlots.Torso" ).GetItemID();
			if( ItemID.IsValid( otherItem ) && transactionSystem.MatchVisualTagByItemID( otherItem, m_paperdollPuppet, 'hide_T1part' ) )
			{
				transactionSystem.ResetItemAppearance( m_paperdollPuppet, item );
			}
		}
	}

}

