implicit cast ( hotkey : EHotkey ) : Int32
{
	return ( ( Int32 )( hotkey ) );
}

import enum EHotkey
{
	INVALID,
	DPAD_UP,
	DPAD_DOWN,
	DPAD_RIGHT,
	RB,
	LBRB,
}

enum EHotkeyRequestType
{
	Assign = 0,
	Cycle = 1,
	Restore = 2,
}

class AssignHotkeyIfEmptySlot extends PlayerScriptableSystemRequest
{
	private var itemID : ItemID;

	public static function Construct( itemID : ItemID, owner : weak< GameObject > ) : AssignHotkeyIfEmptySlot
	{
		var self : AssignHotkeyIfEmptySlot;
		self = new AssignHotkeyIfEmptySlot;
		self.owner = owner;
		self.itemID = itemID;
		return self;
	}

	public const function ItemID() : ItemID
	{
		return itemID;
	}

	public const function Owner() : GameObject
	{
		return owner;
	}

	public const function IsValid() : Bool
	{
		if( owner && ItemID.IsValid( itemID ) )
		{
			return true;
		}
		return false;
	}

}

class HotkeyRefreshRequest extends PlayerScriptableSystemRequest
{
}

class HotkeyAssignmentRequest extends PlayerScriptableSystemRequest
{
	protected var itemID : ItemID;
	private var hotkey : EHotkey;
	protected var requestType : EHotkeyRequestType;

	public const function ItemID() : ItemID
	{
		return itemID;
	}

	public const function GetHotkey() : EHotkey
	{
		return hotkey;
	}

	public const function Owner() : GameObject
	{
		return owner;
	}

	public const function GetRequestType() : EHotkeyRequestType
	{
		return requestType;
	}

	public static function Construct( itemID : ItemID, hotkey : EHotkey, owner : weak< GameObject >, requestType : EHotkeyRequestType ) : HotkeyAssignmentRequest
	{
		var self : HotkeyAssignmentRequest;
		self = new HotkeyAssignmentRequest;
		self.owner = owner;
		self.itemID = itemID;
		self.hotkey = hotkey;
		self.requestType = requestType;
		return self;
	}

	public const function IsValid() : Bool
	{
		if( owner && hotkey != EHotkey.INVALID )
		{
			return true;
		}
		return false;
	}

}

class Hotkey
{
	private persistent var hotkey : EHotkey;
	private persistent var itemID : ItemID;
	private persistent var scope : array< gamedataItemType >;

	public static function Construct( hotk : EHotkey, optional id : ItemID ) : Hotkey
	{
		var h : Hotkey;
		h = new Hotkey;
		h.hotkey = hotk;
		if( ItemID.IsValid( id ) )
		{
			h.itemID = id;
		}
		h.SetScope( Hotkey.GetScope( hotk ) );
		return h;
	}

	public function StoreItem( id : ItemID )
	{
		itemID = id;
	}

	public const function IsEmpty() : Bool
	{
		return itemID == ItemID.None();
	}

	public const function GetItemID() : ItemID
	{
		return itemID;
	}

	public const function GetHotkey() : EHotkey
	{
		return hotkey;
	}

	public const function GetScope() : array< gamedataItemType >
	{
		if( scope.Size() > 0 )
		{
			return scope;
		}
		return Hotkey.GetScope( GetHotkey() );
	}

	public const function IsCompatible( type : gamedataItemType ) : Bool
	{
		var i : Int32;
		var range : array< gamedataItemType >;
		range = GetScope();
		for( i = 0; i < range.Size(); i += 1 )
		{
			if( range[ i ] == type )
			{
				return true;
			}
		}
		return false;
	}

	public const function IsCompatible( equipmentArea : gamedataEquipmentArea ) : Bool
	{
		return hotkey == EHotkey.LBRB && equipmentArea == gamedataEquipmentArea.SystemReplacementCW;
	}

	public function SetScope( const itemTypes : ref< array< gamedataItemType > > )
	{
		scope = itemTypes;
	}

	public static function IsCompatible( hotkey : EHotkey, type : gamedataItemType ) : Bool
	{
		var scope : array< gamedataItemType >;
		scope = GetScope( hotkey );
		return scope.Contains( type );
	}

	public static function IsCompatible( hotkey : EHotkey, equipmentArea : gamedataEquipmentArea ) : Bool
	{
		return hotkey == EHotkey.LBRB && equipmentArea == gamedataEquipmentArea.SystemReplacementCW;
	}

	public static function GetScope( hotkey : EHotkey ) : array< gamedataItemType >
	{
		var scope : array< gamedataItemType >;
		if( hotkey == EHotkey.DPAD_UP )
		{
			scope.PushBack( gamedataItemType.Con_Inhaler );
			scope.PushBack( gamedataItemType.Con_Injector );
			scope.PushBack( gamedataItemType.Cyb_HealingAbility );
		}
		else if( hotkey == EHotkey.RB )
		{
			scope.PushBack( gamedataItemType.Cyb_Ability );
			scope.PushBack( gamedataItemType.Cyb_Launcher );
			scope.PushBack( gamedataItemType.Gad_Grenade );
		}
		return scope;
	}

	public static function ItemTypeMustBeEquipped( itemType : gamedataItemType ) : Bool
	{
		return ( itemType == gamedataItemType.Cyb_Ability || itemType == gamedataItemType.Cyb_HealingAbility ) || itemType == gamedataItemType.Cyb_Launcher;
	}

}

struct HotkeyManager
{

	public static function InitializeHotkeys( hotkeys : ref< array< Hotkey > > )
	{
		var hotkeysCount : Int32;
		var freshHotkey : Hotkey;
		var hotkeyIndex : Int32;
		hotkeys.Clear();
		hotkeysCount = ( ( Int32 )( EnumGetMax( 'EHotkey' ) ) );
		hotkeysCount += 1;
		for( hotkeyIndex = 0; hotkeyIndex < hotkeysCount; hotkeyIndex += 1 )
		{
			freshHotkey = Hotkey.Construct( ( ( EHotkey )( hotkeyIndex ) ) );
			hotkeys.PushBack( freshHotkey );
		}
	}

	public static function AddMissingHotkeys( hotkeys : ref< array< Hotkey > > )
	{
		var hotkeysCount : Int32;
		var freshHotkey : Hotkey;
		var hotkeyIndex : Int32;
		hotkeysCount = ( ( Int32 )( EnumGetMax( 'EHotkey' ) ) ) + 1;
		for( hotkeyIndex = hotkeys.Size(); hotkeyIndex < hotkeysCount; hotkeyIndex += 1 )
		{
			freshHotkey = Hotkey.Construct( ( ( EHotkey )( hotkeyIndex ) ) );
			hotkeys.PushBack( freshHotkey );
		}
	}

	public static function IsItemInHotkey( hotkeys : ref< array< Hotkey > >, itemID : ItemID ) : Bool
	{
		var i : Int32;
		for( i = 0; i < hotkeys.Size(); i += 1 )
		{
			if( hotkeys[ i ].GetItemID() == itemID )
			{
				return true;
			}
		}
		return false;
	}

	public static function GetHotkeyTypeForItemID( owner : weak< GameObject >, hotkeys : ref< array< Hotkey > >, itemID : ItemID ) : EHotkey
	{
		var i : Int32;
		var itemData : weak< gameItemData >;
		itemData = RPGManager.GetItemData( owner.GetGame(), owner, itemID );
		for( i = 0; i < hotkeys.Size(); i += 1 )
		{
			if( hotkeys[ i ].IsCompatible( itemData.GetItemType() ) || hotkeys[ i ].IsCompatible( EquipmentSystem.GetEquipAreaType( itemData.GetID() ) ) )
			{
				return hotkeys[ i ].GetHotkey();
			}
		}
		return EHotkey.INVALID;
	}

	public static function GetHotkeyTypeFromItemID( hotkeys : ref< array< Hotkey > >, itemID : ItemID ) : EHotkey
	{
		var i : Int32;
		for( i = 0; i < hotkeys.Size(); i += 1 )
		{
			if( hotkeys[ i ].GetItemID() == itemID )
			{
				return hotkeys[ i ].GetHotkey();
			}
		}
		return EHotkey.INVALID;
	}

	public static function GetItemIDFromHotkey( hotkeys : ref< array< Hotkey > >, hotkey : EHotkey ) : ItemID
	{
		return hotkeys[ ( ( Int32 )( hotkey ) ) ].GetItemID();
	}

}

class EquipmentSystemPlayerData
{
	var m_owner : weak< ScriptedPuppet >;
	private persistent var m_ownerID : EntityID;
	private persistent var m_equipment : SLoadout;
	private persistent var m_lastUsedStruct : SLastUsedWeapon;
	private persistent var m_slotActiveItemsInHands : SSlotActiveItems;
	private persistent var m_clothingSlotsInfo : array< SSlotInfo >;
	private persistent var m_clothingVisualsInfo : array< SSlotVisualInfo >;
	private var m_visualUnequipTransition : Bool;
	private persistent var m_wardrobeDisabled : Bool;
	private persistent var m_lastActiveWardrobeSet : gameWardrobeClothingSetIndex;
	default m_lastActiveWardrobeSet = gameWardrobeClothingSetIndex.INVALID;
	private var m_visualTagProcessingInfo : array< SVisualTagProcessing >;
	private var m_eventsSent : Int32;
	private persistent var m_hotkeys : array< Hotkey >;
	private var m_inventoryManager : InventoryDataManagerV2;
	private var m_wardrobeSystem : WardrobeSystem;
	private var m_equipPending : Bool;
	private var m_equipAreaIndexCache : array< Int32 >;

	public function OnAttach()
	{
		var scope : array< gamedataItemType >;
		if( ( ( PlayerPuppet )( m_owner ) ) )
		{
			if( m_hotkeys.Size() == 0 )
			{
				HotkeyManager.InitializeHotkeys( m_hotkeys );
			}
			else if( m_hotkeys.Size() < ( ( ( Int32 )( EnumGetMax( 'EHotkey' ) ) ) + 1 ) )
			{
				HotkeyManager.AddMissingHotkeys( m_hotkeys );
			}
			TryFillCyberwareHotkey();
			scope = m_hotkeys[ 0 ].GetScope();
			if( !( scope.Contains( gamedataItemType.Cyb_HealingAbility ) ) )
			{
				scope.PushBack( gamedataItemType.Cyb_HealingAbility );
				m_hotkeys[ 0 ].SetScope( scope );
			}
			m_inventoryManager = new InventoryDataManagerV2;
			m_inventoryManager.Initialize( ( ( PlayerPuppet )( m_owner ) ) );
			UnequipPrereqItems();
			m_wardrobeSystem = GameInstance.GetWardrobeSystem( m_owner.GetGame() );
		}
	}

	public function OnDetach() {}

	public function OnInitialize()
	{
		InitializeEquipment();
		InitializeClothingSlotsInfo();
		InitializeClothingOverrideInfo();
		InitializeEquipmentAreaIndexCache();
	}

	public function OnRestored()
	{
		var i : Int32;
		var j : Int32;
		var areaSize : Int32;
		var slotsSize : Int32;
		var transactionSystem : TransactionSystem;
		var currentItem : ItemID;
		var itemRecord : Item_Record;
		var itemData : gameItemData;
		var playerControlledObject : GameObject;
		var currentEquipmentArea : gamedataEquipmentArea;
		var placementSlot : TweakDBID;
		var currEquipSlot : SEquipSlot;
		InitializeEquipmentAreaIndexCache();
		playerControlledObject = GameInstance.GetPlayerSystem( m_owner.GetGame() ).GetLocalPlayerControlledGameObject();
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		if( transactionSystem == NULL )
		{
			return;
		}
		m_wardrobeSystem = GameInstance.GetWardrobeSystem( m_owner.GetGame() );
		UnequipFootwearAudio();
		UnequipOutfitFootwearAudio();
		UnequipAllFoleyAudio();
		for( i = 0, areaSize = m_equipment.equipAreas.Size(); i < areaSize; i += 1 )
		{
			RestoreEquipSlotsData( m_equipment.equipAreas[ i ] );
			currentEquipmentArea = m_equipment.equipAreas[ i ].areaType;
			if( currentEquipmentArea == gamedataEquipmentArea.QuickWheel )
			{
				continue;
			}
			for( j = 0, slotsSize = m_equipment.equipAreas[ i ].equipSlots.Size(); j < slotsSize; j += 1 )
			{
				currEquipSlot = m_equipment.equipAreas[ i ].equipSlots[ j ];
				currentItem = currEquipSlot.itemID;
				if( ItemID.IsValid( currentItem ) )
				{
					itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( currentItem ) );
					placementSlot = GetPlacementSlot( i, j );
					if( itemRecord == NULL )
					{
						continue;
					}
					if( itemRecord.EquipArea().Type() != gamedataEquipmentArea.Consumable )
					{
						ApplyEquipGLPs( currentItem );
						ApplySlotGLPs( currEquipSlot.slotID );
					}
					if( itemRecord.EquipArea().Type() == gamedataEquipmentArea.SystemReplacementCW )
					{
						transactionSystem.AddItemToSlot( m_owner, placementSlot, currentItem );
					}
					if( itemRecord.EquipArea().Type() == gamedataEquipmentArea.PersonalLink )
					{
						transactionSystem.AddItemToSlot( m_owner, placementSlot, currentItem );
					}
					if( itemRecord.ItemCategory().Type() == gamedataItemCategory.Clothing )
					{
						AddItemToSlot( transactionSystem, placementSlot, currentItem, currentEquipmentArea );
					}
					else if( ( itemRecord.UsesVariants() && itemRecord.EquipArea().Type() != gamedataEquipmentArea.ArmsCW ) || itemRecord.EquipArea().Type() == gamedataEquipmentArea.RightArm )
					{
						itemData = RPGManager.GetItemData( m_owner.GetGame(), m_owner, currentItem );
						if( itemData )
						{
							itemData.AddStatsOnEquip( m_owner );
						}
					}
					if( ( currentEquipmentArea == gamedataEquipmentArea.ArmsCW && ( placementSlot == T"AttachmentSlots.WeaponLeft" ) ) && !( ItemID.IsValid( GetItemInEquipSlot( gamedataEquipmentArea.RightArm, 0 ) ) ) )
					{
						EquipItem( ItemID.CreateQuery( TweakDBInterface.GetWeaponItemRecord( ItemID.GetTDBID( currentItem ) ).HolsteredItem().GetID() ) );
					}
					if( m_owner == playerControlledObject )
					{
						transactionSystem.OnItemAddedToEquipmentSlot( m_owner, currentItem );
						if( ( currentEquipmentArea == gamedataEquipmentArea.Weapon || currentEquipmentArea == gamedataEquipmentArea.WeaponHeavy ) || ( currentEquipmentArea == gamedataEquipmentArea.ArmsCW && ( placementSlot != T"AttachmentSlots.WeaponLeft" ) ) )
						{
							SendPSMWeaponManipulationRequest( EquipmentManipulationRequestType.Equip, EquipmentManipulationRequestSlot.Right, gameEquipAnimationType.Default );
						}
					}
					SendPaperdollUpdate( m_equipment.equipAreas[ i ], true, placementSlot, j, false, true );
				}
				else if( IsSlotOverriden( currentEquipmentArea ) )
				{
					AddVisualItemToSlot( transactionSystem, currentEquipmentArea );
					SendPaperdollUpdate( m_equipment.equipAreas[ i ], true, GetPlacementSlotByAreaType( currentEquipmentArea ), j, false, true );
				}
			}
		}
		HotkeysOnRestore();
		UpdateWeaponWheel();
	}

	public function HotkeysOnRestore()
	{
		var i : Int32;
		var transactionSystem : TransactionSystem;
		var item : ItemID;
		var hotkey : EHotkey;
		var scope : array< gamedataItemType >;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		for( i = 0; i < m_hotkeys.Size(); i += 1 )
		{
			hotkey = ( ( EHotkey )( i ) );
			item = m_hotkeys[ i ].GetItemID();
			scope = Hotkey.GetScope( hotkey );
			m_hotkeys[ i ].SetScope( scope );
			if( ( scope.Size() > 0 ) && !( scope.Contains( RPGManager.GetItemType( item ) ) ) )
			{
				ClearItemFromHotkey( hotkey );
			}
			if( ItemID.IsValid( item ) )
			{
				transactionSystem.OnItemAddedToEquipmentSlot( m_owner, item );
				if( RPGManager.GetItemCategory( item ) == gamedataItemCategory.Consumable )
				{
					ApplyEquipGLPs( item );
				}
			}
		}
	}

	private function TryFillCyberwareHotkey()
	{
		var i : Int32;
		var item : ItemID;
		for( i = 0; i < m_hotkeys.Size(); i += 1 )
		{
			if( m_hotkeys[ i ].GetHotkey() != EHotkey.LBRB )
			{
				continue;
			}
			if( !( ItemID.IsValid( m_hotkeys[ i ].GetItemID() ) ) )
			{
				item = GetActiveItem( gamedataEquipmentArea.SystemReplacementCW );
				if( ItemID.IsValid( item ) )
				{
					AssignItemToHotkey( item, EHotkey.LBRB );
				}
			}
		}
	}

	public function SetOwner( owner : ScriptedPuppet )
	{
		m_owner = owner;
		m_ownerID = owner.GetEntityID();
	}

	public function GetOwner() : weak< ScriptedPuppet >
	{
		return m_owner;
	}

	public function GetOwnerID() : EntityID
	{
		return m_ownerID;
	}

	public function GetEquipment() : SLoadout
	{
		return m_equipment;
	}

	public function GetLastUsedStruct() : SLastUsedWeapon
	{
		return m_lastUsedStruct;
	}

	public function ClearLastUsedStruct()
	{
		var emptyLastUsedStruct : SLastUsedWeapon;
		m_lastUsedStruct = emptyLastUsedStruct;
	}

	public function GetSlotActiveItemStruct() : SSlotActiveItems
	{
		return m_slotActiveItemsInHands;
	}

	private function GetPlayerEquipmentAreas( out list : array< weak< EquipmentArea_Record > > )
	{
		return TweakDBInterface.GetCharacterRecord( m_owner.GetRecordID() ).EquipmentAreas( list );
	}

	private function GetEquipAreaRecordByType( areaType : gamedataEquipmentArea ) : EquipmentArea_Record
	{
		var list : array< weak< EquipmentArea_Record > >;
		var i, size : Int32;
		var retVal : EquipmentArea_Record;
		GetPlayerEquipmentAreas( list );
		for( i = 0, size = list.Size(); i < size; i += 1 )
		{
			retVal = list[ i ];
			if( retVal.Type() == areaType )
			{
				return retVal;
			}
		}
		return NULL;
	}

	private function InitializeEquipment()
	{
		var equipAreas : array< weak< EquipmentArea_Record > >;
		var equipArea : SEquipArea;
		var i, size : Int32;
		var equipAreaRecord : EquipmentArea_Record;
		GetPlayerEquipmentAreas( equipAreas );
		for( i = 0, size = equipAreas.Size(); i < size; i += 1 )
		{
			equipArea = SEquipArea();
			equipAreaRecord = equipAreas[ i ];
			equipArea.areaType = equipAreaRecord.Type();
			equipArea.activeIndex = 0;
			InitializeEquipmentArea( equipAreaRecord, equipArea );
			m_equipment.equipAreas.PushBack( equipArea );
		}
	}

	private function InitializeEquipmentArea( equipAreaRecord : EquipmentArea_Record, out equipArea : SEquipArea )
	{
		var equipSlotRecords : array< weak< EquipSlot_Record > >;
		equipAreaRecord.EquipSlots( equipSlotRecords );
		InitializeEquipSlotsFromRecords( equipSlotRecords, equipArea.equipSlots );
	}

	private function InitializeEquipSlotsFromRecords( slotRecords : array< weak< EquipSlot_Record > >, out equipSlots : array< SEquipSlot > )
	{
		var equipSlot : SEquipSlot;
		var i, size : Int32;
		for( i = 0, size = slotRecords.Size(); i < size; i += 1 )
		{
			equipSlot = SEquipSlot();
			InitializeEquipSlotFromRecord( slotRecords[ i ], equipSlot );
			if( equipSlots.Size() > i )
			{
				if( equipSlot.unlockPrereq.IsFulfilled( m_owner.GetGame(), m_owner ) )
				{
					equipSlot.itemID = equipSlots[ i ].itemID;
				}
				equipSlots[ i ] = equipSlot;
			}
			else
			{
				equipSlots.PushBack( equipSlot );
			}
		}
	}

	private function InitializeEquipSlotFromRecord( slotRecord : EquipSlot_Record, out equipSlot : SEquipSlot )
	{
		var equipPrereqID : TweakDBID;
		equipPrereqID = slotRecord.UnlockPrereqRecord().GetID();
		if( TDBID.IsValid( equipPrereqID ) )
		{
			equipSlot.unlockPrereq = IPrereq.CreatePrereq( equipPrereqID );
		}
		equipSlot.visibleWhenLocked = slotRecord.VisibleWhenLocked();
		equipSlot.slotID = slotRecord.GetID();
	}

	private function RestoreEquipSlotsData( out equipArea : SEquipArea )
	{
		var areaRecord : weak< EquipmentArea_Record >;
		areaRecord = GetEquipAreaRecordByType( equipArea.areaType );
		InitializeEquipmentArea( areaRecord, equipArea );
	}

	private function InitializeEquipmentAreaIndexCache()
	{
		var i, limit : Int32;
		var equipArea : SEquipArea;
		m_equipAreaIndexCache.Resize( ( ( Int32 )( gamedataEquipmentArea.Count ) ) );
		for( i = 0, limit = m_equipAreaIndexCache.Size(); i < limit; i += 1 )
		{
			m_equipAreaIndexCache[ i ] = -1;
		}
		for( i = 0, limit = m_equipment.equipAreas.Size(); i < limit; i += 1 )
		{
			equipArea = m_equipment.equipAreas[ i ];
			if( equipArea.areaType != gamedataEquipmentArea.Invalid )
			{
				m_equipAreaIndexCache[ ( ( Int32 )( equipArea.areaType ) ) ] = i;
			}
		}
	}

	private function InitializeClothingSlotsInfo()
	{
		m_clothingSlotsInfo.Clear();
		m_clothingSlotsInfo.PushBack( CreateSlotInfo( gamedataEquipmentArea.OuterChest, "AttachmentSlots.Torso", 'hide_T2' ) );
		m_clothingSlotsInfo.PushBack( CreateSlotInfo( gamedataEquipmentArea.InnerChest, "AttachmentSlots.Chest", 'hide_T1' ) );
		m_clothingSlotsInfo.PushBack( CreateSlotInfo( gamedataEquipmentArea.Legs, "AttachmentSlots.Legs", 'hide_L1' ) );
		m_clothingSlotsInfo.PushBack( CreateSlotInfo( gamedataEquipmentArea.Feet, "AttachmentSlots.Feet", 'hide_S1' ) );
		m_clothingSlotsInfo.PushBack( CreateSlotInfo( gamedataEquipmentArea.Head, "AttachmentSlots.Head", 'hide_H1' ) );
		m_clothingSlotsInfo.PushBack( CreateSlotInfo( gamedataEquipmentArea.Face, "AttachmentSlots.Eyes", 'hide_F1' ) );
		m_clothingSlotsInfo.PushBack( CreateSlotInfo( gamedataEquipmentArea.UnderwearBottom, "AttachmentSlots.UnderwearBottom", 'hide_Genitals' ) );
	}

	public function InitializeClothingOverrideInfo()
	{
		m_clothingVisualsInfo.Clear();
		m_clothingVisualsInfo.PushBack( CreateClothingVisualSlotInfo( gamedataEquipmentArea.Outfit ) );
		m_clothingVisualsInfo.PushBack( CreateClothingVisualSlotInfo( gamedataEquipmentArea.OuterChest ) );
		m_clothingVisualsInfo.PushBack( CreateClothingVisualSlotInfo( gamedataEquipmentArea.InnerChest ) );
		m_clothingVisualsInfo.PushBack( CreateClothingVisualSlotInfo( gamedataEquipmentArea.Legs ) );
		m_clothingVisualsInfo.PushBack( CreateClothingVisualSlotInfo( gamedataEquipmentArea.Feet ) );
		m_clothingVisualsInfo.PushBack( CreateClothingVisualSlotInfo( gamedataEquipmentArea.Head ) );
		m_clothingVisualsInfo.PushBack( CreateClothingVisualSlotInfo( gamedataEquipmentArea.Face ) );
		m_clothingVisualsInfo.PushBack( CreateClothingVisualSlotInfo( gamedataEquipmentArea.UnderwearTop ) );
		m_clothingVisualsInfo.PushBack( CreateClothingVisualSlotInfo( gamedataEquipmentArea.UnderwearBottom ) );
	}

	public function IsClothingVisualsInfoEmpty() : Bool
	{
		return m_clothingVisualsInfo.Size() == 0;
	}

	private function CreateSlotInfo( area : gamedataEquipmentArea, const slot : ref< String >, visualTag : CName ) : SSlotInfo
	{
		var slotInfo : SSlotInfo;
		slotInfo.areaType = area;
		slotInfo.equipSlot = TDBID.Create( slot );
		slotInfo.visualTag = visualTag;
		return slotInfo;
	}

	private function CreateClothingVisualSlotInfo( area : gamedataEquipmentArea ) : SSlotVisualInfo
	{
		var slotInfo : SSlotVisualInfo;
		slotInfo.areaType = area;
		return slotInfo;
	}

	public function IsEquipPending() : Bool
	{
		return m_equipPending;
	}

	public function EquipItem( itemID : ItemID, optional blockActiveSlotsUpdate : Bool, optional forceEquipWeapon : Bool )
	{
		var i : Int32;
		var equipAreaIndex : Int32;
		var equipAtIndex : Int32;
		var equipArea : SEquipArea;
		var equipAreaType : gamedataEquipmentArea;
		var equipSlot : SEquipSlot;
		if( ItemID.IsValid( itemID ) && !( IsEquipped( itemID ) ) )
		{
			equipAreaType = EquipmentSystem.GetEquipAreaType( itemID );
			equipAreaIndex = GetEquipAreaIndex( equipAreaType );
			equipArea = m_equipment.equipAreas[ equipAreaIndex ];
			for( i = 0; i < equipArea.equipSlots.Size(); i += 1 )
			{
				equipSlot = equipArea.equipSlots[ i ];
				if( !( IsSlotLocked( equipSlot, false ) ) && !( ItemID.IsValid( equipSlot.itemID ) ) )
				{
					EquipItem( itemID, i, blockActiveSlotsUpdate, forceEquipWeapon );
					return;
				}
			}
			EquipItem( itemID, equipArea.activeIndex, blockActiveSlotsUpdate, forceEquipWeapon );
		}
		else if( ItemID.IsValid( itemID ) && IsEquipped( itemID ) )
		{
			equipAtIndex = GetSlotIndex( itemID );
			if( equipAtIndex >= 0 )
			{
				EquipItem( itemID, equipAtIndex, blockActiveSlotsUpdate, forceEquipWeapon );
			}
		}
	}

	private function EquipItem( itemID : ItemID, slotIndex : Int32, optional blockActiveSlotsUpdate : Bool, optional forceEquipWeapon : Bool )
	{
		var i : Int32;
		var equipmentArea : gamedataEquipmentArea;
		var equipAreaIndex : Int32;
		var equipArea : SEquipArea;
		var transactionSystem : TransactionSystem;
		var placementSlot : TweakDBID;
		var weaponRecord : WeaponItem_Record;
		var itemData : gameItemData;
		var cyberwareType : CName;
		var currentItem : ItemID;
		var currentItemData : gameItemData;
		var equipSlot : SEquipSlot;
		itemData = RPGManager.GetItemData( m_owner.GetGame(), m_owner, itemID );
		if( !( IsEquippable( itemData ) ) )
		{
			return;
		}
		equipmentArea = EquipmentSystem.GetEquipAreaType( itemID );
		equipAreaIndex = GetEquipAreaIndex( equipmentArea );
		equipArea = m_equipment.equipAreas[ equipAreaIndex ];
		equipSlot = equipArea.equipSlots[ slotIndex ];
		currentItem = equipSlot.itemID;
		currentItemData = RPGManager.GetItemData( m_owner.GetGame(), m_owner, currentItem );
		if( currentItemData && currentItemData.HasTag( 'UnequipBlocked' ) )
		{
			return;
		}
		if( equipmentArea == gamedataEquipmentArea.Outfit && IsVisualSetActive() )
		{
			UnequipWardrobeSet();
		}
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		m_equipPending = true;
		if( ( ( IsItemOfCategory( itemID, gamedataItemCategory.Weapon ) && ( equipArea.activeIndex == slotIndex ) ) && CheckWeaponAgainstGameplayRestrictions( itemID, true ) ) && !( blockActiveSlotsUpdate ) )
		{
			SetSlotActiveItem( EquipmentManipulationRequestSlot.Right, itemID );
			SetLastUsedItem( itemID );
			SendPSMWeaponManipulationRequest( EquipmentManipulationRequestType.Equip, EquipmentManipulationRequestSlot.Right, gameEquipAnimationType.Default );
		}
		else if( ( IsItemOfCategory( itemID, gamedataItemCategory.Weapon ) && forceEquipWeapon ) && CheckWeaponAgainstGameplayRestrictions( itemID, true ) )
		{
			m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ slotIndex ].itemID = itemID;
			SetSlotActiveItem( EquipmentManipulationRequestSlot.Right, itemID );
			UpdateEquipAreaActiveIndex( itemID );
			SetLastUsedItem( itemID );
		}
		else
		{
			UnequipItem( equipAreaIndex, slotIndex );
			cyberwareType = TweakDBInterface.GetCName( ItemID.GetTDBID( itemID ) + T".cyberwareType", '' );
			for( i = 0; i < m_equipment.equipAreas[ equipAreaIndex ].equipSlots.Size(); i += 1 )
			{
				if( cyberwareType == TweakDBInterface.GetCName( ItemID.GetTDBID( m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ i ].itemID ) + T".cyberwareType", 'type' ) )
				{
					UnequipItem( equipAreaIndex, i );
				}
			}
		}
		m_equipPending = false;
		m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ slotIndex ].itemID = itemID;
		placementSlot = GetPlacementSlot( equipAreaIndex, slotIndex );
		if( itemData.GetItemType() == gamedataItemType.Cyb_StrongArms )
		{
			HandleStrongArmsEquip( itemID );
		}
		if( ( placementSlot == T"AttachmentSlots.WeaponRight" ) || ( placementSlot == T"AttachmentSlots.WeaponLeft" ) )
		{
			weaponRecord = TweakDBInterface.GetWeaponItemRecord( ItemID.GetTDBID( itemID ) );
			if( weaponRecord && weaponRecord.HolsteredItem() )
			{
				EquipmentSystemPlayerData.UpdateArmSlot( ( ( PlayerPuppet )( m_owner ) ), itemID, true );
			}
		}
		if( ( ( placementSlot != T"AttachmentSlots.WeaponRight" ) && ( placementSlot != T"AttachmentSlots.WeaponLeft" ) ) && ( placementSlot != T"AttachmentSlots.Consumable" ) )
		{
			if( !( transactionSystem.HasItemInSlot( m_owner, placementSlot, itemID ) ) )
			{
				transactionSystem.RemoveItemFromSlot( m_owner, placementSlot );
				AddItemToSlot( transactionSystem, placementSlot, itemID, equipmentArea );
			}
		}
		ApplyEquipGLPs( itemID );
		ApplySlotGLPs( equipSlot.slotID );
		if( ( itemData.UsesVariants() && equipArea.areaType != gamedataEquipmentArea.ArmsCW ) || equipArea.areaType == gamedataEquipmentArea.RightArm )
		{
			itemData.AddStatsOnEquip( m_owner );
		}
		UpdateWeaponWheel();
		UpdateQuickWheel();
		UpdateUIBBAreaChanged( equipmentArea, slotIndex );
		SendPaperdollUpdate( m_equipment.equipAreas[ equipAreaIndex ], true, placementSlot, slotIndex, true );
		for( i = 0; i < m_hotkeys.Size(); i += 1 )
		{
			if( m_hotkeys[ i ].IsCompatible( itemData.GetItemType() ) || m_hotkeys[ i ].IsCompatible( EquipmentSystem.GetEquipAreaType( itemData.GetID() ) ) )
			{
				AssignItemToHotkey( itemData.GetID(), m_hotkeys[ i ].GetHotkey() );
			}
		}
		EquipmentSystem.GetInstance( m_owner ).Debug_FillESSlotData( slotIndex, m_equipment.equipAreas[ equipAreaIndex ].areaType, itemID, m_owner );
		if( ItemID.IsValid( currentItem ) && ( currentItem != itemID ) )
		{
			transactionSystem.OnItemRemovedFromEquipmentSlot( m_owner, currentItem );
		}
		transactionSystem.OnItemAddedToEquipmentSlot( m_owner, itemID );
		if( IsItemOfCategory( itemID, gamedataItemCategory.Cyberware ) || equipArea.areaType == gamedataEquipmentArea.ArmsCW )
		{
			CheckCyberjunkieAchievement();
		}
		if( EquipmentSystem.IsItemCyberdeck( itemID ) )
		{
			PlayerPuppet.ChacheQuickHackListCleanup( m_owner );
		}
	}

	private function AddItemToSlot( transactionSystem : TransactionSystem, slot : TweakDBID, itemID : ItemID, area : gamedataEquipmentArea ) : Bool
	{
		var itemData : weak< gameItemData >;
		var visualItem : ItemID;
		var previewItem : ItemID;
		if( RPGManager.IsItemClothing( itemID ) )
		{
			itemData = RPGManager.GetItemData( m_owner.GetGame(), m_owner, itemID );
			if( itemData.HasTag( 'TransmogBlocked' ) )
			{
				if( IsVisualSetActive() )
				{
					UnequipVisuals( area );
				}
				m_clothingVisualsInfo[ GetVisualSlotIndex( area ) ].visualItem = itemID;
			}
			else if( IsSlotHidden( area ) )
			{
				return transactionSystem.AddItemToSlot( m_owner, slot, itemID, , , , , , 'empty_appearance_default' );
			}
			else if( IsSlotOverriden( area ) )
			{
				visualItem = GetSlotOverridenVisualItem( area );
				if( !( ItemID.IsValid( GetActiveItem( area ) ) ) && ItemID.IsValid( itemID ) )
				{
					previewItem = transactionSystem.CreatePreviewItemID( visualItem );
					transactionSystem.RemoveItem( m_owner, previewItem, 1 );
				}
				SendEquipAudioEvents( visualItem );
				return transactionSystem.AddItemToSlot( m_owner, slot, itemID, , , , , , , visualItem );
			}
		}
		SendEquipAudioEvents( itemID );
		return transactionSystem.AddItemToSlot( m_owner, slot, itemID );
	}

	private function AddVisualItemToSlot( transactionSystem : TransactionSystem, area : gamedataEquipmentArea ) : Bool
	{
		var previewItem : ItemID;
		previewItem = transactionSystem.CreatePreviewItemID( GetSlotOverridenVisualItem( area ) );
		if( transactionSystem.AddItemToSlot( m_owner, GetPlacementSlotByAreaType( area ), previewItem ) )
		{
			SendEquipAudioEvents( previewItem );
			return true;
		}
		return false;
	}

	private function SendPaperdollUpdate( const area : ref< SEquipArea >, equipped : Bool, slot : TweakDBID, optional slotindex : Int32, optional ignoreSlot : Bool, optional force : Bool )
	{
		var paperdollEquipData : SPaperdollEquipData;
		paperdollEquipData.equipArea = area;
		paperdollEquipData.equipped = equipped;
		paperdollEquipData.placementSlot = slot;
		paperdollEquipData.slotIndex = slotindex;
		if( ignoreSlot || TDBID.IsValid( paperdollEquipData.placementSlot ) )
		{
			UpdateEquipmentUIBB( paperdollEquipData, force );
		}
	}

	private function SendEquipAudioEvents( itemID : ItemID )
	{
		var audioEventFoley : AudioEvent;
		var audioSystem : AudioSystem;
		audioEventFoley = new AudioEvent;
		audioEventFoley.eventName = 'equipItem';
		audioEventFoley.nameData = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) ).AppearanceName();
		m_owner.QueueEvent( audioEventFoley );
		if( RPGManager.GetItemType( itemID ) == gamedataItemType.Clo_Feet )
		{
			audioSystem = GameInstance.GetAudioSystem( m_owner.GetGame() );
			audioSystem.EquipNewFootwearByPlayer( itemID );
		}
		if( RPGManager.GetItemType( itemID ) == gamedataItemType.Clo_Outfit )
		{
			audioSystem = GameInstance.GetAudioSystem( m_owner.GetGame() );
			audioSystem.EquipNewOutfitByPlayer( itemID );
		}
	}

	private function UnequipFootwearAudio()
	{
		var unequipFootwearEvent : AudioEvent;
		unequipFootwearEvent = new AudioEvent;
		unequipFootwearEvent.eventName = 'equipFootwear';
		unequipFootwearEvent.nameData = 'None';
		m_owner.QueueEvent( unequipFootwearEvent );
	}

	private function UnequipOutfitFootwearAudio()
	{
		var unequipFootwearEvent : AudioEvent;
		unequipFootwearEvent = new AudioEvent;
		unequipFootwearEvent.eventName = 'equipOutfitFootwear';
		unequipFootwearEvent.nameData = 'None';
		m_owner.QueueEvent( unequipFootwearEvent );
	}

	private function UnequipAllFoleyAudio()
	{
		var unequipAllFoleyEvent : AudioEvent;
		unequipAllFoleyEvent = new AudioEvent;
		unequipAllFoleyEvent.eventName = 'unequipAll';
		unequipAllFoleyEvent.nameData = 'None';
		m_owner.QueueEvent( unequipAllFoleyEvent );
	}

	private function SendUnequipAudioEvents( itemID : ItemID )
	{
		var audioEventFoley : AudioEvent;
		var audioSystem : AudioSystem;
		audioEventFoley = new AudioEvent;
		audioEventFoley.eventName = 'unequipItem';
		audioEventFoley.nameData = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) ).AppearanceName();
		m_owner.QueueEvent( audioEventFoley );
		if( RPGManager.GetItemType( itemID ) == gamedataItemType.Clo_Feet )
		{
			UnequipFootwearAudio();
		}
		if( RPGManager.GetItemType( itemID ) == gamedataItemType.Clo_Outfit )
		{
			audioSystem = GameInstance.GetAudioSystem( m_owner.GetGame() );
			audioSystem.UnequipOutfitByPlayer( itemID );
		}
	}

	private function EquipVisuals( item : ItemID )
	{
		var area : gamedataEquipmentArea;
		var visualSlotIndex : Int32;
		var equipAreaIndex : Int32;
		var activeItem : ItemID;
		var oldVisualItem : ItemID;
		area = EquipmentSystem.GetEquipAreaType( item );
		visualSlotIndex = GetVisualSlotIndex( area );
		equipAreaIndex = GetEquipAreaIndex( area );
		activeItem = GetActiveItem( area );
		oldVisualItem = oldVisualItem = m_clothingVisualsInfo[ visualSlotIndex ].visualItem;
		if( ( visualSlotIndex < 0 ) || IsTransmogBlockedOnSlot( area ) )
		{
			return;
		}
		if( ItemID.IsValid( oldVisualItem ) )
		{
			OnUnequipUpdateVisuals( oldVisualItem, area );
			SendUnequipAudioEvents( oldVisualItem );
			if( !( ItemID.IsValid( activeItem ) ) )
			{
				ClearPreviewItem( area );
			}
		}
		else
		{
			SendUnequipAudioEvents( activeItem );
			OnUnequipUpdateVisuals( activeItem, area );
		}
		m_clothingVisualsInfo[ visualSlotIndex ].visualItem = item;
		m_clothingVisualsInfo[ visualSlotIndex ].isHidden = false;
		ChangeAppearanceToItem( item );
		OnEquipProcessVisualTags( item );
		SendPaperdollUpdate( m_equipment.equipAreas[ equipAreaIndex ], true, GetPlacementSlotByAreaType( area ), 0, false, true );
	}

	private function UnequipVisuals( area : gamedataEquipmentArea )
	{
		var visualSlotIndex : Int32;
		var equipAreaIndex : Int32;
		var visualItem : ItemID;
		visualSlotIndex = GetVisualSlotIndex( area );
		equipAreaIndex = GetEquipAreaIndex( area );
		visualItem = GetVisualItemInSlot( area );
		if( ( visualSlotIndex < 0 ) || IsTransmogBlockedOnSlot( area ) )
		{
			return;
		}
		SendUnequipAudioEvents( visualItem );
		OnUnequipProcessVisualTags( visualItem );
		if( !( ItemID.IsValid( GetActiveItem( area ) ) ) )
		{
			ClearPreviewItem( area );
		}
		else
		{
			ResetItemAppearanceEvent( area );
		}
		m_clothingVisualsInfo[ visualSlotIndex ].isHidden = false;
		m_clothingVisualsInfo[ visualSlotIndex ].visualItem = ItemID.None();
		SendPaperdollUpdate( m_equipment.equipAreas[ equipAreaIndex ], false, GetPlacementSlotByAreaType( area ), 0, false, true );
	}

	private function ClearVisuals( area : gamedataEquipmentArea )
	{
		var visualSlotIndex : Int32;
		var equipAreaIndex : Int32;
		var activeItem : ItemID;
		var transactionSystem : TransactionSystem;
		var equippedItemData : weak< gameItemData >;
		visualSlotIndex = GetVisualSlotIndex( area );
		equipAreaIndex = GetEquipAreaIndex( area );
		activeItem = GetActiveItem( area );
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		if( ( visualSlotIndex < 0 ) || IsTransmogBlockedOnSlot( area ) )
		{
			return;
		}
		if( ItemID.IsValid( activeItem ) )
		{
			equippedItemData = transactionSystem.GetItemData( m_owner, activeItem );
			if( equippedItemData && equippedItemData.HasTag( 'TransmogBlocked' ) )
			{
				return;
			}
		}
		if( !( ItemID.IsValid( activeItem ) ) )
		{
			ClearPreviewItem( area );
		}
		else
		{
			OnUnequipUpdateVisuals( activeItem, area );
			ClearItemAppearance( area );
		}
		m_clothingVisualsInfo[ visualSlotIndex ].visualItem = ItemID.None();
		m_clothingVisualsInfo[ visualSlotIndex ].isHidden = true;
		SendPaperdollUpdate( m_equipment.equipAreas[ equipAreaIndex ], false, GetPlacementSlotByAreaType( area ), 0, false, true );
	}

	private function ClearPreviewItem( area : gamedataEquipmentArea )
	{
		var transactionSystem : TransactionSystem;
		var previewItem : ItemID;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		previewItem = transactionSystem.CreatePreviewItemID( GetVisualItemInSlot( area ) );
		transactionSystem.ClearAttachmentAppearance( m_owner, GetPlacementSlotByAreaType( area ) );
		transactionSystem.RemoveItem( m_owner, previewItem, 1 );
	}

	private function IsTransmogBlockedOnSlot( area : gamedataEquipmentArea ) : Bool
	{
		var transactionSystem : TransactionSystem;
		var activeItem : ItemID;
		var equippedItemData : weak< gameItemData >;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		activeItem = GetActiveItem( area );
		equippedItemData = transactionSystem.GetItemData( m_owner, activeItem );
		return equippedItemData && equippedItemData.HasTag( 'TransmogBlocked' );
	}

	public function QuestHideSlot( area : gamedataEquipmentArea )
	{
		ClearVisuals( area );
	}

	public function QuestRestoreSlot( area : gamedataEquipmentArea )
	{
		if( IsVisualSetActive() )
		{
			EquipVisuals( GetVisualItemInSlot( area ) );
		}
		else if( ItemID.IsValid( GetActiveItem( area ) ) )
		{
			ResetItemAppearanceEvent( area );
		}
	}

	private function ChangeAppearanceToItem( item : ItemID )
	{
		var transactionSystem : TransactionSystem;
		var oldItemID : ItemID;
		oldItemID = GetItemInEquipSlot( EquipmentSystem.GetEquipAreaType( item ), 0 );
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		if( ItemID.IsValid( oldItemID ) )
		{
			transactionSystem.ChangeItemAppearanceByItemID( m_owner, oldItemID, item );
		}
		else
		{
			transactionSystem.GivePreviewItemByItemID( m_owner, item );
			transactionSystem.AddItemToSlot( m_owner, EquipmentSystem.GetPlacementSlot( item ), transactionSystem.CreatePreviewItemID( item ), true );
		}
		SendEquipAudioEvents( item );
	}

	private function ProcessGadgetsTutorials( item : ItemID )
	{
		var questSystem : QuestsSystem;
		questSystem = GameInstance.GetQuestsSystem( m_owner.GetGame() );
		if( ( RPGManager.GetItemCategory( item ) == gamedataItemCategory.Gadget && ( questSystem.GetFact( 'grenade_use_tutorial' ) == 0 ) ) && ( questSystem.GetFact( 'disable_tutorials' ) == 0 ) )
		{
			questSystem.SetFact( 'grenade_use_tutorial', 1 );
		}
		if( ( ( RPGManager.GetItemType( item ) == gamedataItemType.Con_Inhaler || RPGManager.GetItemType( item ) == gamedataItemType.Con_Injector ) && ( questSystem.GetFact( 'consumable_use_tutorial' ) == 0 ) ) && ( questSystem.GetFact( 'disable_tutorials' ) == 0 ) )
		{
			questSystem.SetFact( 'consumable_use_tutorial', 1 );
		}
	}

	public function OnEquipProcessVisualTags( itemID : ItemID )
	{
		var transactionSystem : TransactionSystem;
		var areaType : gamedataEquipmentArea;
		var i : Int32;
		var visualTagsTweakDB : array< CName >;
		var isUnderwearHidden : Bool;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		areaType = EquipmentSystem.GetEquipAreaType( itemID );
		if( IsVisualTagActive( GetVisualTagByAreaType( areaType ) ) )
		{
			ClearItemAppearanceEvent( areaType );
		}
		else
		{
			visualTagsTweakDB = transactionSystem.GetVisualTagsByItemID( itemID, m_owner );
			for( i = 0; i < visualTagsTweakDB.Size(); i += 1 )
			{
				if( GetSlotsInfoIndex( visualTagsTweakDB[ i ] ) > -1 )
				{
					ClearItemAppearanceEvent( m_clothingSlotsInfo[ GetSlotsInfoIndex( visualTagsTweakDB[ i ] ) ].areaType );
				}
			}
			if( areaType == gamedataEquipmentArea.OuterChest && IsPartialVisualTagActive( itemID, transactionSystem ) )
			{
				UpdateInnerChest();
			}
			if( ( !( IsUnderwearHidden() ) || areaType == gamedataEquipmentArea.UnderwearBottom ) && ( ItemID.IsValid( GetVisualItemInSlot( gamedataEquipmentArea.Legs ) ) || IsVisualTagActive( 'hide_L1' ) ) )
			{
				ClearItemAppearanceEvent( gamedataEquipmentArea.UnderwearBottom );
			}
			isUnderwearHidden = EvaluateUnderwearTopHiddenState();
			if( ( ( !( isUnderwearHidden ) || areaType == gamedataEquipmentArea.UnderwearTop ) && IsBuildCensored() ) && ( ItemID.IsValid( GetVisualItemInSlot( gamedataEquipmentArea.InnerChest ) ) || IsVisualTagActive( 'hide_T1' ) ) )
			{
				ClearItemAppearanceEvent( gamedataEquipmentArea.UnderwearTop );
			}
		}
	}

	private function GetSlotsInfoIndex( tag : CName ) : Int32
	{
		var i : Int32;
		for( i = 0; i < m_clothingSlotsInfo.Size(); i += 1 )
		{
			if( tag == m_clothingSlotsInfo[ i ].visualTag )
			{
				return i;
			}
		}
		return -1;
	}

	private function ClearItemAppearanceEvent( areaType : gamedataEquipmentArea )
	{
		var evt : ClearItemAppearanceEvent;
		var resetItemID : ItemID;
		HideItem( areaType, true );
		resetItemID = GetActiveItem( areaType );
		if( !( ItemID.IsValid( resetItemID ) ) )
		{
			resetItemID = GetVisualItemInSlot( areaType );
		}
		if( ItemID.IsValid( resetItemID ) )
		{
			evt = new ClearItemAppearanceEvent;
			evt.itemID = resetItemID;
			m_eventsSent += 1;
			UpdateVisualTagProcessingInfo( areaType, false );
			m_owner.QueueEvent( evt );
		}
	}

	public function OnClearItemAppearance( resetItemID : ItemID )
	{
		OnUnequipProcessVisualTags( resetItemID, true );
		m_eventsSent -= 1;
		FinalizeVisualTagProcessing();
	}

	protected function ClearItemAppearance( area : gamedataEquipmentArea )
	{
		var currentID : ItemID;
		var equipAreaIndex : Int32;
		var slotIndex : Int32;
		var emptySlotTransmog : Bool;
		var transactionSystem : TransactionSystem;
		currentID = GetActiveItem( area );
		if( !( ItemID.IsValid( currentID ) ) && ItemID.IsValid( GetVisualItemInSlot( area ) ) )
		{
			emptySlotTransmog = true;
			currentID = GetVisualItemInSlot( area );
		}
		equipAreaIndex = GetEquipAreaIndex( area );
		slotIndex = GetSlotIndex( currentID );
		if( emptySlotTransmog )
		{
			ClearPreviewItem( area );
		}
		else
		{
			transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
			transactionSystem.ChangeItemAppearanceByName( m_owner, currentID, 'empty_appearance_default' );
		}
		SendPaperdollUpdate( m_equipment.equipAreas[ equipAreaIndex ], false, GetPlacementSlot( equipAreaIndex, slotIndex ), slotIndex, false, true );
		SendUnequipAudioEvents( currentID );
	}

	public function OnUnequipProcessVisualTags( currentItem : ItemID, optional forceIfHidden : Bool )
	{
		var i : Int32;
		var area : gamedataEquipmentArea;
		var transactionSystem : TransactionSystem;
		var visualTagsTweakDB : array< CName >;
		area = EquipmentSystem.GetEquipAreaType( currentItem );
		if( !( ItemID.IsValid( currentItem ) ) || ( IsSlotHidden( area ) && !( forceIfHidden ) ) )
		{
			return;
		}
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		visualTagsTweakDB = transactionSystem.GetVisualTagsByItemID( currentItem, m_owner );
		for( i = 0; i < visualTagsTweakDB.Size(); i += 1 )
		{
			if( GetSlotsInfoIndex( visualTagsTweakDB[ i ] ) > -1 )
			{
				ResetItemAppearanceEvent( m_clothingSlotsInfo[ GetSlotsInfoIndex( visualTagsTweakDB[ i ] ) ].areaType );
			}
		}
		OnUnequipUpdateVisuals( currentItem, area );
	}

	private function OnUnequipUpdateVisuals( currentItem : ItemID, area : gamedataEquipmentArea )
	{
		var isUnderwearHidden : Bool;
		if( area == gamedataEquipmentArea.OuterChest && IsPartialVisualTagActive( currentItem, GameInstance.GetTransactionSystem( m_owner.GetGame() ) ) )
		{
			UpdateInnerChest();
		}
		if( IsUnderwearHidden() && ShouldUnderwearBeVisible( currentItem ) )
		{
			ResetItemAppearanceEvent( gamedataEquipmentArea.UnderwearBottom );
		}
		if( area != gamedataEquipmentArea.UnderwearTop )
		{
			isUnderwearHidden = EvaluateUnderwearTopHiddenState();
			if( ( isUnderwearHidden && IsBuildCensored() ) && ShouldUnderwearTopBeVisible( currentItem ) )
			{
				ResetItemAppearanceEvent( gamedataEquipmentArea.UnderwearTop );
			}
		}
	}

	private function ResetItemAppearanceEvent( area : gamedataEquipmentArea )
	{
		var evt : ResetItemAppearanceEvent;
		var resetItemID : ItemID;
		HideItem( area, false );
		resetItemID = GetActiveItem( area );
		if( ItemID.IsValid( resetItemID ) )
		{
			evt = new ResetItemAppearanceEvent;
			evt.itemID = resetItemID;
			m_eventsSent += 1;
			UpdateVisualTagProcessingInfo( area, true );
			m_owner.QueueEvent( evt );
		}
	}

	public function OnResetItemAppearance( resetItemID : ItemID )
	{
		OnEquipProcessVisualTags( resetItemID );
		m_eventsSent -= 1;
		FinalizeVisualTagProcessing();
	}

	private function ResetItemAppearance( area : gamedataEquipmentArea, optional force : Bool )
	{
		var resetItemID : ItemID;
		var equipAreaIndex : Int32;
		var slotIndex : Int32;
		var visualSlotIndex : Int32;
		var hasVisualOverride : Bool;
		var transactionSystem : TransactionSystem;
		resetItemID = GetActiveItem( area );
		equipAreaIndex = GetEquipAreaIndex( area );
		slotIndex = GetSlotIndex( resetItemID );
		visualSlotIndex = GetVisualSlotIndex( area );
		if( ItemID.IsValid( m_clothingVisualsInfo[ visualSlotIndex ].visualItem ) && ( resetItemID != m_clothingVisualsInfo[ visualSlotIndex ].visualItem ) )
		{
			hasVisualOverride = true;
		}
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		if( ( visualSlotIndex >= 0 ) && hasVisualOverride )
		{
			transactionSystem.ChangeItemAppearanceByItemID( m_owner, resetItemID, m_clothingVisualsInfo[ visualSlotIndex ].visualItem );
		}
		else
		{
			transactionSystem.ResetItemAppearance( m_owner, resetItemID );
		}
		SendPaperdollUpdate( m_equipment.equipAreas[ equipAreaIndex ], true, GetPlacementSlot( equipAreaIndex, slotIndex ), slotIndex, false, force );
		SendEquipAudioEvents( resetItemID );
	}

	private function UpdateInnerChest()
	{
		var itemID : ItemID;
		itemID = GetActiveItem( gamedataEquipmentArea.InnerChest );
		if( ItemID.IsValid( itemID ) && !( IsSlotHidden( gamedataEquipmentArea.InnerChest ) ) )
		{
			ResetItemAppearance( gamedataEquipmentArea.InnerChest, true );
		}
	}

	private function UpdateVisualTagProcessingInfo( area : gamedataEquipmentArea, show : Bool )
	{
		var i : Int32;
		var updated : Bool;
		var info : SVisualTagProcessing;
		info.areaType = area;
		info.showItem = show;
		for( i = 0; i < m_visualTagProcessingInfo.Size(); i += 1 )
		{
			if( m_visualTagProcessingInfo[ i ].areaType == area )
			{
				m_visualTagProcessingInfo[ i ].showItem = show;
				updated = true;
			}
		}
		if( !( updated ) )
		{
			m_visualTagProcessingInfo.PushBack( info );
		}
	}

	private function FinalizeVisualTagProcessing()
	{
		var i : Int32;
		if( m_eventsSent == 0 )
		{
			for( i = 0; i < m_visualTagProcessingInfo.Size(); i += 1 )
			{
				if( m_visualTagProcessingInfo[ i ].showItem )
				{
					ResetItemAppearance( m_visualTagProcessingInfo[ i ].areaType );
				}
				else
				{
					ClearItemAppearance( m_visualTagProcessingInfo[ i ].areaType );
				}
			}
			m_visualTagProcessingInfo.Clear();
		}
	}

	public const function IsSlotHidden( area : gamedataEquipmentArea ) : Bool
	{
		return m_clothingVisualsInfo[ GetVisualSlotIndex( area ) ].isHidden;
	}

	public const function ShouldSlotBeHidden( area : gamedataEquipmentArea ) : Bool
	{
		if( area == gamedataEquipmentArea.UnderwearBottom || area == gamedataEquipmentArea.UnderwearTop )
		{
			return IsSlotHidden( area );
		}
		else
		{
			return IsVisualTagActive( GetVisualTagByAreaType( area ) );
		}
	}

	public const function GetSlotOverridenVisualItem( area : gamedataEquipmentArea ) : ItemID
	{
		var visualSlotIndex : Int32;
		visualSlotIndex = GetVisualSlotIndex( area );
		if( visualSlotIndex < 0 )
		{
			return ItemID.None();
		}
		if( ItemID.IsValid( m_clothingVisualsInfo[ visualSlotIndex ].visualItem ) )
		{
			return m_clothingVisualsInfo[ visualSlotIndex ].visualItem;
		}
		else
		{
			return ItemID.None();
		}
	}

	public function IsUnderwearHidden() : Bool
	{
		var item : ItemID;
		item = GetActiveItem( gamedataEquipmentArea.UnderwearBottom );
		if( ItemID.IsValid( item ) )
		{
			return IsSlotHidden( gamedataEquipmentArea.UnderwearBottom );
		}
		else
		{
			UnderwearEquipFailsafe();
			return true;
		}
	}

	public function EvaluateUnderwearTopHiddenState() : Bool
	{
		var item : ItemID;
		var ts : TransactionSystem;
		var underwearHidden : Bool;
		item = GetActiveItem( gamedataEquipmentArea.UnderwearTop );
		underwearHidden = true;
		if( IsBuildCensored() )
		{
			if( ItemID.IsValid( item ) )
			{
				return IsSlotHidden( gamedataEquipmentArea.UnderwearTop );
			}
			if( IsVisualSetActive() && !( IsVisualSetUnequipInTransition() ) )
			{
				underwearHidden = !( ShouldUnderwearTopBeVisibleInSet() );
			}
			else if( !( ItemID.IsValid( GetVisualItemInSlot( gamedataEquipmentArea.InnerChest ) ) ) && !( IsVisualTagActive( 'hide_T1' ) ) )
			{
				underwearHidden = false;
			}
			else
			{
				underwearHidden = true;
			}
			UnderwearTopEquipFailsafe();
			m_clothingVisualsInfo[ GetVisualSlotIndex( gamedataEquipmentArea.UnderwearTop ) ].isHidden = underwearHidden;
			return underwearHidden;
		}
		else
		{
			if( ItemID.IsValid( item ) )
			{
				UnequipItem( item );
				ts = GameInstance.GetTransactionSystem( m_owner.GetGame() );
				ts.RemoveItem( m_owner, item, 1 );
			}
		}
		return true;
	}

	private function HideItem( area : gamedataEquipmentArea, hide : Bool )
	{
		var index : Int32;
		index = GetVisualSlotIndex( area );
		if( index >= 0 )
		{
			m_clothingVisualsInfo[ GetVisualSlotIndex( area ) ].isHidden = hide;
		}
	}

	private function GetPlacementSlotByAreaType( area : gamedataEquipmentArea ) : TweakDBID
	{
		var i : Int32;
		for( i = 0; i < m_clothingSlotsInfo.Size(); i += 1 )
		{
			if( m_clothingSlotsInfo[ i ].areaType == area )
			{
				return m_clothingSlotsInfo[ i ].equipSlot;
			}
		}
		return TDBID.None();
	}

	private const function GetVisualTagByAreaType( area : gamedataEquipmentArea ) : CName
	{
		var i : Int32;
		for( i = 0; i < m_clothingSlotsInfo.Size(); i += 1 )
		{
			if( m_clothingSlotsInfo[ i ].areaType == area )
			{
				return m_clothingSlotsInfo[ i ].visualTag;
			}
		}
		return '';
	}

	private function GetAreaTypeByVisualTag( tag : CName ) : gamedataEquipmentArea
	{
		var i : Int32;
		for( i = 0; i < m_clothingSlotsInfo.Size(); i += 1 )
		{
			if( m_clothingSlotsInfo[ i ].visualTag == tag )
			{
				return m_clothingSlotsInfo[ i ].areaType;
			}
		}
		return gamedataEquipmentArea.Invalid;
	}

	private function IsVisualTagValid( tag : CName ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_clothingSlotsInfo.Size(); i += 1 )
		{
			if( m_clothingSlotsInfo[ i ].visualTag == tag )
			{
				return true;
			}
		}
		return false;
	}

	private const function IsVisualTagActive( tag : CName ) : Bool
	{
		var activeItem : ItemID;
		var transactionSystem : TransactionSystem;
		var i : Int32;
		if( tag == '' )
		{
			return false;
		}
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		activeItem = GetActiveItem( gamedataEquipmentArea.Outfit );
		if( ItemID.IsValid( activeItem ) && transactionSystem.MatchVisualTagByItemID( activeItem, m_owner, tag ) )
		{
			return true;
		}
		else
		{
			for( i = 0; i < m_clothingSlotsInfo.Size(); i += 1 )
			{
				activeItem = GetVisualItemInSlot( m_clothingSlotsInfo[ i ].areaType );
				if( ( ItemID.IsValid( activeItem ) && transactionSystem.MatchVisualTagByItemID( activeItem, m_owner, tag ) ) && !( IsSlotHidden( m_clothingSlotsInfo[ i ].areaType ) ) )
				{
					return true;
				}
			}
		}
		return false;
	}

	private const function IsPartialVisualTagActive( itemID : ItemID, transactionSystem : TransactionSystem ) : Bool
	{
		if( transactionSystem.MatchVisualTagByItemID( itemID, m_owner, 'hide_T1part' ) && !( IsSlotHidden( gamedataEquipmentArea.OuterChest ) ) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	private const function ShouldUnderwearBeVisible( unequippedItem : ItemID ) : Bool
	{
		return ( ( IsVisualSetActive() && !( IsVisualSetUnequipInTransition() ) ) ? ( ShouldUnderwearBeVisibleInSet() ) : ( EvaluateUnderwearVisibility( unequippedItem ) ) );
	}

	private const function ShouldUnderwearBeVisibleInSet() : Bool
	{
		var set : ClothingSet;
		var i : Int32;
		var activeItem : ItemID;
		var tagCounter : Int32;
		set = GetActiveWardrobeSet();
		for( i = 0; i < set.clothingList.Size(); i += 1 )
		{
			activeItem = set.clothingList[ i ].visualItem;
			if( ItemID.IsValid( activeItem ) && ( set.clothingList[ i ].areaType == gamedataEquipmentArea.Legs || HasUnderwearVisualTags( activeItem ) ) )
			{
				tagCounter += 1;
			}
		}
		return tagCounter == 0;
	}

	private const function HasUnderwearVisualTags( item : ItemID ) : Bool
	{
		var transactionSystem : TransactionSystem;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		return transactionSystem.MatchVisualTagByItemID( item, m_owner, 'hide_L1' ) || transactionSystem.MatchVisualTagByItemID( item, m_owner, 'hide_Genitals' );
	}

	private const function EvaluateUnderwearVisibility( unequippedItem : ItemID ) : Bool
	{
		var i : Int32;
		var tagCounter : Int32;
		var activeItem : ItemID;
		if( HasUnderwearVisualTags( unequippedItem ) || EquipmentSystem.GetEquipAreaType( unequippedItem ) == gamedataEquipmentArea.Legs )
		{
			for( i = 0; i < m_clothingSlotsInfo.Size(); i += 1 )
			{
				activeItem = GetActiveItem( m_clothingSlotsInfo[ i ].areaType );
				if( ItemID.IsValid( activeItem ) )
				{
					if( activeItem == unequippedItem )
					{
						continue;
					}
					else if( HasUnderwearVisualTags( activeItem ) || m_clothingSlotsInfo[ i ].areaType == gamedataEquipmentArea.Legs )
					{
						tagCounter += 1;
					}
				}
			}
			activeItem = GetActiveItem( gamedataEquipmentArea.Outfit );
			if( ( ItemID.IsValid( activeItem ) && HasUnderwearVisualTags( activeItem ) ) && ( activeItem != unequippedItem ) )
			{
				tagCounter += 1;
			}
			return tagCounter == 0;
		}
		else
		{
			return false;
		}
	}

	private const function ShouldUnderwearTopBeVisible( unequippedItem : ItemID ) : Bool
	{
		return ( ( IsVisualSetActive() && !( IsVisualSetUnequipInTransition() ) ) ? ( ShouldUnderwearTopBeVisibleInSet() ) : ( EvaluateUnderwearTopVisibility( unequippedItem ) ) );
	}

	private const function ShouldUnderwearTopBeVisibleInSet() : Bool
	{
		var transactionSystem : TransactionSystem;
		var set : ClothingSet;
		var i : Int32;
		var activeItem : ItemID;
		var tagCounter : Int32;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		set = GetActiveWardrobeSet();
		for( i = 0; i < set.clothingList.Size(); i += 1 )
		{
			activeItem = set.clothingList[ i ].visualItem;
			if( ItemID.IsValid( activeItem ) && ( set.clothingList[ i ].areaType == gamedataEquipmentArea.InnerChest || transactionSystem.MatchVisualTagByItemID( activeItem, m_owner, 'hide_T1' ) ) )
			{
				tagCounter += 1;
			}
		}
		return tagCounter == 0;
	}

	private const function EvaluateUnderwearTopVisibility( unequippedItem : ItemID ) : Bool
	{
		var i : Int32;
		var tagCounter : Int32;
		var activeItem : ItemID;
		var transactionSystem : TransactionSystem;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		if( transactionSystem.MatchVisualTagByItemID( unequippedItem, m_owner, 'hide_T1' ) || EquipmentSystem.GetEquipAreaType( unequippedItem ) == gamedataEquipmentArea.InnerChest )
		{
			for( i = 0; i < m_clothingSlotsInfo.Size(); i += 1 )
			{
				activeItem = GetActiveItem( m_clothingSlotsInfo[ i ].areaType );
				if( ItemID.IsValid( activeItem ) )
				{
					if( activeItem == unequippedItem )
					{
						continue;
					}
					else if( transactionSystem.MatchVisualTagByItemID( activeItem, m_owner, 'hide_T1' ) || m_clothingSlotsInfo[ i ].areaType == gamedataEquipmentArea.InnerChest )
					{
						tagCounter += 1;
					}
				}
			}
			activeItem = GetActiveItem( gamedataEquipmentArea.Outfit );
			if( ( ItemID.IsValid( activeItem ) && transactionSystem.MatchVisualTagByItemID( activeItem, m_owner, 'hide_T1' ) ) && ( activeItem != unequippedItem ) )
			{
				tagCounter += 1;
			}
			return tagCounter == 0;
		}
		else
		{
			return false;
		}
	}

	private function UnderwearEquipFailsafe()
	{
		var transactionSystem : TransactionSystem;
		var underwear : ItemID;
		var evt : UnderwearEquipFailsafeEvent;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		underwear = ItemID.CreateQuery( T"Items.Underwear_Basic_01_Bottom" );
		if( !( transactionSystem.HasItem( m_owner, underwear ) ) )
		{
			transactionSystem.GiveItem( m_owner, underwear, 1 );
		}
		if( !( transactionSystem.HasItemInSlot( m_owner, T"AttachmentSlots.UnderwearBottom", underwear ) ) )
		{
			evt = new UnderwearEquipFailsafeEvent;
			evt.bottom = true;
			GameInstance.GetDelaySystem( m_owner.GetGame() ).DelayEventNextFrame( m_owner, evt );
		}
	}

	private function UnderwearTopEquipFailsafe()
	{
		var transactionSystem : TransactionSystem;
		var underwear : ItemID;
		var evt : UnderwearEquipFailsafeEvent;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		underwear = ItemID.CreateQuery( T"Items.Underwear_Basic_01_Top" );
		if( !( transactionSystem.HasItem( m_owner, underwear ) ) )
		{
			transactionSystem.GiveItem( m_owner, underwear, 1 );
		}
		if( !( transactionSystem.HasItemInSlot( m_owner, T"AttachmentSlots.UnderwearTop", underwear ) ) )
		{
			evt = new UnderwearEquipFailsafeEvent;
			evt.bottom = false;
			GameInstance.GetDelaySystem( m_owner.GetGame() ).DelayEventNextFrame( m_owner, evt );
		}
	}

	public function OnUnderwearEquipFailsafe( bottom : Bool )
	{
		var underwear : ItemID;
		if( bottom )
		{
			underwear = ItemID.CreateQuery( T"Items.Underwear_Basic_01_Bottom" );
		}
		else
		{
			underwear = ItemID.CreateQuery( T"Items.Underwear_Basic_01_Top" );
		}
		EquipItem( underwear, false, false );
	}

	public const function GetActiveWardrobeSet() : ClothingSet
	{
		var set : ClothingSet;
		if( IsVisualSetActive() )
		{
			set = m_wardrobeSystem.GetActiveClothingSet();
		}
		else
		{
			set = new ClothingSet;
		}
		return set;
	}

	public function OnQuestDisableWardrobeSetRequest( request : QuestDisableWardrobeSetRequest )
	{
		m_wardrobeDisabled = request.blockReequipping;
		if( IsVisualSetActive() )
		{
			m_lastActiveWardrobeSet = m_wardrobeSystem.GetActiveClothingSetIndex();
			UnequipWardrobeSet();
		}
	}

	public function OnQuestRestoreWardrobeSetRequest( request : QuestRestoreWardrobeSetRequest )
	{
		m_wardrobeDisabled = false;
		if( m_lastActiveWardrobeSet != gameWardrobeClothingSetIndex.INVALID )
		{
			EquipWardrobeSet( m_lastActiveWardrobeSet );
			m_lastActiveWardrobeSet = gameWardrobeClothingSetIndex.INVALID;
		}
	}

	public function OnQuestEnableWardrobeSetRequest( request : QuestEnableWardrobeSetRequest )
	{
		m_wardrobeDisabled = false;
	}

	public function EquipWardrobeSet( setID : gameWardrobeClothingSetIndex )
	{
		var clothingSet : ClothingSet;
		var outfit : ItemID;
		var outfitData : weak< gameItemData >;
		var i : Int32;
		var visualItem : ItemID;
		clothingSet = FindWardrobeClothingSetByID( setID );
		outfit = GetActiveItem( gamedataEquipmentArea.Outfit );
		if( ( m_wardrobeDisabled || setID == gameWardrobeClothingSetIndex.INVALID ) || ( clothingSet.clothingList.Size() == 0 ) )
		{
			return;
		}
		if( ItemID.IsValid( outfit ) )
		{
			outfitData = GameInstance.GetTransactionSystem( m_owner.GetGame() ).GetItemData( m_owner, outfit );
		}
		if( outfitData && outfitData.HasTag( 'UnequipBlocked' ) )
		{
			return;
		}
		else
		{
			if( ItemID.IsValid( outfit ) )
			{
				UnequipItem( outfit );
			}
			m_wardrobeSystem.SetActiveClothingSetIndex( setID );
			for( i = 0; i <= clothingSet.clothingList.Size(); i += 1 )
			{
				visualItem = clothingSet.clothingList[ i ].visualItem;
				if( ItemID.IsValid( visualItem ) )
				{
					EquipVisuals( visualItem );
				}
				else
				{
					ClearVisuals( clothingSet.clothingList[ i ].areaType );
				}
			}
		}
	}

	public const function FindWardrobeClothingSetByID( setID : gameWardrobeClothingSetIndex ) : ClothingSet
	{
		var clothingSets : array< ClothingSet >;
		var i : Int32;
		clothingSets = m_wardrobeSystem.GetClothingSets();
		for( i = 0; i <= clothingSets.Size(); i += 1 )
		{
			if( clothingSets[ i ].setID == setID )
			{
				return clothingSets[ i ];
			}
		}
		return new ClothingSet;
	}

	public function UnequipWardrobeSet()
	{
		var currentSet : ClothingSet;
		var i : Int32;
		currentSet = GetActiveWardrobeSet();
		if( m_wardrobeSystem.GetActiveClothingSetIndex() != gameWardrobeClothingSetIndex.INVALID )
		{
			m_visualUnequipTransition = true;
			for( i = 0; i <= currentSet.clothingList.Size(); i += 1 )
			{
				UnequipVisuals( currentSet.clothingList[ i ].areaType );
			}
			m_visualUnequipTransition = false;
			m_wardrobeSystem.SetActiveClothingSetIndex( gameWardrobeClothingSetIndex.INVALID );
		}
		UpdateUIBBAreaChanged( gamedataEquipmentArea.Outfit, 0 );
	}

	public function DeleteWardrobeSet( setID : gameWardrobeClothingSetIndex )
	{
		if( m_wardrobeSystem.GetActiveClothingSetIndex() == setID )
		{
			UnequipWardrobeSet();
		}
		m_wardrobeSystem.DeleteClothingSet( setID );
	}

	public const function IsVisualSetActive() : Bool
	{
		var activeClothingSetIndex : gameWardrobeClothingSetIndex;
		activeClothingSetIndex = m_wardrobeSystem.GetActiveClothingSetIndex();
		return activeClothingSetIndex != gameWardrobeClothingSetIndex.INVALID;
	}

	public const function IsVisualSetUnequipInTransition() : Bool
	{
		return m_visualUnequipTransition;
	}

	public const function IsSlotOverriden( area : gamedataEquipmentArea ) : Bool
	{
		var visualSlotIndex : Int32;
		visualSlotIndex = GetVisualSetIndex( area );
		return visualSlotIndex >= 0;
	}

	private const function GetVisualSetIndex( area : gamedataEquipmentArea ) : Int32
	{
		var i : Int32;
		i = -1;
		if( IsVisualSetActive() )
		{
			i = GetVisualSlotIndex( area );
		}
		return ( ( ( i >= 0 ) && ItemID.IsValid( m_clothingVisualsInfo[ i ].visualItem ) ) ? ( i ) : ( -1 ) );
	}

	private const function GetVisualSlotIndex( area : gamedataEquipmentArea, optional excludeUnderwear : Bool ) : Int32
	{
		var i : Int32;
		if( area == gamedataEquipmentArea.Outfit || ( excludeUnderwear && IsUnderwear( area ) ) )
		{
			return -1;
		}
		for( i = 0; i <= m_clothingVisualsInfo.Size(); i += 1 )
		{
			if( m_clothingVisualsInfo[ i ].areaType == area )
			{
				return i;
			}
		}
		return -1;
	}

	public const function GetVisualItemInSlot( area : gamedataEquipmentArea ) : ItemID
	{
		var item : ItemID;
		var visualSlotIndex : Int32;
		visualSlotIndex = GetVisualSlotIndex( area, true );
		if( IsVisualSetActive() && ( visualSlotIndex != -1 ) )
		{
			item = m_clothingVisualsInfo[ visualSlotIndex ].visualItem;
		}
		else
		{
			item = GetActiveItem( area );
		}
		return item;
	}

	private const function IsUnderwear( area : gamedataEquipmentArea ) : Bool
	{
		return area == gamedataEquipmentArea.UnderwearBottom || area == gamedataEquipmentArea.UnderwearTop;
	}

	public const function IsWardrobeEnabled() : Bool
	{
		return !( m_wardrobeDisabled );
	}

	private function GetHighestPriorityMovementAudio() : CName
	{
		var i : Int32;
		var j : Int32;
		var soundName : CName;
		var priority, maxPriority : Float;
		for( i = 0; i < m_equipment.equipAreas.Size(); i += 1 )
		{
			for( j = 0; j < m_equipment.equipAreas[ i ].equipSlots.Size(); j += 1 )
			{
				priority = RPGManager.GetItemRecord( m_equipment.equipAreas[ i ].equipSlots[ j ].itemID ).MovementSound().Priority();
				if( priority > maxPriority )
				{
					maxPriority = priority;
					soundName = RPGManager.GetItemRecord( m_equipment.equipAreas[ i ].equipSlots[ j ].itemID ).MovementSound().AudioMovementName();
				}
			}
		}
		return soundName;
	}

	private const function IsItemAWeapon( item : ItemID ) : Bool
	{
		var record : Item_Record;
		record = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) );
		return record.ItemCategory().Type() == gamedataItemCategory.Weapon;
	}

	private const function IsItemOfCategory( item : ItemID, category : gamedataItemCategory ) : Bool
	{
		var record : Item_Record;
		record = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) );
		if( record && record.ItemCategory() )
		{
			return record.ItemCategory().Type() == category;
		}
		return false;
	}

	private const function IsItemConstructed( item : ItemID ) : Bool
	{
		var record : Item_Record;
		var blueprint : ItemBlueprint_Record;
		record = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) );
		blueprint = record.Blueprint();
		return TDBID.IsValid( blueprint.GetID() );
	}

	public const function IsEquippable( itemData : weak< gameItemData > ) : Bool
	{
		var statsSys : StatsSystem;
		var itemLevel, ownerLevel : Float;
		if( itemData == NULL )
		{
			return false;
		}
		if( RPGManager.IsItemBroken( itemData ) )
		{
			return false;
		}
		if( !( CheckEquipPrereqs( itemData.GetID(), itemData.GetVariant() ) ) )
		{
			return false;
		}
		statsSys = GameInstance.GetStatsSystem( m_owner.GetGame() );
		ownerLevel = statsSys.GetStatValue( m_owner.GetEntityID(), gamedataStatType.Level );
		itemLevel = ( ( Float )( FloorF( itemData.GetStatValueByType( gamedataStatType.Level ) ) ) );
		return ownerLevel >= itemLevel;
	}

	public const function IsItemInHotkey( itemID : ItemID ) : Bool
	{
		return HotkeyManager.IsItemInHotkey( m_hotkeys, itemID );
	}

	public const function GetHotkeyTypeForItemID( itemID : ItemID ) : EHotkey
	{
		return HotkeyManager.GetHotkeyTypeForItemID( m_owner, m_hotkeys, itemID );
	}

	public const function GetHotkeyTypeFromItemID( itemID : ItemID ) : EHotkey
	{
		return HotkeyManager.GetHotkeyTypeFromItemID( m_hotkeys, itemID );
	}

	public const function GetItemIDFromHotkey( hotkey : EHotkey ) : ItemID
	{
		return HotkeyManager.GetItemIDFromHotkey( m_hotkeys, hotkey );
	}

	private const function CheckEquipPrereqs( itemID : ItemID, randomVariant : Int32 ) : Bool
	{
		var i : Int32;
		var result : Bool;
		var prereqs : array< weak< IPrereq_Record > >;
		var itemRecord : weak< Item_Record >;
		itemRecord = RPGManager.GetItemRecord( itemID );
		itemRecord.EquipPrereqs( prereqs );
		if( itemRecord.UsesVariants() )
		{
			itemRecord.GetVariantsItem( randomVariant ).VariantPrereqs( prereqs );
		}
		for( i = 0; i < prereqs.Size(); i += 1 )
		{
			result = RPGManager.CheckPrereq( prereqs[ i ], m_owner, ( ( StatsObjectID )( itemID ) ) );
			if( !( result ) )
			{
				return false;
			}
		}
		return true;
	}

	private function AssignNextValidItemToHotkey( currentItem : ItemID ) : Bool
	{
		var currentItemType : gamedataItemType;
		var sameTypeItems : array< ItemID >;
		var newHotkeyItem : ItemID;
		var hotkey : EHotkey;
		var i : Int32;
		hotkey = GetHotkeyTypeFromItemID( currentItem );
		currentItemType = RPGManager.GetItemType( currentItem );
		if( currentItemType == gamedataItemType.Cyb_Launcher || currentItemType == gamedataItemType.Cyb_Ability )
		{
			m_inventoryManager.GetPlayerItemsIDsByType( gamedataItemType.Gad_Grenade, sameTypeItems );
		}
		else if( currentItemType == gamedataItemType.Cyb_HealingAbility )
		{
			m_inventoryManager.GetPlayerItemsIDsByType( gamedataItemType.Con_Inhaler, sameTypeItems );
			m_inventoryManager.GetPlayerItemsIDsByType( gamedataItemType.Con_Injector, sameTypeItems );
		}
		else
		{
			m_inventoryManager.GetPlayerItemsIDsByType( currentItemType, sameTypeItems );
		}
		if( sameTypeItems.Size() > 0 )
		{
			for( i = 0; i < sameTypeItems.Size(); i += 1 )
			{
				if( sameTypeItems[ i ] == currentItem )
				{
					if( sameTypeItems.Size() == 1 )
					{
						ClearItemFromHotkey( hotkey );
						return false;
					}
					newHotkeyItem = GetNextItemInList( sameTypeItems, i );
					if( ItemID.IsValid( newHotkeyItem ) )
					{
						AssignItemToHotkey( newHotkeyItem, hotkey );
						return true;
					}
				}
			}
			AssignItemToHotkey( sameTypeItems[ 0 ], hotkey );
		}
		else
		{
			ClearItemFromHotkey( hotkey );
		}
		return false;
	}

	public function OnHotkeyRefreshRequest( request : HotkeyRefreshRequest )
	{
		var i : Int32;
		var transactionSystem : TransactionSystem;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		if( !( transactionSystem ) )
		{
			return;
		}
		for( i = 0; i < m_hotkeys.Size(); i += 1 )
		{
			if( m_hotkeys[ i ].GetHotkey() == EHotkey.RB || m_hotkeys[ i ].GetHotkey() == EHotkey.DPAD_UP )
			{
				if( transactionSystem.HasItem( m_owner, m_hotkeys[ i ].GetItemID() ) )
				{
					SyncHotkeyData( m_hotkeys[ i ].GetHotkey() );
				}
				else
				{
					AssignNextValidItemToHotkey( m_hotkeys[ i ].GetItemID() );
				}
			}
		}
	}

	public function OnHotkeyAssignmentRequest( request : HotkeyAssignmentRequest )
	{
		AssignItemToHotkey( request.ItemID(), request.GetHotkey() );
		if( request.GetRequestType() == EHotkeyRequestType.Assign )
		{
			ProcessGadgetsTutorials( request.ItemID() );
		}
	}

	public function OnAssignHotkeyIfEmptySlot( request : AssignHotkeyIfEmptySlot )
	{
		var hotkey : EHotkey;
		if( ShouldPickedUpItemBeAddedToHotkey( request.ItemID(), hotkey ) )
		{
			AssignItemToHotkey( request.ItemID(), hotkey );
		}
	}

	public function AssignItemToHotkey( newID : ItemID, hotkey : EHotkey )
	{
		var oldID : ItemID;
		var transactionSystem : TransactionSystem;
		oldID = m_hotkeys[ ( ( Int32 )( hotkey ) ) ].GetItemID();
		if( hotkey != EHotkey.INVALID )
		{
			if( newID != oldID )
			{
				transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
				transactionSystem.OnItemRemovedFromEquipmentSlot( m_owner, oldID );
				transactionSystem.OnItemAddedToEquipmentSlot( m_owner, newID );
				if( RPGManager.GetItemCategory( oldID ) == gamedataItemCategory.Consumable )
				{
					RemoveEquipGLPs( oldID );
				}
				m_hotkeys[ ( ( Int32 )( hotkey ) ) ].StoreItem( newID );
				if( RPGManager.GetItemCategory( newID ) == gamedataItemCategory.Consumable )
				{
					ApplyEquipGLPs( newID );
				}
				SyncHotkeyData( hotkey );
			}
		}
	}

	public function ClearItemFromHotkey( hotkey : EHotkey )
	{
		var oldID : ItemID;
		oldID = m_hotkeys[ ( ( Int32 )( hotkey ) ) ].GetItemID();
		if( hotkey != EHotkey.INVALID )
		{
			if( RPGManager.GetItemCategory( oldID ) == gamedataItemCategory.Consumable )
			{
				RemoveEquipGLPs( oldID );
			}
			m_hotkeys[ ( ( Int32 )( hotkey ) ) ].StoreItem( ItemID.None() );
			SyncHotkeyData( hotkey );
		}
	}

	private function SyncHotkeyData( hotkey : EHotkey )
	{
		var blackboard : IBlackboard;
		blackboard = GameInstance.GetBlackboardSystem( m_owner.GetGame() ).Get( GetAllBlackboardDefs().UI_Hotkeys );
		if( !( blackboard ) )
		{
			return;
		}
		blackboard.SetVariant( GetAllBlackboardDefs().UI_Hotkeys.ModifiedHotkey, hotkey, true );
	}

	private const function ShouldPickedUpItemBeAddedToHotkey( itemID : ItemID, out hotkey : EHotkey ) : Bool
	{
		var i : Int32;
		var type : gamedataItemType;
		type = RPGManager.GetItemType( itemID );
		for( i = 0; i < m_hotkeys.Size(); i += 1 )
		{
			if( m_hotkeys[ i ].IsEmpty() && ( m_hotkeys[ i ].IsCompatible( type ) || m_hotkeys[ i ].IsCompatible( EquipmentSystem.GetEquipAreaType( itemID ) ) ) )
			{
				hotkey = m_hotkeys[ i ].GetHotkey();
				return true;
			}
		}
		hotkey = EHotkey.INVALID;
		return false;
	}

	private function GetNextItemInList( const arr : ref< array< ItemID > >, fromIndex : Int32 ) : ItemID
	{
		if( ( fromIndex > ( arr.Size() - 1 ) ) || ( fromIndex < 0 ) )
		{
			return ItemID.None();
		}
		if( fromIndex == ( arr.Size() - 1 ) )
		{
			return arr[ 0 ];
		}
		else
		{
			return arr[ fromIndex + 1 ];
		}
	}

	private function UnequipItem( itemID : ItemID )
	{
		var equipAreaIndex : Int32;
		if( IsEquipped( itemID ) )
		{
			equipAreaIndex = GetEquipAreaIndex( EquipmentSystem.GetEquipAreaType( itemID ) );
			UnequipItem( equipAreaIndex, GetSlotIndex( itemID ) );
		}
	}

	private function UnequipItem( equipAreaIndex : Int32, slotIndex : Int32, optional forceRemove : Bool )
	{
		var currentItem : ItemID;
		var transactionSystem : TransactionSystem;
		var placementSlot : TweakDBID;
		var unequipNotifyEvent : AudioNotifyItemUnequippedEvent;
		var equipArea : SEquipArea;
		var currentItemRecord : Item_Record;
		var itemData : weak< gameItemData >;
		var visualItemID : ItemID;
		var itemType : gamedataItemType;
		currentItem = m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ slotIndex ].itemID;
		equipArea = GetEquipAreaFromItemID( currentItem );
		currentItemRecord = RPGManager.GetItemRecord( currentItem );
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		itemData = RPGManager.GetItemData( m_owner.GetGame(), m_owner, currentItem );
		if( ( !( forceRemove ) && itemData ) && itemData.HasTag( 'UnequipBlocked' ) )
		{
			return;
		}
		if( equipArea.areaType == gamedataEquipmentArea.SystemReplacementCW )
		{
			AssignItemToHotkey( ItemID.None(), EHotkey.LBRB );
		}
		if( RPGManager.GetItemType( currentItem ) == gamedataItemType.Cyb_Ability )
		{
			AssignNextValidItemToHotkey( GetItemIDFromHotkey( EHotkey.RB ) );
		}
		else if( RPGManager.GetItemType( currentItem ) == gamedataItemType.Cyb_HealingAbility )
		{
			AssignNextValidItemToHotkey( GetItemIDFromHotkey( EHotkey.DPAD_UP ) );
		}
		placementSlot = GetPlacementSlot( equipAreaIndex, slotIndex );
		if( IsItemOfCategory( currentItem, gamedataItemCategory.Weapon ) && ( equipArea.activeIndex == slotIndex ) )
		{
			if( ( currentItem != GetActiveHeavyWeapon() ) && ( currentItem == GetSlotActiveItem( GetRequestSlotFromItemID( currentItem ) ) ) )
			{
				CreateUnequipWeaponManipulationRequest();
			}
			m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ slotIndex ].itemID = ItemID.None();
			if( ( PlayerDevelopmentSystem.GetData( m_owner ).IsNewPerkBought( gamedataNewPerkType.Espionage_Central_Milestone_1 ) > 0 ) && RPGManager.GetItemType( currentItem ) == gamedataItemType.Cyb_NanoWires )
			{
				UnequipCyberwareParts( itemData );
			}
		}
		else if( ( IsItemOfCategory( currentItem, gamedataItemCategory.Gadget ) || RPGManager.GetItemType( currentItem ) == gamedataItemType.Cyb_Launcher ) && ( equipArea.activeIndex == slotIndex ) )
		{
			if( IsItemInHotkey( currentItem ) )
			{
				CreateUnequipGadgetWeaponManipulationRequest();
				AssignNextValidItemToHotkey( GetItemIDFromHotkey( EHotkey.RB ) );
			}
		}
		else if( IsItemOfCategory( currentItem, gamedataItemCategory.Consumable ) && ( equipArea.activeIndex == slotIndex ) )
		{
			itemType = RPGManager.GetItemType( currentItem );
			if( itemType == gamedataItemType.Con_Inhaler || itemType == gamedataItemType.Con_Injector )
			{
				CreateUnequipConsumableWeaponManipulationRequest();
				AssignNextValidItemToHotkey( GetItemIDFromHotkey( EHotkey.DPAD_UP ) );
			}
		}
		else if( ItemID.IsValid( currentItem ) )
		{
			if( IsItemOfCategory( currentItem, gamedataItemCategory.Clothing ) )
			{
				OnUnequipProcessVisualTags( currentItem );
			}
			if( transactionSystem.HasItemInSlot( m_owner, placementSlot, currentItem ) || transactionSystem.IsSlotSpawningItem( m_owner, placementSlot, currentItem ) )
			{
				unequipNotifyEvent = new AudioNotifyItemUnequippedEvent;
				unequipNotifyEvent.itemName = currentItemRecord.EntityName();
				m_owner.QueueEvent( unequipNotifyEvent );
				transactionSystem.RemoveItemFromSlot( m_owner, placementSlot );
				if( IsItemOfCategory( currentItem, gamedataItemCategory.Clothing ) && IsSlotOverriden( equipArea.areaType ) )
				{
					visualItemID = GetVisualItemInSlot( equipArea.areaType );
					transactionSystem.GivePreviewItemByItemID( m_owner, visualItemID );
					transactionSystem.AddItemToSlot( m_owner, placementSlot, transactionSystem.CreatePreviewItemID( visualItemID ), true );
				}
			}
			RemoveSlotGLPs( m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ slotIndex ].slotID );
			m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ slotIndex ].itemID = ItemID.None();
			RemoveEquipGLPs( currentItem );
			SendUnequipAudioEvents( currentItem );
			if( IsItemOfCategory( currentItem, gamedataItemCategory.Cyberware ) && IsItemConstructed( currentItem ) )
			{
				UnequipCyberwareParts( itemData );
			}
		}
		if( itemData.UsesVariants() || equipArea.areaType == gamedataEquipmentArea.RightArm )
		{
			itemData.SubtractStatsOnUnequip( m_owner );
		}
		if( ItemID.IsValid( currentItem ) && equipArea.areaType == gamedataEquipmentArea.ArmsCW )
		{
			HandleArmsCWUnequip( ( ( PlayerPuppet )( m_owner ) ) );
		}
		UpdateWeaponWheel();
		UpdateQuickWheel();
		SendPaperdollUpdate( m_equipment.equipAreas[ equipAreaIndex ], false, placementSlot, slotIndex, true );
		UpdateUIBBAreaChanged( m_equipment.equipAreas[ equipAreaIndex ].areaType, slotIndex );
		transactionSystem.OnItemRemovedFromEquipmentSlot( m_owner, currentItem );
	}

	private function ClearEquipment()
	{
		var i, j : Int32;
		var equipArea : SEquipArea;
		for( i = 0; i < m_equipment.equipAreas.Size(); i += 1 )
		{
			equipArea = m_equipment.equipAreas[ i ];
			if( equipArea.areaType != gamedataEquipmentArea.BaseFists && equipArea.areaType != gamedataEquipmentArea.VDefaultHandgun )
			{
				for( j = 0; j < equipArea.equipSlots.Size(); j += 1 )
				{
					UnequipItem( i, j );
				}
			}
		}
	}

	private function HandleStrongArmsEquip( armsCWID : ItemID )
	{
		m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.BaseFists ) ].equipSlots[ 0 ].itemID = armsCWID;
	}

	private function UnequipCyberwareParts( cyberwareData : weak< gameItemData > )
	{
		var i : Int32;
		var transactionSystem : TransactionSystem;
		var usedSlots : array< TweakDBID >;
		var partData : InnerItemData;
		var staticData : weak< Item_Record >;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		transactionSystem.GetUsedSlotsOnItem( m_owner, cyberwareData.GetID(), usedSlots );
		for( i = 0; i < usedSlots.Size(); i += 1 )
		{
			if( usedSlots[ i ] == T"AttachmentSlots.StatsShardSlot" )
			{
				continue;
			}
			cyberwareData.GetItemPart( partData, usedSlots[ i ] );
			staticData = InnerItemData.GetStaticData( partData );
			if( staticData && staticData.TagsContains( 'DummyPart' ) )
			{
				continue;
			}
			transactionSystem.RemovePart( m_owner, cyberwareData.GetID(), usedSlots[ i ] );
		}
	}

	private function HandleArmsCWUnequip( owner : PlayerPuppet )
	{
		var baseFistsID : ItemID;
		baseFistsID = EquipBaseFists();
		EquipmentSystemPlayerData.UpdateArmSlot( owner, baseFistsID, true );
	}

	private function EquipBaseFists() : ItemID
	{
		var baseFistsID : ItemID;
		var fistsData : gameItemData;
		baseFistsID = GetBaseFistsItemID();
		fistsData = GameInstance.GetTransactionSystem( m_owner.GetGame() ).GetItemData( m_owner, baseFistsID );
		if( fistsData )
		{
			baseFistsID = fistsData.GetID();
		}
		else
		{
			GameInstance.GetTransactionSystem( m_owner.GetGame() ).GiveItem( m_owner, baseFistsID, 1 );
		}
		m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.BaseFists ) ].equipSlots[ 0 ].itemID = baseFistsID;
		return baseFistsID;
	}

	private function ApplyEquipGLPs( itemID : ItemID )
	{
		var gameplayLogicPackageSystem : GameplayLogicPackageSystem;
		var itemRecord : Item_Record;
		var packages : array< weak< GameplayLogicPackage_Record > >;
		var itemData : gameItemData;
		var itemParts : array< InnerItemData >;
		var i : Int32;
		var j : Int32;
		gameplayLogicPackageSystem = GameInstance.GetGameplayLogicPackageSystem( m_owner.GetGame() );
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) );
		packages = GetItemGLPs( ItemID.GetTDBID( itemID ) );
		itemData = GameInstance.GetTransactionSystem( m_owner.GetGame() ).GetItemData( m_owner, itemID );
		for( i = 0; i < packages.Size(); i += 1 )
		{
			gameplayLogicPackageSystem.ApplyPackage( m_owner, m_owner, packages[ i ].GetID() );
		}
		packages.Clear();
		itemData.GetItemParts( itemParts );
		for( i = 0; i < itemParts.Size(); i += 1 )
		{
			itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( InnerItemData.GetItemID( itemParts[ i ] ) ) );
			itemRecord.OnEquip( packages );
			for( j = 0; j < packages.Size(); j += 1 )
			{
				gameplayLogicPackageSystem.ApplyPackage( m_owner, m_owner, packages[ j ].GetID() );
			}
			packages.Clear();
		}
	}

	private function RemoveEquipGLPs( itemID : ItemID )
	{
		var gameplayLogicPackageSystem : GameplayLogicPackageSystem;
		var itemRecord : Item_Record;
		var packages : array< weak< GameplayLogicPackage_Record > >;
		var itemData : gameItemData;
		var itemParts : array< InnerItemData >;
		var i : Int32;
		var j : Int32;
		gameplayLogicPackageSystem = GameInstance.GetGameplayLogicPackageSystem( m_owner.GetGame() );
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) );
		packages = GetItemGLPs( ItemID.GetTDBID( itemID ) );
		itemData = GameInstance.GetTransactionSystem( m_owner.GetGame() ).GetItemData( m_owner, itemID );
		for( i = 0; i < packages.Size(); i += 1 )
		{
			gameplayLogicPackageSystem.RemovePackage( m_owner, packages[ i ].GetID() );
		}
		packages.Clear();
		if( itemData )
		{
			itemData.GetItemParts( itemParts );
		}
		for( i = 0; i < itemParts.Size(); i += 1 )
		{
			packages.Clear();
			itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( InnerItemData.GetItemID( itemParts[ i ] ) ) );
			if( itemRecord )
			{
				itemRecord.OnEquip( packages );
			}
			for( j = 0; j < packages.Size(); j += 1 )
			{
				gameplayLogicPackageSystem.RemovePackage( m_owner, packages[ j ].GetID() );
			}
		}
	}

	private function ApplySlotGLPs( equipSlotID : TweakDBID )
	{
		var gameplayLogicPackageSystem : GameplayLogicPackageSystem;
		var packages : array< weak< GameplayLogicPackage_Record > >;
		var i : Int32;
		gameplayLogicPackageSystem = GameInstance.GetGameplayLogicPackageSystem( m_owner.GetGame() );
		packages = GetSlotGLPs( equipSlotID );
		for( i = 0; i < packages.Size(); i += 1 )
		{
			gameplayLogicPackageSystem.ApplyPackage( m_owner, m_owner, packages[ i ].GetID() );
		}
	}

	private function RemoveSlotGLPs( equipSlotID : TweakDBID )
	{
		var gameplayLogicPackageSystem : GameplayLogicPackageSystem;
		var packages : array< weak< GameplayLogicPackage_Record > >;
		var i : Int32;
		gameplayLogicPackageSystem = GameInstance.GetGameplayLogicPackageSystem( m_owner.GetGame() );
		packages = GetSlotGLPs( equipSlotID );
		for( i = 0; i < packages.Size(); i += 1 )
		{
			gameplayLogicPackageSystem.RemovePackage( m_owner, packages[ i ].GetID() );
		}
	}

	private function GetSlotGLPs( equipSlotID : TweakDBID ) : array< weak< GameplayLogicPackage_Record > >
	{
		var slotRecord : EquipSlot_Record;
		var packages : array< weak< GameplayLogicPackage_Record > >;
		slotRecord = TweakDBInterface.GetEquipSlotRecord( equipSlotID );
		slotRecord.OnInsertion( packages );
		return packages;
	}

	private function GetItemGLPs( itemID : TweakDBID ) : array< weak< GameplayLogicPackage_Record > >
	{
		var itemRecord : Item_Record;
		var packages : array< weak< GameplayLogicPackage_Record > >;
		itemRecord = TweakDBInterface.GetItemRecord( itemID );
		itemRecord.OnEquip( packages );
		return packages;
	}

	public function GetLastUsedItemID( lastUsedWeaponType : ELastUsed ) : ItemID
	{
		var lastUsedStruct : SLastUsedWeapon;
		lastUsedStruct = GetLastUsedStruct();
		switch( lastUsedWeaponType )
		{
			case ELastUsed.Melee:
				return lastUsedStruct.lastUsedMelee;
			case ELastUsed.Ranged:
				return lastUsedStruct.lastUsedRanged;
			case ELastUsed.Weapon:
				return lastUsedStruct.lastUsedWeapon;
			case ELastUsed.Heavy:
				return lastUsedStruct.lastUsedHeavy;
			default:
				return ItemID.None();
		}
	}

	private function SetLastUsedItem( item : ItemID )
	{
		var lastUsedStruct : SLastUsedWeapon;
		var tags : array< CName >;
		lastUsedStruct = GetLastUsedStruct();
		tags = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) ).Tags();
		if( tags.Contains( WeaponObject.GetRangedWeaponTag() ) )
		{
			if( tags.Contains( 'HeavyWeapon' ) )
			{
				lastUsedStruct.lastUsedHeavy = item;
			}
			else
			{
				lastUsedStruct.lastUsedRanged = item;
				lastUsedStruct.lastUsedWeapon = item;
				lastUsedStruct.lastUsedHeavy = ItemID.None();
			}
		}
		else if( tags.Contains( WeaponObject.GetMeleeWeaponTag() ) )
		{
			lastUsedStruct.lastUsedMelee = item;
			lastUsedStruct.lastUsedWeapon = item;
			lastUsedStruct.lastUsedHeavy = ItemID.None();
		}
		else
		{
			return;
		}
		m_lastUsedStruct = lastUsedStruct;
	}

	private function SetSlotActiveItem( slot : EquipmentManipulationRequestSlot, item : ItemID )
	{
		var sink : SDOSink;
		var slotItems : SSlotActiveItems;
		sink = GameInstance.GetScriptsDebugOverlaySystem( m_owner.GetGame() ).CreateSink();
		slotItems = GetSlotActiveItemStruct();
		switch( slot )
		{
			case EquipmentManipulationRequestSlot.Left:
			{
				m_slotActiveItemsInHands.leftHandItem = item;
				break;
			}
			case EquipmentManipulationRequestSlot.Right:
			{
				m_slotActiveItemsInHands.rightHandItem = item;
				break;
			}
			case EquipmentManipulationRequestSlot.Both:
			{
				m_slotActiveItemsInHands.leftHandItem = item;
				m_slotActiveItemsInHands.rightHandItem = item;
				break;
			}
		}
		SDOSink.SetRoot( sink, EquipmentSystem.ComposeSDORootPath( GetOwner(), "Slot active items" ) );
		SDOSink.PushString( sink, "Left hand", ( ( String )( slotItems.leftHandItem ) ) );
		SDOSink.PushString( sink, "Right hand", ( ( String )( slotItems.rightHandItem ) ) );
	}

	public function GetSlotActiveItem( slot : EquipmentManipulationRequestSlot ) : ItemID
	{
		var slotsStruct : SSlotActiveItems;
		slotsStruct = GetSlotActiveItemStruct();
		switch( slot )
		{
			case EquipmentManipulationRequestSlot.Left:
			{
				return slotsStruct.leftHandItem;
			}
			case EquipmentManipulationRequestSlot.Right:
			{
				return slotsStruct.rightHandItem;
			}
			default:
				return ItemID.None();
		}
	}

	public function RemoveItemFromSlotActiveItem( item : ItemID )
	{
		var slotsStruct : SSlotActiveItems;
		slotsStruct = GetSlotActiveItemStruct();
		if( slotsStruct.rightHandItem == item )
		{
			m_slotActiveItemsInHands.rightHandItem = ItemID.None();
		}
		if( slotsStruct.leftHandItem == item )
		{
			m_slotActiveItemsInHands.leftHandItem = ItemID.None();
		}
	}

	private function DrawItem( itemToDraw : ItemID, drawAnimationType : gameEquipAnimationType )
	{
		var equipArea : SEquipArea;
		var equipAreaIndex : Int32;
		var slotIndex : Int32;
		var request : EquipmentSystemWeaponManipulationRequest;
		equipAreaIndex = GetEquipAreaIndex( EquipmentSystem.GetEquipAreaType( itemToDraw ) );
		slotIndex = GetSlotIndex( itemToDraw );
		request = new EquipmentSystemWeaponManipulationRequest;
		equipArea = m_equipment.equipAreas[ equipAreaIndex ];
		request.requestType = EquipmentManipulationAction.Undefined;
		request.equipAnimType = drawAnimationType;
		if( slotIndex == -1 )
		{
			EquipItem( itemToDraw, false, false );
			slotIndex = GetSlotIndex( itemToDraw );
		}
		if( ( slotIndex >= 0 ) && ( slotIndex < equipArea.equipSlots.Size() ) )
		{
			m_equipment.equipAreas[ equipAreaIndex ].activeIndex = slotIndex;
			UpdateActiveWheelItem( GetItemInEquipSlot( equipAreaIndex, slotIndex ) );
			switch( equipArea.areaType )
			{
				case gamedataEquipmentArea.Weapon:
				case gamedataEquipmentArea.BaseFists:
				case gamedataEquipmentArea.ArmsCW:
				case gamedataEquipmentArea.VDefaultHandgun:
				{
					request.requestType = EquipmentManipulationAction.RequestSlotActiveWeapon;
					if( CheckWeaponAgainstGameplayRestrictions( itemToDraw ) )
					{
						SetSlotActiveItem( EquipmentManipulationRequestSlot.Right, itemToDraw );
					}
					UpdateEquipAreaActiveIndex( itemToDraw );
					SetLastUsedItem( itemToDraw );
					break;
				}
				;
				case gamedataEquipmentArea.WeaponHeavy:
				{
					if( CheckWeaponAgainstGameplayRestrictions( itemToDraw ) )
					{
						SetSlotActiveItem( EquipmentManipulationRequestSlot.Right, itemToDraw );
					}
					UpdateEquipAreaActiveIndex( itemToDraw );
					SetLastUsedItem( itemToDraw );
					request.requestType = EquipmentManipulationAction.RequestHeavyWeapon;
					break;
				}
			}
			if( request.requestType != EquipmentManipulationAction.Undefined )
			{
				OnEquipmentSystemWeaponManipulationRequest( request );
			}
		}
	}

	public static function UpdateArmSlot( owner : PlayerPuppet, itemToDraw : ItemID, equipHolsteredItem : Bool )
	{
		var holsteredArms, equippedArmsCW : ItemID;
		var transactionSystem : TransactionSystem;
		var itemTags : array< CName >;
		var equipmentSystemData : EquipmentSystemPlayerData;
		var record : WeaponItem_Record;
		var slotID : TweakDBID;
		if( !( owner ) )
		{
			return;
		}
		record = TweakDBInterface.GetWeaponItemRecord( ItemID.GetTDBID( itemToDraw ) );
		if( !( record ) )
		{
			return;
		}
		if( !( record.HolsteredItem() ) )
		{
			return;
		}
		equipmentSystemData = EquipmentSystem.GetData( owner );
		if( !( equipmentSystemData ) )
		{
			return;
		}
		holsteredArms = ItemID.CreateQuery( record.HolsteredItem().GetID() );
		if( !( ItemID.IsValid( holsteredArms ) ) )
		{
			return;
		}
		transactionSystem = GameInstance.GetTransactionSystem( owner.GetGame() );
		itemTags = record.Tags();
		equippedArmsCW = equipmentSystemData.GetActiveItem( gamedataEquipmentArea.ArmsCW );
		slotID = T"AttachmentSlots.RightArm";
		if( ItemID.IsValid( equippedArmsCW ) )
		{
			if( itemToDraw != equippedArmsCW )
			{
				return;
			}
		}
		else if( itemToDraw != equipmentSystemData.GetItemInEquipSlot( equipmentSystemData.GetEquipAreaIndex( gamedataEquipmentArea.BaseFists ), 0 ) )
		{
			return;
		}
		if( equipHolsteredItem )
		{
			if( !( transactionSystem.HasItem( owner, holsteredArms ) ) )
			{
				transactionSystem.GiveItem( owner, holsteredArms, 1 );
			}
			ForceQualityAndDuplicateStatsShard( owner, itemToDraw, holsteredArms );
			if( !( transactionSystem.HasItemInSlot( owner, slotID, holsteredArms ) ) )
			{
				equipmentSystemData.EquipItem( holsteredArms, false, false );
			}
		}
		else if( !( itemTags.Contains( 'base_fists' ) ) )
		{
			equipmentSystemData.UnequipItem( holsteredArms );
		}
	}

	public static function ForceQualityAndDuplicateStatsShard( owner : PlayerPuppet, originalItemID : ItemID, destinationItemID : ItemID )
	{
		var itemDataOriginal, itemDataDestination : gameItemData;
		var originalStatsShard, destinationStatsShard : InnerItemData;
		var installPartRequest : InstallItemPart;
		var itemModificationSystem : ItemModificationSystem;
		var transactionSystem : TransactionSystem;
		var statsSystem : StatsSystem;
		var originalItemQuality : Float;
		var forcedQualityMod : gameStatModifierData;
		var statsShardSlotTDBID : TweakDBID;
		var duplicateStatsShardItemID : ItemID;
		var emptySlots : array< TweakDBID >;
		statsShardSlotTDBID = T"AttachmentSlots.StatsShardSlot";
		itemDataDestination = RPGManager.GetItemData( owner.GetGame(), owner, destinationItemID );
		if( !( itemDataDestination ) )
		{
			return;
		}
		statsSystem = GameInstance.GetStatsSystem( owner.GetGame() );
		originalItemQuality = statsSystem.GetStatValue( ( ( StatsObjectID )( originalItemID ) ), gamedataStatType.Quality );
		forcedQualityMod = RPGManager.CreateStatModifier( gamedataStatType.Quality, gameStatModifierType.Additive, originalItemQuality );
		statsSystem.ForceModifier( ( ( StatsObjectID )( itemDataDestination.GetID() ) ), forcedQualityMod );
		itemDataOriginal = RPGManager.GetItemData( owner.GetGame(), owner, originalItemID );
		if( itemDataOriginal.HasPartInSlot( statsShardSlotTDBID ) )
		{
			itemDataOriginal.GetItemPart( originalStatsShard, statsShardSlotTDBID );
			if( itemDataDestination.HasPartInSlot( statsShardSlotTDBID ) )
			{
				itemDataDestination.GetItemPart( destinationStatsShard, statsShardSlotTDBID );
				if( RPGManager.IsItemEffectivelyIdentical( InnerItemData.GetItemID( originalStatsShard ), InnerItemData.GetItemID( destinationStatsShard ) ) )
				{
					return;
				}
			}
			else
			{
				itemDataDestination.GetEmptySlotsOnItem( emptySlots );
				if( !( emptySlots.Contains( statsShardSlotTDBID ) ) )
				{
					return;
				}
			}
			duplicateStatsShardItemID = ItemID.DuplicateRandomSeedWithOffset( InnerItemData.GetItemID( originalStatsShard ), InnerItemData.GetStaticData( originalStatsShard ).GetRecordID(), 0 );
			transactionSystem = GameInstance.GetTransactionSystem( owner.GetGame() );
			transactionSystem.GiveItem( owner, duplicateStatsShardItemID, 1 );
			installPartRequest = new InstallItemPart;
			installPartRequest.Set( owner, destinationItemID, duplicateStatsShardItemID, statsShardSlotTDBID );
			itemModificationSystem = ( ( ItemModificationSystem )( GameInstance.GetScriptableSystemsContainer( owner.GetGame() ).Get( 'ItemModificationSystem' ) ) );
			itemModificationSystem.QueueRequest( installPartRequest );
		}
	}

	private function SaveEquipmentSet( const setName : ref< String >, setType : EEquipmentSetType )
	{
		var equipmentSet : SEquipmentSet;
		var areasToSave : array< gamedataEquipmentArea >;
		var itemInfo : SItemInfo;
		var i, j : Int32;
		equipmentSet.setName = StringToName( setName );
		switch( setType )
		{
			case EEquipmentSetType.Offensive:
				areasToSave.PushBack( gamedataEquipmentArea.Weapon );
			areasToSave.PushBack( gamedataEquipmentArea.QuickSlot );
			areasToSave.PushBack( gamedataEquipmentArea.Consumable );
			areasToSave.PushBack( gamedataEquipmentArea.Gadget );
			break;
			case EEquipmentSetType.Defensive:
				break;
			case EEquipmentSetType.Cyberware:
				areasToSave.PushBack( gamedataEquipmentArea.ArmsCW );
			default:
				break;
		}
		for( i = 0; i < m_equipment.equipAreas.Size(); i += 1 )
		{
			if( areasToSave.Contains( m_equipment.equipAreas[ i ].areaType ) )
			{
				for( j = 0; j < m_equipment.equipAreas[ i ].equipSlots.Size(); j += 1 )
				{
					itemInfo.itemID = m_equipment.equipAreas[ i ].equipSlots[ j ].itemID;
					itemInfo.slotIndex = j;
					equipmentSet.setItems.PushBack( itemInfo );
				}
			}
		}
		if( equipmentSet.setItems.Size() > 0 )
		{
			m_equipment.equipmentSets.PushBack( equipmentSet );
		}
	}

	private function LoadEquipmentSet( const setName : ref< String > )
	{
		var i, j, slotIndex : Int32;
		var equipmentSet : SEquipmentSet;
		var itemToEquip : ItemID;
		for( i = 0; i < m_equipment.equipmentSets.Size(); i += 1 )
		{
			equipmentSet = m_equipment.equipmentSets[ i ];
			if( equipmentSet.setName == StringToName( setName ) )
			{
				for( j = 0; j < equipmentSet.setItems.Size(); j += 1 )
				{
					itemToEquip = equipmentSet.setItems[ j ].itemID;
					slotIndex = equipmentSet.setItems[ j ].slotIndex;
					if( GameInstance.GetTransactionSystem( m_owner.GetGame() ).HasItem( m_owner, itemToEquip ) )
					{
						EquipItem( itemToEquip, slotIndex, false );
					}
				}
				return;
			}
		}
		ClearLastUsedStruct();
	}

	private function DeleteEquipmentSet( const setName : ref< String > )
	{
		var i : Int32;
		var equipmentSet : SEquipmentSet;
		for( i = 0; i < m_equipment.equipmentSets.Size(); i += 1 )
		{
			equipmentSet = m_equipment.equipmentSets[ i ];
			if( equipmentSet.setName == StringToName( setName ) )
			{
				m_equipment.equipmentSets.Erase( i );
			}
		}
	}

	private const function GetEquipAreaIndex( equipAreaID : TweakDBID ) : Int32
	{
		var areaType : gamedataEquipmentArea;
		if( TDBID.IsValid( equipAreaID ) )
		{
			areaType = TweakDBInterface.GetEquipmentAreaRecord( equipAreaID ).Type();
			if( areaType != gamedataEquipmentArea.Invalid )
			{
				return m_equipAreaIndexCache[ ( ( Int32 )( areaType ) ) ];
			}
		}
		return -1;
	}

	private const function GetEquipAreaIndex( areaType : gamedataEquipmentArea ) : Int32
	{
		if( areaType != gamedataEquipmentArea.Invalid )
		{
			return m_equipAreaIndexCache[ ( ( Int32 )( areaType ) ) ];
		}
		return -1;
	}

	private const function GetEquipArea( areaType : gamedataEquipmentArea ) : SEquipArea
	{
		var i : Int32;
		var emptyArea : SEquipArea;
		for( i = 0; i < m_equipment.equipAreas.Size(); i += 1 )
		{
			if( m_equipment.equipAreas[ i ].areaType == areaType )
			{
				return m_equipment.equipAreas[ i ];
			}
		}
		return emptyArea;
	}

	public const function GetActiveItemID( equipAreaIndex : Int32 ) : ItemID
	{
		var activeIndex : Int32;
		var activeItem : ItemID;
		activeIndex = m_equipment.equipAreas[ equipAreaIndex ].activeIndex;
		activeItem = GetItemInEquipSlot( equipAreaIndex, activeIndex );
		if( activeItem == ItemID.None() )
		{
			activeIndex = GetNextActiveItemIndex( equipAreaIndex );
			m_equipment.equipAreas[ equipAreaIndex ].activeIndex = activeIndex;
			activeItem = GetItemInEquipSlot( equipAreaIndex, activeIndex );
		}
		return activeItem;
	}

	public const function GetEquipAreaFromItemID( item : ItemID ) : SEquipArea
	{
		var equipAreaIndex : Int32;
		var voidEmptyArea : SEquipArea;
		equipAreaIndex = GetEquipAreaIndex( EquipmentSystem.GetEquipAreaType( item ) );
		if( equipAreaIndex != -1 )
		{
			return m_equipment.equipAreas[ equipAreaIndex ];
		}
		return voidEmptyArea;
	}

	private const function GetItemInEquipSlot( equipAreaIndex : Int32, slotIndex : Int32 ) : ItemID
	{
		return m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ slotIndex ].itemID;
	}

	private const function GetNextActiveItemIndex( equipAreaIndex : Int32 ) : Int32
	{
		var requiredTags : array< CName >;
		return GetNextActiveItemIndex( equipAreaIndex, requiredTags );
	}

	private const function GetNextActiveItemIndex( equipAreaIndex : Int32, const requiredTags : ref< array< CName > > ) : Int32
	{
		var nextIndex : Int32;
		var numSlots : Int32;
		var i : Int32;
		var checkIndex : Int32;
		var equipArea : SEquipArea;
		equipArea = m_equipment.equipAreas[ equipAreaIndex ];
		numSlots = equipArea.equipSlots.Size();
		nextIndex = ( m_equipment.equipAreas[ equipAreaIndex ].activeIndex + 1 ) % numSlots;
		for( i = 0; i < numSlots; i += 1 )
		{
			checkIndex = ( nextIndex + i ) % numSlots;
			if( ItemID.IsValid( equipArea.equipSlots[ checkIndex ].itemID ) && CheckTagsInItem( equipArea.equipSlots[ checkIndex ].itemID, requiredTags ) )
			{
				return checkIndex;
			}
		}
		return 0;
	}

	private const function CheckTagsInItem( itemID : ItemID, const requiredTags : ref< array< CName > > ) : Bool
	{
		var tagNo : Int32;
		var itemTags : array< CName >;
		if( requiredTags.Size() > 0 )
		{
			itemTags = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) ).Tags();
			for( tagNo = 0; tagNo < requiredTags.Size(); tagNo += 1 )
			{
				if( !( itemTags.Contains( requiredTags[ tagNo ] ) ) )
				{
					return false;
				}
			}
		}
		return true;
	}

	private const function GetPlacementSlot( equipAreaIndex : Int32, slotIndex : Int32 ) : TweakDBID
	{
		return EquipmentSystem.GetPlacementSlot( GetItemInEquipSlot( equipAreaIndex, slotIndex ) );
	}

	private const function HasItemInInventory( item : ItemID ) : Bool
	{
		return GameInstance.GetTransactionSystem( m_owner.GetGame() ).HasItem( m_owner, item );
	}

	private const function HasItemEquipped( equipAreaIndex : Int32, optional slotIndex : Int32 ) : Bool
	{
		return ItemID.IsValid( m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ slotIndex ].itemID );
	}

	public const function GetSlotIndex( itemID : ItemID ) : Int32
	{
		var i, j : Int32;
		var equipAreaType : gamedataEquipmentArea;
		var equipSlots : array< SEquipSlot >;
		if( ItemID.IsValid( itemID ) )
		{
			equipAreaType = EquipmentSystem.GetEquipAreaType( itemID );
			i = GetEquipAreaIndex( equipAreaType );
			if( i >= 0 )
			{
				equipSlots = m_equipment.equipAreas[ i ].equipSlots;
				for( j = 0; j < equipSlots.Size(); j += 1 )
				{
					if( equipSlots[ j ].itemID == itemID )
					{
						return j;
					}
				}
			}
		}
		return -1;
	}

	public const function GetSlotIndex( itemID : ItemID, equipAreaType : gamedataEquipmentArea ) : Int32
	{
		var i, j : Int32;
		var equipSlots : array< SEquipSlot >;
		if( ItemID.IsValid( itemID ) )
		{
			i = GetEquipAreaIndex( equipAreaType );
			if( i >= 0 )
			{
				equipSlots = m_equipment.equipAreas[ i ].equipSlots;
				for( j = 0; j < equipSlots.Size(); j += 1 )
				{
					if( equipSlots[ j ].itemID == itemID )
					{
						return j;
					}
				}
			}
		}
		return -1;
	}

	public const function IsSlotLocked( equipAreaType : gamedataEquipmentArea, index : Int32, out visibleWhenLocked : Bool ) : Bool
	{
		var retVal : Bool;
		var i : Int32;
		var equipSlots : array< SEquipSlot >;
		retVal = false;
		i = GetEquipAreaIndex( equipAreaType );
		if( i >= 0 )
		{
			equipSlots = m_equipment.equipAreas[ i ].equipSlots;
			if( index < equipSlots.Size() )
			{
				retVal = IsSlotLocked( equipSlots[ index ], visibleWhenLocked );
			}
		}
		return retVal;
	}

	private const function IsSlotLocked( slot : SEquipSlot, out visibleWhenLocked : Bool ) : Bool
	{
		var retVal : Bool;
		retVal = !( slot.unlockPrereq.IsFulfilled( m_owner.GetGame(), m_owner ) );
		visibleWhenLocked = slot.visibleWhenLocked;
		return retVal;
	}

	private const function GetOwnerGender() : CName
	{
		return m_owner.GetResolvedGenderName();
	}

	private const function GetItemAppearanceForGender( itemID : ItemID ) : CName
	{
		var gender : CName;
		var appearanceName : CName;
		gender = GetOwnerGender();
		if( gender == 'Female' )
		{
			appearanceName = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) ).AppearanceName();
		}
		else
		{
			appearanceName = TweakDBInterface.GetCName( ItemID.GetTDBID( itemID ) + T".appearanceNameMale", '' );
		}
		return appearanceName;
	}

	public const function GetItemInEquipSlot( areaType : gamedataEquipmentArea, slotIndex : Int32 ) : ItemID
	{
		return m_equipment.equipAreas[ GetEquipAreaIndex( areaType ) ].equipSlots[ slotIndex ].itemID;
	}

	public const function GetNumberOfSlots( areaType : gamedataEquipmentArea, optional includeLocked : Bool ) : Int32
	{
		var slots : array< SEquipSlot >;
		var i, size, retVal : Int32;
		retVal = 0;
		slots = m_equipment.equipAreas[ GetEquipAreaIndex( areaType ) ].equipSlots;
		if( includeLocked )
		{
			retVal = slots.Size();
		}
		else
		{
			for( i = 0, size = slots.Size(); i < size; i += 1 )
			{
				if( !( IsSlotLocked( slots[ i ], false ) ) )
				{
					retVal += 1;
				}
			}
		}
		return retVal;
	}

	public const function GetNumberOfItemsInEquipmentArea( areaType : gamedataEquipmentArea ) : Int32
	{
		var items, i : Int32;
		var equipArea : SEquipArea;
		equipArea = m_equipment.equipAreas[ GetEquipAreaIndex( areaType ) ];
		for( i = 0; i < equipArea.equipSlots.Size(); i += 1 )
		{
			if( ItemID.IsValid( equipArea.equipSlots[ i ].itemID ) )
			{
				items += 1;
			}
		}
		return items;
	}

	public const function GetNumberEquippedWeapons() : Int32
	{
		var equipArea : SEquipArea;
		var equipAreaIndex : Int32;
		var numWeaponsEquipped : Int32;
		var i : Int32;
		numWeaponsEquipped = 0;
		equipAreaIndex = GetEquipAreaIndex( gamedataEquipmentArea.WeaponWheel );
		equipArea = m_equipment.equipAreas[ equipAreaIndex ];
		for( i = 0; i < equipArea.equipSlots.Size(); i += 1 )
		{
			if( HasItemEquipped( equipAreaIndex, i ) )
			{
				numWeaponsEquipped += 1;
			}
		}
		return numWeaponsEquipped;
	}

	public const function GetEquippedQuestItems() : array< ItemID >
	{
		var i, j : Int32;
		var itemData : weak< gameItemData >;
		var itemID : ItemID;
		var questItems : array< ItemID >;
		for( i = 0; i < m_equipment.equipAreas.Size(); i += 1 )
		{
			for( j = 0; j < m_equipment.equipAreas[ i ].equipSlots.Size(); j += 1 )
			{
				itemID = m_equipment.equipAreas[ i ].equipSlots[ j ].itemID;
				if( ItemID.IsValid( itemID ) )
				{
					itemData = GameInstance.GetTransactionSystem( m_owner.GetGame() ).GetItemData( m_owner, itemID );
					if( itemData.HasTag( 'Quest' ) )
					{
						questItems.PushBack( itemID );
					}
				}
			}
		}
		return questItems;
	}

	public const function GetActiveItem( equipArea : gamedataEquipmentArea ) : ItemID
	{
		return GetActiveItemID( GetEquipAreaIndex( equipArea ) );
	}

	public const function GetActiveWeaponObject( equipArea : gamedataEquipmentArea ) : ItemObject
	{
		var itemID : ItemID;
		itemID = GetActiveItem( equipArea );
		return GameInstance.GetTransactionSystem( m_owner.GetGame() ).GetItemInSlotByItemID( m_owner, itemID );
	}

	public const function GetNextActiveItem( equipArea : gamedataEquipmentArea ) : ItemID
	{
		return GetItemInEquipSlot( equipArea, GetNextActiveItemIndex( GetEquipAreaIndex( equipArea ) ) );
	}

	public const function GetActiveConsumable() : ItemID
	{
		var consumable : ItemID;
		var containerConsumable : ItemID;
		var blackboard : IBlackboard;
		blackboard = GameInstance.GetBlackboardSystem( m_owner.GetGame() ).Get( GetAllBlackboardDefs().UI_QuickSlotsData );
		containerConsumable = ( ( ItemID )( blackboard.GetVariant( GetAllBlackboardDefs().UI_QuickSlotsData.containerConsumable ) ) );
		if( ItemID.IsValid( containerConsumable ) )
		{
			return containerConsumable;
		}
		consumable = GetItemIDFromHotkey( EHotkey.DPAD_UP );
		if( ItemID.IsValid( consumable ) )
		{
			return consumable;
		}
		return ItemID.None();
	}

	public const function GetNextWeaponWheelItem() : ItemID
	{
		var weaponWheelEquipArea : gamedataEquipmentArea;
		var requiredTags : array< CName >;
		weaponWheelEquipArea = gamedataEquipmentArea.WeaponWheel;
		if( IsMultiplayer() || GameInstance.GetPlayerSystem( m_owner.GetGame() ).IsCPOControlSchemeForced() )
		{
			requiredTags.PushBack( WeaponObject.GetRangedWeaponTag() );
		}
		if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'OneHandedFirearms' ) )
		{
			requiredTags.PushBack( WeaponObject.GetOneHandedRangedWeaponTag() );
		}
		else if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'DriverCombatFirearms' ) )
		{
			requiredTags.PushBack( WeaponObject.GetDriverCombatRangedWeaponTag() );
		}
		else if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'DriverCombatBikeWeapons' ) )
		{
			requiredTags.PushBack( WeaponObject.GetDriverCombatBikeWeaponTag() );
		}
		return GetItemInEquipSlot( weaponWheelEquipArea, GetNextActiveItemIndex( GetEquipAreaIndex( weaponWheelEquipArea ), requiredTags ) );
	}

	public const function GetActiveHeavyWeapon() : ItemID
	{
		return GetActiveItem( gamedataEquipmentArea.WeaponHeavy );
	}

	public const function GetActiveGadget() : ItemID
	{
		var gadget : ItemID;
		gadget = GetItemIDFromHotkey( EHotkey.RB );
		if( ItemID.IsValid( gadget ) )
		{
			return gadget;
		}
		return ItemID.None();
	}

	public const function GetActiveCyberware() : ItemID
	{
		var moduleID : ItemID;
		var moduleRecord : Item_Record;
		var i : Int32;
		var equipArea : SEquipArea;
		if( TweakDBInterface.GetItemRecord( ItemID.GetTDBID( GetItemIDFromHotkey( EHotkey.RB ) ) ).ItemType().Type() == gamedataItemType.Cyb_Launcher )
		{
			return GetItemIDFromHotkey( EHotkey.RB );
		}
		equipArea = m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.ArmsCW ) ];
		for( i = 0; i < GetNumberOfSlots( gamedataEquipmentArea.ArmsCW ); i += 1 )
		{
			moduleID = equipArea.equipSlots[ i ].itemID;
			if( ItemID.IsValid( moduleID ) )
			{
				moduleRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( moduleID ) );
				if( moduleRecord.ItemType().Type() == gamedataItemType.Cyb_Launcher )
				{
					return moduleID;
				}
			}
			else
			{
				moduleID = GetActiveGadget();
				if( ItemID.IsValid( moduleID ) )
				{
					moduleRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( moduleID ) );
					if( moduleRecord.ItemType().Type() == gamedataItemType.Cyb_Ability )
					{
						return moduleID;
					}
				}
			}
		}
		return ItemID.None();
	}

	public const function GetAllAbilityCyberwareSlots() : array< SEquipSlot >
	{
		var cyberwareList : array< SEquipSlot >;
		GetItemsByEquipAreaAndItemType( gamedataEquipmentArea.ArmsCW, gamedataItemType.Cyb_Launcher, cyberwareList );
		GetItemsByEquipAreaAndItemType( gamedataEquipmentArea.AbilityCW, gamedataItemType.Cyb_Launcher, cyberwareList );
		return cyberwareList;
	}

	public const function GetAllCyberwareEquipmentAreas() : array< gamedataEquipmentArea >
	{
		var equipmentAreas : array< gamedataEquipmentArea >;
		equipmentAreas.PushBack( gamedataEquipmentArea.SystemReplacementCW );
		equipmentAreas.PushBack( gamedataEquipmentArea.FrontalCortexCW );
		equipmentAreas.PushBack( gamedataEquipmentArea.EyesCW );
		equipmentAreas.PushBack( gamedataEquipmentArea.MusculoskeletalSystemCW );
		equipmentAreas.PushBack( gamedataEquipmentArea.NervousSystemCW );
		equipmentAreas.PushBack( gamedataEquipmentArea.CardiovascularSystemCW );
		equipmentAreas.PushBack( gamedataEquipmentArea.IntegumentarySystemCW );
		equipmentAreas.PushBack( gamedataEquipmentArea.ArmsCW );
		equipmentAreas.PushBack( gamedataEquipmentArea.LegsCW );
		equipmentAreas.PushBack( gamedataEquipmentArea.HandsCW );
		return equipmentAreas;
	}

	public const function GetActiveMeleeWare() : ItemID
	{
		var moduleID : ItemID;
		var moduleRecord : Item_Record;
		var i : Int32;
		var equipArea : SEquipArea;
		equipArea = m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.ArmsCW ) ];
		for( i = 0; i < GetNumberOfSlots( gamedataEquipmentArea.ArmsCW ); i += 1 )
		{
			moduleID = equipArea.equipSlots[ i ].itemID;
			if( ItemID.IsValid( moduleID ) )
			{
				moduleRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( moduleID ) );
				if( moduleRecord.ItemCategory().Type() == gamedataItemCategory.Weapon )
				{
					return moduleID;
				}
			}
		}
		return ItemID.None();
	}

	public const function IsEquipped( item : ItemID ) : Bool
	{
		return GetSlotIndex( item ) >= 0;
	}

	public const function IsEquipped( item : ItemID, equipmentArea : gamedataEquipmentArea ) : Bool
	{
		return GetSlotIndex( item, equipmentArea ) >= 0;
	}

	public const function IsSideUpgradeEquipped( itemID : ItemID ) : Bool
	{
		var sideUpgradeRecord : Item_Record;
		var itemRecord : Item_Record;
		var retVal : Bool;
		var i : Int32;
		var returnArray : array< SEquipSlot >;
		retVal = false;
		if( RPGManager.CyberwareHasSideUpgrade( itemID, sideUpgradeRecord ) )
		{
			itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) );
			GetItemsByEquipAreaAndItemType( EquipmentSystem.GetEquipAreaType( itemID ), itemRecord.ItemType().Type(), returnArray );
			for( i = 0; i < returnArray.Size(); i += 1 )
			{
				if( ItemID.GetTDBID( returnArray[ i ].itemID ) == sideUpgradeRecord.GetID() )
				{
					retVal = true;
				}
			}
		}
		return retVal;
	}

	public const function GetOriginalItemIDFromSideUpgrade( sideUpgradeID : ItemID ) : ItemID
	{
		var transactionSystem : TransactionSystem;
		var itemList : array< weak< gameItemData > >;
		var itemID : ItemID;
		var j : Int32;
		var partData : InnerItemData;
		var statsShardSlotTDBID : TweakDBID;
		var shardTDBID : TweakDBID;
		var sideUpgradeRecord : Item_Record;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		statsShardSlotTDBID = T"AttachmentSlots.StatsShardSlot";
		if( !( ItemID.IsValid( sideUpgradeID ) ) )
		{
			return ItemID.None();
		}
		sideUpgradeRecord = TDB.GetItemRecord( ItemID.GetTDBID( sideUpgradeID ) );
		transactionSystem.GetItemListByTags( m_owner, sideUpgradeRecord.Tags(), itemList );
		for( j = 0; j < itemList.Size(); j += 1 )
		{
			itemID = itemList[ j ].GetID();
			if( ( ( itemID != sideUpgradeID ) && TDB.GetItemRecord( ItemID.GetTDBID( itemID ) ).Quality().Type() == sideUpgradeRecord.Quality().Type() ) && TDB.GetCName( ItemID.GetTDBID( itemID ) + T".cyberwareType", '' ) == TDB.GetCName( ItemID.GetTDBID( sideUpgradeID ) + T".cyberwareType", '' ) )
			{
				transactionSystem.GetItemData( m_owner, itemID ).GetItemPart( partData, statsShardSlotTDBID );
				shardTDBID = InnerItemData.GetStaticData( partData ).GetRecordID();
				transactionSystem.GetItemData( m_owner, sideUpgradeID ).GetItemPart( partData, statsShardSlotTDBID );
				if( shardTDBID == InnerItemData.GetStaticData( partData ).GetRecordID() )
				{
					return itemID;
				}
			}
		}
		return ItemID.None();
	}

	public function GetLastUsedWeaponItemID() : ItemID
	{
		var item : ItemID;
		var lastUsedWeaponID : ItemID;
		item = ItemID.None();
		lastUsedWeaponID = ItemID.None();
		item = FindItemInEquipArea( GetLastUsedItemID( ELastUsed.Heavy ), gamedataEquipmentArea.WeaponHeavy );
		if( !( ItemID.IsValid( item ) ) )
		{
			lastUsedWeaponID = GetLastUsedItemID( ELastUsed.Weapon );
			item = FindItemInEquipArea( lastUsedWeaponID, gamedataEquipmentArea.WeaponWheel );
			if( !( ItemID.IsValid( item ) ) )
			{
				item = FindItemInEquipArea( lastUsedWeaponID, gamedataEquipmentArea.Weapon );
			}
			if( !( ItemID.IsValid( item ) ) )
			{
				item = FindItemInEquipArea( lastUsedWeaponID, gamedataEquipmentArea.ArmsCW );
			}
			if( !( ItemID.IsValid( item ) ) )
			{
				item = FindItemInEquipArea( lastUsedWeaponID, gamedataEquipmentArea.BaseFists );
			}
		}
		if( CheckWeaponAgainstGameplayRestrictions( item, true ) )
		{
			return item;
		}
		return ItemID.None();
	}

	public function GetActiveWeaponToUnequip() : ItemID
	{
		var equipArea : SEquipArea;
		equipArea = GetEquipAreaFromItemID( GetSlotActiveItem( EquipmentManipulationRequestSlot.Right ) );
		if( equipArea.areaType == gamedataEquipmentArea.BaseFists )
		{
			return GetFistsItemID();
		}
		else
		{
			return GetActiveItem( equipArea.areaType );
		}
	}

	public function GetActiveWeapon() : ItemID
	{
		return GetActiveItem( gamedataEquipmentArea.WeaponWheel );
	}

	public function GetSlotActiveWeapon() : ItemID
	{
		return GetSlotActiveItem( EquipmentManipulationRequestSlot.Right );
	}

	public function GetFirstMeleeWeaponItemID() : ItemID
	{
		var item : ItemID;
		item = ItemID.None();
		item = GetActiveMeleeWare();
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		item = FindItemInEquipAreaByTag( WeaponObject.GetMeleeWeaponTag(), gamedataEquipmentArea.Weapon );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		item = GetFistsItemID();
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		return item;
	}

	public function GetLastUsedMeleeWeaponItemID() : ItemID
	{
		var item : ItemID;
		var lastUsedWeaponID : ItemID;
		item = ItemID.None();
		lastUsedWeaponID = ItemID.None();
		lastUsedWeaponID = GetLastUsedItemID( ELastUsed.Melee );
		item = FindItemInEquipArea( lastUsedWeaponID, gamedataEquipmentArea.WeaponWheel );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		item = FindItemInEquipArea( lastUsedWeaponID, gamedataEquipmentArea.ArmsCW );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		item = FindItemInEquipArea( lastUsedWeaponID, gamedataEquipmentArea.BaseFists );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		return item;
	}

	public function GetLastUsedOrFirstAvailableWeapon() : ItemID
	{
		var item : ItemID;
		item = ItemID.None();
		item = FindItemInEquipArea( GetLastUsedItemID( ELastUsed.Weapon ), gamedataEquipmentArea.WeaponWheel );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		item = FindItemInEquipArea( GetLastUsedItemID( ELastUsed.Weapon ), gamedataEquipmentArea.ArmsCW );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		item = FindItemInEquipArea( GetLastUsedItemID( ELastUsed.Heavy ), gamedataEquipmentArea.WeaponHeavy );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		item = FindItemInEquipArea( GetLastUsedItemID( ELastUsed.Weapon ), gamedataEquipmentArea.BaseFists );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		item = EquipmentSystem.GetFirstAvailableWeapon( m_owner );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		return item;
	}

	public function GetLastUsedOrFirstAvailableRangedWeapon() : ItemID
	{
		var item : ItemID;
		item = ItemID.None();
		item = FindItemInEquipArea( GetLastUsedItemID( ELastUsed.Ranged ), gamedataEquipmentArea.WeaponWheel );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		item = FindItemInEquipAreaByTag( WeaponObject.GetRangedWeaponTag(), gamedataEquipmentArea.Weapon );
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		return item;
	}

	public function GetLastUsedOrFirstAvailableMeleeWeapon() : ItemID
	{
		var item : ItemID;
		item = ItemID.None();
		item = GetLastUsedMeleeWeaponItemID();
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		item = GetFirstMeleeWeaponItemID();
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		return item;
	}

	public function GetLastUsedOrFirstAvailableOneHandedRangedWeapon() : ItemID
	{
		var item : ItemID;
		var itemTags : array< CName >;
		item = ItemID.None();
		item = FindItemInEquipArea( GetLastUsedItemID( ELastUsed.Ranged ), gamedataEquipmentArea.WeaponWheel );
		if( ItemID.IsValid( item ) )
		{
			itemTags = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) ).Tags();
			if( itemTags.Contains( WeaponObject.GetOneHandedRangedWeaponTag() ) )
			{
				return item;
			}
		}
		item = FindItemInEquipAreaByTag( WeaponObject.GetOneHandedRangedWeaponTag(), gamedataEquipmentArea.Weapon );
		return item;
	}

	public function GetLastUsedOrFirstAvailableDriverCombatWeapon( driverCombatWeaponTag : CName ) : ItemID
	{
		var item : ItemID;
		var itemTags : array< CName >;
		item = ItemID.None();
		item = FindItemInEquipArea( GetLastUsedItemID( ELastUsed.Weapon ), gamedataEquipmentArea.WeaponWheel );
		if( ItemID.IsValid( item ) )
		{
			itemTags = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) ).Tags();
			if( itemTags.Contains( driverCombatWeaponTag ) && CheckWeaponAgainstGameplayRestrictions( item ) )
			{
				return item;
			}
		}
		item = FindItemInEquipAreaByTag( driverCombatWeaponTag, gamedataEquipmentArea.Weapon );
		if( ItemID.IsValid( item ) && CheckWeaponAgainstGameplayRestrictions( item ) )
		{
			return item;
		}
		return ItemID.None();
	}

	public function GetWeaponSlotItem( weaponSlot : Int32 ) : ItemID
	{
		var equipArea : SEquipArea;
		var activeItem : ItemID;
		var requestedWeapon : ItemID;
		var item : ItemObject;
		equipArea = m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.WeaponWheel ) ];
		item = GameInstance.GetTransactionSystem( m_owner.GetGame() ).GetItemInSlot( m_owner, T"AttachmentSlots.WeaponRight" );
		if( item )
		{
			activeItem = item.GetItemID();
		}
		if( weaponSlot == 4 )
		{
			requestedWeapon = GetMeleewareOrFistsItemID();
		}
		else
		{
			requestedWeapon = equipArea.equipSlots[ weaponSlot - 1 ].itemID;
		}
		if( ( ItemID.IsValid( requestedWeapon ) && ( requestedWeapon != activeItem ) ) && CheckWeaponAgainstGameplayRestrictions( requestedWeapon ) )
		{
			return requestedWeapon;
		}
		return ItemID.None();
	}

	public function GetNextThrowableWeapon() : ItemID
	{
		var i : Int32;
		var currentItemSlot : Int32;
		var nextItem : ItemID;
		var nextItemSlot : Int32;
		var eqAreaSize : Int32;
		var equipArea : SEquipArea;
		var activeItem : ItemID;
		var itemTags : array< CName >;
		equipArea = m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.WeaponWheel ) ];
		eqAreaSize = equipArea.equipSlots.Size();
		activeItem = GetLastUsedWeaponItemID();
		currentItemSlot = equipArea.activeIndex;
		nextItemSlot = currentItemSlot;
		for( i = 0; i < eqAreaSize; i += 1 )
		{
			nextItemSlot = ( nextItemSlot + 1 ) % eqAreaSize;
			nextItem = equipArea.equipSlots[ nextItemSlot ].itemID;
			if( ( ItemID.IsValid( nextItem ) && ( nextItem != activeItem ) ) && CheckWeaponAgainstGameplayRestrictions( nextItem, true ) )
			{
				itemTags = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( nextItem ) ).Tags();
				if( itemTags.Contains( 'Throwable' ) )
				{
					return nextItem;
				}
			}
		}
		return CycleWeapon( true, false );
	}

	public function CycleWeapon( cycleNext : Bool, onlyCheck : Bool ) : ItemID
	{
		var i : Int32;
		var x : Int32;
		var currentItemSlot : Int32;
		var nextItem : ItemID;
		var nextItemSlot : Int32;
		var eqAreaSize : Int32;
		var equipArea : SEquipArea;
		var activeItem : ItemID;
		var barebonesWeapon : ItemID;
		var direction : Int32;
		equipArea = m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.WeaponWheel ) ];
		eqAreaSize = equipArea.equipSlots.Size();
		if( !( ( ( PlayerPuppet )( m_owner ) ).ShouldAllowCycleToFistCyberware() ) )
		{
			eqAreaSize = eqAreaSize - 1;
		}
		activeItem = GetLastUsedWeaponItemID();
		currentItemSlot = equipArea.activeIndex;
		nextItemSlot = currentItemSlot;
		barebonesWeapon = GetMeleewareOrFistsItemID();
		direction = ( ( cycleNext ) ? ( 1 ) : ( -1 ) );
		if( EquipmentSystem.GetEquipAreaType( activeItem ) == gamedataEquipmentArea.WeaponHeavy )
		{
			nextItem = GetActiveWeapon();
			if( ItemID.IsValid( nextItem ) )
			{
				return nextItem;
			}
		}
		for( i = 0; i < eqAreaSize; i += 1 )
		{
			x = nextItemSlot + direction;
			nextItemSlot = ( ( x % eqAreaSize ) + eqAreaSize ) % eqAreaSize;
			nextItem = equipArea.equipSlots[ nextItemSlot ].itemID;
			if( ( ItemID.IsValid( nextItem ) && ( nextItem != activeItem ) ) && CheckWeaponAgainstGameplayRestrictions( nextItem, true ) )
			{
				return nextItem;
			}
			else if( ( ( !( ItemID.IsValid( nextItem ) ) && ( activeItem != barebonesWeapon ) ) && ( ( nextItemSlot + direction ) != eqAreaSize ) ) && CheckWeaponAgainstGameplayRestrictions( barebonesWeapon, true ) )
			{
				if( !( WeaponObject.IsCyberwareWeapon( barebonesWeapon ) ) && ( nextItemSlot == ( eqAreaSize - 1 ) ) )
				{
					continue;
				}
				else if( WeaponObject.IsCyberwareWeapon( barebonesWeapon ) && ( nextItemSlot != ( eqAreaSize - 1 ) ) )
				{
					continue;
				}
				if( !( onlyCheck ) )
				{
					m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.WeaponWheel ) ].activeIndex = nextItemSlot;
				}
				return barebonesWeapon;
			}
		}
		return ItemID.None();
	}

	public function CheckWeaponAgainstGameplayRestrictions( weaponItem : ItemID, optional suppressDriverWarnings : Bool ) : Bool
	{
		var itemRecord : Item_Record;
		var itemType : gamedataItemType;
		var equipmentArea : gamedataEquipmentArea;
		var itemTags : array< CName >;
		var notificationEvent : UIInGameNotificationEvent;
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( weaponItem ) );
		itemType = itemRecord.ItemType().Type();
		equipmentArea = itemRecord.EquipArea().Type();
		itemTags = itemRecord.Tags();
		notificationEvent = new UIInGameNotificationEvent;
		notificationEvent.m_notificationType = UIInGameNotificationType.ActionRestriction;
		if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'NoWeapons' ) )
		{
			GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
			return false;
		}
		if( ( equipmentArea == gamedataEquipmentArea.ArmsCW && StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'NoArmsCW' ) ) && itemType != gamedataItemType.Cyb_StrongArms )
		{
			return false;
		}
		if( itemTags.Contains( WeaponObject.GetRangedWeaponTag() ) )
		{
			if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'Melee' ) || StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'Fists' ) )
			{
				GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
				return false;
			}
			else if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'OneHandedFirearms' ) && !( itemTags.Contains( WeaponObject.GetOneHandedRangedWeaponTag() ) ) )
			{
				GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
				return false;
			}
			else if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'DriverCombatFirearms' ) && !( itemTags.Contains( WeaponObject.GetDriverCombatRangedWeaponTag() ) ) )
			{
				if( !( suppressDriverWarnings ) )
				{
					GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
				}
				return false;
			}
			else if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'DriverCombatBikeWeapons' ) && !( itemTags.Contains( WeaponObject.GetDriverCombatBikeWeaponTag() ) ) )
			{
				if( !( suppressDriverWarnings ) )
				{
					GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
				}
				return false;
			}
			else
			{
				return true;
			}
		}
		if( itemTags.Contains( WeaponObject.GetMeleeWeaponTag() ) )
		{
			if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'Firearms' ) || StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'OneHandedFirearms' ) )
			{
				GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
				return false;
			}
			else if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'DriverCombatFirearms' ) && !( itemTags.Contains( WeaponObject.GetDriverCombatRangedWeaponTag() ) ) )
			{
				if( !( suppressDriverWarnings ) )
				{
					GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
				}
				return false;
			}
			else if( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'DriverCombatBikeWeapons' ) && !( itemTags.Contains( WeaponObject.GetDriverCombatBikeWeaponTag() ) ) )
			{
				if( !( suppressDriverWarnings ) )
				{
					GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
				}
				return false;
			}
			else if( ( !( WeaponObject.IsFists( weaponItem ) ) && StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'Fists' ) ) && !( StatusEffectSystem.ObjectHasStatusEffect( m_owner, T"GameplayRestriction.FistFight" ) ) )
			{
				GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
				return false;
			}
			else if( ( !( WeaponObject.IsFists( weaponItem ) ) && !( WeaponObject.IsOfType( weaponItem, gamedataItemType.Cyb_StrongArms ) ) ) && StatusEffectSystem.ObjectHasStatusEffect( m_owner, T"GameplayRestriction.FistFight" ) )
			{
				GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
				return false;
			}
			else
			{
				return true;
			}
		}
		if( !( suppressDriverWarnings ) || ( !( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'DriverCombatFirearms' ) ) && !( StatusEffectSystem.ObjectHasStatusEffectWithTag( m_owner, 'DriverCombatBikeWeapons' ) ) ) )
		{
			GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( notificationEvent );
		}
		return false;
	}

	private function RequestEquipmentStateMachine( reqType : EquipmentManipulationRequestType, reqSlot : EquipmentManipulationRequestSlot, equipAnim : gameEquipAnimationType, referenceName : CName, requestName : CName )
	{
		var weaRequest : EquipmentManipulationRequest;
		var psmRequest : PSMPostponedParameterScriptable;
		var psmAdd : PSMAddOnDemandStateMachine;
		var instanceData : StateMachineInstanceData;
		var equipmentInitData : EquipmentInitData;
		weaRequest = new EquipmentManipulationRequest;
		psmRequest = new PSMPostponedParameterScriptable;
		psmAdd = new PSMAddOnDemandStateMachine;
		equipmentInitData = new EquipmentInitData;
		if( ( ( PlayerPuppet )( m_owner ) ).GetPlayerStateMachineBlackboard().GetInt( GetAllBlackboardDefs().PlayerStateMachine.UpperBody ) != ( ( Int32 )( gamePSMUpperBodyStates.ForceEmptyHands ) ) )
		{
			weaRequest.requestType = reqType;
			weaRequest.requestSlot = reqSlot;
			weaRequest.equipAnim = equipAnim;
			psmRequest.value = weaRequest;
			psmRequest.id = requestName;
			psmRequest.aspect = gamestateMachineParameterAspect.Permanent;
			m_owner.QueueEvent( psmRequest );
		}
		psmAdd.stateMachineName = 'Equipment';
		instanceData.referenceName = referenceName;
		psmAdd.instanceData = instanceData;
		equipmentInitData.eqManipulationVarName = requestName;
		psmAdd.instanceData.initData = equipmentInitData;
		psmAdd.owner = m_owner;
		m_owner.QueueEvent( psmAdd );
	}

	public function SendPSMWeaponManipulationRequest( reqType : EquipmentManipulationRequestType, reqSlot : EquipmentManipulationRequestSlot, equipAnim : gameEquipAnimationType )
	{
		if( reqSlot == EquipmentManipulationRequestSlot.Right || reqSlot == EquipmentManipulationRequestSlot.Both )
		{
			RequestEquipmentStateMachine( reqType, reqSlot, equipAnim, 'RightHand', 'EqManipulationRight' );
		}
		if( reqSlot == EquipmentManipulationRequestSlot.Left || reqSlot == EquipmentManipulationRequestSlot.Both )
		{
			RequestEquipmentStateMachine( reqType, reqSlot, equipAnim, 'LeftHand', 'EqManipulationLeft' );
		}
	}

	public function FindItemInEquipArea( item : ItemID, area : gamedataEquipmentArea ) : ItemID
	{
		var items : array< ItemID >;
		var i : Int32;
		items = EquipmentSystem.GetItemsInArea( m_owner, area );
		for( i = 0; i < items.Size(); i += 1 )
		{
			if( items[ i ] == item )
			{
				return items[ i ];
			}
		}
		return ItemID.None();
	}

	public function FindItemInEquipAreaByTag( tag : CName, area : gamedataEquipmentArea ) : ItemID
	{
		var items : array< ItemID >;
		var i : Int32;
		var itemTags : array< CName >;
		items = EquipmentSystem.GetItemsInArea( m_owner, area );
		for( i = 0; i < items.Size(); i += 1 )
		{
			itemTags = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( items[ i ] ) ).Tags();
			if( itemTags.Contains( tag ) )
			{
				return items[ i ];
			}
		}
		return ItemID.None();
	}

	public function RemoveItemFromEquipSlot( item : ItemID )
	{
		var equipAreaIndex : Int32;
		var slotIndex : Int32;
		equipAreaIndex = GetEquipAreaIndex( EquipmentSystem.GetEquipAreaType( item ) );
		slotIndex = GetSlotIndex( item );
		m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ slotIndex ].itemID = ItemID.None();
	}

	private const function UpdateWeaponWheel()
	{
		var weaponWheelItems : array< SEquipSlot >;
		var meleeWare : SEquipSlot;
		weaponWheelItems = m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.Weapon ) ].equipSlots;
		meleeWare.itemID = GetActiveMeleeWare();
		weaponWheelItems.PushBack( meleeWare );
		m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.WeaponWheel ) ].equipSlots = weaponWheelItems;
	}

	public function ClearAllWeaponSlots()
	{
		var i : Int32;
		var index : Int32;
		index = GetEquipAreaIndex( gamedataEquipmentArea.Weapon );
		for( i = 0; i < 3; i += 1 )
		{
			m_equipment.equipAreas[ index ].equipSlots[ i ].itemID = ItemID.None();
		}
		UpdateWeaponWheel();
	}

	private const function UpdateQuickWheel()
	{
		var returnArray : array< SEquipSlot >;
		GetItemsByEquipAreaAndItemType( gamedataEquipmentArea.QuickSlot, gamedataItemType.Invalid, returnArray );
		GetItemsByEquipAreaAndItemType( gamedataEquipmentArea.IntegumentarySystemCW, gamedataItemType.Invalid, returnArray );
		GetItemsByEquipAreaAndItemType( gamedataEquipmentArea.ArmsCW, gamedataItemType.Cyb_Launcher, returnArray );
		GetItemsByEquipAreaAndItemType( gamedataEquipmentArea.SystemReplacementCW, gamedataItemType.Cyb_Ability, returnArray );
		m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.QuickWheel ) ].equipSlots = returnArray;
	}

	private const function GetItemsByEquipAreaAndItemType( equipmentArea : gamedataEquipmentArea, itemType : gamedataItemType, outItems : ref< array< SEquipSlot > > )
	{
		var equipSlots : array< SEquipSlot >;
		var i : Int32;
		var record : Item_Record;
		equipSlots = m_equipment.equipAreas[ GetEquipAreaIndex( equipmentArea ) ].equipSlots;
		for( i = 0; i < equipSlots.Size(); i += 1 )
		{
			if( ItemID.IsValid( equipSlots[ i ].itemID ) )
			{
				if( itemType == gamedataItemType.Invalid )
				{
					outItems.PushBack( equipSlots[ i ] );
				}
				else
				{
					record = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( equipSlots[ i ].itemID ) );
					if( record.ItemType().Type() == itemType )
					{
						outItems.PushBack( equipSlots[ i ] );
					}
				}
			}
		}
	}

	private const function GetAllAbilityCyberwareSlotsByEquipmentArea( equipmentArea : gamedataEquipmentArea, outCyberwareList : ref< array< SEquipSlot > > )
	{
		var equipArea : SEquipArea;
		var cyberwareID : ItemID;
		var cyberwareRecord : Item_Record;
		var i : Int32;
		equipArea = m_equipment.equipAreas[ GetEquipAreaIndex( equipmentArea ) ];
		for( i = 0; i < GetNumberOfSlots( equipmentArea ); i += 1 )
		{
			cyberwareID = equipArea.equipSlots[ i ].itemID;
			if( ItemID.IsValid( cyberwareID ) )
			{
				cyberwareRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( cyberwareID ) );
				if( cyberwareRecord.ItemType().Type() == gamedataItemType.Cyb_Launcher )
				{
					outCyberwareList.PushBack( equipArea.equipSlots[ i ] );
				}
			}
		}
	}

	private function GetFistsItemID() : ItemID
	{
		var items : array< ItemID >;
		items = EquipmentSystem.GetItemsInArea( m_owner, gamedataEquipmentArea.BaseFists );
		if( items.Size() > 0 )
		{
			if( ItemID.IsValid( items[ 0 ] ) )
			{
				return items[ 0 ];
			}
			else
			{
				return EquipBaseFists();
			}
		}
		return ItemID.None();
	}

	private function GetBaseFistsItemID() : ItemID
	{
		return ItemID.CreateQuery( T"Items.w_melee_004__fists_a" );
	}

	private function GetMeleewareOrFistsItemID() : ItemID
	{
		var item : ItemID;
		item = ItemID.None();
		item = GetActiveMeleeWare();
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		return GetFistsItemID();
	}

	private const function UpdateActiveWheelItem( itemID : ItemID )
	{
		var i, equipAreaIndex : Int32;
		equipAreaIndex = GetEquipAreaIndex( gamedataEquipmentArea.WeaponWheel );
		for( i = 0; i < GetNumberOfSlots( gamedataEquipmentArea.WeaponWheel ); i += 1 )
		{
			if( m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ i ].itemID == itemID )
			{
				m_equipment.equipAreas[ equipAreaIndex ].activeIndex = i;
				return;
			}
		}
		equipAreaIndex = GetEquipAreaIndex( gamedataEquipmentArea.QuickWheel );
		for( i = 0; i < GetNumberOfSlots( gamedataEquipmentArea.QuickWheel ); i += 1 )
		{
			if( m_equipment.equipAreas[ equipAreaIndex ].equipSlots[ i ].itemID == itemID )
			{
				m_equipment.equipAreas[ equipAreaIndex ].activeIndex = i;
				return;
			}
		}
	}

	private const function UpdateEquipAreaActiveIndex( newCurrentItem : ItemID )
	{
		var i : Int32;
		var areaIndex : Int32;
		var areaType : gamedataEquipmentArea;
		areaType = EquipmentSystem.GetEquipAreaType( newCurrentItem );
		areaIndex = GetEquipAreaIndex( areaType );
		for( i = 0; i < GetNumberOfSlots( areaType ); i += 1 )
		{
			if( m_equipment.equipAreas[ areaIndex ].equipSlots[ i ].itemID == newCurrentItem )
			{
				m_equipment.equipAreas[ areaIndex ].activeIndex = i;
				break;
			}
		}
		UpdateActiveWheelItem( newCurrentItem );
	}

	private const function UpdateEquipmentUIBB( paperDollEqData : SPaperdollEquipData, optional forceFire : Bool )
	{
		var equipmentBB : IBlackboard;
		var paperdollAreas : array< gamedataEquipmentArea >;
		equipmentBB = GameInstance.GetBlackboardSystem( m_owner.GetGame() ).Get( GetAllBlackboardDefs().UI_Equipment );
		if( equipmentBB )
		{
			equipmentBB.SetVariant( GetAllBlackboardDefs().UI_Equipment.itemEquipped, paperDollEqData.equipArea.equipSlots[ paperDollEqData.slotIndex ].itemID, true );
			paperdollAreas = GetPaperDollSlots();
			paperdollAreas.PushBack( gamedataEquipmentArea.Weapon );
			if( paperdollAreas.Contains( paperDollEqData.equipArea.areaType ) )
			{
				equipmentBB.SetVariant( GetAllBlackboardDefs().UI_Equipment.lastModifiedArea, paperDollEqData, forceFire );
				equipmentBB.FireCallbacks();
			}
		}
	}

	private const function UpdateUIBBAreaChanged( equipmentArea : gamedataEquipmentArea, slotIndex : Int32 )
	{
		var equipmentBB : IBlackboard;
		equipmentBB = GameInstance.GetBlackboardSystem( m_owner.GetGame() ).Get( GetAllBlackboardDefs().UI_Equipment );
		if( equipmentBB )
		{
			equipmentBB.SetInt( GetAllBlackboardDefs().UI_Equipment.areaChangedSlotIndex, slotIndex );
			equipmentBB.SetInt( GetAllBlackboardDefs().UI_Equipment.areaChanged, ( ( Int32 )( equipmentArea ) ), true );
		}
	}

	public const function GetPaperDollEquipAreas() : array< SEquipArea >
	{
		var i : Int32;
		var areas : array< SEquipArea >;
		var slots : array< gamedataEquipmentArea >;
		slots = GetPaperDollSlots();
		for( i = 0; i < slots.Size(); i += 1 )
		{
			areas.PushBack( GetEquipArea( slots[ i ] ) );
		}
		return areas;
	}

	public const function GetPaperDollItems() : array< ItemID >
	{
		var i : Int32;
		var item : ItemID;
		var items : array< ItemID >;
		var slots : array< gamedataEquipmentArea >;
		slots = GetPaperDollSlots();
		for( i = 0; i < slots.Size(); i += 1 )
		{
			item = GetActiveItem( slots[ i ] );
			if( ItemID.IsValid( item ) )
			{
				items.PushBack( item );
			}
		}
		return items;
	}

	public const function GetPaperDollSlots() : array< gamedataEquipmentArea >
	{
		var slots : array< gamedataEquipmentArea >;
		slots.PushBack( gamedataEquipmentArea.Outfit );
		slots.PushBack( gamedataEquipmentArea.OuterChest );
		slots.PushBack( gamedataEquipmentArea.InnerChest );
		slots.PushBack( gamedataEquipmentArea.Head );
		slots.PushBack( gamedataEquipmentArea.Face );
		slots.PushBack( gamedataEquipmentArea.Legs );
		slots.PushBack( gamedataEquipmentArea.Feet );
		slots.PushBack( gamedataEquipmentArea.HandsCW );
		slots.PushBack( gamedataEquipmentArea.RightArm );
		if( IsBuildCensored() )
		{
			slots.PushBack( gamedataEquipmentArea.UnderwearTop );
		}
		if( !( ShouldShowGenitals() ) || IsBuildCensored() )
		{
			slots.PushBack( gamedataEquipmentArea.UnderwearBottom );
		}
		return slots;
	}

	public const function ShouldShowGenitals() : Bool
	{
		var charCustomization : gameuiICharacterCustomizationState;
		charCustomization = GameInstance.GetCharacterCustomizationSystem( m_owner.GetGame() ).GetState();
		if( charCustomization != NULL )
		{
			return ( charCustomization.HasOption( 'genitals', 'genitals_01', false ) || charCustomization.HasOption( 'genitals', 'genitals_02', false ) ) || charCustomization.HasOption( 'genitals', 'genitals_03', false );
		}
		return false;
	}

	public const function IsBuildCensored() : Bool
	{
		var charCustomization : gameuiICharacterCustomizationSystem;
		charCustomization = GameInstance.GetCharacterCustomizationSystem( m_owner.GetGame() );
		if( charCustomization != NULL )
		{
			return !( charCustomization.IsNudityAllowed() );
		}
		else
		{
			return false;
		}
	}

	public function OnEquipRequest( request : EquipRequest )
	{
		ProcessEquipRequest( request.owner, request.slotIndex, request.addToInventory, request.itemID, request.equipToCurrentActiveSlot, false, true );
	}

	public function OnGameplayEquipRequest( request : GameplayEquipRequest )
	{
		var equipProgramsRequest : GameplayEquipProgramsRequest;
		ProcessEquipRequest( request.owner, request.slotIndex, request.addToInventory, request.itemID, request.equipToCurrentActiveSlot, request.blockUpdateWeaponActiveSlots, request.forceEquipWeapon, request.extraQuality );
		if( request.partsToAdd.Size() > 0 )
		{
			equipProgramsRequest = new GameplayEquipProgramsRequest;
			equipProgramsRequest.owner = request.owner;
			equipProgramsRequest.programIDs = request.partsToAdd;
			OnGameplayEquipProgramsRequest( equipProgramsRequest );
		}
	}

	public function OnGameplayEquipProgramsRequest( request : GameplayEquipProgramsRequest )
	{
		var cyberdeckID : ItemID;
		var i : Int32;
		var transactionSystem : TransactionSystem;
		var availableSlots : array< TweakDBID >;
		transactionSystem = GameInstance.GetTransactionSystem( request.owner.GetGame() );
		cyberdeckID = EquipmentSystem.GetData( request.owner ).GetActiveItem( gamedataEquipmentArea.SystemReplacementCW );
		if( !( EquipmentSystem.IsItemCyberdeck( cyberdeckID ) ) )
		{
			return;
		}
		transactionSystem.GetAvailableSlotsOnItem( request.owner, cyberdeckID, availableSlots );
		for( i = 0; ( i < availableSlots.Size() ) && ( i < request.programIDs.Size() ); i += 1 )
		{
			transactionSystem.AddPart( request.owner, cyberdeckID, request.programIDs[ i ], availableSlots[ i ] );
			ApplyEquipGLPs( request.programIDs[ i ] );
		}
	}

	private function ProcessEquipRequest( owner : weak< GameObject >, slotIndex : Int32, addToInventory : Bool, itemID : ItemID, equipToCurrentActiveSlot : Bool, optional blockUpdateWeaponActiveSlots : Bool, optional forceEquipWeapon : Bool, optional extraQuality : Float )
	{
		var statsSystem : StatsSystem;
		var modifier : gameConstantStatModifierData;
		if( IsMultiplayer() && equipToCurrentActiveSlot )
		{
			slotIndex = m_equipment.equipAreas[ GetEquipAreaIndex( EquipmentSystem.GetEquipAreaType( itemID ) ) ].activeIndex;
		}
		if( addToInventory )
		{
			if( !( GameInstance.GetTransactionSystem( owner.GetGame() ).HasItem( owner, itemID ) ) )
			{
				itemID = ItemID.FromTDBID( ItemID.GetTDBID( itemID ) );
				GameInstance.GetTransactionSystem( owner.GetGame() ).GiveItem( owner, itemID, 1, RPGManager.GetItemRecord( itemID ).Tags() );
			}
			else
			{
				itemID = GameInstance.GetTransactionSystem( owner.GetGame() ).GetItemData( owner, itemID ).GetID();
			}
		}
		if( extraQuality > 0.0 )
		{
			statsSystem = GameInstance.GetStatsSystem( owner.GetGame() );
			modifier = new gameConstantStatModifierData;
			modifier.modifierType = gameStatModifierType.Additive;
			modifier.statType = gamedataStatType.Quality;
			modifier.value = extraQuality;
			statsSystem.AddSavedModifier( ( ( StatsObjectID )( itemID ) ), modifier );
		}
		if( slotIndex == -1 )
		{
			EquipItem( itemID, blockUpdateWeaponActiveSlots, forceEquipWeapon );
		}
		else
		{
			EquipItem( itemID, slotIndex, blockUpdateWeaponActiveSlots, forceEquipWeapon );
		}
	}

	public function OnEquipVisualsRequest( request : EquipVisualsRequest )
	{
		EquipVisuals( request.itemID );
	}

	public function OnUnequipVisualsRequest( request : UnequipVisualsRequest )
	{
		UnequipVisuals( request.area );
	}

	public function OnAssignToCyberwareWheelRequest( request : AssignToCyberwareWheelRequest )
	{
		var cyberwareBB : IBlackboard;
		if( m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.CyberwareWheel ) ].equipSlots.Size() <= request.slotIndex )
		{
			return;
		}
		m_equipment.equipAreas[ GetEquipAreaIndex( gamedataEquipmentArea.CyberwareWheel ) ].equipSlots[ request.slotIndex ].itemID = request.itemID;
		UpdateQuickWheel();
		cyberwareBB = GameInstance.GetBlackboardSystem( m_owner.GetGame() ).Get( GetAllBlackboardDefs().UI_QuickSlotsData );
		cyberwareBB.SetBool( GetAllBlackboardDefs().UI_QuickSlotsData.CyberwareAssignmentComplete, true, true );
	}

	public function OnUnequipRequest( request : UnequipRequest )
	{
		UnequipItem( GetEquipAreaIndex( request.areaType ), request.slotIndex, request.force );
	}

	public function OnUnequipItemsRequest( request : UnequipItemsRequest )
	{
		var hotkey : EHotkey;
		var itemID : ItemID;
		var i : Int32;
		for( i = 0; i < request.items.Size(); i += 1 )
		{
			itemID = request.items[ i ];
			UnequipItem( itemID );
			hotkey = GetHotkeyTypeFromItemID( itemID );
			if( hotkey != EHotkey.INVALID )
			{
				if( AssignNextValidItemToHotkey( itemID ) )
				{
					return;
				}
				AssignItemToHotkey( ItemID.None(), hotkey );
			}
		}
	}

	public function OnUnequipByTDBIDRequest( request : UnequipByTDBIDRequest )
	{
		var itemQuery : ItemID;
		var eqRequest : EquipmentSystemWeaponManipulationRequest;
		itemQuery = ItemID.CreateQuery( request.itemTDBID );
		if( RPGManager.GetItemCategory( itemQuery ) == gamedataItemCategory.Weapon )
		{
			eqRequest = new EquipmentSystemWeaponManipulationRequest;
			eqRequest.requestType = EquipmentManipulationAction.UnequipWeapon;
			OnEquipmentSystemWeaponManipulationRequest( eqRequest );
		}
		else
		{
			UnequipItem( itemQuery );
		}
	}

	public function OnInstallCyberwareRequest( request : InstallCyberwareRequest )
	{
		if( request.slotIndex == -1 )
		{
			EquipItem( request.itemID, false );
		}
		else
		{
			EquipItem( request.itemID, request.slotIndex, false );
		}
	}

	public function OnUninstallCyberwareRequest( request : UninstallCyberwareRequest )
	{
		UnequipItem( GetEquipAreaIndex( request.areaType ), request.slotIndex );
	}

	public function OnReplaceEquipmentRequest( request : ReplaceEquipmentRequest )
	{
		var transactionSystem : TransactionSystem;
		var owner : GameObject;
		var itemID : ItemID;
		var oldItemID : ItemID;
		var equipAreaIndex : Int32;
		var itemModParams : ItemModParams;
		var itemModParamsArray : array< ItemModParams >;
		var equipArea : gamedataEquipmentArea;
		var i : Int32;
		var j : Int32;
		var availableSlots : array< TweakDBID >;
		var parts : array< SPartSlots >;
		var sideUpgradeItem : Item_Record;
		var uiEvent : UIEquipmentReplacedEvent;
		owner = request.owner;
		if( !( owner ) )
		{
			return;
		}
		if( !( ItemID.IsValid( request.itemID ) ) )
		{
			return;
		}
		transactionSystem = GameInstance.GetTransactionSystem( owner.GetGame() );
		if( transactionSystem.HasItem( owner, request.itemID ) )
		{
			itemID = request.itemID;
		}
		else
		{
			if( request.addToInventory )
			{
				if( request.rerollIdOnAddToInventory )
				{
					itemID = ItemID.FromTDBID( ItemID.GetTDBID( request.itemID ) );
				}
				else
				{
					itemID = request.itemID;
				}
				itemModParams.itemID = itemID;
				itemModParams.quantity = 1;
				if( ItemID.IsValid( request.customPartToGenerateID ) )
				{
					itemModParams.customPartsToInstall.PushBack( request.customPartToGenerateID );
				}
				itemModParamsArray.PushBack( itemModParams );
				transactionSystem.GiveItems( owner, itemModParamsArray );
			}
			else
			{
				return;
			}
		}
		equipArea = EquipmentSystem.GetEquipAreaType( itemID );
		equipAreaIndex = GetEquipAreaIndex( equipArea );
		oldItemID = GetItemInEquipSlot( equipAreaIndex, request.slotIndex );
		if( request.transferInstalledParts )
		{
			parts = ItemModificationSystem.GetAllSlots( m_owner, oldItemID );
		}
		UnequipItem( equipAreaIndex, request.slotIndex );
		if( request.slotIndex == -1 )
		{
			EquipItem( itemID, false );
		}
		else
		{
			EquipItem( itemID, request.slotIndex, false );
		}
		if( request.transferInstalledParts && ItemID.IsValid( GetItemInEquipSlot( equipAreaIndex, request.slotIndex ) ) )
		{
			transactionSystem.GetAvailableSlotsOnItem( m_owner, itemID, availableSlots );
			for( i = 0, j = 0; ( i < parts.Size() ) && ( j < availableSlots.Size() ); i += 1 )
			{
				if( parts[ i ].status != ESlotState.Empty && availableSlots.Contains( parts[ i ].slotID ) )
				{
					transactionSystem.AddPart( m_owner, itemID, parts[ i ].installedPart, parts[ i ].slotID );
					j += 1;
				}
			}
		}
		if( request.removeOldItem )
		{
			if( ( ItemID.IsValid( oldItemID ) && equipArea == gamedataEquipmentArea.MusculoskeletalSystemCW ) && !( RPGManager.CyberwareHasSideUpgrade( oldItemID, sideUpgradeItem ) ) )
			{
				oldItemID = GetOriginalItemIDFromSideUpgrade( oldItemID );
			}
			transactionSystem.RemoveItem( owner, oldItemID, 1 );
		}
		uiEvent = new UIEquipmentReplacedEvent;
		uiEvent.itemID = request.itemID;
		GameInstance.GetUISystem( ( ( PlayerPuppet )( m_owner ) ).GetGame() ).QueueEvent( uiEvent );
	}

	public function OnDrawItemRequest( request : DrawItemRequest )
	{
		DrawItem( request.itemID, request.equipAnimationType );
	}

	public function OnPartInstallRequest( request : PartInstallRequest )
	{
		if( IsEquipped( request.itemID ) )
		{
			ApplyEquipGLPs( request.partID );
		}
	}

	public function OnPartUninstallRequest( request : PartUninstallRequest )
	{
		if( IsEquipped( request.itemID ) )
		{
			RemoveEquipGLPs( request.partID );
		}
	}

	public function OnClearEquipmentRequest( request : ClearEquipmentRequest )
	{
		ClearEquipment();
	}

	public function OnSaveEquipmentSetRequest( request : SaveEquipmentSetRequest )
	{
		SaveEquipmentSet( request.setName, request.setType );
	}

	public function OnLoadEquipmentSetRequest( request : LoadEquipmentSetRequest )
	{
		LoadEquipmentSet( request.setName );
	}

	public function OnDeleteEquipmentSetRequest( request : DeleteEquipmentSetRequest )
	{
		DeleteEquipmentSet( request.setName );
	}

	public function OnEquipmentUIBBRequest( request : EquipmentUIBBRequest )
	{
		var equipData : SPaperdollEquipData;
		UpdateEquipmentUIBB( equipData );
	}

	public function OnCheckRemovedItemWithSlotActiveItem( request : CheckRemovedItemWithSlotActiveItem )
	{
		var activeItems : SSlotActiveItems;
		activeItems = GetSlotActiveItemStruct();
		if( ( activeItems.rightHandItem == request.itemID ) || ( activeItems.leftHandItem == request.itemID ) )
		{
			RemoveItemFromSlotActiveItem( request.itemID );
		}
	}

	public function OnSynchronizeAttachmentSlotRequest( request : SynchronizeAttachmentSlotRequest )
	{
		var activeItemID : ItemID;
		activeItemID = GameInstance.GetTransactionSystem( m_owner.GetGame() ).GetActiveItemInSlot( request.owner, request.slotID );
		if( !( ItemID.IsValid( activeItemID ) ) )
		{
			return;
		}
		if( IsEquipped( activeItemID ) )
		{
			m_equipment.equipAreas[ GetEquipAreaIndex( EquipmentSystem.GetEquipAreaType( activeItemID ) ) ].activeIndex = GetSlotIndex( activeItemID );
		}
	}

	public function OnEquipmentSystemWeaponManipulationRequest( request : EquipmentSystemWeaponManipulationRequest )
	{
		var isUnequip : Bool;
		var isActivatedCyberware : Bool;
		var requestSlot : EquipmentManipulationRequestSlot;
		var item : ItemID;
		var actions : array< weak< ObjectAction_Record > >;
		isUnequip = IsEquipmentManipulationAnUnequipRequest( request.requestType );
		item = GetItemIDfromEquipmentManipulationAction( request.requestType );
		if( !( isUnequip ) )
		{
			if( GetItemIDFromHotkey( EHotkey.RB ) == item )
			{
				if( PlayerGameplayRestrictions.IsHotkeyRestricted( m_owner.GetGame(), EHotkey.RB ) )
				{
					return;
				}
			}
			else if( GetItemIDFromHotkey( EHotkey.DPAD_UP ) == item )
			{
				if( PlayerGameplayRestrictions.IsHotkeyRestricted( m_owner.GetGame(), EHotkey.DPAD_UP ) )
				{
					return;
				}
			}
		}
		if( request.requestType == EquipmentManipulationAction.UnequipAll )
		{
			requestSlot = EquipmentManipulationRequestSlot.Both;
		}
		if( ( ( !( ItemID.IsValid( item ) ) && requestSlot != EquipmentManipulationRequestSlot.Both ) && request.requestType != EquipmentManipulationAction.UnequipConsumable ) && request.requestType != EquipmentManipulationAction.UnequipGadget )
		{
			return;
		}
		isActivatedCyberware = CheckCyberwareItemForActivatedAction( item );
		if( isActivatedCyberware && request.requestType != EquipmentManipulationAction.UnequipConsumable )
		{
			TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) ).ObjectActions( actions );
			ItemActionsHelper.UseItem( m_owner, item );
			return;
		}
		if( !( isUnequip ) )
		{
			if( !( HasItemInInventory( item ) ) )
			{
				return;
			}
			requestSlot = GetRequestSlotFromItemID( item );
			SetSlotActiveItem( requestSlot, item );
			UpdateEquipAreaActiveIndex( item );
			SetLastUsedItem( item );
			SendPSMWeaponManipulationRequest( EquipmentManipulationRequestType.Equip, requestSlot, request.equipAnimType );
		}
		else
		{
			if( requestSlot != EquipmentManipulationRequestSlot.Both )
			{
				if( ItemID.IsValid( item ) )
				{
					requestSlot = GetRequestSlotFromItemID( item );
				}
				else if( request.requestType == EquipmentManipulationAction.UnequipConsumable || request.requestType == EquipmentManipulationAction.UnequipGadget )
				{
					requestSlot = EquipmentManipulationRequestSlot.Left;
				}
			}
			SetSlotActiveItem( requestSlot, ItemID.None() );
			SendPSMWeaponManipulationRequest( EquipmentManipulationRequestType.Unequip, requestSlot, request.equipAnimType );
			if( request.removeItemFromEquipSlot )
			{
				RemoveItemFromEquipSlot( item );
			}
		}
	}

	public function UnequipPrereqItems()
	{
		var itemData : weak< gameItemData >;
		var items : array< ItemID >;
		var i : Int32;
		var ts : TransactionSystem;
		ts = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		items = GetEquippedClothesAndWeapons();
		for( i = 0; i < items.Size(); i += 1 )
		{
			itemData = ts.GetItemData( m_owner, items[ i ] );
			if( RPGManager.IsItemCrafted( itemData ) && !( IsEquippable( itemData ) ) )
			{
				UnequipItem( items[ i ] );
			}
		}
	}

	private function GetEquippedClothesAndWeapons() : array< ItemID >
	{
		var itemList : array< ItemID >;
		var i, j : Int32;
		var equipArea : SEquipArea;
		for( i = 0; i < m_equipment.equipAreas.Size(); i += 1 )
		{
			equipArea = m_equipment.equipAreas[ i ];
			if( ( ( ( ( ( equipArea.areaType == gamedataEquipmentArea.Face || equipArea.areaType == gamedataEquipmentArea.Head ) || equipArea.areaType == gamedataEquipmentArea.InnerChest ) || equipArea.areaType == gamedataEquipmentArea.OuterChest ) || equipArea.areaType == gamedataEquipmentArea.Legs ) || equipArea.areaType == gamedataEquipmentArea.Feet ) || equipArea.areaType == gamedataEquipmentArea.Weapon )
			{
				for( j = 0; j < equipArea.equipSlots.Size(); j += 1 )
				{
					if( ItemID.IsValid( equipArea.equipSlots[ j ].itemID ) )
					{
						itemList.PushBack( equipArea.equipSlots[ j ].itemID );
					}
				}
			}
		}
		return itemList;
	}

	public function OnClearAllWeaponSlotsRequest( request : ClearAllWeaponSlotsRequest )
	{
		ClearAllWeaponSlots();
	}

	public function CreateUnequipWeaponManipulationRequest()
	{
		var request : EquipmentSystemWeaponManipulationRequest;
		request = new EquipmentSystemWeaponManipulationRequest;
		request.requestType = EquipmentManipulationAction.UnequipWeapon;
		OnEquipmentSystemWeaponManipulationRequest( request );
	}

	private function CreateUnequipGadgetWeaponManipulationRequest()
	{
		var request : EquipmentSystemWeaponManipulationRequest;
		request = new EquipmentSystemWeaponManipulationRequest;
		request.requestType = EquipmentManipulationAction.UnequipGadget;
		request.removeItemFromEquipSlot = true;
		OnEquipmentSystemWeaponManipulationRequest( request );
	}

	private function CreateUnequipConsumableWeaponManipulationRequest()
	{
		var request : EquipmentSystemWeaponManipulationRequest;
		request = new EquipmentSystemWeaponManipulationRequest;
		request.requestType = EquipmentManipulationAction.UnequipConsumable;
		request.removeItemFromEquipSlot = true;
		OnEquipmentSystemWeaponManipulationRequest( request );
	}

	public function IsEquipmentManipulationAnUnequipRequest( eqManipulationAction : EquipmentManipulationAction ) : Bool
	{
		return ( ( ( eqManipulationAction == EquipmentManipulationAction.UnequipWeapon || eqManipulationAction == EquipmentManipulationAction.UnequipConsumable ) || eqManipulationAction == EquipmentManipulationAction.UnequipGadget ) || eqManipulationAction == EquipmentManipulationAction.UnequipLeftHandCyberware ) || eqManipulationAction == EquipmentManipulationAction.UnequipAll;
	}

	public function GetRequestSlotFromEquipmentManipulationAction( eqManipulationAction : EquipmentManipulationAction ) : EquipmentManipulationRequestSlot
	{
		if( eqManipulationAction == EquipmentManipulationAction.Undefined )
		{
			return EquipmentManipulationRequestSlot.Undefined;
		}
		else if( ( ( ( ( eqManipulationAction == EquipmentManipulationAction.UnequipConsumable || eqManipulationAction == EquipmentManipulationAction.UnequipGadget ) || eqManipulationAction == EquipmentManipulationAction.UnequipLeftHandCyberware ) || eqManipulationAction == EquipmentManipulationAction.RequestGadget ) || eqManipulationAction == EquipmentManipulationAction.RequestLeftHandCyberware ) || eqManipulationAction == EquipmentManipulationAction.RequestConsumable )
		{
			return EquipmentManipulationRequestSlot.Left;
		}
		else if( eqManipulationAction == EquipmentManipulationAction.UnequipAll )
		{
			return EquipmentManipulationRequestSlot.Both;
		}
		else
		{
			return EquipmentManipulationRequestSlot.Right;
		}
	}

	public function GetRequestSlotFromItemID( item : ItemID ) : EquipmentManipulationRequestSlot
	{
		var record : Item_Record;
		record = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) );
		switch( record.ItemCategory().Type() )
		{
			case gamedataItemCategory.Weapon:
			{
				if( record.ItemType().Type() == gamedataItemType.Cyb_Launcher )
				{
					return EquipmentManipulationRequestSlot.Left;
				}
				return EquipmentManipulationRequestSlot.Right;
			}
			case gamedataItemCategory.Consumable:
			{
				return EquipmentManipulationRequestSlot.Left;
			}
			case gamedataItemCategory.Gadget:
			{
				return EquipmentManipulationRequestSlot.Left;
			}
			case gamedataItemCategory.Cyberware:
			{
				return EquipmentManipulationRequestSlot.Left;
			}
			default:
			{
				return EquipmentManipulationRequestSlot.Undefined;
			}
		}
	}

	public function GetItemIDfromEquipmentManipulationAction( eqManipulationAction : EquipmentManipulationAction ) : ItemID
	{
		switch( eqManipulationAction )
		{
			case EquipmentManipulationAction.RequestActiveMeleeware:
			{
				return GetActiveMeleeWare();
			}
			case EquipmentManipulationAction.RequestSlotActiveWeapon:
			{
				return GetSlotActiveWeapon();
			}
			case EquipmentManipulationAction.RequestActiveWeapon:
			{
				return GetActiveWeapon();
			}
			case EquipmentManipulationAction.RequestLastUsedWeapon:
			{
				return GetLastUsedWeaponItemID();
			}
			case EquipmentManipulationAction.RequestFirstMeleeWeapon:
			{
				return GetFirstMeleeWeaponItemID();
			}
			case EquipmentManipulationAction.RequestLastUsedMeleeWeapon:
			{
				return GetLastUsedMeleeWeaponItemID();
			}
			case EquipmentManipulationAction.RequestLastUsedOrFirstAvailableWeapon:
			{
				return GetLastUsedOrFirstAvailableWeapon();
			}
			case EquipmentManipulationAction.RequestLastUsedOrFirstAvailableRangedWeapon:
			{
				return GetLastUsedOrFirstAvailableRangedWeapon();
			}
			case EquipmentManipulationAction.RequestLastUsedOrFirstAvailableMeleeWeapon:
			{
				return GetLastUsedOrFirstAvailableMeleeWeapon();
			}
			case EquipmentManipulationAction.RequestLastUsedOrFirstAvailableOneHandedRangedWeapon:
			{
				return GetLastUsedOrFirstAvailableOneHandedRangedWeapon();
			}
			case EquipmentManipulationAction.RequestLastUsedOrFirstAvailableDriverCombatRangedWeapon:
			{
				return GetLastUsedOrFirstAvailableDriverCombatWeapon( WeaponObject.GetDriverCombatRangedWeaponTag() );
			}
			case EquipmentManipulationAction.RequestLastUsedOrFirstAvailableDriverCombatBikeWeapon:
			{
				return GetLastUsedOrFirstAvailableDriverCombatWeapon( WeaponObject.GetDriverCombatBikeWeaponTag() );
			}
			case EquipmentManipulationAction.RequestHeavyWeapon:
			{
				return GetActiveHeavyWeapon();
			}
			case EquipmentManipulationAction.RequestConsumable:
			{
				return GetActiveConsumable();
			}
			case EquipmentManipulationAction.RequestGadget:
			{
				return GetActiveGadget();
			}
			case EquipmentManipulationAction.RequestLeftHandCyberware:
			{
				return GetActiveCyberware();
			}
			case EquipmentManipulationAction.RequestFists:
			{
				return GetFistsItemID();
			}
			case EquipmentManipulationAction.UnequipGadget:
			{
				return GetActiveGadget();
			}
			case EquipmentManipulationAction.UnequipLeftHandCyberware:
			{
				return GetActiveCyberware();
			}
			case EquipmentManipulationAction.UnequipConsumable:
			{
				return GetActiveConsumable();
			}
			case EquipmentManipulationAction.UnequipWeapon:
			{
				return GetActiveWeaponToUnequip();
			}
			case EquipmentManipulationAction.CycleWeaponWheelItem:
			{
				return GetNextWeaponWheelItem();
			}
			case EquipmentManipulationAction.CycleNextWeaponWheelItem:
			{
				return CycleWeapon( true, false );
			}
			case EquipmentManipulationAction.CyclePreviousWeaponWheelItem:
			{
				return CycleWeapon( false, false );
			}
			case EquipmentManipulationAction.ReequipWeapon:
			{
				return GetLastUsedWeaponItemID();
			}
			case EquipmentManipulationAction.RequestWeaponSlot1:
			{
				return GetWeaponSlotItem( 1 );
			}
			case EquipmentManipulationAction.RequestWeaponSlot2:
			{
				return GetWeaponSlotItem( 2 );
			}
			case EquipmentManipulationAction.RequestWeaponSlot3:
			{
				return GetWeaponSlotItem( 3 );
			}
			case EquipmentManipulationAction.RequestWeaponSlot4:
			{
				return GetWeaponSlotItem( 4 );
			}
			case EquipmentManipulationAction.RequestNextThrowableWeapon:
			{
				return GetNextThrowableWeapon();
			}
			default:
				return ItemID.None();
		}
	}

	public function CheckCyberwareItemForActivatedAction( item : ItemID ) : Bool
	{
		var record : weak< Item_Record >;
		var actions : array< weak< ObjectAction_Record > >;
		record = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) );
		if( record && ( record.ItemCategory().Type() != gamedataItemCategory.Cyberware || record.ItemType().Type() == gamedataItemType.Cyb_Launcher ) )
		{
			return false;
		}
		if( record )
		{
			record.ObjectActions( actions );
		}
		return actions.Size() > 0;
	}

	public function OnSetActiveItemInEquipmentArea( request : SetActiveItemInEquipmentArea )
	{
		var slotIndex : Int32;
		var equipAreaIndex : Int32;
		var equipArea : SEquipArea;
		slotIndex = GetSlotIndex( request.itemID );
		equipAreaIndex = GetEquipAreaIndex( EquipmentSystem.GetEquipAreaTypeForDpad( request.itemID ) );
		equipArea = m_equipment.equipAreas[ equipAreaIndex ];
		if( ( slotIndex >= 0 ) && ( slotIndex < equipArea.equipSlots.Size() ) )
		{
			m_equipment.equipAreas[ equipAreaIndex ].activeIndex = slotIndex;
			UpdateActiveWheelItem( GetItemInEquipSlot( equipAreaIndex, slotIndex ) );
		}
	}

	public function CheckCyberjunkieAchievement()
	{
		var equipmentAreas : array< gamedataEquipmentArea >;
		var i, progress : Int32;
		var achievementRequest : AddAchievementRequest;
		var dataTrackingSystem : DataTrackingSystem;
		var progressionRequest : SetAchievementProgressRequest;
		var achievement : gamedataAchievement;
		dataTrackingSystem = ( ( DataTrackingSystem )( GameInstance.GetScriptableSystemsContainer( m_owner.GetGame() ).Get( 'DataTrackingSystem' ) ) );
		achievement = gamedataAchievement.Cyberjunkie;
		equipmentAreas = GetAllCyberwareEquipmentAreas();
		for( i = 0; i < equipmentAreas.Size(); i += 1 )
		{
			if( GetNumberOfItemsInEquipmentArea( equipmentAreas[ i ] ) > 0 )
			{
				progress += 1;
			}
		}
		progressionRequest = new SetAchievementProgressRequest;
		progressionRequest.achievement = achievement;
		progressionRequest.currentValue = progress;
		dataTrackingSystem.QueueRequest( progressionRequest );
		for( i = 0; i < equipmentAreas.Size(); i += 1 )
		{
			if( GetNumberOfItemsInEquipmentArea( equipmentAreas[ i ] ) == 0 )
			{
				return;
			}
		}
		achievementRequest = new AddAchievementRequest;
		achievementRequest.achievement = achievement;
		dataTrackingSystem.QueueRequest( achievementRequest );
	}

	public function GetInventoryManager() : weak< InventoryDataManagerV2 >
	{
		return m_inventoryManager;
	}

}

importonly class IEquipmentSystem extends ScriptableSystem
{
}

class EquipmentSystem extends IEquipmentSystem
{
	private persistent var m_ownerData : array< EquipmentSystemPlayerData >;

	public static function GetInstance( owner : GameObject ) : EquipmentSystem
	{
		var equipmentSystem : EquipmentSystem;
		equipmentSystem = ( ( EquipmentSystem )( GameInstance.GetScriptableSystemsContainer( owner.GetGame() ).Get( 'EquipmentSystem' ) ) );
		return equipmentSystem;
	}

	private export const function GetHairSuffix( itemId : ItemID, owner : weak< GameObject >, suffixRecord : ItemsFactoryAppearanceSuffixBase_Record ) : String
	{
		var customizationState : gameuiICharacterCustomizationState;
		var characterCustomizationSystem : gameuiICharacterCustomizationSystem;
		characterCustomizationSystem = GameInstance.GetCharacterCustomizationSystem( owner.GetGame() );
		if( ( ( ( PlayerPuppet )( owner ) ) == NULL ) && !( characterCustomizationSystem.HasCharacterCustomizationComponent( owner ) ) )
		{
			return "Bald";
		}
		customizationState = characterCustomizationSystem.GetState();
		if( customizationState != NULL )
		{
			if( customizationState.HasTag( 'Short' ) )
			{
				return "Short";
			}
			else if( customizationState.HasTag( 'Long' ) )
			{
				return "Long";
			}
			else if( customizationState.HasTag( 'Dreads' ) )
			{
				return "Dreads";
			}
			else if( customizationState.HasTag( 'Buzz' ) )
			{
				return "Buzz";
			}
			else
			{
				return "Bald";
			}
		}
		return "Error";
	}

	private export function OnPlayerAttach( request : PlayerAttachRequest )
	{
		var data : EquipmentSystemPlayerData;
		data = GetPlayerData( request.owner );
		if( !( data ) )
		{
			data = new EquipmentSystemPlayerData;
			data.SetOwner( ( ( ScriptedPuppet )( request.owner ) ) );
			m_ownerData.PushBack( data );
			data.OnInitialize();
		}
		else
		{
			if( data.IsClothingVisualsInfoEmpty() )
			{
				data.InitializeClothingOverrideInfo();
			}
			data.EvaluateUnderwearTopHiddenState();
		}
		data.OnAttach();
		if( !( IsFinal() ) )
		{
			Debug_SetupEquipmentSystemOverlay( request.owner );
		}
	}

	private function OnPlayerDetach( request : PlayerDetachRequest )
	{
		var i : Int32;
		for( i = 0; i < m_ownerData.Size(); i += 1 )
		{
			if( m_ownerData[ i ].GetOwner() == request.owner )
			{
				m_ownerData[ i ].OnDetach();
				m_ownerData.EraseFast( i );
				return;
			}
		}
	}

	public const function GetPlayerData( const owner : GameObject ) : EquipmentSystemPlayerData
	{
		var i : Int32;
		for( i = 0; i < m_ownerData.Size(); i += 1 )
		{
			if( m_ownerData[ i ].GetOwner() == owner )
			{
				return m_ownerData[ i ];
			}
		}
		return NULL;
	}

	private export override function OnRestored( saveVersion : Int32, gameVersion : Int32 )
	{
		var i : Int32;
		var ownerID : EntityID;
		var owner : ScriptedPuppet;
		var factVal : Int32;
		for( i = 0; i < m_ownerData.Size(); i += 1 )
		{
			ownerID = m_ownerData[ i ].GetOwnerID();
			owner = ( ( ScriptedPuppet )( GameInstance.FindEntityByID( GetGameInstance(), ownerID ) ) );
			if( owner )
			{
				m_ownerData[ i ].SetOwner( owner );
				m_ownerData[ i ].OnRestored();
			}
		}
		factVal = GetFact( GetGameInstance(), 'WardrobeInitialized' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1500 ) )
		{
			InitializeWardrobeDatabase();
			SetFactValue( GetGameInstance(), 'WardrobeInitialized', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'PowerLevelRescaled2' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1600 ) )
		{
			RefreshItemPlayerScaling();
			SetFactValue( GetGameInstance(), 'PowerLevelRescaled2', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'ScalingBlocked' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1510 ) ) && ( saveVersion <= 212 ) )
		{
			BlockAndCompensateScaling();
			SetFactValue( GetGameInstance(), 'ScalingBlocked', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'FixerShirtAdded' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1610 ) )
		{
			if( ( GetFact( GetGameInstance(), 'loc_ma_hey_rey_114_finished' ) >= 1 ) && ( GetFact( GetGameInstance(), 'loc_ma_hey_rey_110_finished' ) <= 0 ) )
			{
				GiveFixerShirt();
			}
			SetFactValue( GetGameInstance(), 'FixerShirtAdded', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'IconicReworkCompleted' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) ) && ( saveVersion <= 224 ) )
		{
			IconicsReworkCompensate();
			SetFactValue( GetGameInstance(), 'IconicReworkCompleted', 1 );
		}
		if( gameVersion <= 1650 )
		{
			SetFactValue( GetGameInstance(), 'ripperdoc_screen_glitched', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'RetrofixQuickhacks' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1650 ) ) && ( saveVersion <= 250 ) )
		{
			RetrofixQuickhacks();
			SetFactValue( GetGameInstance(), 'RetrofixQuickhacks', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'RetrofixCyberwares' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1650 ) ) && ( saveVersion <= 250 ) )
		{
			RetrofixCyberwares();
			SetFactValue( GetGameInstance(), 'RetrofixCyberwares', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'ConsumablesUpgraded' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) ) && ( saveVersion <= 224 ) )
		{
			ConsumablesChargesRework();
			SetFactValue( GetGameInstance(), 'ConsumablesUpgraded', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'SaburoTantoAdded' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) ) && ( saveVersion <= 224 ) )
		{
			if( GetFact( GetGameInstance(), 'q005_done' ) <= 0 )
			{
				CheckSaburoDogTagPresence();
			}
			SetFactValue( GetGameInstance(), 'SaburoTantoAdded', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'AutoscalingFleshFistsEquipped' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) ) && ( saveVersion <= 224 ) )
		{
			GiveAndEquipAutoscalingFleshFists();
			SetFactValue( GetGameInstance(), 'AutoscalingFleshFistsEquipped', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'IconicsFactsForBlackMarketerAdded' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) ) && ( saveVersion <= 224 ) )
		{
			ProcessIconicsFactsForBlackMarketer();
			SetFactValue( GetGameInstance(), 'IconicsFactsForBlackMarketerAdded', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'LeftHandWeaponsCompensated' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) ) && ( saveVersion <= 224 ) )
		{
			ReplaceLeftHandVariantWeaponsWithRegular();
			SetFactValue( GetGameInstance(), 'LeftHandWeaponsCompensated', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'NonIconicWeaponsRescaled' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) ) && ( saveVersion <= 254 ) )
		{
			ProcessNonIconicWeaponsRescale();
			SetFactValue( GetGameInstance(), 'NonIconicWeaponsRescaled', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'CWQualityRestorationHack' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2020 ) ) && ( saveVersion <= 257 ) )
		{
			RestoreCybWeaponQualities();
			SetFactValue( GetGameInstance(), 'CWQualityRestorationHack', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'ReginaRewardCompensated' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2099 ) ) && ( saveVersion <= 257 ) )
		{
			if( GetFact( GetGameInstance(), 'wat_sts_counter' ) >= 23 )
			{
				CheckReginaRewardsPresence();
			}
			SetFactValue( GetGameInstance(), 'ReginaRewardCompensated', 1 );
		}
		if( saveVersion < 258 )
		{
			RetrofixHolsteredArms();
		}
		factVal = GetFact( GetGameInstance(), 'NPCMeleewareRemoved' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2099 ) ) && ( saveVersion <= 257 ) )
		{
			RemoveNPCMeleeware();
			SetFactValue( GetGameInstance(), 'NPCMeleewareRemoved', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'Q105KeycardFactsAdded' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2099 ) ) && ( saveVersion <= 257 ) )
		{
			ProcessQ105AccessCardFacts();
			SetFactValue( GetGameInstance(), 'Q105KeycardFactsAdded', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'RasetsuRescaledandLocked' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2099 ) ) && ( saveVersion <= 257 ) )
		{
			RasetsuItemPlayerScaling();
			SetFactValue( GetGameInstance(), 'RasetsuRescaledandLocked', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'IconicsUpgradeCountWithEffectiveTierUnified' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2099 ) ) && ( saveVersion <= 257 ) )
		{
			IconicsUpgradeCountWithEffectiveTierMatch();
			SetFactValue( GetGameInstance(), 'IconicsUpgradeCountWithEffectiveTierUnified', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'KurtMetelFactRetrofixed' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2099 ) ) && ( saveVersion <= 257 ) )
		{
			SetFactValue( GetGameInstance(), 'metel_kurt_owned', 0 );
			ProcessIconicsFactsForBlackMarketer();
			SetFactValue( GetGameInstance(), 'KurtMetelFactRetrofixed', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'MaskCWDupeExploitSecured' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2110 ) ) && ( saveVersion <= 261 ) )
		{
			ProcessMaskCWRestoration();
			SetFactValue( GetGameInstance(), 'MaskCWDupeExploitSecured', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'Allow_mq043_reward_retrofix' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2110 ) ) && ( saveVersion <= 261 ) )
		{
			SetFactValue( GetGameInstance(), 'Allow_mq043_reward_retrofix', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'RetrofixOverallocatedCyberware' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2110 ) ) && ( saveVersion <= 261 ) )
		{
			RetrofixOverallocatedCyberware();
			SetFactValue( GetGameInstance(), 'RetrofixOverallocatedCyberware', 1 );
		}
	}

	private function InitializeWardrobeDatabase()
	{
		var player : weak< PlayerPuppet >;
		var transactionSystem : TransactionSystem;
		var wardrobeSystem : WardrobeSystem;
		var itemList : array< weak< gameItemData > >;
		var i : Int32;
		player = GetPlayer( GetGameInstance() );
		if( player )
		{
			transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
			transactionSystem.GetItemList( player, itemList );
			wardrobeSystem = GameInstance.GetWardrobeSystem( GetGameInstance() );
			for( i = 0; i < itemList.Size(); i += 1 )
			{
				if( RPGManager.IsItemClothing( itemList[ i ].GetID() ) )
				{
					wardrobeSystem.StoreUniqueItemIDAndMarkNew( GetGameInstance(), itemList[ i ].GetID() );
				}
			}
		}
	}

	private function RefreshItemPlayerScaling()
	{
		var player : weak< PlayerPuppet >;
		var evt : RefreshItemPlayerScalingEvent;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			evt = new RefreshItemPlayerScalingEvent;
			player.QueueEvent( evt );
		}
	}

	private function ProcessNonIconicWeaponsRescale()
	{
		var player : weak< PlayerPuppet >;
		var evt : RescaleNonIconicWeaponsEvent;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			evt = new RescaleNonIconicWeaponsEvent;
			player.QueueEvent( evt );
		}
	}

	private function RestoreCybWeaponQualities()
	{
		var player : weak< PlayerPuppet >;
		var evt : RestoreCybWeaponQualitiesEvent;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			evt = new RestoreCybWeaponQualitiesEvent;
			player.QueueEvent( evt );
		}
	}

	private function ConsumablesChargesRework()
	{
		var player : weak< PlayerPuppet >;
		var evt : ConsumablesChargesReworkEvent;
		player = GetPlayer( GetGameInstance() );
		if( player )
		{
			evt = new ConsumablesChargesReworkEvent;
			player.QueueEvent( evt );
		}
	}

	private function BlockAndCompensateScaling()
	{
		var player : weak< PlayerPuppet >;
		var evt : BlockAndCompensateScalingEvent;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			evt = new BlockAndCompensateScalingEvent;
			player.QueueEvent( evt );
		}
	}

	private function IconicsReworkCompensate()
	{
		var player : weak< PlayerPuppet >;
		var evt : IconicsReworkCompensateEvent;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			evt = new IconicsReworkCompensateEvent;
			player.QueueEvent( evt );
		}
	}

	private function GiveFixerShirt()
	{
		var ts : TransactionSystem;
		var item : ItemID;
		var player : weak< PlayerPuppet >;
		player = GetMainPlayer( GetGameInstance() );
		ts = GameInstance.GetTransactionSystem( GetGameInstance() );
		item = ItemID.FromTDBID( T"Items.Fixer_01_Set_TShirt" );
		ts.GiveItem( player, item, 1 );
	}

	private function GiveSaburoTanto()
	{
		var ts : TransactionSystem;
		var item : ItemID;
		var player : weak< PlayerPuppet >;
		player = GetPlayer( GetGameInstance() );
		ts = GameInstance.GetTransactionSystem( GetGameInstance() );
		item = ItemID.FromTDBID( T"Items.Preset_Tanto_Saburo_Retrofix" );
		ts.GiveItem( player, item, 1 );
	}

	private function CheckSaburoDogTagPresence()
	{
		var i : Int32;
		var itemList : array< weak< gameItemData > >;
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		player = GetPlayer( GetGameInstance() );
		if( player )
		{
			TS = GameInstance.GetTransactionSystem( GetGameInstance() );
			TS.GetItemList( player, itemList );
		}
		for( i = 0; i < itemList.Size(); i += 1 )
		{
			if( itemList[ i ].HasTag( 'q005_saburo_dogtag' ) )
			{
				GiveSaburoTanto();
			}
		}
	}

	private function ProcessIconicsFactsForBlackMarketer()
	{
		var i : Int32;
		var itemList : array< weak< gameItemData > >;
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		player = GetPlayer( GetGameInstance() );
		if( player )
		{
			TS = GameInstance.GetTransactionSystem( GetGameInstance() );
			TS.GetItemList( player, itemList );
		}
		for( i = 0; i < itemList.Size(); i += 1 )
		{
			if( itemList[ i ].HasTag( 'IconicWeapon' ) )
			{
				RPGManager.ProcessOnLootedPackages( player, itemList[ i ].GetID() );
			}
		}
	}

	private function GiveAndEquipAutoscalingFleshFists()
	{
		var ts : TransactionSystem;
		var es : EquipmentSystem;
		var item : ItemID;
		var player : weak< PlayerPuppet >;
		var equipRequest : GameplayEquipRequest;
		es = ( ( EquipmentSystem )( GameInstance.GetScriptableSystemsContainer( GetGameInstance() ).Get( 'EquipmentSystem' ) ) );
		player = GetMainPlayer( GetGameInstance() );
		ts = GameInstance.GetTransactionSystem( GetGameInstance() );
		item = ItemID.FromTDBID( T"Items.w_melee_004__fists_a" );
		ts.GiveItem( player, item, 1 );
		equipRequest = new GameplayEquipRequest;
		equipRequest.owner = player;
		equipRequest.itemID = item;
		equipRequest.blockUpdateWeaponActiveSlots = true;
		es.QueueRequest( equipRequest );
	}

	private function ReplaceLeftHandVariantWeaponsWithRegular()
	{
		var i : Int32;
		var itemList : array< weak< gameItemData > >;
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			TS = GameInstance.GetTransactionSystem( GetGameInstance() );
			TS.GetItemList( player, itemList );
		}
		for( i = 0; i < itemList.Size(); i += 1 )
		{
			if( itemList[ i ].HasTag( 'Left_Hand' ) )
			{
				RPGManager.ProcessOnLootedPackages( player, itemList[ i ].GetID() );
			}
		}
	}

	private function RetrofixQuickhacks()
	{
		var evt : RetrofixQuickhacksEvent;
		var player : PlayerPuppet;
		evt = new RetrofixQuickhacksEvent;
		player = GetPlayer( GetGameInstance() );
		if( player )
		{
			player.QueueEvent( evt );
		}
	}

	private function RetrofixHolsteredArms()
	{
		var ts : TransactionSystem;
		var i : Int32;
		var slotID : TweakDBID;
		var player : PlayerPuppet;
		var armsItemID, activeItemID : ItemID;
		slotID = T"AttachmentSlots.WeaponRight";
		ts = GameInstance.GetTransactionSystem( GetGameInstance() );
		for( i = 0; i < m_ownerData.Size(); i += 1 )
		{
			player = ( ( PlayerPuppet )( m_ownerData[ i ].GetOwner() ) );
			if( !( player ) )
			{
				continue;
			}
			activeItemID = ts.GetActiveItemInSlot( player, slotID );
			armsItemID = m_ownerData[ i ].GetActiveItem( gamedataEquipmentArea.ArmsCW );
			if( ItemID.IsValid( armsItemID ) )
			{
				if( activeItemID != armsItemID )
				{
					EquipmentSystemPlayerData.UpdateArmSlot( player, armsItemID, true );
				}
			}
			else
			{
				armsItemID = m_ownerData[ i ].GetActiveItem( gamedataEquipmentArea.BaseFists );
				if( ItemID.IsValid( armsItemID ) && ( activeItemID != armsItemID ) )
				{
					EquipmentSystemPlayerData.UpdateArmSlot( player, armsItemID, true );
				}
			}
		}
	}

	private function RetrofixCyberwares()
	{
		var evt : RetrofixCyberwaresEvent;
		var player : PlayerPuppet;
		evt = new RetrofixCyberwaresEvent;
		player = GetPlayer( GetGameInstance() );
		if( player )
		{
			player.QueueEvent( evt );
		}
	}

	private function RetrofixOverallocatedCyberware()
	{
		var evt : RetrofixOverallocatedCyberwareEvent;
		var player : PlayerPuppet;
		evt = new RetrofixOverallocatedCyberwareEvent;
		player = GetPlayer( GetGameInstance() );
		if( player )
		{
			player.QueueEvent( evt );
		}
	}

	private function CheckReginaRewardsPresence()
	{
		var i : Int32;
		var itemList : array< weak< gameItemData > >;
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			TS = GameInstance.GetTransactionSystem( GetGameInstance() );
			TS.GetItemList( player, itemList );
		}
		for( i = 0; i < itemList.Size(); i += 1 )
		{
			if( itemList[ i ].HasTag( 'AdvancedSubdermalCoProcessor_Regina' ) )
			{
				RPGManager.ProcessOnLootedPackages( player, itemList[ i ].GetID() );
			}
		}
		RemoveDeprecatedReginaCWReward();
	}

	private function RemoveDeprecatedReginaCWReward()
	{
		var ts : TransactionSystem;
		var player : weak< PlayerPuppet >;
		player = GetMainPlayer( GetGameInstance() );
		ts = GameInstance.GetTransactionSystem( GetGameInstance() );
		ts.RemoveItemByTDBID( player, T"Items.NeoFiberLegendary", 1 );
	}

	private function RemoveNPCMeleeware()
	{
		var i : Int32;
		var itemList : array< weak< gameItemData > >;
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		var itemData : ItemID;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			TS = GameInstance.GetTransactionSystem( GetGameInstance() );
			TS.GetItemList( player, itemList );
		}
		for( i = 0; i < itemList.Size(); i += 1 )
		{
			if( itemList[ i ].HasTag( 'NPCMeleeware' ) )
			{
				itemData = itemList[ i ].GetID();
				TS.RemoveItemByTDBID( player, ItemID.GetTDBID( itemData ), 1 );
			}
		}
	}

	private function ProcessMaskCWRestoration()
	{
		var i : Int32;
		var itemList : array< weak< gameItemData > >;
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		var itemData : ItemID;
		var maskPlusCounter : Float;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			TS = GameInstance.GetTransactionSystem( GetGameInstance() );
			TS.GetItemList( player, itemList );
		}
		if( GetFact( GetGameInstance(), 'q304_04d_farida_done' ) >= 1 )
		{
			maskPlusCounter = 0.0;
			for( i = 0; i < itemList.Size(); i += 1 )
			{
				if( itemList[ i ].HasTag( 'MaskCWPlus' ) )
				{
					maskPlusCounter += 1.0;
					itemData = itemList[ i ].GetID();
					TS.RemoveItemByTDBID( player, ItemID.GetTDBID( itemData ), 1 );
				}
			}
			if( maskPlusCounter >= 1.0 )
			{
				itemData = ItemID.FromTDBID( T"Items.MaskCWPlus" );
				TS.GiveItem( player, itemData, 1 );
			}
		}
	}

	private function ProcessQ105AccessCardFacts()
	{
		var i : Int32;
		var itemList : array< weak< gameItemData > >;
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			TS = GameInstance.GetTransactionSystem( GetGameInstance() );
			TS.GetItemList( player, itemList );
		}
		for( i = 0; i < itemList.Size(); i += 1 )
		{
			if( itemList[ i ].HasTag( 'Clouds_VIP' ) )
			{
				RPGManager.ProcessOnLootedPackages( player, itemList[ i ].GetID() );
			}
		}
	}

	private function IconicsUpgradeCountWithEffectiveTierMatch()
	{
		var player : weak< PlayerPuppet >;
		var evt : UnifyIconicsUpgradeCountWithEffectiveTierEvent;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			evt = new UnifyIconicsUpgradeCountWithEffectiveTierEvent;
			player.QueueEvent( evt );
		}
	}

	private function RasetsuItemPlayerScaling()
	{
		var player : weak< PlayerPuppet >;
		var evt : RasetsuToPlayerScalingEvent;
		player = GetMainPlayer( GetGameInstance() );
		if( player )
		{
			evt = new RasetsuToPlayerScalingEvent;
			player.QueueEvent( evt );
		}
	}

	public const function PrintEquipment()
	{
		var equipmentId : Int32;
		for( equipmentId = 0; equipmentId < m_ownerData.Size(); equipmentId += 1 )
		{
		}
	}

	public const function GetItemInEquipSlot( owner : GameObject, equipArea : gamedataEquipmentArea, slotIndex : Int32 ) : ItemID
	{
		return GetPlayerData( owner ).GetItemInEquipSlot( equipArea, slotIndex );
	}

	public const function IsEquipped( owner : GameObject, item : ItemID ) : Bool
	{
		return GetPlayerData( owner ).IsEquipped( item );
	}

	public const function IsEquippable( owner : GameObject, itemData : weak< gameItemData > ) : Bool
	{
		return GetPlayerData( owner ).IsEquippable( itemData );
	}

	public const function IsEquipped( owner : GameObject, item : ItemID, equipmentArea : gamedataEquipmentArea ) : Bool
	{
		return GetPlayerData( owner ).IsEquipped( item, equipmentArea );
	}

	public const function GetActiveItem( owner : GameObject, area : gamedataEquipmentArea ) : ItemID
	{
		return GetPlayerData( owner ).GetActiveItem( area );
	}

	public const function GetActiveVisualItem( owner : GameObject, area : gamedataEquipmentArea ) : ItemID
	{
		return GetPlayerData( owner ).GetVisualItemInSlot( area );
	}

	public const function GetPaperDollSlots( owner : GameObject ) : array< gamedataEquipmentArea >
	{
		return GetPlayerData( owner ).GetPaperDollSlots();
	}

	public const function GetActiveWeaponObject( owner : GameObject, area : gamedataEquipmentArea ) : ItemObject
	{
		return GetPlayerData( owner ).GetActiveWeaponObject( area );
	}

	public const function GetAllInstalledCyberwareAbilities( owner : GameObject ) : array< SEquipSlot >
	{
		return GetPlayerData( owner ).GetAllAbilityCyberwareSlots();
	}

	public static function GetLastUsedItemByType( owner : GameObject, type : ELastUsed ) : ItemID
	{
		return GetData( owner ).GetLastUsedItemID( type );
	}

	public const function GetItemSlotIndex( owner : GameObject, item : ItemID ) : Int32
	{
		if( !( GetData( owner ) ) )
		{
			return -1;
		}
		return GetData( owner ).GetSlotIndex( item );
	}

	public static function IsCyberdeckEquipped( owner : GameObject ) : Bool
	{
		var systemReplacementID : ItemID;
		systemReplacementID = GetData( owner ).GetActiveItem( gamedataEquipmentArea.SystemReplacementCW );
		return IsItemCyberdeck( systemReplacementID );
	}

	public static function IsItemCyberdeck( itemID : ItemID ) : Bool
	{
		var itemTags : array< CName >;
		var itemRecord : weak< Item_Record >;
		itemRecord = RPGManager.GetItemRecord( itemID );
		itemTags = itemRecord.Tags();
		return itemTags.Contains( 'Cyberdeck' );
	}

	public static function GetPlacementSlot( item : ItemID ) : TweakDBID
	{
		var placementSlots : array< weak< AttachmentSlot_Record > >;
		var itemRecord : Item_Record;
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) );
		if( itemRecord )
		{
			itemRecord.PlacementSlots( placementSlots );
		}
		if( placementSlots.Size() > 0 )
		{
			return placementSlots[ 0 ].GetID();
		}
		return TDBID.None();
	}

	public static function GetEquipAreaType( item : ItemID ) : gamedataEquipmentArea
	{
		var equipAreaRecord : EquipmentArea_Record;
		var itemRecord : Item_Record;
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) );
		if( itemRecord )
		{
			equipAreaRecord = itemRecord.EquipArea();
			if( equipAreaRecord && TDBID.IsValid( equipAreaRecord.GetID() ) )
			{
				return equipAreaRecord.Type();
			}
		}
		return gamedataEquipmentArea.Invalid;
	}

	public static function GetClothingItemAppearanceName( itemID : ItemID ) : CName
	{
		var appearance : CName;
		var itemRecord : weak< Item_Record >;
		itemRecord = RPGManager.GetItemRecord( itemID );
		if( itemRecord )
		{
			appearance = itemRecord.AppearanceName();
		}
		return appearance;
	}

	public static function GetEquipAreaTypeForDpad( item : ItemID ) : gamedataEquipmentArea
	{
		var equipAreaRecord : EquipmentArea_Record;
		var itemRecord : Item_Record;
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) );
		equipAreaRecord = itemRecord.EquipArea();
		if( TDBID.IsValid( equipAreaRecord.GetID() ) )
		{
			if( itemRecord.ItemType().Type() == gamedataItemType.Cyb_Launcher )
			{
				return gamedataEquipmentArea.ArmsCW;
			}
			return equipAreaRecord.Type();
		}
		return gamedataEquipmentArea.Invalid;
	}

	public const function IsItemInHotkey( const owner : weak< GameObject >, itemID : ItemID ) : Bool
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( owner );
		if( playerData )
		{
			return playerData.IsItemInHotkey( itemID );
		}
		return false;
	}

	public const function GetHotkeyTypeForItemID( owner : weak< GameObject >, itemID : ItemID ) : EHotkey
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( owner );
		if( playerData )
		{
			return playerData.GetHotkeyTypeForItemID( itemID );
		}
		return EHotkey.INVALID;
	}

	public const function GetHotkeyTypeFromItemID( owner : weak< GameObject >, itemID : ItemID ) : EHotkey
	{
		return GetPlayerData( owner ).GetHotkeyTypeFromItemID( itemID );
	}

	public const function GetItemIDFromHotkey( owner : weak< GameObject >, hotkey : EHotkey ) : ItemID
	{
		return GetPlayerData( owner ).GetItemIDFromHotkey( hotkey );
	}

	public static function GetData( owner : GameObject ) : EquipmentSystemPlayerData
	{
		return GetInstance( owner ).GetPlayerData( owner );
	}

	public static function GetSlotActiveItem( owner : GameObject, requestSlot : EquipmentManipulationRequestSlot ) : ItemID
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetData( owner );
		if( playerData )
		{
			return playerData.GetSlotActiveItem( requestSlot );
		}
		return ItemID.None();
	}

	public export static function GetItemsInArea( owner : GameObject, area : gamedataEquipmentArea ) : array< ItemID >
	{
		var returnArray : array< ItemID >;
		var i : Int32;
		var equipment : EquipmentSystemPlayerData;
		equipment = GetData( owner );
		if( equipment )
		{
			for( i = 0; i < equipment.GetNumberOfSlots( area ); i += 1 )
			{
				returnArray.PushBack( equipment.GetItemInEquipSlot( area, i ) );
			}
		}
		return returnArray;
	}

	public static function GetSlotOverridenItem( owner : GameObject, area : gamedataEquipmentArea ) : ItemID
	{
		var equipment : EquipmentSystemPlayerData;
		equipment = GetData( owner );
		return equipment.GetSlotOverridenVisualItem( area );
	}

	public static function HasItemInArea( owner : GameObject, area : gamedataEquipmentArea ) : Bool
	{
		var itemsInArea : array< ItemID >;
		var i : Int32;
		itemsInArea = GetItemsInArea( owner, area );
		for( i = 0; i < itemsInArea.Size(); i += 1 )
		{
			if( ItemID.IsValid( itemsInArea[ i ] ) )
			{
				return true;
			}
		}
		return false;
	}

	public static function GetFirstAvailableWeapon( owner : GameObject ) : ItemID
	{
		var i : Int32;
		var items : array< ItemID >;
		var item : ItemID;
		var playerData : EquipmentSystemPlayerData;
		items = GetItemsInArea( owner, gamedataEquipmentArea.WeaponWheel );
		for( i = 0; i < items.Size(); i += 1 )
		{
			if( ItemID.IsValid( items[ i ] ) )
			{
				return items[ i ];
			}
		}
		playerData = GetData( owner );
		if( playerData )
		{
			item = playerData.GetActiveMeleeWare();
		}
		if( ItemID.IsValid( item ) )
		{
			return item;
		}
		items = GetItemsInArea( owner, gamedataEquipmentArea.BaseFists );
		if( items.Size() > 0 )
		{
			return items[ 0 ];
		}
		return ItemID.None();
	}

	public static function HasTag( item : ItemObject, tag : CName ) : Bool
	{
		var tags : array< CName >;
		tags = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item.GetItemID() ) ).Tags();
		return tags.Contains( tag );
	}

	public static function IsClothing( item : ItemID ) : Bool
	{
		return IsItemOfCategory( item, gamedataItemCategory.Clothing );
	}

	public static function IsItemOfCategory( item : ItemID, category : gamedataItemCategory ) : Bool
	{
		var record : Item_Record;
		record = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( item ) );
		if( record && record.ItemCategory() )
		{
			return record.ItemCategory().Type() == category;
		}
		return false;
	}

	public static function GetClothingEquipmentAreas() : array< gamedataEquipmentArea >
	{
		var slots : array< gamedataEquipmentArea >;
		slots.PushBack( gamedataEquipmentArea.OuterChest );
		slots.PushBack( gamedataEquipmentArea.InnerChest );
		slots.PushBack( gamedataEquipmentArea.Head );
		slots.PushBack( gamedataEquipmentArea.Legs );
		slots.PushBack( gamedataEquipmentArea.Feet );
		slots.PushBack( gamedataEquipmentArea.Face );
		return slots;
	}

	public const function GetEquipAreaFromItemID( owner : GameObject, item : ItemID ) : SEquipArea
	{
		var voidEquipArea : SEquipArea;
		var playerData : EquipmentSystemPlayerData;
		playerData = GetData( owner );
		if( playerData )
		{
			return playerData.GetEquipAreaFromItemID( item );
		}
		return voidEquipArea;
	}

	public static function RequestUnequipItem( owner : GameObject, equipmentArea : gamedataEquipmentArea, slotIndex : Int32 )
	{
		var equipmentSystem : EquipmentSystem;
		var itemInSlot : ItemID;
		var unequipRequest : UnequipRequest;
		equipmentSystem = GetInstance( owner );
		itemInSlot = equipmentSystem.GetItemInEquipSlot( owner, equipmentArea, slotIndex );
		if( ItemID.IsValid( itemInSlot ) )
		{
			unequipRequest = new UnequipRequest;
			unequipRequest.owner = owner;
			unequipRequest.areaType = equipmentArea;
			unequipRequest.slotIndex = slotIndex;
			equipmentSystem.QueueRequest( unequipRequest );
		}
	}

	private export function OnEquipRequest( request : EquipRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnEquipRequest( request );
	}

	private export function OnGameplayEquipRequest( request : GameplayEquipRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnGameplayEquipRequest( request );
	}

	private export function OnGameplayEquipProgramsRequest( request : GameplayEquipProgramsRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnGameplayEquipProgramsRequest( request );
	}

	private function OnClearAllWeaponSlotsRequest( request : ClearAllWeaponSlotsRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnClearAllWeaponSlotsRequest( request );
	}

	private function OnEquipVisualsRequest( request : EquipVisualsRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnEquipVisualsRequest( request );
	}

	private function OnUnequipVisualsRequest( request : UnequipVisualsRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnUnequipVisualsRequest( request );
	}

	private function OnUnequipRequest( request : UnequipRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnUnequipRequest( request );
	}

	private export function OnUnequipItemsRequest( request : UnequipItemsRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnUnequipItemsRequest( request );
	}

	private export function OnReplaceEquipmentRequest( request : ReplaceEquipmentRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnReplaceEquipmentRequest( request );
	}

	private export function OnHotkeyRefreshRequest( request : HotkeyRefreshRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnHotkeyRefreshRequest( request );
	}

	private function OnHotkeyAssignmentRequest( request : HotkeyAssignmentRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.Owner() );
		playerData.OnHotkeyAssignmentRequest( request );
	}

	private export function OnAssignHotkeyIfEmptySlot( request : AssignHotkeyIfEmptySlot )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.Owner() );
		playerData.OnAssignHotkeyIfEmptySlot( request );
	}

	private function OnInstallCyberwareRequest( request : InstallCyberwareRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnInstallCyberwareRequest( request );
	}

	private function OnUninstallCyberwareRequest( request : UninstallCyberwareRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnUninstallCyberwareRequest( request );
	}

	private export function OnDrawItemRequest( request : DrawItemRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnDrawItemRequest( request );
	}

	private function OnPartInstallRequest( request : PartInstallRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnPartInstallRequest( request );
	}

	private export function OnPartUninstallRequest( request : PartUninstallRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnPartUninstallRequest( request );
	}

	private export function OnClearEquipmentRequest( request : ClearEquipmentRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnClearEquipmentRequest( request );
	}

	private function OnSaveEquipmentSetRequest( request : SaveEquipmentSetRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnSaveEquipmentSetRequest( request );
	}

	private function OnLoadEquipmentSetRequest( request : LoadEquipmentSetRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnLoadEquipmentSetRequest( request );
	}

	private function OnDeleteEquipmentSetRequest( request : DeleteEquipmentSetRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnDeleteEquipmentSetRequest( request );
	}

	private function OnAssignToCyberwareWheelRequest( request : AssignToCyberwareWheelRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnAssignToCyberwareWheelRequest( request );
	}

	private function OnEquipmentUIBBRequest( request : EquipmentUIBBRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnEquipmentUIBBRequest( request );
	}

	private export function OnCheckRemovedItemWithSlotActiveItem( request : CheckRemovedItemWithSlotActiveItem )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnCheckRemovedItemWithSlotActiveItem( request );
	}

	private function OnSynchronizeAttachmentSlotRequest( request : SynchronizeAttachmentSlotRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnSynchronizeAttachmentSlotRequest( request );
	}

	private function OnEquipWardrobeSetRequest( request : EquipWardrobeSetRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.EquipWardrobeSet( request.setID );
	}

	private function OnUnequipWardrobeSetRequest( request : UnequipWardrobeSetRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.UnequipWardrobeSet();
	}

	private function OnDeleteWardrobeSetRequest( request : DeleteWardrobeSetRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.DeleteWardrobeSet( request.setID );
	}

	private function OnQuestRestoreWardrobeSetRequest( request : QuestRestoreWardrobeSetRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnQuestRestoreWardrobeSetRequest( request );
	}

	private function OnQuestDisableWardrobeSetRequest( request : QuestDisableWardrobeSetRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnQuestDisableWardrobeSetRequest( request );
	}

	private function OnQuestEnableWardrobeSetRequest( request : QuestEnableWardrobeSetRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnQuestEnableWardrobeSetRequest( request );
	}

	private function OnQuestHideSlotRequest( request : QuestHideSlotRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.QuestHideSlot( request.slot );
	}

	private function OnQuestRestoreSlotRequest( request : QuestRestoreSlotRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.QuestRestoreSlot( request.slot );
	}

	public static function GetActiveWardrobeSetID( owner : GameObject ) : gameWardrobeClothingSetIndex
	{
		return GameInstance.GetWardrobeSystem( owner.GetGame() ).GetActiveClothingSetIndex();
	}

	public static function GetActiveWardrobeSet( owner : GameObject ) : ClothingSet
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetData( owner );
		return playerData.GetActiveWardrobeSet();
	}

	public static function UnequipPrereqItems( owner : GameObject )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetData( owner );
		playerData.UnequipPrereqItems();
	}

	public const function EquipCyberwareByTDBID( player : PlayerPuppet, tdbid : TweakDBID )
	{
		var ts : TransactionSystem;
		var equipRequest : EquipRequest;
		var itemData : gameItemData;
		ts = GameInstance.GetTransactionSystem( player.GetGame() );
		equipRequest = new EquipRequest;
		itemData = ts.GetItemDataByTDBID( player, tdbid );
		if( ItemID.IsValid( itemData.GetID() ) )
		{
			equipRequest.owner = player;
			equipRequest.itemID = itemData.GetID();
			QueueRequest( equipRequest );
		}
	}

	private function EquipTutorialCyberware( player : PlayerPuppet )
	{
		var requiredQuality : gamedataQuality;
		requiredQuality = RPGManager.ConvertPlayerLevelToCyberwareQuality( GameInstance.GetStatsSystem( player.GetGame() ).GetStatValue( player.GetEntityID(), gamedataStatType.Level ), false );
		EquipCyberwareByTDBID( player, RipperDocGameController.GetAppropriateEyesTutorialCyberware( requiredQuality ) );
		EquipCyberwareByTDBID( player, RipperDocGameController.GetAppropriateHandsTutorialCyberware( requiredQuality, false ) );
	}

	private function OnDrawItemByContextRequest( request : DrawItemByContextRequest )
	{
		var equipData : EquipmentSystemPlayerData;
		var eqRequest : EquipmentSystemWeaponManipulationRequest;
		var player : PlayerPuppet;
		eqRequest = new EquipmentSystemWeaponManipulationRequest;
		player = ( ( PlayerPuppet )( request.owner ) );
		equipData = GetData( request.owner );
		switch( request.itemEquipContext )
		{
			case gameItemEquipContexts.LastWeaponEquipped:
				eqRequest.requestType = EquipmentManipulationAction.RequestLastUsedWeapon;
			break;
			case gameItemEquipContexts.LastUsedMeleeWeapon:
				eqRequest.requestType = EquipmentManipulationAction.RequestLastUsedOrFirstAvailableMeleeWeapon;
			break;
			case gameItemEquipContexts.LastUsedRangedWeapon:
				eqRequest.requestType = EquipmentManipulationAction.RequestLastUsedOrFirstAvailableRangedWeapon;
			break;
			case gameItemEquipContexts.Gadget:
				eqRequest.requestType = EquipmentManipulationAction.RequestGadget;
			break;
			case gameItemEquipContexts.MeleeCyberware:
				eqRequest.requestType = EquipmentManipulationAction.RequestActiveMeleeware;
			break;
			case gameItemEquipContexts.LauncherCyberware:
				break;
			case gameItemEquipContexts.Fists:
				eqRequest.requestType = EquipmentManipulationAction.RequestFists;
			break;
			case gameItemEquipContexts.TutorialCyberware:
				if( player )
				{
					EquipTutorialCyberware( player );
				}
			return;
		}
		eqRequest.equipAnimType = request.equipAnimationType;
		equipData.OnEquipmentSystemWeaponManipulationRequest( eqRequest );
	}

	private export function OnUnequipByTDBIDRequest( request : UnequipByTDBIDRequest )
	{
		var equipData : EquipmentSystemPlayerData;
		equipData = GetData( request.owner );
		equipData.OnUnequipByTDBIDRequest( request );
	}

	private export function OnUnequipByContextRequest( request : UnequipByContextRequest )
	{
		var equipData : EquipmentSystemPlayerData;
		var clearRequest : ClearEquipmentRequest;
		var unequipRequest : UnequipRequest;
		var unequipItemsRequest : UnequipItemsRequest;
		var unequipVisualsRequest : UnequipWardrobeSetRequest;
		var eqRequest : EquipmentSystemWeaponManipulationRequest;
		eqRequest = new EquipmentSystemWeaponManipulationRequest;
		equipData = GetData( request.owner );
		unequipRequest = new UnequipRequest;
		unequipRequest.slotIndex = 0;
		switch( request.itemUnequipContext )
		{
			case gameItemUnequipContexts.AllItems:
				clearRequest = new ClearEquipmentRequest;
			equipData.OnClearEquipmentRequest( clearRequest );
			break;
			case gameItemUnequipContexts.HeadClothing:
				unequipRequest.areaType = gamedataEquipmentArea.Head;
			equipData.OnUnequipRequest( unequipRequest );
			break;
			case gameItemUnequipContexts.FaceClothing:
				unequipRequest.areaType = gamedataEquipmentArea.Face;
			equipData.OnUnequipRequest( unequipRequest );
			break;
			case gameItemUnequipContexts.OuterChestClothing:
				unequipRequest.areaType = gamedataEquipmentArea.OuterChest;
			equipData.OnUnequipRequest( unequipRequest );
			break;
			case gameItemUnequipContexts.InnerChestClothing:
				unequipRequest.areaType = gamedataEquipmentArea.InnerChest;
			equipData.OnUnequipRequest( unequipRequest );
			break;
			case gameItemUnequipContexts.LegClothing:
				unequipRequest.areaType = gamedataEquipmentArea.Legs;
			equipData.OnUnequipRequest( unequipRequest );
			break;
			case gameItemUnequipContexts.FootClothing:
				unequipRequest.areaType = gamedataEquipmentArea.Feet;
			equipData.OnUnequipRequest( unequipRequest );
			break;
			case gameItemUnequipContexts.AllClothing:
				unequipRequest.areaType = gamedataEquipmentArea.Head;
			equipData.OnUnequipRequest( unequipRequest );
			unequipRequest.areaType = gamedataEquipmentArea.Face;
			equipData.OnUnequipRequest( unequipRequest );
			unequipRequest.areaType = gamedataEquipmentArea.OuterChest;
			equipData.OnUnequipRequest( unequipRequest );
			unequipRequest.areaType = gamedataEquipmentArea.InnerChest;
			equipData.OnUnequipRequest( unequipRequest );
			unequipRequest.areaType = gamedataEquipmentArea.Legs;
			equipData.OnUnequipRequest( unequipRequest );
			unequipRequest.areaType = gamedataEquipmentArea.Feet;
			equipData.OnUnequipRequest( unequipRequest );
			unequipRequest.areaType = gamedataEquipmentArea.Outfit;
			equipData.OnUnequipRequest( unequipRequest );
			unequipVisualsRequest = new UnequipWardrobeSetRequest;
			unequipVisualsRequest.owner = request.owner;
			OnUnequipWardrobeSetRequest( unequipVisualsRequest );
			break;
			case gameItemUnequipContexts.RightHandWeapon:
				eqRequest.requestType = EquipmentManipulationAction.UnequipWeapon;
			equipData.OnEquipmentSystemWeaponManipulationRequest( eqRequest );
			break;
			case gameItemUnequipContexts.LeftHandWeapon:
				eqRequest.requestType = EquipmentManipulationAction.UnequipConsumable;
			equipData.OnEquipmentSystemWeaponManipulationRequest( eqRequest );
			break;
			case gameItemUnequipContexts.AllWeapons:
				eqRequest.requestType = EquipmentManipulationAction.UnequipAll;
			equipData.OnEquipmentSystemWeaponManipulationRequest( eqRequest );
			break;
			case gameItemUnequipContexts.AllQuestItems:
				unequipItemsRequest = new UnequipItemsRequest;
			unequipItemsRequest.items = equipData.GetEquippedQuestItems();
			equipData.OnUnequipItemsRequest( unequipItemsRequest );
			break;
		}
	}

	private function Debug_SetupEquipmentSystemOverlay( dataOwner : weak< GameObject > )
	{
		var i : Int32;
		var sink : SDOSink;
		var data : EquipmentSystemPlayerData;
		var areas : array< SEquipArea >;
		var loadout : SLoadout;
		data = GetData( dataOwner );
		sink = GameInstance.GetScriptsDebugOverlaySystem( GetGameInstance() ).CreateSink();
		SDOSink.SetRoot( sink, "Equipment" );
		loadout = data.GetEquipment();
		areas = loadout.equipAreas;
		for( i = 0; i < areas.Size(); i += 1 )
		{
			Debug_SetupESAreaButton( areas[ i ], dataOwner );
		}
	}

	public static function ComposeSDORootPath( ownerGameObject : weak< GameObject >, optional suffix : String ) : String
	{
		var path : String;
		path = ( "Equipment/[Player: " + ( ( String )( ownerGameObject.GetControllingPeerID() ) ) ) + "]";
		if( StrLen( suffix ) > 0 )
		{
			path = ( path + "/" ) + suffix;
		}
		return path;
	}

	public const function Debug_SetupESAreaButton( const equipArea : ref< SEquipArea >, ownerGameObject : weak< GameObject > )
	{
		var i : Int32;
		var sink : SDOSink;
		var area : String;
		sink = GameInstance.GetScriptsDebugOverlaySystem( GetGameInstance() ).CreateSink();
		SDOSink.SetRoot( sink, ComposeSDORootPath( ownerGameObject ) );
		area = EnumValueToString( "gamedataEquipmentArea", ( ( Int32 )( equipArea.areaType ) ) );
		SDOSink.PushString( sink, area, "" );
		for( i = 0; i < equipArea.equipSlots.Size(); i += 1 )
		{
			Debug_SetupESSlotButton( i, area, ownerGameObject );
		}
	}

	public const function Debug_SetupESSlotButton( slotIndex : Int32, const areaStr : ref< String >, ownerGameObject : weak< GameObject > )
	{
		var sink : SDOSink;
		sink = GameInstance.GetScriptsDebugOverlaySystem( GetGameInstance() ).CreateSink();
		SDOSink.SetRoot( sink, ComposeSDORootPath( ownerGameObject, areaStr ) );
		SDOSink.PushString( sink, "Slot " + slotIndex, "EMPTY" );
		Debug_SetESSlotData( slotIndex, areaStr, ownerGameObject );
	}

	public const function Debug_SetESSlotData( slotIndex : Int32, const areaStr : ref< String >, ownerGameObject : weak< GameObject > )
	{
		var sink : SDOSink;
		sink = GameInstance.GetScriptsDebugOverlaySystem( GetGameInstance() ).CreateSink();
		SDOSink.SetRoot( sink, ComposeSDORootPath( ownerGameObject, ( areaStr + "/Slot " ) + slotIndex ) );
	}

	public const function Debug_FillESSlotData( slotIndex : Int32, area : gamedataEquipmentArea, itemID : ItemID, ownerGameObject : weak< GameObject > )
	{
		Debug_FillESSlotData( slotIndex, EnumValueToString( "gamedataEquipmentArea", ( ( Int32 )( area ) ) ), itemID, ownerGameObject );
	}

	public const function Debug_FillESSlotData( slotIndex : Int32, const areaStr : ref< String >, itemID : ItemID, ownerGameObject : weak< GameObject > )
	{
		var sink : SDOSink;
		sink = GameInstance.GetScriptsDebugOverlaySystem( GetGameInstance() ).CreateSink();
		SDOSink.SetRoot( sink, ComposeSDORootPath( ownerGameObject, areaStr ) );
		SDOSink.PushString( sink, "Slot " + slotIndex, TDBID.ToStringDEBUG( ItemID.GetTDBID( itemID ) ) );
		SDOSink.SetRoot( sink, ComposeSDORootPath( ownerGameObject, ( areaStr + "/Slot " ) + slotIndex ) );
		SDOSink.PushString( sink, "Item: ", TDBID.ToStringDEBUG( ItemID.GetTDBID( itemID ) ) );
	}

	private export function OnEquipmentSystemWeaponManipulationRequest( request : EquipmentSystemWeaponManipulationRequest )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnEquipmentSystemWeaponManipulationRequest( request );
	}

	private function OnSetActiveItemInEquipmentArea( request : SetActiveItemInEquipmentArea )
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( request.owner );
		playerData.OnSetActiveItemInEquipmentArea( request );
	}

	public const function GetInventoryManager( owner : weak< GameObject > ) : weak< InventoryDataManagerV2 >
	{
		var playerData : EquipmentSystemPlayerData;
		playerData = GetPlayerData( owner );
		return playerData.GetInventoryManager();
	}

}

import enum gameItemEquipContexts
{
	LastWeaponEquipped,
	LastUsedMeleeWeapon,
	LastUsedRangedWeapon,
	Gadget,
	MeleeCyberware,
	LauncherCyberware,
	Fists,
	TutorialCyberware,
}

import enum gameEquipAnimationType
{
	Default,
	Instant,
	FirstEquip,
	HACK_ForceInstantEquip,
}

import enum gameItemUnequipContexts
{
	AllWeapons,
	HeadClothing,
	FaceClothing,
	OuterChestClothing,
	InnerChestClothing,
	LegClothing,
	FootClothing,
	AllClothing,
	RightHandWeapon,
	LeftHandWeapon,
	AllQuestItems,
	AllItems,
}

importonly class EquipRequest extends PlayerScriptableSystemRequest
{
	import var itemID : ItemID;
	import var slotIndex : Int32;
	import var addToInventory : Bool;
	import var equipToCurrentActiveSlot : Bool;
}

class EquipVisualsRequest extends PlayerScriptableSystemRequest
{
	var itemID : ItemID;
}

class UnequipVisualsRequest extends PlayerScriptableSystemRequest
{
	var area : gamedataEquipmentArea;
	var removeItem : Bool;
}

class GameplayEquipRequest extends PlayerScriptableSystemRequest
{
	var itemID : ItemID;
	var slotIndex : Int32;
	default slotIndex = -1;
	var addToInventory : Bool;
	var equipToCurrentActiveSlot : Bool;
	default equipToCurrentActiveSlot = false;
	var blockUpdateWeaponActiveSlots : Bool;
	default blockUpdateWeaponActiveSlots = false;
	var forceEquipWeapon : Bool;
	default forceEquipWeapon = false;
	var extraQuality : Float;
	var partsToAdd : array< ItemID >;
}

class GameplayEquipProgramsRequest extends PlayerScriptableSystemRequest
{
	var programIDs : array< ItemID >;
}

importonly class DrawItemRequest extends PlayerScriptableSystemRequest
{
	import var itemID : ItemID;
	import var equipAnimationType : gameEquipAnimationType;
}

importonly class DrawItemByContextRequest extends PlayerScriptableSystemRequest
{
	import var itemEquipContext : gameItemEquipContexts;
	import var equipAnimationType : gameEquipAnimationType;
}

importonly class UnequipByTDBIDRequest extends PlayerScriptableSystemRequest
{
	import var itemTDBID : TweakDBID;
}

importonly class UnequipByContextRequest extends PlayerScriptableSystemRequest
{
	import var itemUnequipContext : gameItemUnequipContexts;
}

class AssignToCyberwareWheelRequest extends PlayerScriptableSystemRequest
{
	var itemID : ItemID;
	var slotIndex : Int32;
	default slotIndex = -1;
}

class UnequipRequest extends PlayerScriptableSystemRequest
{
	var areaType : gamedataEquipmentArea;
	var slotIndex : Int32;
	default slotIndex = -1;
	var force : Bool;
}

class UnequipItemsRequest extends PlayerScriptableSystemRequest
{
	var items : array< ItemID >;
}

class ReplaceEquipmentRequest extends PlayerScriptableSystemRequest
{
	var itemID : ItemID;
	var slotIndex : Int32;
	var addToInventory : Bool;
	var rerollIdOnAddToInventory : Bool;
	var removeOldItem : Bool;
	var customPartToGenerateID : ItemID;
	var transferInstalledParts : Bool;
}

class ThrowEquipmentRequest extends PlayerScriptableSystemRequest
{
	var itemObject : weak< ItemObject >;
}

class InstallCyberwareRequest extends EquipRequest
{
}

class UninstallCyberwareRequest extends UnequipRequest
{
}

class PartInstallRequest extends PlayerScriptableSystemRequest
{
	var itemID : ItemID;
	var partID : ItemID;
}

class PartUninstallRequest extends PlayerScriptableSystemRequest
{
	var itemID : ItemID;
	var partID : ItemID;
}

class ClearEquipmentRequest extends PlayerScriptableSystemRequest
{
}

class SaveEquipmentSetRequest extends PlayerScriptableSystemRequest
{
	var setName : String;
	var setType : EEquipmentSetType;
}

class LoadEquipmentSetRequest extends PlayerScriptableSystemRequest
{
	var setName : String;
}

class DeleteEquipmentSetRequest extends PlayerScriptableSystemRequest
{
	var setName : String;
}

class EquipmentUIBBRequest extends PlayerScriptableSystemRequest
{
}

class ProcessVisualTags extends PlayerScriptableSystemRequest
{
	var itemTDBID : TweakDBID;
}

class CheckRemovedItemWithSlotActiveItem extends PlayerScriptableSystemRequest
{
	var itemID : ItemID;
}

class ClearAllWeaponSlotsRequest extends PlayerScriptableSystemRequest
{
}

class EquipmentSystemWeaponManipulationRequest extends PlayerScriptableSystemRequest
{
	var requestType : EquipmentManipulationAction;
	var equipAnimType : gameEquipAnimationType;
	default equipAnimType = gameEquipAnimationType.Default;
	var removeItemFromEquipSlot : Bool;
	default removeItemFromEquipSlot = false;
}

class SetActiveItemInEquipmentArea extends PlayerScriptableSystemRequest
{
	var itemID : ItemID;
}

class ClearItemAppearanceEvent extends Event
{
	var itemID : ItemID;
}

class ResetItemAppearanceEvent extends Event
{
	var itemID : ItemID;
}

class UnderwearEquipFailsafeEvent extends Event
{
	var bottom : Bool;
}

class PrepareForForcedVehicleCombat extends Event
{
}

importonly class SynchronizeAttachmentSlotRequest extends PlayerScriptableSystemRequest
{
	import var slotID : TweakDBID;
}

class EquipWardrobeSetRequest extends PlayerScriptableSystemRequest
{
	var setID : gameWardrobeClothingSetIndex;
}

class UnequipWardrobeSetRequest extends PlayerScriptableSystemRequest
{
}

class DeleteWardrobeSetRequest extends PlayerScriptableSystemRequest
{
	var setID : gameWardrobeClothingSetIndex;
}

class QuestDisableWardrobeSetRequest extends PlayerScriptableSystemRequest
{
	var blockReequipping : Bool;
}

class QuestRestoreWardrobeSetRequest extends PlayerScriptableSystemRequest
{
}

class QuestEnableWardrobeSetRequest extends PlayerScriptableSystemRequest
{
}

class QuestHideSlotRequest extends PlayerScriptableSystemRequest
{
	var slot : gamedataEquipmentArea;
}

class QuestRestoreSlotRequest extends PlayerScriptableSystemRequest
{
	var slot : gamedataEquipmentArea;
}

class ResetItemAppearanceTaskData extends ScriptTaskData
{
	var ts : TransactionSystem;
	var area : gamedataEquipmentArea;
	var force : Bool;
}

class ClearItemAppearanceTaskData extends ScriptTaskData
{
	var ts : TransactionSystem;
	var area : gamedataEquipmentArea;
}

importonly struct SEquipArea
{
	import persistent var areaType : gamedataEquipmentArea;
	import persistent var equipSlots : array< SEquipSlot >;
	import persistent var activeIndex : Int32;
}

importonly struct SEquipSlot
{
	import persistent var itemID : ItemID;
	import var slotID : TweakDBID;
	import var unlockPrereq : IPrereq;
	import var visibleWhenLocked : Bool;
}

importonly struct SEquipmentSet
{
	import persistent var setItems : array< SItemInfo >;
	import persistent var setName : CName;
	import persistent var setType : EEquipmentSetType;
}

importonly struct SItemInfo
{
	import persistent var itemID : ItemID;
	import persistent var slotIndex : Int32;
}

importonly struct SSlotInfo
{
	import persistent var areaType : gamedataEquipmentArea;
	import persistent var equipSlot : TweakDBID;
	import persistent var visualTag : CName;
}

importonly struct SSlotVisualInfo
{
	import persistent var areaType : gamedataEquipmentArea;
	import persistent var isHidden : Bool;
	import persistent var visualItem : ItemID;
}

importonly struct SVisualTagProcessing
{
	import persistent var areaType : gamedataEquipmentArea;
	import persistent var showItem : Bool;
}

importonly struct SLastUsedWeapon
{
	import persistent var lastUsedWeapon : ItemID;
	import persistent var lastUsedRanged : ItemID;
	import persistent var lastUsedMelee : ItemID;
	import persistent var lastUsedHeavy : ItemID;
}

importonly struct SSlotActiveItems
{
	import persistent var rightHandItem : ItemID;
	import persistent var leftHandItem : ItemID;
}

enum ELastUsed
{
	Weapon = 0,
	Melee = 1,
	Ranged = 2,
	Heavy = 3,
}

importonly struct SLoadout
{
	import persistent var equipAreas : array< SEquipArea >;
	import persistent var equipmentSets : array< SEquipmentSet >;
}

import enum EEquipmentSetType
{
	Offensive,
	Defensive,
	Cyberware,
}

enum EquipmentManipulationAction
{
	Undefined = 0,
	RequestActiveMeleeware = 1,
	RequestActiveWeapon = 2,
	RequestSlotActiveWeapon = 3,
	RequestLastUsedWeapon = 4,
	RequestFirstMeleeWeapon = 5,
	RequestLastUsedMeleeWeapon = 6,
	RequestLastUsedOrFirstAvailableWeapon = 7,
	RequestLastUsedOrFirstAvailableRangedWeapon = 8,
	RequestLastUsedOrFirstAvailableMeleeWeapon = 9,
	RequestLastUsedOrFirstAvailableOneHandedRangedWeapon = 10,
	RequestLastUsedOrFirstAvailableDriverCombatRangedWeapon = 11,
	RequestLastUsedOrFirstAvailableDriverCombatBikeWeapon = 12,
	RequestHeavyWeapon = 13,
	CycleWeaponWheelItem = 14,
	CycleNextWeaponWheelItem = 15,
	CyclePreviousWeaponWheelItem = 16,
	RequestConsumable = 17,
	RequestGadget = 18,
	RequestFists = 19,
	RequestLeftHandCyberware = 20,
	UnequipWeapon = 21,
	UnequipConsumable = 22,
	UnequipGadget = 23,
	UnequipLeftHandCyberware = 24,
	UnequipAll = 25,
	ReequipWeapon = 26,
	RequestWeaponSlot1 = 27,
	RequestWeaponSlot2 = 28,
	RequestWeaponSlot3 = 29,
	RequestWeaponSlot4 = 30,
	RequestNextThrowableWeapon = 31,
}

class UIEquipmentReplacedEvent extends Event
{
	var itemID : ItemID;
}

