struct ItemAttachments
{
	var itemID : ItemID;
	var attachmentSlotID : TweakDBID;

	public static function Create( itemID : ItemID, attachmentSlotID : TweakDBID ) : ItemAttachments
	{
		var itemAttachment : ItemAttachments;
		itemAttachment.itemID = itemID;
		itemAttachment.attachmentSlotID = attachmentSlotID;
		return itemAttachment;
	}

}

class CraftingSystem extends ScriptableSystem
{
	private var m_lastActionStatus : Bool;
	private persistent var m_playerCraftBook : CraftBook;
	private var m_callback : CraftingSystemInventoryCallback;
	private var m_inventoryListener : InventoryScriptListener;
	private var m_itemIconGender : ItemIconGender;

	private export override function OnAttach()
	{
		if( !( m_playerCraftBook ) )
		{
			m_playerCraftBook = new CraftBook;
		}
	}

	private export function OnPlayerAttach( request : PlayerAttachRequest )
	{
		var player : PlayerPuppet;
		player = ( ( PlayerPuppet )( GameInstance.GetPlayerSystem( request.owner.GetGame() ).GetLocalPlayerMainGameObject() ) );
		m_itemIconGender = UIGenderHelper.GetIconGender( player );
		m_callback = new CraftingSystemInventoryCallback;
		m_callback.player = player;
		m_inventoryListener = GameInstance.GetTransactionSystem( player.GetGame() ).RegisterInventoryListener( player, m_callback );
		if( m_playerCraftBook )
		{
			m_playerCraftBook.InitializeCraftBookOwner( player );
		}
	}

	private function OnPlayerDetach( request : PlayerDetachRequest )
	{
		var player : PlayerPuppet;
		player = ( ( PlayerPuppet )( request.owner ) );
		GameInstance.GetTransactionSystem( player.GetGame() ).UnregisterInventoryListener( player, m_inventoryListener );
		m_inventoryListener = NULL;
	}

	private export override function OnRestored( saveVersion : Int32, gameVersion : Int32 )
	{
		var factVal : Int32;
		var warningMsg : SimpleScreenMessage;
		warningMsg.isShown = true;
		warningMsg.duration = 20.0;
		warningMsg.message = IntToString( saveVersion );
		GameInstance.GetBlackboardSystem( GetGameInstance() ).Get( GetAllBlackboardDefs().UI_Notifications ).SetVariant( GetAllBlackboardDefs().UI_Notifications.WarningMessage, warningMsg, true );
		factVal = GetFact( GetGameInstance(), 'IconicItemsRevampCompleted' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2 ) )
		{
			ProcessIconicRevampRestoration();
			SetFactValue( GetGameInstance(), 'IconicItemsRevampCompleted', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'AmmoRecipesAdded' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2 ) )
		{
			AddAmmoRecipes();
			SetFactValue( GetGameInstance(), 'AmmoRecipesAdded', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'RecipesCraftedAmountRestored' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2 ) )
		{
			m_playerCraftBook.ResetRecipeCraftedAmount();
			SetFactValue( GetGameInstance(), 'RecipesCraftedAmountRestored', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'LegendaryLizzieFixed' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2 ) )
		{
			if( GameInstance.GetTransactionSystem( GetGameInstance() ).HasItem( m_playerCraftBook.GetOwner(), ItemID.CreateQuery( T"Items.Preset_Omaha_Suzie_Epic" ) ) )
			{
				m_playerCraftBook.AddRecipe( T"Items.Preset_Omaha_Suzie_Legendary",  );
				SetFactValue( GetGameInstance(), 'LegendaryLizzieFixed', 1 );
			}
		}
		factVal = GetFact( GetGameInstance(), 'UncommonKnifeAdded' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1300 ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Uncommon_Knife",  );
			SetFactValue( GetGameInstance(), 'UncommonKnifeAdded', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'CraftedItemsDynamicBonus' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1500 ) )
		{
			ProcessCraftedItemsPowerBoost();
			SetFactValue( GetGameInstance(), 'CraftedItemsDynamicBonus', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'DLCStashItemsRevamp' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1500 ) ) && ( saveVersion <= 212 ) )
		{
			HideDLCRecipes();
			AddDLCBaseRecipes();
			SetFactValue( GetGameInstance(), 'DLCStashItemsRevamp', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'ButchersKnifeRemoved' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1600 ) )
		{
			HideButchersKnifeRecipes();
			CompensateForOwnedButchersKnifeRecipes();
			SetFactValue( GetGameInstance(), 'ButchersKnifeRemoved', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'BuckGradScopeFix' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1600 ) )
		{
			SetFactValue( GetGameInstance(), 'BuckGradScopeFix', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'VendorIconicKnivesSecured' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 1610 ) )
		{
			VendorIconicKnivesSecured();
			SetFactValue( GetGameInstance(), 'VendorIconicKnivesSecured', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'MilitaryKatanaReworked' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) )
		{
			HideMilitaryKatanaRecipes();
			CompensateForOwnedMilitaryKatanaRecipes();
			SetFactValue( GetGameInstance(), 'MilitaryKatanaReworked', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'PipeWrenchRemoved' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) )
		{
			HidePipeWrenchRecipes();
			CompensateForOwnedPipeWrenchRecipes();
			SetFactValue( GetGameInstance(), 'PipeWrenchRemoved', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'WeaponAndClothingModsAdjusted' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) ) && ( saveVersion <= 224 ) )
		{
			ProcessWeaponsAndClothingModsPurge();
			SetFactValue( GetGameInstance(), 'WeaponAndClothingModsAdjusted', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'DeprecatedRecipesHidden' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) ) && ( saveVersion <= 224 ) )
		{
			CompensateForOwnedCraftableIconics();
			HideIconicWeaponsRecipes();
			HideDeprecatedCraftingRecipes();
			SetFactValue( GetGameInstance(), 'DeprecatedRecipesHidden', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'StartingCraftbookAdjusted' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2000 ) )
		{
			HideDeprecatedCraftbookRecipes();
			AddCraftbookRecipes();
			SetFactValue( GetGameInstance(), 'StartingCraftbookAdjusted', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'WeaponModsAdjusted_201' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2010 ) )
		{
			ProcessWeaponsModsCompensate();
			InstallModsToRedesignedItems();
			SetFactValue( GetGameInstance(), 'WeaponModsAdjusted_201', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'Craftbook_201_hotfixes' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2010 ) )
		{
			HideDeprecatedCraftingRecipes();
			AddCraftbookRecipes();
			SetFactValue( GetGameInstance(), 'Craftbook_201_hotfixes', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'AmmoRecipesRefreshed' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2010 ) )
		{
			AddAmmoRecipes();
			SetFactValue( GetGameInstance(), 'AmmoRecipesRefreshed', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'GritModsPurged' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2099 ) ) && ( saveVersion <= 257 ) )
		{
			ProcessGritModsPurge();
			SetFactValue( GetGameInstance(), 'GritModsPurged', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'AmmoRecipesRefreshed_UE' );
		if( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2099 ) )
		{
			AddAmmoRecipes();
			SetFactValue( GetGameInstance(), 'AmmoRecipesRefreshed_UE', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'AmazonGritAttachmentsPurged' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2110 ) ) && ( saveVersion <= 261 ) )
		{
			ProcessAmazonGritAttachmentsPurge();
			SetFactValue( GetGameInstance(), 'AmazonGritAttachmentsPurged', 1 );
		}
		factVal = GetFact( GetGameInstance(), 'BuzzsawPsalmRecipesRetrofixed' );
		if( ( ( factVal <= 0 ) && ( ( ( Int32 )( gameGameVersion.Current ) ) >= 2110 ) ) && ( saveVersion <= 261 ) )
		{
			CompensateMissingBuzzsawPsalmRecipes();
			SetFactValue( GetGameInstance(), 'BuzzsawPsalmRecipesRetrofixed', 1 );
		}
	}

	public static function GetInstance( gameInstance : GameInstance ) : CraftingSystem
	{
		var cs : CraftingSystem;
		cs = ( ( CraftingSystem )( GameInstance.GetScriptableSystemsContainer( gameInstance ).Get( 'CraftingSystem' ) ) );
		return cs;
	}

	public const function GetPlayerCraftBook() : CraftBook
	{
		return m_playerCraftBook;
	}

	public const function GetPlayerCraftableItems() : array< weak< Item_Record > >
	{
		return m_playerCraftBook.GetCraftableItems();
	}

	public const function GetItemFinalUpgradeCost( itemData : weak< gameItemData > ) : array< IngredientData >
	{
		var i : Int32;
		var tempStat : Float;
		var statsSystem : StatsSystem;
		var ingredients : array< IngredientData >;
		var upgradeNumber : Float;
		statsSystem = GameInstance.GetStatsSystem( GetGameInstance() );
		upgradeNumber = itemData.GetStatValueByType( gamedataStatType.WasItemUpgraded );
		upgradeNumber += 1.0;
		ingredients = GetItemBaseUpgradeCost( itemData.GetItemType(), RPGManager.GetItemTierForUpgrades( itemData ) );
		for( i = 0; i < ingredients.Size(); i += 1 )
		{
			ingredients[ i ].quantity = ingredients[ i ].quantity;
			ingredients[ i ].baseQuantity = ingredients[ i ].quantity;
		}
		tempStat = statsSystem.GetStatValue( m_playerCraftBook.GetOwner().GetEntityID(), gamedataStatType.UpgradingCostReduction );
		if( tempStat > 0.0 )
		{
			for( i = 0; i < ingredients.Size(); i += 1 )
			{
				ingredients[ i ].quantity = ( ( Int32 )( ( ( Float )( ingredients[ i ].quantity ) ) * ( 1.0 - tempStat ) ) );
			}
		}
		return ingredients;
	}

	public const function GetItemBaseUpgradeCost( itemType : gamedataItemType, quality : gamedataQuality ) : array< IngredientData >
	{
		var i : Int32;
		var record : UpgradingData_Record;
		var upgradeData : array< weak< RecipeElement_Record > >;
		var baseIngredients : array< IngredientData >;
		record = TweakDBInterface.GetUpgradingDataRecord( T"Upgrading." + TDBID.Create( EnumValueToString( "gamedataItemType", ( ( Int32 )( itemType ) ) ) ) );
		record.Ingredients( upgradeData );
		for( i = 0; i < upgradeData.Size(); i += 1 )
		{
			baseIngredients.PushBack( CreateIngredientData( upgradeData[ i ] ) );
		}
		upgradeData.Clear();
		record = TweakDBInterface.GetUpgradingDataRecord( T"Upgrading." + TDBID.Create( EnumValueToString( "gamedataQuality", ( ( Int32 )( quality ) ) ) ) );
		record.Ingredients( upgradeData );
		for( i = 0; i < upgradeData.Size(); i += 1 )
		{
			baseIngredients.PushBack( CreateIngredientData( upgradeData[ i ] ) );
		}
		return baseIngredients;
	}

	public const function GetItemCraftingCost( itemData : weak< gameItemData > ) : array< IngredientData >
	{
		var itemRecord : weak< Item_Record >;
		var baseIngredients : array< IngredientData >;
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemData.GetID() ) );
		baseIngredients = GetItemCraftingCost( itemRecord );
		return baseIngredients;
	}

	public const function GetItemCraftingCost( itemRecord : weak< Item_Record > ) : array< IngredientData >
	{
		var record : weak< CraftingPackage_Record >;
		var craftingData : array< weak< RecipeElement_Record > >;
		var baseIngredients : array< IngredientData >;
		record = itemRecord.CraftingData();
		record.CraftingRecipe( craftingData );
		baseIngredients = GetItemCraftingCost( itemRecord, craftingData );
		return baseIngredients;
	}

	public const function GetItemCraftingCost( record : weak< Item_Record >, const craftingData : ref< array< weak< RecipeElement_Record > > > ) : array< IngredientData >
	{
		var i : Int32;
		var modifiedQuantity : Int32;
		var tempStat : Float;
		var statsSystem : StatsSystem;
		var baseIngredients : array< IngredientData >;
		var expectedQuality : gamedataQuality;
		statsSystem = GameInstance.GetStatsSystem( GetGameInstance() );
		for( i = 0; i < craftingData.Size(); i += 1 )
		{
			baseIngredients.PushBack( CreateIngredientData( craftingData[ i ] ) );
		}
		if( record.Quality().Type() == gamedataQuality.Random )
		{
			expectedQuality = ( ( gamedataQuality )( ( ( Int32 )( EnumValueFromName( 'gamedataQuality', RPGManager.SetQualityBasedOnLevel( m_playerCraftBook.GetOwner() ) ) ) ) ) );
			if( expectedQuality >= gamedataQuality.Uncommon )
			{
				baseIngredients.PushBack( CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Uncommon, false ), 75 ) );
			}
			if( expectedQuality >= gamedataQuality.Rare )
			{
				baseIngredients.PushBack( CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Rare, false ), 55 ) );
			}
			if( expectedQuality >= gamedataQuality.Epic )
			{
				baseIngredients.PushBack( CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Epic, false ), 35 ) );
			}
			if( expectedQuality >= gamedataQuality.Legendary )
			{
				baseIngredients.PushBack( CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Legendary, false ), 15 ) );
			}
		}
		tempStat = statsSystem.GetStatValue( m_playerCraftBook.GetOwner().GetEntityID(), gamedataStatType.CraftingCostReduction );
		if( tempStat > 0.0 )
		{
			for( i = 0; i < baseIngredients.Size(); i += 1 )
			{
				if( baseIngredients[ i ].quantity > 1 )
				{
					modifiedQuantity = ( ( Int32 )( CeilF( ( ( Float )( baseIngredients[ i ].quantity ) ) * ( 1.0 - tempStat ) ) ) );
					baseIngredients[ i ].quantity = modifiedQuantity;
				}
			}
		}
		return baseIngredients;
	}

	public const function CanItemBeDisassembled( owner : weak< GameObject >, itemID : ItemID ) : Bool
	{
		var itemData : weak< gameItemData >;
		itemData = GameInstance.GetTransactionSystem( GetGameInstance() ).GetItemData( owner, itemID );
		if( RPGManager.IsItemEquipped( owner, itemID ) && !( itemData.HasTag( 'LongLasting' ) ) )
		{
			return false;
		}
		return CanItemBeDisassembled( itemData );
	}

	public const function CanItemBeDisassembled( itemData : weak< gameItemData > ) : Bool
	{
		if( itemData )
		{
			return ( ( !( itemData.HasTag( 'IconicWeapon' ) ) && !( itemData.HasTag( 'Quest' ) ) ) && !( itemData.HasTag( 'UnequipBlocked' ) ) ) && ItemActionsHelper.GetDisassembleAction( itemData.GetID() );
		}
		return false;
	}

	public const function CanItemBeCrafted( itemData : weak< gameItemData > ) : Bool
	{
		var result : Bool;
		var requiredIngredients : array< IngredientData >;
		var ammoCap, currentQuantity, resultQuantity : Int32;
		var transactionSystem : TransactionSystem;
		var itemRecord : Item_Record;
		var itemTweakDBID : TweakDBID;
		transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
		requiredIngredients = GetItemCraftingCost( itemData );
		result = HasIngredients( requiredIngredients );
		if( result )
		{
			itemTweakDBID = ItemID.GetTDBID( itemData.GetID() );
			itemRecord = TweakDBInterface.GetItemRecord( itemTweakDBID );
			if( itemRecord.TagsContains( 'Ammo' ) )
			{
				ammoCap = ( ( Int32 )( itemData.GetStatValueByType( gamedataStatType.Quantity ) ) );
				currentQuantity = transactionSystem.GetItemQuantity( m_playerCraftBook.GetOwner(), itemData.GetID() );
				resultQuantity = ( ammoCap - currentQuantity ) / GetAmmoBulletAmount( itemTweakDBID );
				result = resultQuantity > 0;
			}
		}
		return result;
	}

	public const function CanItemBeCrafted( itemRecord : weak< Item_Record > ) : Bool
	{
		var result : Bool;
		var requiredIngredients : array< IngredientData >;
		var quality : gamedataQuality;
		requiredIngredients = GetItemCraftingCost( itemRecord );
		if( itemRecord.ItemType().Type() == gamedataItemType.Prt_Program || itemRecord.TagsContains( 'ChimeraMod' ) )
		{
			result = HasIngredients( requiredIngredients );
		}
		else
		{
			result = HasIngredients( requiredIngredients ) && CanCraftGivenQuality( itemRecord, quality );
		}
		return result;
	}

	public const function EnoughIngredientsForCrafting( itemData : weak< gameItemData > ) : Bool
	{
		var result : Bool;
		var requiredIngredients : array< IngredientData >;
		requiredIngredients = GetItemCraftingCost( itemData );
		result = HasIngredients( requiredIngredients );
		return result;
	}

	public const function GetMaxCraftingAmount( itemData : weak< gameItemData > ) : Int32
	{
		var result, i, currentQuantity : Int32;
		var requiredIngredients : array< IngredientData >;
		var transactionSystem : TransactionSystem;
		var ammoCap : Int32;
		var itemRecord : Item_Record;
		var itemTweakDBID : TweakDBID;
		transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
		requiredIngredients = GetItemCraftingCost( itemData );
		result = 10000000;
		for( i = 0; i < requiredIngredients.Size(); i += 1 )
		{
			currentQuantity = transactionSystem.GetItemQuantityWithDuplicates( m_playerCraftBook.GetOwner(), ItemID.CreateQuery( requiredIngredients[ i ].id.GetID() ) );
			if( currentQuantity > requiredIngredients[ i ].quantity )
			{
				result = Min( result, currentQuantity / requiredIngredients[ i ].quantity );
			}
			else
			{
				return 0;
			}
		}
		itemTweakDBID = ItemID.GetTDBID( itemData.GetID() );
		itemRecord = TweakDBInterface.GetItemRecord( itemTweakDBID );
		if( itemRecord.TagsContains( 'Ammo' ) )
		{
			currentQuantity = transactionSystem.GetItemQuantity( m_playerCraftBook.GetOwner(), itemData.GetID() );
			ammoCap = ( ( ( Int32 )( itemData.GetStatValueByType( gamedataStatType.Quantity ) ) ) - currentQuantity ) / GetAmmoBulletAmount( itemTweakDBID );
			result = Min( ammoCap, result );
		}
		return Max( result, 0 );
	}

	public const function EnoughIngredientsForUpgrading( itemData : weak< gameItemData > ) : Bool
	{
		var result : Bool;
		var requiredIngredients : array< IngredientData >;
		requiredIngredients = GetItemFinalUpgradeCost( itemData );
		result = HasIngredients( requiredIngredients );
		return result;
	}

	public const function CanItemBeUpgraded( itemData : weak< gameItemData > ) : Bool
	{
		var result : Bool;
		var requiredIngredients : array< IngredientData >;
		if( RPGManager.IsItemMaxTier( itemData ) )
		{
			return false;
		}
		requiredIngredients = GetItemFinalUpgradeCost( itemData );
		result = HasIngredients( requiredIngredients );
		return result;
	}

	public const function HasIngredients( const required : ref< array< IngredientData > > ) : Bool
	{
		var i : Int32;
		var currentQuantity : Int32;
		var transactionSystem : TransactionSystem;
		transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
		for( i = 0; i < required.Size(); i += 1 )
		{
			currentQuantity = transactionSystem.GetItemQuantityWithDuplicates( m_playerCraftBook.GetOwner(), ItemID.CreateQuery( required[ i ].id.GetID() ) );
			if( currentQuantity < required[ i ].quantity )
			{
				return false;
			}
		}
		return true;
	}

	public const function CanCraftGivenQuality( itemData : weak< gameItemData >, out quality : gamedataQuality ) : Bool
	{
		var ss : StatsSystem;
		var canCraft : Bool;
		var player : weak< PlayerPuppet >;
		var playerLevel : Float;
		ss = GameInstance.GetStatsSystem( GetGameInstance() );
		quality = RPGManager.GetItemQuality( itemData.GetStatValueByType( gamedataStatType.Quality ) );
		player = GetPlayer( GetGameInstance() );
		playerLevel = ss.GetStatValue( player.GetEntityID(), gamedataStatType.Level );
		switch( quality )
		{
			case gamedataQuality.Uncommon:
				canCraft = playerLevel >= 1.0;
			break;
			case gamedataQuality.Rare:
				canCraft = playerLevel >= 1.0;
			break;
			case gamedataQuality.Epic:
				canCraft = playerLevel >= 1.0;
			break;
			case gamedataQuality.Legendary:
				canCraft = playerLevel >= 1.0;
			break;
			default:
				canCraft = true;
			break;
		}
		return canCraft;
	}

	public const function CanCraftGivenQuality( itemRecord : weak< Item_Record >, out quality : gamedataQuality ) : Bool
	{
		var ss : StatsSystem;
		var canCraft : Bool;
		var player : weak< PlayerPuppet >;
		var playerLevel : Float;
		ss = GameInstance.GetStatsSystem( GetGameInstance() );
		quality = itemRecord.Quality().Type();
		player = GetPlayer( GetGameInstance() );
		playerLevel = ss.GetStatValue( player.GetEntityID(), gamedataStatType.Level );
		if( quality == gamedataQuality.Random )
		{
			quality = UIItemsHelper.QualityNameToEnum( RPGManager.SetQualityBasedOnLevel( GetPlayer( GetGameInstance() ) ) );
		}
		switch( quality )
		{
			case gamedataQuality.Uncommon:
				canCraft = playerLevel >= 1.0;
			break;
			case gamedataQuality.Rare:
				canCraft = playerLevel >= 1.0;
			break;
			case gamedataQuality.Epic:
				canCraft = playerLevel >= 1.0;
			break;
			case gamedataQuality.Legendary:
				canCraft = playerLevel >= 1.0;
			break;
			default:
				canCraft = true;
			break;
		}
		return canCraft;
	}

	public const function IsRecipeKnown( recipe : TweakDBID, playerCraftBook : CraftBook ) : Bool
	{
		var recipeRecord : weak< ItemRecipe_Record >;
		var itemToAdd : weak< CraftingResult_Record >;
		recipeRecord = TweakDBInterface.GetItemRecipeRecord( recipe );
		itemToAdd = recipeRecord.CraftingResult();
		if( playerCraftBook.GetRecipeIndex( itemToAdd.Item().GetID() ) >= 0 )
		{
			return true;
		}
		return false;
	}

	private export function OnCraftItemRequest( request : CraftItemRequest )
	{
		var craftedItem : weak< gameItemData >;
		craftedItem = CraftItem( request.target, request.itemRecord, request.amount, request.bulletAmount );
		UpdateBlackboard( CraftingCommands.CraftingFinished, craftedItem.GetID() );
		if( request.itemRecord.TagsContains( 'Tier6Shard' ) )
		{
			RPGManager.AwardExperienceInstantly( ( ( PlayerPuppet )( request.target ) ), 300, gamedataProficiencyType.IntelligenceSkill );
		}
		else if( request.itemRecord.TagsContains( 'Tier4Shard' ) )
		{
			RPGManager.AwardExperienceInstantly( ( ( PlayerPuppet )( request.target ) ), 125, gamedataProficiencyType.IntelligenceSkill );
		}
		else if( request.itemRecord.TagsContains( 'Tier3Shard' ) )
		{
			RPGManager.AwardExperienceInstantly( ( ( PlayerPuppet )( request.target ) ), 80, gamedataProficiencyType.IntelligenceSkill );
		}
		else if( request.itemRecord.TagsContains( 'Tier2Shard' ) )
		{
			RPGManager.AwardExperienceInstantly( ( ( PlayerPuppet )( request.target ) ), 50, gamedataProficiencyType.IntelligenceSkill );
		}
		else if( request.itemRecord.TagsContains( 'Tier1Shard' ) )
		{
			RPGManager.AwardExperienceInstantly( ( ( PlayerPuppet )( request.target ) ), 30, gamedataProficiencyType.IntelligenceSkill );
		}
	}

	private function OnDisassembleItemRequest( request : DisassembleItemRequest )
	{
		if( CanItemBeDisassembled( GetPlayer( GetGameInstance() ), request.itemID ) )
		{
			DisassembleItem( request.target, request.itemID, request.amount );
		}
	}

	private function OnUpgradeItemRequest( request : UpgradeItemRequest )
	{
		UpgradeItem( request.owner, request.itemID );
		UpdateBlackboard( CraftingCommands.UpgradingFinished, request.itemID );
	}

	private export function OnAddRecipeRequest( request : AddRecipeRequest )
	{
		GetPlayerCraftBook().AddRecipe( request.recipe, request.hideOnItemsAdded, request.amount );
	}

	private function OnHideRecipeRequest( request : HideRecipeRequest )
	{
		GetPlayerCraftBook().HideRecipe( request.recipe, true );
	}

	private function OnShowRecipeRequest( request : ShowRecipeRequest )
	{
		GetPlayerCraftBook().HideRecipe( request.recipe, false );
	}

	public const function GetLastActionStatus() : Bool
	{
		return m_lastActionStatus;
	}

	private function CraftItem( target : weak< GameObject >, itemRecord : Item_Record, amount : Int32, optional ammoBulletAmount : Int32 ) : weak< gameItemData >
	{
		var ingredientRecords : array< weak< RecipeElement_Record > >;
		var requiredIngredients : array< IngredientData >;
		var tempStat : Float;
		var ingredient : ItemID;
		var transactionSystem : TransactionSystem;
		var statsSystem : StatsSystem;
		var j : Int32;
		var i, recipeXP : Int32;
		var craftedItemID : ItemID;
		var itemData : weak< gameItemData >;
		var randF : Float;
		var xpID : TweakDBID;
		var ingredientQuality : gamedataQuality;
		var isAmmo : Bool;
		var savedAmount : Int32;
		var savedAmountLocked : Bool;
		transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
		statsSystem = GameInstance.GetStatsSystem( GetGameInstance() );
		randF = RandF();
		itemRecord.CraftingData().CraftingRecipe( ingredientRecords );
		requiredIngredients = GetItemCraftingCost( itemRecord );
		isAmmo = itemRecord.TagsContains( 'Ammo' );
		for( i = 0; i < requiredIngredients.Size(); i += 1 )
		{
			ingredient = ItemID.CreateQuery( requiredIngredients[ i ].id.GetID() );
			if( ( RPGManager.IsItemWeapon( ingredient ) || RPGManager.IsItemClothing( ingredient ) ) || RPGManager.IsItemMisc( ingredient ) )
			{
				itemData = transactionSystem.GetItemData( target, ingredient );
				if( itemData && itemData.HasTag( 'Quest' ) )
				{
					itemData.RemoveDynamicTag( 'Quest' );
				}
				ClearNonIconicSlots( itemData );
				break;
			}
		}
		tempStat = statsSystem.GetStatValue( target.GetEntityID(), gamedataStatType.CraftingMaterialRetrieveChance );
		savedAmount = 0;
		for( i = 0; i < requiredIngredients.Size(); i += 1 )
		{
			ingredient = ItemID.CreateQuery( requiredIngredients[ i ].id.GetID() );
			if( ( ( RPGManager.IsItemWeapon( ingredient ) || RPGManager.IsItemClothing( ingredient ) ) || RPGManager.IsItemProgram( ingredient ) ) || RPGManager.IsItemGadget( ingredient ) )
			{
				randF = 100.0;
			}
			else if( ( tempStat > 0.0 ) && !( savedAmountLocked ) )
			{
				for( j = 0; j < amount; j += 1 )
				{
					if( RandF() < tempStat )
					{
						savedAmount += 1;
					}
				}
				savedAmountLocked = true;
			}
			transactionSystem.RemoveItemByTDBID( target, ItemID.GetTDBID( ingredient ), requiredIngredients[ i ].quantity * ( amount - savedAmount ), true );
			if( ( randF >= tempStat ) && ( ( RPGManager.IsItemWeapon( ingredient ) || RPGManager.IsItemClothing( ingredient ) ) || RPGManager.IsItemProgram( ingredient ) ) )
			{
				transactionSystem.RemoveItemByTDBID( target, ItemID.GetTDBID( ingredient ), requiredIngredients[ i ].quantity * amount, true );
			}
			ingredientQuality = RPGManager.GetItemQualityFromRecord( TweakDBInterface.GetItemRecord( requiredIngredients[ i ].id.GetID() ) );
			switch( ingredientQuality )
			{
				case gamedataQuality.Common:
					xpID = T"Constants.CraftingSystem.commonIngredientXP";
				break;
				case gamedataQuality.Uncommon:
					xpID = T"Constants.CraftingSystem.uncommonIngredientXP";
				break;
				case gamedataQuality.Rare:
					xpID = T"Constants.CraftingSystem.rareIngredientXP";
				break;
				case gamedataQuality.Epic:
					xpID = T"Constants.CraftingSystem.epicIngredientXP";
				break;
				case gamedataQuality.Legendary:
					xpID = T"Constants.CraftingSystem.legendaryIngredientXP";
				break;
				default:
					break;
			}
			recipeXP += ( ( TweakDBInterface.GetInt( xpID, 0 ) * requiredIngredients[ i ].baseQuantity ) * amount );
		}
		craftedItemID = ItemID.FromTDBID( itemRecord.GetID() );
		transactionSystem.GiveItem( target, craftedItemID, ( ( isAmmo ) ? ( amount * ammoBulletAmount ) : ( amount ) ) );
		if( ( ( itemRecord.ItemType().Type() == gamedataItemType.Gad_Grenade || itemRecord.ItemType().Type() == gamedataItemType.Con_Inhaler ) || itemRecord.ItemType().Type() == gamedataItemType.Con_Injector ) || ( itemRecord.TagsContains( 'CraftableIconic' ) && !( itemRecord.TagsContains( 'Haunted_Gun' ) ) ) )
		{
			ProcessProgramCrafting( itemRecord.GetID() );
		}
		itemData = transactionSystem.GetItemData( target, craftedItemID );
		SetItemLevel( itemData );
		MarkItemAsCrafted( itemData );
		SendItemCraftedDataTrackingRequest( craftedItemID, amount );
		ProcessCraftSkill( ( ( Float )( recipeXP ) ) );
		return itemData;
	}

	private function MarkItemAsCrafted( itemData : weak< gameItemData > )
	{
		var statMod : gameStatModifierData;
		statMod = RPGManager.CreateStatModifier( gamedataStatType.IsItemCrafted, gameStatModifierType.Additive, 1.0 );
		GameInstance.GetStatsSystem( GetGameInstance() ).AddSavedModifier( itemData.GetStatsObjectID(), statMod );
	}

	private function ClearNonIconicSlots( itemData : weak< gameItemData > )
	{
		var i : Int32;
		var slots : array< TweakDBID >;
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		var partData : InnerItemData;
		var staticData : weak< Item_Record >;
		TS = GameInstance.GetTransactionSystem( GetGameInstance() );
		player = ( ( PlayerPuppet )( m_playerCraftBook.GetOwner() ) );
		slots.Clear();
		slots = RPGManager.GetModsSlotIDs( itemData.GetItemType() );
		for( i = 0; i < slots.Size(); i += 1 )
		{
			itemData.GetItemPart( partData, slots[ i ] );
			staticData = InnerItemData.GetStaticData( partData );
			if( staticData && staticData.TagsContains( 'DummyPart' ) )
			{
				continue;
			}
			TS.RemovePart( player, itemData.GetID(), slots[ i ] );
		}
		slots.Clear();
		slots = RPGManager.GetAttachmentSlotIDs();
		for( i = 0; i < slots.Size(); i += 1 )
		{
			TS.RemovePart( player, itemData.GetID(), slots[ i ] );
		}
	}

	private function ClearNonIconicSlotsFromWeaponsAndClothes( itemData : weak< gameItemData > )
	{
		var i : Int32;
		var slots : array< TweakDBID >;
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		TS = GameInstance.GetTransactionSystem( GetGameInstance() );
		player = GetMainPlayer( GetGameInstance() );
		slots.Clear();
		slots = RPGManager.GetModsSlotIDs( itemData.GetItemType() );
		for( i = 0; i < slots.Size(); i += 1 )
		{
			TS.RemovePart( player, itemData.GetID(), slots[ i ] );
		}
		slots.Clear();
		slots = RPGManager.GetAttachmentSlotIDs();
		for( i = 0; i < slots.Size(); i += 1 )
		{
			TS.RemovePart( player, itemData.GetID(), slots[ i ] );
		}
	}

	private function CompensateForDeprecatedWeaponMods( itemData : weak< gameItemData > )
	{
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		var playerLevel : Float;
		var statSystem : StatsSystem;
		statSystem = GameInstance.GetStatsSystem( GetGameInstance() );
		TS = GameInstance.GetTransactionSystem( GetGameInstance() );
		player = GetMainPlayer( GetGameInstance() );
		playerLevel = statSystem.GetStatValue( player.GetEntityID(), gamedataStatType.PowerLevel );
		if( playerLevel < 17.0 )
		{
			TS.GiveItemByItemQuery( player, T"Query.CommonWeaponModsQuery" );
		}
		else if( playerLevel < 33.0 )
		{
			TS.GiveItemByItemQuery( player, T"Query.UncommonWeaponModsQuery" );
		}
		else
		{
			TS.GiveItemByItemQuery( player, T"Query.RareWeaponModsQuery" );
		}
	}

	private function ClearNonIconicSlotsWithoutDummyMods( itemData : weak< gameItemData > )
	{
		var i : Int32;
		var slots : array< TweakDBID >;
		var TS : TransactionSystem;
		var player : weak< PlayerPuppet >;
		var partData : InnerItemData;
		var staticData : weak< Item_Record >;
		TS = GameInstance.GetTransactionSystem( GetGameInstance() );
		player = GetMainPlayer( GetGameInstance() );
		slots.Clear();
		slots = RPGManager.GetModsSlotIDs( itemData.GetItemType() );
		for( i = 0; i < slots.Size(); i += 1 )
		{
			itemData.GetItemPart( partData, slots[ i ] );
			staticData = InnerItemData.GetStaticData( partData );
			if( staticData && staticData.TagsContains( 'DummyPart' ) )
			{
				continue;
			}
			TS.RemovePart( player, itemData.GetID(), slots[ i ] );
		}
		slots.Clear();
		slots = RPGManager.GetAttachmentSlotIDs();
		for( i = 0; i < slots.Size(); i += 1 )
		{
			itemData.GetItemPart( partData, slots[ i ] );
			staticData = InnerItemData.GetStaticData( partData );
			if( staticData && staticData.TagsContains( 'DummyPart' ) )
			{
				continue;
			}
			TS.RemovePart( player, itemData.GetID(), slots[ i ] );
		}
	}

	public static function MarkItemAsCrafted( target : weak< GameObject >, itemData : weak< gameItemData > )
	{
		var statMod : gameStatModifierData;
		if( itemData.HasStatData( gamedataStatType.IsItemCrafted ) == false )
		{
			statMod = RPGManager.CreateStatModifier( gamedataStatType.IsItemCrafted, gameStatModifierType.Additive, 1.0 );
			GameInstance.GetStatsSystem( target.GetGame() ).AddSavedModifier( itemData.GetStatsObjectID(), statMod );
		}
	}

	private function SetItemLevel( itemData : weak< gameItemData > )
	{
		var playerPLValue : Float;
		var craftingLevelBoost : Float;
		var modifier : gameConstantStatModifierData;
		var statMod : gameStatModifierData;
		var statsSystem : StatsSystem;
		statsSystem = GameInstance.GetStatsSystem( GetGameInstance() );
		if( ItemID.GetStructure( itemData.GetID() ) == gamedataItemStructure.Unique )
		{
			if( !( RPGManager.IsItemSingleInstance( itemData ) ) )
			{
				playerPLValue = statsSystem.GetStatValue( m_playerCraftBook.GetOwner().GetEntityID(), gamedataStatType.PowerLevel );
				craftingLevelBoost = CalculateCraftingLevelBoost();
				statsSystem.RemoveAllModifiers( itemData.GetStatsObjectID(), gamedataStatType.PowerLevel, true );
				modifier = new gameConstantStatModifierData;
				modifier.modifierType = gameStatModifierType.Additive;
				modifier.statType = gamedataStatType.PowerLevel;
				modifier.value = playerPLValue;
				statsSystem.AddSavedModifier( itemData.GetStatsObjectID(), modifier );
				statsSystem.RemoveAllModifiers( itemData.GetStatsObjectID(), gamedataStatType.ItemLevel, true );
				modifier = new gameConstantStatModifierData;
				modifier.modifierType = gameStatModifierType.Additive;
				modifier.statType = gamedataStatType.ItemLevel;
				modifier.value = ( playerPLValue * 10.0 ) - craftingLevelBoost;
				statsSystem.AddSavedModifier( itemData.GetStatsObjectID(), modifier );
				statMod = RPGManager.CreateCombinedStatModifier( gamedataStatType.ItemLevel, gameStatModifierType.Additive, gamedataStatType.WasItemUpgraded, gameCombinedStatOperation.Multiplication, 10.0, gameStatObjectsRelation.Self );
				statsSystem.AddSavedModifier( itemData.GetStatsObjectID(), statMod );
			}
		}
	}

	private function SetItemQualityBasedOnPlayerSkill( itemData : weak< gameItemData > )
	{
		var quality : CName;
		var modifier : gameConstantStatModifierData;
		var statsSystem : StatsSystem;
		statsSystem = GameInstance.GetStatsSystem( GetGameInstance() );
		if( RPGManager.GetItemRecord( itemData.GetID() ).Quality().Type() == gamedataQuality.Random )
		{
			statsSystem.RemoveAllModifiers( itemData.GetStatsObjectID(), gamedataStatType.Quality, true );
			modifier = new gameConstantStatModifierData;
			modifier.modifierType = gameStatModifierType.Additive;
			modifier.statType = gamedataStatType.Quality;
			quality = RPGManager.SetQualityBasedOnLevel( m_playerCraftBook.GetOwner() );
			modifier.value = RPGManager.ItemQualityNameToValue( quality );
			statsSystem.AddSavedModifier( itemData.GetStatsObjectID(), modifier );
		}
	}

	public static function SetItemLevel( target : weak< GameObject >, itemData : weak< gameItemData > )
	{
		var playerPLValue : Float;
		var craftingLevelBoost : Float;
		var modifier : gameConstantStatModifierData;
		var statsSystem : StatsSystem;
		statsSystem = GameInstance.GetStatsSystem( target.GetGame() );
		if( ItemID.GetStructure( itemData.GetID() ) == gamedataItemStructure.Unique )
		{
			if( !( RPGManager.IsItemSingleInstance( itemData ) ) )
			{
				playerPLValue = statsSystem.GetStatValue( target.GetEntityID(), gamedataStatType.PowerLevel );
				craftingLevelBoost = statsSystem.GetStatValue( target.GetEntityID(), gamedataStatType.CraftingItemLevelBoost );
				statsSystem.RemoveAllModifiers( itemData.GetStatsObjectID(), gamedataStatType.PowerLevel, true );
				modifier = new gameConstantStatModifierData;
				modifier.modifierType = gameStatModifierType.Additive;
				modifier.statType = gamedataStatType.PowerLevel;
				modifier.value = playerPLValue;
				statsSystem.AddSavedModifier( itemData.GetStatsObjectID(), modifier );
				statsSystem.RemoveAllModifiers( itemData.GetStatsObjectID(), gamedataStatType.ItemLevel, true );
				modifier = new gameConstantStatModifierData;
				modifier.modifierType = gameStatModifierType.Additive;
				modifier.statType = gamedataStatType.ItemLevel;
				modifier.value = ( playerPLValue * 10.0 ) - ( 5.0 - craftingLevelBoost );
				statsSystem.AddSavedModifier( itemData.GetStatsObjectID(), modifier );
			}
		}
	}

	private function CalculateCraftingLevelBoost() : Float
	{
		var reductionValue : Float;
		reductionValue = GameInstance.GetStatsSystem( GetGameInstance() ).GetStatValue( m_playerCraftBook.GetOwner().GetEntityID(), gamedataStatType.CraftingItemLevelBoost );
		reductionValue = 5.0 - reductionValue;
		return reductionValue;
	}

	private function ProcessProgramCrafting( itemTDBID : TweakDBID )
	{
		GetPlayerCraftBook().HideRecipe( itemTDBID, true );
	}

	public const function GetDisassemblyResultItems( target : weak< GameObject >, itemID : ItemID, amount : Int32, restoredAttachments : ref< array< ItemAttachments > >, optional calledFromUI : Bool ) : array< IngredientData >
	{
		var i : Int32;
		var itemData : weak< gameItemData >;
		var newIngrData : IngredientData;
		var itemType : gamedataItemType;
		var itemCategory : gamedataItemCategory;
		var itemQual : gamedataQuality;
		var itemBroken : Bool;
		var itemPlus : Float;
		var isSlaughtomatic : Bool;
		var dissResult : weak< DisassemblingResult_Record >;
		var ingredients : array< weak< RecipeElement_Record > >;
		var outResult : array< IngredientData >;
		itemType = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) ).ItemType().Type();
		itemCategory = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) ).ItemCategory().Type();
		dissResult = TweakDBInterface.GetDisassemblingResultRecord( T"Crafting." + TDBID.Create( EnumValueToString( "gamedataItemType", ( ( Int32 )( itemType ) ) ) ) );
		if( !( dissResult ) )
		{
			dissResult = TweakDBInterface.GetDisassemblingResultRecord( T"Crafting.DisassemblingResult_Default" );
		}
		dissResult.Ingredients( ingredients );
		itemData = GameInstance.GetTransactionSystem( GetGameInstance() ).GetItemData( target, itemID );
		itemQual = RPGManager.GetItemQuality( itemData );
		itemBroken = RPGManager.IsItemBroken( itemData );
		itemPlus = RPGManager.GetItemPlus( itemData );
		isSlaughtomatic = itemData.HasTag( 'Slaughtomatic' );
		if( amount > 0 )
		{
			for( i = 0; i < ingredients.Size(); i += 1 )
			{
				newIngrData = CreateIngredientData( ingredients[ i ] );
				AddIngredientToResult( newIngrData, amount, outResult );
			}
			itemQual = RPGManager.GetItemQuality( itemData );
			if( ( ( itemCategory == gamedataItemCategory.Weapon && !( itemBroken ) ) && ( itemPlus == 0.0 ) ) && !( isSlaughtomatic ) )
			{
				if( itemQual == gamedataQuality.Common )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Common ), 5 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Uncommon )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Uncommon ), 5 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Rare )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Rare ), 5 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Epic )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Epic ), 5 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Legendary )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Legendary ), 5 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
			}
			if( ( ( itemType != gamedataItemType.Prt_Program && !( itemBroken ) ) && ( itemPlus == 1.0 ) ) && !( isSlaughtomatic ) )
			{
				if( itemQual == gamedataQuality.Common )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Common ), 7 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Uncommon )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Uncommon ), 7 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Rare )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Rare ), 7 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Epic )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Epic ), 7 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Legendary )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Legendary ), 7 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
			}
			if( ( ( itemType != gamedataItemType.Prt_Program && !( itemBroken ) ) && ( itemPlus == 2.0 ) ) && !( isSlaughtomatic ) )
			{
				if( itemQual == gamedataQuality.Legendary )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Legendary ), 15 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
			}
			if( itemBroken || isSlaughtomatic )
			{
				if( itemQual == gamedataQuality.Common )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Common ), 1 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
			}
			if( itemCategory != gamedataItemCategory.Weapon && itemType != gamedataItemType.Prt_Program )
			{
				if( itemQual == gamedataQuality.Common )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Common ), 1 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Uncommon )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Uncommon ), 1 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Rare )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Rare ), 1 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Epic )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Epic ), 1 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Legendary )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Legendary ), 1 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
			}
			if( itemType == gamedataItemType.Prt_Program && ( itemPlus == 0.0 ) )
			{
				if( itemQual == gamedataQuality.Common )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Uncommon, true ), 1 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Uncommon )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Uncommon, true ), 7 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Rare )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Rare, true ), 6 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Epic )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Epic, true ), 5 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
				if( itemQual == gamedataQuality.Legendary )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Legendary, true ), 3 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
			}
			if( itemType == gamedataItemType.Prt_Program && ( itemPlus == 2.0 ) )
			{
				if( itemQual == gamedataQuality.Legendary )
				{
					newIngrData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( gamedataQuality.Legendary, true ), 20 );
					AddIngredientToResult( newIngrData, amount, outResult );
				}
			}
			ProcessDisassemblingPerks( amount, outResult, itemData, restoredAttachments, calledFromUI );
		}
		return outResult;
	}

	private const function AddIngredientToResult( ingredient : IngredientData, amountMultiplier : Int32, out outputResult : array< IngredientData > )
	{
		var i : Int32;
		var quantityIncreased : Bool;
		ingredient.quantity *= amountMultiplier;
		for( i = 0; i < outputResult.Size(); i += 1 )
		{
			if( outputResult[ i ].id == ingredient.id )
			{
				outputResult[ i ].quantity += ingredient.quantity;
				quantityIncreased = true;
				break;
			}
		}
		if( !( quantityIncreased ) )
		{
			outputResult.PushBack( ingredient );
		}
	}

	private const function DisassembleItem( target : weak< GameObject >, itemID : ItemID, amount : Int32 )
	{
		var transactionSystem : TransactionSystem;
		var i : Int32;
		var listOfIngredients : array< IngredientData >;
		var restoredAttachments : array< ItemAttachments >;
		transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
		listOfIngredients = GetDisassemblyResultItems( target, itemID, amount, restoredAttachments );
		for( i = 0; i < restoredAttachments.Size(); i += 1 )
		{
			transactionSystem.RemovePart( m_playerCraftBook.GetOwner(), itemID, restoredAttachments[ i ].attachmentSlotID );
		}
		GameInstance.GetTelemetrySystem( GetGameInstance() ).LogItemDisassembled( target, itemID );
		transactionSystem.RemoveItem( target, itemID, amount );
		for( i = 0; i < listOfIngredients.Size(); i += 1 )
		{
			transactionSystem.GiveItem( target, ItemID.FromTDBID( listOfIngredients[ i ].id.GetID() ), listOfIngredients[ i ].quantity );
		}
		UpdateBlackboard( CraftingCommands.DisassemblingFinished, itemID, listOfIngredients );
	}

	private function UpgradeItem( owner : weak< GameObject >, itemID : ItemID )
	{
		var i : Int32;
		var newVal, oldVal : Float;
		var tempStat : Float;
		var randF : Float;
		var statsSystem : StatsSystem;
		var TS : TransactionSystem;
		var itemData : weak< gameItemData >;
		var mod : gameStatModifierData;
		var ingredients : array< IngredientData >;
		var ingredientQuality : gamedataQuality;
		var xpID : TweakDBID;
		var recipeXP : Int32;
		randF = RandF();
		statsSystem = GameInstance.GetStatsSystem( GetGameInstance() );
		TS = GameInstance.GetTransactionSystem( GetGameInstance() );
		itemData = TS.GetItemData( owner, itemID );
		oldVal = itemData.GetStatValueByType( gamedataStatType.WasItemUpgraded );
		newVal = oldVal + 1.0;
		tempStat = statsSystem.GetStatValue( owner.GetEntityID(), gamedataStatType.UpgradingMaterialRetrieveChance );
		ingredients = GetItemFinalUpgradeCost( itemData );
		for( i = 0; i < ingredients.Size(); i += 1 )
		{
			if( randF >= tempStat )
			{
				TS.RemoveItemByTDBID( owner, ingredients[ i ].id.GetID(), ingredients[ i ].quantity, true );
			}
			ingredientQuality = RPGManager.GetItemQualityFromRecord( TweakDBInterface.GetItemRecord( ingredients[ i ].id.GetID() ) );
			switch( ingredientQuality )
			{
				case gamedataQuality.Common:
					xpID = T"Constants.CraftingSystem.commonIngredientXP";
				break;
				case gamedataQuality.Uncommon:
					xpID = T"Constants.CraftingSystem.uncommonIngredientXP";
				break;
				case gamedataQuality.Rare:
					xpID = T"Constants.CraftingSystem.rareIngredientXP";
				break;
				case gamedataQuality.Epic:
					xpID = T"Constants.CraftingSystem.epicIngredientXP";
				break;
				case gamedataQuality.Legendary:
					xpID = T"Constants.CraftingSystem.legendaryIngredientXP";
				break;
				default:
					break;
			}
			recipeXP += ( TweakDBInterface.GetInt( xpID, 0 ) * ingredients[ i ].quantity );
		}
		statsSystem.RemoveAllModifiers( itemData.GetStatsObjectID(), gamedataStatType.WasItemUpgraded, true );
		mod = RPGManager.CreateStatModifier( gamedataStatType.WasItemUpgraded, gameStatModifierType.Additive, newVal );
		statsSystem.AddSavedModifier( itemData.GetStatsObjectID(), mod );
		ProcessCraftSkill( ( ( Float )( recipeXP ) ) );
	}

	private function ProcessUpgradingPerksData( target : weak< GameObject >, itemRecord : Item_Record )
	{
		var statsSystem : StatsSystem;
		var transactionSystem : TransactionSystem;
		var tempStat : Float;
		var randF : Float;
		var randI : Int32;
		var recipe : array< weak< RecipeElement_Record > >;
		statsSystem = GameInstance.GetStatsSystem( GetGameInstance() );
		transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
		randF = RandF();
		tempStat = statsSystem.GetStatValue( target.GetEntityID(), gamedataStatType.UpgradingMaterialRandomGrantChance );
		if( randF <= tempStat )
		{
			randI = RandRange( 0, recipe.Size() - 1 );
			transactionSystem.GiveItemByTDBID( target, recipe[ randI ].Ingredient().GetID(), 1 );
		}
	}

	private const function CreateIngredientDataOfQuality( amount : Int32, matQuality : gamedataQuality, out disassembleResult : array< IngredientData > )
	{
		var rand : Float;
		var num : Int32;
		var ingredientData : IngredientData;
		rand = RandF();
		num = ( ( Int32 )( rand * ( ( Float )( amount ) ) ) );
		if( num > 0 )
		{
			ingredientData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( matQuality ), 1 );
			AddIngredientToResult( ingredientData, num, disassembleResult );
		}
		if( ( amount - num ) > 0 )
		{
			ingredientData = CreateIngredientData( RPGManager.GetCraftingMaterialRecord( matQuality, true ), 1 );
			AddIngredientToResult( ingredientData, amount - num, disassembleResult );
		}
	}

	private const function GetSuccessNum( probability : Float, eventsNum : Int32 ) : Int32
	{
		var i : Int32;
		var rand : Float;
		var num : Int32;
		for( i; i < eventsNum; i += 1 )
		{
			rand = RandF();
			if( rand < probability )
			{
				num += 1;
			}
		}
		return num;
	}

	private const function ProcessDisassemblingPerks( amount : Int32, out disassembleResult : array< IngredientData >, itemData : weak< gameItemData >, restoredAttachments : ref< array< ItemAttachments > >, optional calledFromUI : Bool )
	{
		var i : Int32;
		var tempStat : Float;
		var matQuality : gamedataQuality;
		var innerPart : InnerItemData;
		var itemCategory : gamedataItemCategory;
		var innerPartID : ItemID;
		var succNum : Int32;
		var slotsToCheck : array< TweakDBID >;
		var tempArr : array< TweakDBID >;
		var statsSystem : StatsSystem;
		var partTags : array< CName >;
		statsSystem = GameInstance.GetStatsSystem( GetGameInstance() );
		tempStat = statsSystem.GetStatValue( m_playerCraftBook.GetOwner().GetEntityID(), gamedataStatType.DisassemblingIngredientsDoubleBonus );
		if( tempStat > 0.0 )
		{
			for( i = 0; i < disassembleResult.Size(); i += 1 )
			{
				disassembleResult[ i ].quantity = ( ( Int32 )( ( ( Float )( disassembleResult[ i ].quantity ) ) * 1.5 ) );
			}
		}
		if( !( calledFromUI ) )
		{
			tempStat = statsSystem.GetStatValue( m_playerCraftBook.GetOwner().GetEntityID(), gamedataStatType.DisassemblingMaterialQualityObtainChance );
			matQuality = RPGManager.GetItemDataQuality( itemData );
			if( matQuality != gamedataQuality.Invalid )
			{
				succNum = GetSuccessNum( tempStat, amount );
				if( succNum > 0 )
				{
					CreateIngredientDataOfQuality( succNum, matQuality, disassembleResult );
				}
				if( matQuality <= gamedataQuality.Epic )
				{
					matQuality = RPGManager.GetBumpedQuality( matQuality );
					succNum = GetSuccessNum( tempStat / 4.0, amount );
					if( succNum > 0 )
					{
						CreateIngredientDataOfQuality( succNum, matQuality, disassembleResult );
					}
				}
			}
		}
		itemCategory = RPGManager.GetItemCategory( itemData.GetID() );
		if( itemCategory == gamedataItemCategory.Weapon )
		{
			slotsToCheck = RPGManager.GetAttachmentSlotIDs();
			tempArr = RPGManager.GetModsSlotIDs( itemData.GetItemType() );
			for( i = 0; i < tempArr.Size(); i += 1 )
			{
				slotsToCheck.PushBack( tempArr[ i ] );
			}
			for( i = 0; i < slotsToCheck.Size(); i += 1 )
			{
				itemData.GetItemPart( innerPart, slotsToCheck[ i ] );
				innerPartID = InnerItemData.GetItemID( innerPart );
				partTags = InnerItemData.GetStaticData( innerPart ).Tags();
				if( ItemID.IsValid( innerPartID ) && partTags.Contains( 'Retrievable' ) )
				{
					restoredAttachments.PushBack( ItemAttachments.Create( innerPartID, slotsToCheck[ i ] ) );
				}
			}
		}
	}

	private function ProcessCraftSkill( xpAmount : Float )
	{
		RPGManager.AwardXP( GetGameInstance(), xpAmount, gamedataProficiencyType.TechnicalAbilitySkill );
	}

	public const function GetRecipeData( itemRecord : Item_Record ) : RecipeData
	{
		var newRecipeData : RecipeData;
		var tempRecipeData : ItemRecipe;
		var tempItemCategory : ItemCategory_Record;
		var tempListOfIngredients : array< weak< RecipeElement_Record > >;
		var listOfIngredients : array< IngredientData >;
		var i : Int32;
		tempRecipeData = m_playerCraftBook.GetRecipeData( itemRecord.GetID() );
		tempItemCategory = itemRecord.ItemCategory();
		newRecipeData = new RecipeData;
		newRecipeData.label = GetLocalizedItemNameByCName( itemRecord.DisplayName() );
		newRecipeData.icon = itemRecord.IconPath();
		newRecipeData.iconGender = m_itemIconGender;
		newRecipeData.description = GetLocalizedItemNameByCName( itemRecord.LocalizedDescription() );
		newRecipeData.type = LocKeyToString( tempItemCategory.LocalizedCategory() );
		newRecipeData.id = itemRecord;
		newRecipeData.amount = tempRecipeData.amount;
		newRecipeData.quality = itemRecord.Quality().Type();
		itemRecord.CraftingData().CraftingRecipe( tempListOfIngredients );
		for( i = 0; i < tempListOfIngredients.Size(); i += 1 )
		{
			listOfIngredients.PushBack( CreateIngredientData( tempListOfIngredients[ i ] ) );
		}
		newRecipeData.ingredients = listOfIngredients;
		return newRecipeData;
	}

	public const function GetUpgradeRecipeData( itemID : ItemID ) : RecipeData
	{
		var newRecipeData : RecipeData;
		var tempItemCategory : ItemCategory_Record;
		var itemRecord : Item_Record;
		var itemdata : weak< gameItemData >;
		itemdata = GameInstance.GetTransactionSystem( GetGameInstance() ).GetItemData( GetPlayer( GetGameInstance() ), itemID );
		itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( itemID ) );
		tempItemCategory = itemRecord.ItemCategory();
		newRecipeData = new RecipeData;
		newRecipeData.label = GetLocalizedItemNameByCName( itemRecord.DisplayName() );
		newRecipeData.icon = itemRecord.IconPath();
		newRecipeData.iconGender = m_itemIconGender;
		newRecipeData.description = GetLocalizedItemNameByCName( itemRecord.LocalizedDescription() );
		newRecipeData.type = LocKeyToString( tempItemCategory.LocalizedCategory() );
		newRecipeData.id = itemRecord;
		newRecipeData.ingredients = GetItemFinalUpgradeCost( itemdata );
		return newRecipeData;
	}

	private const function GetIngredientQuality( const data : ref< IngredientData > ) : gamedataQuality
	{
		var quality : gamedataQuality;
		quality = RPGManager.GetItemQualityFromRecord( data.id );
		return quality;
	}

	private const function CreateIngredientData( ingredientData : RecipeElement_Record ) : IngredientData
	{
		var newIngredientData : IngredientData;
		var itemRecord : weak< Item_Record >;
		var transactionSystem : TransactionSystem;
		transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
		itemRecord = ingredientData.Ingredient();
		newIngredientData.quantity = ingredientData.Amount();
		newIngredientData.baseQuantity = ingredientData.Amount();
		newIngredientData.label = itemRecord.FriendlyName();
		newIngredientData.inventoryQuantity = transactionSystem.GetItemQuantityWithDuplicates( m_playerCraftBook.GetOwner(), ItemID.CreateQuery( itemRecord.GetID() ) );
		newIngredientData.id = itemRecord;
		newIngredientData.icon = itemRecord.IconPath();
		newIngredientData.iconGender = m_itemIconGender;
		return newIngredientData;
	}

	private const function CreateIngredientData( item : Item_Record, amount : Int32 ) : IngredientData
	{
		var newIngredientData : IngredientData;
		var transactionSystem : TransactionSystem;
		transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
		newIngredientData.quantity = amount;
		newIngredientData.baseQuantity = amount;
		newIngredientData.label = item.FriendlyName();
		newIngredientData.inventoryQuantity = transactionSystem.GetItemQuantityWithDuplicates( m_playerCraftBook.GetOwner(), ItemID.CreateQuery( item.GetID() ) );
		newIngredientData.id = item;
		newIngredientData.icon = item.IconPath();
		newIngredientData.iconGender = m_itemIconGender;
		return newIngredientData;
	}

	private const function UpdateBlackboard( lastCommand : CraftingCommands, optional lastItem : ItemID, optional lastIngredients : array< IngredientData > )
	{
		var Blackboard : IBlackboard;
		Blackboard = GameInstance.GetBlackboardSystem( GetGameInstance() ).Get( GetAllBlackboardDefs().UI_Crafting );
		if( Blackboard )
		{
			Blackboard.SetVariant( GetAllBlackboardDefs().UI_Crafting.lastCommand, lastCommand, true );
			Blackboard.SetVariant( GetAllBlackboardDefs().UI_Crafting.lastItem, lastItem, true );
			if( lastIngredients.Size() > 0 )
			{
				Blackboard.SetVariant( GetAllBlackboardDefs().UI_Crafting.lastIngredients, lastIngredients );
			}
		}
	}

	private function SendItemCraftedDataTrackingRequest( targetItem : ItemID, amount : Int32 )
	{
		var request : ItemCraftedDataTrackingRequest;
		var dataTrackingSystem : DataTrackingSystem;
		request = new ItemCraftedDataTrackingRequest;
		request.targetItem = targetItem;
		request.amount = amount;
		dataTrackingSystem = ( ( DataTrackingSystem )( GameInstance.GetScriptableSystemsContainer( GetGameInstance() ).Get( 'DataTrackingSystem' ) ) );
		dataTrackingSystem.QueueRequest( request );
	}

	private function ProcessIconicRevampRestoration()
	{
		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( RPGManager.IsItemIconic( itemList[ i ] ) && RPGManager.IsItemWeapon( itemList[ i ].GetID() ) )
			{
				ClearNonIconicSlots( itemList[ i ] );
				RPGManager.ProcessOnLootedPackages( player, itemList[ i ].GetID() );
			}
		}
	}

	private function ProcessWeaponsAndClothingModsPurge()
	{
		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( RPGManager.IsItemWeapon( itemList[ i ].GetID() ) || RPGManager.IsItemClothing( itemList[ i ].GetID() ) )
			{
				ClearNonIconicSlotsFromWeaponsAndClothes( itemList[ i ] );
			}
		}
	}

	private function ProcessWeaponsModsCompensate()
	{
		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( 'DeprecatedWeaponMod' ) && !( itemList[ i ].HasTag( 'DummyWeaponMod' ) ) )
			{
				CompensateForDeprecatedWeaponMods( itemList[ i ] );
			}
		}
	}

	private function ProcessGritModsPurge()
	{
		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( 'Grit' ) )
			{
				ClearNonIconicSlotsWithoutDummyMods( itemList[ i ] );
			}
		}
	}

	private function ProcessAmazonGritAttachmentsPurge()
	{
		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( 'Grit' ) && itemList[ i ].HasTag( 'IconicWeapon' ) )
			{
				ClearNonIconicSlotsWithoutDummyMods( itemList[ i ] );
			}
		}
	}

	private function VendorIconicKnivesSecured()
	{
		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( 'VendorIconicItem' ) )
			{
				RPGManager.ProcessOnLootedPackages( player, itemList[ i ].GetID() );
			}
		}
	}

	private function ProcessCraftedItemsPowerBoost()
	{
		var i : Int32;
		var itemList : array< weak< gameItemData > >;
		var transactionSystem : TransactionSystem;
		var statsSystem : StatsSystem;
		var player : weak< PlayerPuppet >;
		player = GetPlayer( GetGameInstance() );
		if( player )
		{
			transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
			statsSystem = GameInstance.GetStatsSystem( GetGameInstance() );
			transactionSystem.GetItemList( player, itemList );
		}
		for( i = 0; i < itemList.Size(); i += 1 )
		{
			if( RPGManager.IsItemCrafted( itemList[ i ] ) )
			{
				if( RPGManager.IsItemWeapon( itemList[ i ].GetID() ) )
				{
					statsSystem.RemoveSavedModifiers( itemList[ i ].GetStatsObjectID(), gamedataStatType.CraftingBonusWeaponDamage );
					statsSystem.RemoveSavedModifiers( itemList[ i ].GetStatsObjectID(), gamedataStatType.CanLegendaryCraftedWeaponsBeBoosted );
				}
				else if( RPGManager.IsItemClothing( itemList[ i ].GetID() ) )
				{
					statsSystem.RemoveSavedModifiers( itemList[ i ].GetStatsObjectID(), gamedataStatType.CraftingBonusArmorValue );
				}
			}
		}
	}

	private function AddAmmoRecipes()
	{
		m_playerCraftBook.AddRecipe( T"Ammo.HandgunAmmo", , GetAmmoBulletAmount( T"Ammo.HandgunAmmo" ) );
		m_playerCraftBook.AddRecipe( T"Ammo.ShotgunAmmo", , GetAmmoBulletAmount( T"Ammo.ShotgunAmmo" ) );
		m_playerCraftBook.AddRecipe( T"Ammo.RifleAmmo", , GetAmmoBulletAmount( T"Ammo.RifleAmmo" ) );
		m_playerCraftBook.AddRecipe( T"Ammo.SniperRifleAmmo", , GetAmmoBulletAmount( T"Ammo.SniperRifleAmmo" ) );
	}

	private function HideDLCRecipes()
	{
		m_playerCraftBook.HideRecipe( T"Items.Jacket_19_basic_04", true );
		m_playerCraftBook.HideRecipe( T"Items.Jacket_19_basic_04_DLC_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Jacket_19_basic_04_DLC_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Jacket_20_basic_01", true );
		m_playerCraftBook.HideRecipe( T"Items.Jacket_20_basic_01_DLC_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Jacket_20_basic_01_DLC_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.GOG_DLC_TShirt_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.GOG_DLC_TShirt_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.GOG_DLC_Jacket_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.GOG_DLC_Jacket_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.GOG_Galaxy_TShirt_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.GOG_Galaxy_TShirt_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_GoG_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_GoG_Legendary", true );
	}

	private function AddDLCBaseRecipes()
	{
		if( m_playerCraftBook.KnowsRecipe( T"Items.Preset_Katana_GoG_Epic" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Preset_Katana_GoG_Crafted",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.GOG_DLC_TShirt_Epic" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.GOG_DLC_TShirt_Crafted",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.GOG_DLC_Jacket_Epic" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.GOG_DLC_Jacket_Crafted",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.GOG_Galaxy_TShirt_Epic" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.GOG_Galaxy_TShirt_Crafted",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Jacket_19_basic_04" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Jacket_19_basic_04_Crafted",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Jacket_20_basic_01" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Jacket_20_basic_01_Crafted",  );
		}
	}

	private function InstallModsToRedesignedItems()
	{
		var i : Int32;
		var itemList : array< weak< gameItemData > >;
		var transactionSystem : TransactionSystem;
		var itemModificationSystem : weak< ItemModificationSystem >;
		var player : weak< PlayerPuppet >;
		var partItemID : ItemID;
		player = GetPlayer( GetGameInstance() );
		if( player )
		{
			transactionSystem = GameInstance.GetTransactionSystem( GetGameInstance() );
			transactionSystem.GetItemList( player, itemList );
		}
		itemModificationSystem = ( ( ItemModificationSystem )( GameInstance.GetScriptableSystemsContainer( GetGameInstance() ).Get( 'ItemModificationSystem' ) ) );
		for( i = 0; i < itemList.Size(); i += 1 )
		{
			if( itemList[ i ].HasTag( 'Gog_Katana' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.GogKatanaWeaponMod" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'Buck_Grad' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.Buck_scope" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Attachment( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'Tactician_Headsman' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.Headsman_scope" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Attachment( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'Sasquatch_Hammer' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.Hammer_Sasquatch_Mod" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'Nekomata_Breakthrough' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.Breakthrough_scope" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Attachment( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'Competition_Lexington' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.Lexington_Shooting_Competition_scope" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Attachment( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'Competition_Lexington' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.CollectibleIconicWeaponMod" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'Grad_Panam' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.Panam_scope" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Attachment( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'ChemResMod' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.IntrinsicFabricEnhancer12" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'ZoomMod' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.IntrinsicFabricEnhancer07a" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'QuickhackUploadMod' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.IntrinsicFabricEnhancer10" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'VisibilityMod' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.IntrinsicFabricEnhancer05" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'MeleeDmgRedMod' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.IntrinsicFabricEnhancer09" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'QuickhackDmgRedMod' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.IntrinsicFabricEnhancer11" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'ArmorMod' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.IntrinsicFabricEnhancer01" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
			if( itemList[ i ].HasTag( 'ReloadMod' ) )
			{
				partItemID = ItemID.FromTDBID( T"Items.IntrinsicFabricEnhancer08" );
				transactionSystem.GiveItem( player, partItemID, 1 );
				itemModificationSystem.QueueRequest( CreateInstallPartRequest_Mod( player, itemList[ i ], partItemID ) );
			}
		}
	}

	private function CreateInstallPartRequest_Mod( player : weak< PlayerPuppet >, itemData : weak< gameItemData >, part : ItemID ) : InstallItemPart
	{
		var installPartRequest : InstallItemPart;
		var slotID : TweakDBID;
		switch( itemData.GetItemType() )
		{
			case gamedataItemType.Wea_Katana:
			case gamedataItemType.Wea_Hammer:
				slotID = T"AttachmentSlots.IconicMeleeWeaponMod1";
			break;
			case gamedataItemType.Wea_Handgun:
				slotID = T"AttachmentSlots.IconicWeaponModLegendary";
			break;
			case gamedataItemType.Clo_InnerChest:
				slotID = T"AttachmentSlots.InnerChestFabricEnhancer1";
			break;
			case gamedataItemType.Clo_OuterChest:
				slotID = T"AttachmentSlots.OuterChestFabricEnhancer1";
			break;
			case gamedataItemType.Clo_Head:
				slotID = T"AttachmentSlots.HeadFabricEnhancer1";
			break;
			case gamedataItemType.Clo_Face:
				slotID = T"AttachmentSlots.FaceFabricEnhancer1";
			break;
			default:
				break;
		}
		installPartRequest = new InstallItemPart;
		installPartRequest.Set( player, itemData.GetID(), part, slotID );
		return installPartRequest;
	}

	private function CreateInstallPartRequest_Attachment( player : weak< PlayerPuppet >, itemData : weak< gameItemData >, part : ItemID ) : InstallItemPart
	{
		var installPartRequest : InstallItemPart;
		var slotID : TweakDBID;
		switch( itemData.GetItemType() )
		{
			case gamedataItemType.Wea_Handgun:
			case gamedataItemType.Wea_SniperRifle:
			case gamedataItemType.Wea_Shotgun:
				slotID = T"AttachmentSlots.Scope";
			break;
			default:
				break;
		}
		installPartRequest = new InstallItemPart;
		installPartRequest.Set( player, itemData.GetID(), part, slotID );
		return installPartRequest;
	}

	private function HideButchersKnifeRecipes()
	{
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Common_Butchers_Knife", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Uncommon_Butchers_Knife", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Rare_Butchers_Knife", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Epic_Butchers_Knife", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Legendary_Butchers_Knife", true );
	}

	private function CompensateForOwnedButchersKnifeRecipes()
	{
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Common_Butchers_Knife" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Knife",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Uncommon_Butchers_Knife" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Uncommon_Tanto",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Rare_Butchers_Knife" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Rare_Tanto",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Epic_Butchers_Knife" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Epic_Knife",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Legendary_Butchers_Knife" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Legendary_Knife",  );
		}
	}

	private function HideMilitaryKatanaRecipes()
	{
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Common_Katana_Military", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Uncommon_Katana_Military", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Rare_Katana_Military_1", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Epic_Katana_Military", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Legendary_Katana_Military", true );
	}

	private function CompensateForOwnedMilitaryKatanaRecipes()
	{
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Common_Katana_Military" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Katana",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Uncommon_Katana_Military" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Uncommon_Katana",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Rare_Katana_Military_1" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Rare_Katana",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Epic_Katana_Military" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Epic_Katana",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Legendary_Katana_Military" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Proficiency_Craftable_Legendary_Katana",  );
		}
	}

	private function HidePipeWrenchRecipes()
	{
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Common_Pipe_Wrench", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Uncommon_Pipe_Wrench", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Rare_Pipe_Wrench", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Epic_Pipe_Wrench", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Legendary_Pipe_Wrench", true );
	}

	private function CompensateForOwnedPipeWrenchRecipes()
	{
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Common_Pipe_Wrench" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Tire_Iron",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Uncommon_Pipe_Wrench" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Uncommon_Tire_Iron",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Rare_Pipe_Wrench" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Rare_Tire_Iron",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Epic_Pipe_Wrench" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Epic_Tire_Iron",  );
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Craftable_Legendary_Pipe_Wrench" ) )
		{
			m_playerCraftBook.AddRecipe( T"Items.Craftable_Legendary_Tire_Iron",  );
		}
	}

	private function HideIconicWeaponsRecipes()
	{
		m_playerCraftBook.HideRecipe( T"Items.Preset_Baseball_Bat_Denny_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Baseball_Bat_Denny_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Baton_Tinker_Bell_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Baton_Tinker_Bell_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Cane_Fingers_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Cane_Fingers_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Dildo_Stout_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Dildo_Stout_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_Cocktail_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_Cocktail_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_Hiromi_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_Hiromi_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_Takemura_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_Saburo_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_Saburo_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_Surgeon_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_Surgeon_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_Wakako_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Knife_Stinger_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Knife_Stinger_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Neurotoxin_Knife_Iconic_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Neurotoxin_Knife_Iconic_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Punk_Knife_Iconic_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Punk_Knife_Iconic_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Butchers_Knife_Iconic_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Butchers_Knife_Iconic_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Kenshin_Frank_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Kenshin_Royce_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Kenshin_Royce_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Lexington_Wilson_Rare", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Lexington_Wilson_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Lexington_Wilson_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Liberty_Yorinobu_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Liberty_Yorinobu_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Liberty_Dex_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Liberty_Dex_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Liberty_Padre_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Nue_Jackie_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Nue_Jackie_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Nue_Maiko_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Nue_Maiko_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Omaha_Suzie_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Omaha_Suzie_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Yukimura_Kiji_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Burya_Comrade_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Overture_River_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Overture_Kerry_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Overture_Kerry_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Overture_Cassidy_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Nova_Doom_Doom_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Nova_Doom_Doom_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Achilles_Nash_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Achilles_Nash_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Ajax_Moron_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Copperhead_Genesis_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Copperhead_Genesis_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Grad_Panam_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Grad_Panam_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Grad_Buck_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Kolac_Tiny_Mike_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Nekomata_Breakthrough_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Sidewinder_Divided_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Sidewinder_Divided_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Carnage_Mox_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Carnage_Mox_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Carnage_Edgerunners_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Igla_Sovereign_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Tactician_Headsman_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Tactician_Dino_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Pulsar_Buzzsaw_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Pulsar_Buzzsaw_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Saratoga_Maelstrom_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Saratoga_Maelstrom_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Saratoga_Raffen_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Saratoga_Raffen_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Igla_Sovereign", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Pulsar_Buzzsaw", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Nekomata_Breakthrough", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Burya_Comrade", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Copperhead_Genesis", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Ajax_Moron", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Zhuo_Eight_Star", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Dian_Yinglong", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Tactician_Headsman", true );
	}

	private function HideDeprecatedCraftingRecipes()
	{
		m_playerCraftBook.HideRecipe( T"Items.Glasses_03_basic_06_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Glasses_01_basic_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Glasses_05_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Mask_03_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Mask_02_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Mask_02_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Tech_02_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Tech_01_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Tech_02_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Visor_02_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Visor_01_basic_05_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Visor_02_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Boots_09_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Boots_03_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Boots_07_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Boots_11_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.CasualShoes_05_basic_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.CasualShoes_01_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.CasualShoes_02_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_CasualShoes_07_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.FormalShoes_03_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.FormalShoes_01_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_FormalShoes_02_rich_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_FormalShoes_02_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Balaclava_01_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Cap_02_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Cap_03_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Cap_06_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Hat_02_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Hat_03_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Hat_01_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Helmet_03_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Helmet_01_basic_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Helmet_04_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Scarf_01_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Scarf_03_basic_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Scarf_02_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.FormalShirt_01_rich_06_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.FormalShirt_02_basic_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_TightJumpsuit_01_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Shirt_01_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Shirt_03_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Shirt_02_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.TShirt_01_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.TShirt_02_basic_04_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_TShirt_03_rich_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Undershirt_03_basic_04_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Undershirt_02_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Undershirt_03_basic_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.FormalPants_03_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.FormalPants_02_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_FormalPants_01_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Pants_04_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Pants_02_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Pants_08_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Pants_13_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Shorts_02_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Shorts_01_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Shorts_02_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.FormalSkirt_02_rich_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.FormalSkirt_01_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_FormalSkirt_02_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Coat_01_basic_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Coat_04_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Dress_01_rich_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.FormalJacket_02_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.FormalJacket_04_basic_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Jacket_01_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Jacket_17_rich_06_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Jacket_06_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Jumpsuit_02_rich_03_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.LooseShirt_01_rich_02_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_LooseShirt_02_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Vest_13_rich_04_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Vest_20_rich_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Vest_18_basic_01_Crafting", true );
		m_playerCraftBook.HideRecipe( T"Items.Preset_Katana_GoG_Crafted", true );
		m_playerCraftBook.HideRecipe( T"Items.GOG_DLC_TShirt_Crafted", true );
		m_playerCraftBook.HideRecipe( T"Items.GOG_DLC_Jacket_Crafted", true );
		m_playerCraftBook.HideRecipe( T"Items.GOG_Galaxy_TShirt_Crafted", true );
		m_playerCraftBook.HideRecipe( T"Items.Jacket_19_basic_04_Crafted", true );
		m_playerCraftBook.HideRecipe( T"Items.Jacket_20_basic_01_Crafted", true );
		m_playerCraftBook.HideRecipe( T"Items.Q005_Johnny_Glasses_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Q005_Johnny_Glasses_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Q005_Johnny_Shirt_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Q005_Johnny_Shirt_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Q005_Johnny_Pants_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Q005_Johnny_Pants_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.Q005_Johnny_Shoes_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.Q005_Johnny_Shoes_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.SQ031_Samurai_Jacket_Epic", true );
		m_playerCraftBook.HideRecipe( T"Items.SQ031_Samurai_Jacket_Legendary", true );
		m_playerCraftBook.HideRecipe( T"Items.PhysicalDamageEdge", true );
		m_playerCraftBook.HideRecipe( T"Items.ThermalDamageEdge", true );
		m_playerCraftBook.HideRecipe( T"Items.ChemicalDamageEdge", true );
		m_playerCraftBook.HideRecipe( T"Items.ElectricDamageEdge", true );
		m_playerCraftBook.HideRecipe( T"Items.SlowRotor", true );
		m_playerCraftBook.HideRecipe( T"Items.FastRotor", true );
		m_playerCraftBook.HideRecipe( T"Items.PhysicalDamageCable", true );
		m_playerCraftBook.HideRecipe( T"Items.ThermalDamageCable", true );
		m_playerCraftBook.HideRecipe( T"Items.ChemicalDamageCable", true );
		m_playerCraftBook.HideRecipe( T"Items.ElectricDamageCable", true );
		m_playerCraftBook.HideRecipe( T"Items.LowChargedWiresBattery", true );
		m_playerCraftBook.HideRecipe( T"Items.MediumChargedWiresBattery", true );
		m_playerCraftBook.HideRecipe( T"Items.HighChargedWiresBattery", true );
		m_playerCraftBook.HideRecipe( T"Items.ExplosiveDamageRound", true );
		m_playerCraftBook.HideRecipe( T"Items.ElectricDamageRound", true );
		m_playerCraftBook.HideRecipe( T"Items.ThermalDamageRound", true );
		m_playerCraftBook.HideRecipe( T"Items.ChemicalDamageRound", true );
		m_playerCraftBook.HideRecipe( T"Items.NeoplasticPlating", true );
		m_playerCraftBook.HideRecipe( T"Items.MetalPlating", true );
		m_playerCraftBook.HideRecipe( T"Items.TitaniumPlating", true );
		m_playerCraftBook.HideRecipe( T"Items.ArmsCyberwareSharedFragment1", true );
		m_playerCraftBook.HideRecipe( T"Items.ArmsCyberwareSharedFragment2", true );
		m_playerCraftBook.HideRecipe( T"Items.ArmsCyberwareSharedFragment3", true );
		m_playerCraftBook.HideRecipe( T"Items.ArmsCyberwareSharedFragment4", true );
		m_playerCraftBook.HideRecipe( T"Items.PhysicalDamageKnuckles", true );
		m_playerCraftBook.HideRecipe( T"Items.ThermalDamageKnuckles", true );
		m_playerCraftBook.HideRecipe( T"Items.ChemicalDamageKnuckles", true );
		m_playerCraftBook.HideRecipe( T"Items.ElectricDamageKnuckles", true );
		m_playerCraftBook.HideRecipe( T"Items.LowChargedBattery", true );
		m_playerCraftBook.HideRecipe( T"Items.MediumChargedBattery", true );
		m_playerCraftBook.HideRecipe( T"Items.HighChargedBattery", true );
		m_playerCraftBook.HideRecipe( T"Items.KiroshiOpticsFragment1", true );
		m_playerCraftBook.HideRecipe( T"Items.KiroshiOpticsFragment2", true );
		m_playerCraftBook.HideRecipe( T"Items.KiroshiOpticsFragment3", true );
		m_playerCraftBook.HideRecipe( T"Items.KiroshiOpticsFragment4", true );
		m_playerCraftBook.HideRecipe( T"Items.KiroshiOpticsFragment5", true );
		m_playerCraftBook.HideRecipe( T"Items.SandevistanFragment1", true );
		m_playerCraftBook.HideRecipe( T"Items.SandevistanFragment2", true );
		m_playerCraftBook.HideRecipe( T"Items.SandevistanFragment3", true );
		m_playerCraftBook.HideRecipe( T"Items.SandevistanFragment4", true );
		m_playerCraftBook.HideRecipe( T"Items.TygerClawsSandevistanFragment1", true );
		m_playerCraftBook.HideRecipe( T"Items.ValentinosSandevistanFragment1", true );
		m_playerCraftBook.HideRecipe( T"Items.ArasakaSandevistanFragment1", true );
		m_playerCraftBook.HideRecipe( T"Items.BerserkFragment1", true );
		m_playerCraftBook.HideRecipe( T"Items.BerserkFragment2", true );
		m_playerCraftBook.HideRecipe( T"Items.BerserkFragment3", true );
		m_playerCraftBook.HideRecipe( T"Items.BerserkFragment4", true );
		m_playerCraftBook.HideRecipe( T"Items.BerserkFragment5", true );
		m_playerCraftBook.HideRecipe( T"Items.BerserkFragment6", true );
		m_playerCraftBook.HideRecipe( T"Items.BerserkFragment7", true );
		m_playerCraftBook.HideRecipe( T"Items.BerserkFragment8", true );
		m_playerCraftBook.HideRecipe( T"Items.AnimalsBerserkFragment1", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Uncommon_Satara", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Uncommon_Nue", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Uncommon_Copperhead", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Uncommon_Baton_Alpha", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Rare_Nova", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Rare_Pulsar", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Rare_Grad", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Rare_Knife", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Epic_Yukimura", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Epic_Sor22", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Epic_Tactician", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Epic_Bat", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Legendary_Quasar", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Legendary_Nekomata", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Legendary_Carnage", true );
		m_playerCraftBook.HideRecipe( T"Items.Proficiency_Craftable_Legendary_Katana", true );
		m_playerCraftBook.HideRecipe( T"Items.SimpleFabricEnhancer01", true );
		m_playerCraftBook.HideRecipe( T"Items.SimpleFabricEnhancer02", true );
		m_playerCraftBook.HideRecipe( T"Items.SimpleFabricEnhancer03", true );
		m_playerCraftBook.HideRecipe( T"Items.SimpleFabricEnhancer04", true );
		m_playerCraftBook.HideRecipe( T"Items.SimpleFabricEnhancer05", true );
		m_playerCraftBook.HideRecipe( T"Items.PowerfulFabricEnhancer01", true );
		m_playerCraftBook.HideRecipe( T"Items.PowerfulFabricEnhancer02", true );
		m_playerCraftBook.HideRecipe( T"Items.PowerfulFabricEnhancer03", true );
		m_playerCraftBook.HideRecipe( T"Items.PowerfulFabricEnhancer04", true );
		m_playerCraftBook.HideRecipe( T"Items.PowerfulFabricEnhancer05", true );
		m_playerCraftBook.HideRecipe( T"Items.PowerfulFabricEnhancer06", true );
		m_playerCraftBook.HideRecipe( T"Items.PowerfulFabricEnhancer07", true );
		m_playerCraftBook.HideRecipe( T"Items.PowerfulFabricEnhancer08", true );
		m_playerCraftBook.HideRecipe( T"Items.SimpleWeaponMod01", true );
		m_playerCraftBook.HideRecipe( T"Items.SimpleWeaponMod02", true );
		m_playerCraftBook.HideRecipe( T"Items.SimpleWeaponMod03", true );
		m_playerCraftBook.HideRecipe( T"Items.SimpleWeaponMod04", true );
		m_playerCraftBook.HideRecipe( T"Items.OxyBooster", true );
		m_playerCraftBook.HideRecipe( T"Items.EMPOverloadProgram", true );
		m_playerCraftBook.HideRecipe( T"Items.OverheatProgram", true );
		m_playerCraftBook.HideRecipe( T"Items.BlindProgram", true );
		m_playerCraftBook.HideRecipe( T"Items.WhistleProgram", true );
		m_playerCraftBook.HideRecipe( T"Items.PingProgram", true );
		m_playerCraftBook.HideRecipe( T"Items.CommsCallInProgram", true );
		m_playerCraftBook.HideRecipe( T"Items.PingLvl3Program", true );
	}

	private function HideDeprecatedCraftbookRecipes()
	{
		m_playerCraftBook.HideRecipe( T"Items.GrenadeFragRegular", true );
		m_playerCraftBook.HideRecipe( T"Items.GrenadeFlashRegular", true );
		m_playerCraftBook.HideRecipe( T"Items.GrenadeEMPRegular", true );
		m_playerCraftBook.HideRecipe( T"Items.FirstAidWhiffV0", true );
		m_playerCraftBook.HideRecipe( T"Items.BonesMcCoy70V0", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Uncommon_Knife", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Uncommon_Nekomata", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Uncommon_Igla", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Uncommon_Nova", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Common_Satara", true );
		m_playerCraftBook.HideRecipe( T"Items.Craftable_Common_Lexington", true );
	}

	private function AddCraftbookRecipes()
	{
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Copperhead",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Sidewinder",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Guillotine",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Pulsar",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Unity",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Nova",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Igla",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Carnage",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Uncommon_Umbra",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Uncommon_Liberty",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Uncommon_Quasar",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Uncommon_Palica",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Uncommon_Satara",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Katana",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Bat",  );
		m_playerCraftBook.AddRecipe( T"Items.Craftable_Common_Knife",  );
		m_playerCraftBook.AddRecipe( T"Items.w_att_scope_short_01_Craftable",  );
		m_playerCraftBook.AddRecipe( T"Items.w_att_scope_short_03_Craftable",  );
		m_playerCraftBook.AddRecipe( T"Items.w_att_scope_short_06_Craftable",  );
		m_playerCraftBook.AddRecipe( T"Items.w_att_scope_long_02_Craftable",  );
		m_playerCraftBook.AddRecipe( T"Items.w_silencer_01_Craftable",  );
		m_playerCraftBook.AddRecipe( T"Items.w_muzzle_brake_01_Craftable",  );
		m_playerCraftBook.AddRecipe( T"Items.w_muzzle_brake_09_Craftable",  );
		m_playerCraftBook.AddRecipe( T"Items.UncommonMaterial1",  );
		m_playerCraftBook.AddRecipe( T"Items.RareMaterial1",  );
		m_playerCraftBook.AddRecipe( T"Items.EpicMaterial1",  );
		m_playerCraftBook.AddRecipe( T"Items.LegendaryMaterial1",  );
	}

	private function CompensateForOwnedCraftableIconics()
	{
		var ss : StatsSystem;
		var player : weak< PlayerPuppet >;
		var playerLevel : Float;
		ss = GameInstance.GetStatsSystem( GetGameInstance() );
		player = GetMainPlayer( GetGameInstance() );
		playerLevel = ss.GetStatValue( player.GetEntityID(), gamedataStatType.Level );
		if( m_playerCraftBook.KnowsRecipe( T"Items.Preset_Igla_Sovereign" ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Igla_Sovereign",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Igla_Sovereign",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Igla_Sovereign",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Igla_Sovereign",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Igla_Sovereign",  );
			}
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Preset_Pulsar_Buzzsaw" ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Pulsar_Buzzsaw",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Pulsar_Buzzsaw",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Pulsar_Buzzsaw",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Pulsar_Buzzsaw",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Pulsar_Buzzsaw",  );
			}
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Preset_Nekomata_Breakthrough" ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Nekomata_Breakthrough",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Nekomata_Breakthrough",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Nekomata_Breakthrough",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Nekomata_Breakthrough",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Nekomata_Breakthrough",  );
			}
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Preset_Burya_Comrade" ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Burya_Comrade",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Burya_Comrade",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Burya_Comrade",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Burya_Comrade",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Burya_Comrade",  );
			}
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Preset_Copperhead_Genesis" ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Copperhead_Genesis",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Copperhead_Genesis",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Copperhead_Genesis",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Copperhead_Genesis",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Copperhead_Genesis",  );
			}
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Preset_Ajax_Moron" ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Ajax_Moron",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Ajax_Moron",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Ajax_Moron",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Ajax_Moron",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Ajax_Moron",  );
			}
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Preset_Zhuo_Eight_Star" ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Zhuo_Eight_Star",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Zhuo_Eight_Star",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Zhuo_Eight_Star",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Zhuo_Eight_Star",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Zhuo_Eight_Star",  );
			}
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Preset_Dian_Yinglong" ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Dian_Yinglong",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Dian_Yinglong",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Dian_Yinglong",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Dian_Yinglong",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Dian_Yinglong",  );
			}
		}
		if( m_playerCraftBook.KnowsRecipe( T"Items.Preset_Tactician_Headsman" ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Tactician_Headsman",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Tactician_Headsman",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Tactician_Headsman",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Tactician_Headsman",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Tactician_Headsman",  );
			}
		}
	}

	private function CompensateMissingBuzzsawPsalmRecipes()
	{
		var ss : StatsSystem;
		var player : weak< PlayerPuppet >;
		var playerLevel : Float;
		ss = GameInstance.GetStatsSystem( GetGameInstance() );
		player = GetMainPlayer( GetGameInstance() );
		playerLevel = ss.GetStatValue( player.GetEntityID(), gamedataStatType.Level );
		if( ( ( ( ( ( GetFact( GetGameInstance(), 'ma_nid_01_finished' ) >= 1 ) && !( m_playerCraftBook.KnowsRecipe( T"Items.Common_Pulsar_Buzzsaw" ) ) ) && !( m_playerCraftBook.KnowsRecipe( T"Items.Uncommon_Pulsar_Buzzsaw" ) ) ) && !( m_playerCraftBook.KnowsRecipe( T"Items.Rare_Pulsar_Buzzsaw" ) ) ) && !( m_playerCraftBook.KnowsRecipe( T"Items.Epic_Pulsar_Buzzsaw" ) ) ) && !( m_playerCraftBook.KnowsRecipe( T"Items.Legendary_Pulsar_Buzzsaw" ) ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Pulsar_Buzzsaw",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Pulsar_Buzzsaw",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Pulsar_Buzzsaw",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Pulsar_Buzzsaw",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Pulsar_Buzzsaw",  );
			}
		}
		if( ( ( ( ( ( GetFact( GetGameInstance(), 'ma_nid_02_finished' ) >= 1 ) && !( m_playerCraftBook.KnowsRecipe( T"Items.Common_Copperhead_Genesis" ) ) ) && !( m_playerCraftBook.KnowsRecipe( T"Items.Uncommon_Copperhead_Genesis" ) ) ) && !( m_playerCraftBook.KnowsRecipe( T"Items.Rare_Copperhead_Genesis" ) ) ) && !( m_playerCraftBook.KnowsRecipe( T"Items.Epic_Copperhead_Genesis" ) ) ) && !( m_playerCraftBook.KnowsRecipe( T"Items.Legendary_Copperhead_Genesis" ) ) )
		{
			if( playerLevel < 9.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Common_Copperhead_Genesis",  );
			}
			else if( playerLevel < 17.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Uncommon_Copperhead_Genesis",  );
			}
			else if( playerLevel < 25.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Rare_Copperhead_Genesis",  );
			}
			else if( playerLevel < 33.0 )
			{
				m_playerCraftBook.AddRecipe( T"Items.Epic_Copperhead_Genesis",  );
			}
			else
			{
				m_playerCraftBook.AddRecipe( T"Items.Legendary_Copperhead_Genesis",  );
			}
		}
	}

	public static function GetAmmoBulletAmount( ammoId : TweakDBID ) : Int32
	{
		var recipeRecord : weak< ItemRecipe_Record >;
		var craftingResult : weak< CraftingResult_Record >;
		var ammoRecipeId : TweakDBID;
		var amount : Int32;
		switch( ammoId )
		{
			case T"Ammo.HandgunAmmo":
				ammoRecipeId = T"Ammo.RecipeHandgunAmmo";
			break;
			case T"Ammo.ShotgunAmmo":
				ammoRecipeId = T"Ammo.RecipeShotgunAmmo";
			break;
			case T"Ammo.RifleAmmo":
				ammoRecipeId = T"Ammo.RecipeRifleAmmo";
			break;
			case T"Ammo.SniperRifleAmmo":
				ammoRecipeId = T"Ammo.RecipeSniperRifleAmmo";
			break;
		}
		recipeRecord = TweakDBInterface.GetItemRecipeRecord( ammoRecipeId );
		craftingResult = recipeRecord.CraftingResult();
		amount = craftingResult.Amount();
		return amount;
	}

}

class CraftBook
{
	protected persistent var m_knownRecipes : array< ItemRecipe >;
	var m_newRecipes : array< TweakDBID >;
	var m_owner : weak< GameObject >;

	public function InitializeCraftBookOwner( owner : weak< GameObject > )
	{
		m_owner = owner;
		return;
	}

	public function InitializeCraftBook( owner : weak< GameObject >, recipes : weak< Craftable_Record > )
	{
		var craftItems : array< weak< Item_Record > >;
		var i : Int32;
		recipes.CraftableItem( craftItems );
		for( i = 0; i < craftItems.Size(); i += 1 )
		{
			if( GetRecipeIndex( craftItems[ i ].GetID() ) == -1 )
			{
				AddRecipe( craftItems[ i ].GetID() );
			}
		}
		return;
	}

	public const function GetCraftableItems() : array< weak< Item_Record > >
	{
		var itemList : array< weak< Item_Record > >;
		var i : Int32;
		for( i = 0; i < m_knownRecipes.Size(); i += 1 )
		{
			if( !( m_knownRecipes[ i ].isHidden ) )
			{
				itemList.PushBack( TweakDBInterface.GetItemRecord( m_knownRecipes[ i ].targetItem ) );
			}
		}
		return itemList;
	}

	public const function GetRecipeData( Recipe : TweakDBID ) : ItemRecipe
	{
		var nullRecipe : ItemRecipe;
		var index : Int32;
		index = GetRecipeIndex( Recipe );
		if( index != -1 )
		{
			return m_knownRecipes[ index ];
		}
		return nullRecipe;
	}

	public const function GetRecipeIndex( recipe : TweakDBID ) : Int32
	{
		var i : Int32;
		for( i = 0; i < m_knownRecipes.Size(); i += 1 )
		{
			if( m_knownRecipes[ i ].targetItem == recipe )
			{
				return i;
			}
		}
		return -1;
	}

	public const function KnowsRecipe( recipe : TweakDBID ) : Bool
	{
		var i : Int32;
		for( i = 0; i < m_knownRecipes.Size(); i += 1 )
		{
			if( m_knownRecipes[ i ].targetItem == recipe )
			{
				return true;
			}
		}
		return false;
	}

	public function HideRecipesForOwnedItems()
	{
		var i : Int32;
		var j : Int32;
		var transactionSystem : TransactionSystem;
		transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
		for( i = 0; i < m_knownRecipes.Size(); i += 1 )
		{
			if( !( m_knownRecipes[ i ].isHidden ) && ( m_knownRecipes[ i ].hideOnItemsAdded.Size() > 0 ) )
			{
				for( j = 0; j < m_knownRecipes[ i ].hideOnItemsAdded.Size(); j += 1 )
				{
					if( transactionSystem.HasItem( m_owner, m_knownRecipes[ i ].hideOnItemsAdded[ j ] ) )
					{
						m_knownRecipes[ i ].isHidden = true;
						break;
					}
				}
			}
		}
	}

	public function AddRecipe( targetItem : TweakDBID, optional hideOnItemsAdded : array< weak< Item_Record > >, optional amount : Int32 )
	{
		var itemRecipe : ItemRecipe;
		var transactionSystem : TransactionSystem;
		var itemID : ItemID;
		var i : Int32;
		if( !( TDBID.IsValid( targetItem ) ) )
		{
			return;
		}
		itemRecipe.targetItem = targetItem;
		if( ( amount > 0 ) && ( amount != 1 ) )
		{
			itemRecipe.amount = amount;
		}
		else
		{
			itemRecipe.amount = 1;
		}
		if( hideOnItemsAdded.Size() > 0 )
		{
			transactionSystem = GameInstance.GetTransactionSystem( m_owner.GetGame() );
			for( i = 0; i < hideOnItemsAdded.Size(); i += 1 )
			{
				itemID = ItemID.CreateQuery( hideOnItemsAdded[ i ].GetID() );
				itemRecipe.hideOnItemsAdded.PushBack( itemID );
				if( transactionSystem.HasItem( m_owner, itemID ) )
				{
					itemRecipe.isHidden = true;
				}
			}
		}
		i = GetRecipeIndex( targetItem );
		if( i != -1 )
		{
			m_knownRecipes[ i ] = itemRecipe;
			return;
		}
		m_knownRecipes.PushBack( itemRecipe );
		m_newRecipes.PushBack( itemRecipe.targetItem );
	}

	public function SetRecipeInspected( itemID : TweakDBID )
	{
		if( m_newRecipes.Contains( itemID ) )
		{
			m_newRecipes.Remove( itemID );
		}
	}

	public function IsRecipeNew( itemID : TweakDBID ) : Bool
	{
		return m_newRecipes.Contains( itemID );
	}

	public function HideRecipe( recipe : TweakDBID, shouldHide : Bool ) : Bool
	{
		var index : Int32;
		index = GetRecipeIndex( recipe );
		if( index != -1 )
		{
			m_knownRecipes[ index ].isHidden = shouldHide;
			return true;
		}
		return false;
	}

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

	public function ResetRecipeCraftedAmount()
	{
		var i : Int32;
		for( i = 0; i < m_knownRecipes.Size(); i += 1 )
		{
			if( m_knownRecipes[ i ].amount == 0 )
			{
				m_knownRecipes[ i ].amount = 1;
			}
		}
	}

}

class CraftItemRequest extends PlayerScriptableSystemRequest
{
	var target : weak< GameObject >;
	var itemRecord : Item_Record;
	var amount : Int32;
	var bulletAmount : Int32;
}

class DisassembleItemRequest extends PlayerScriptableSystemRequest
{
	var target : weak< GameObject >;
	var itemID : ItemID;
	var amount : Int32;
}

class UpgradeItemRequest extends PlayerScriptableSystemRequest
{
	var itemID : ItemID;
}

class AddRecipeRequest extends PlayerScriptableSystemRequest
{
	var recipe : TweakDBID;
	var amount : Int32;
	var hideOnItemsAdded : array< weak< Item_Record > >;
}

class HideRecipeRequest extends PlayerScriptableSystemRequest
{
	var recipe : TweakDBID;
}

class ShowRecipeRequest extends PlayerScriptableSystemRequest
{
	var recipe : TweakDBID;
}

class CraftingSystemInventoryCallback extends InventoryScriptCallback
{
	var player : weak< PlayerPuppet >;

	public export override function OnItemAdded( item : ItemID, itemData : weak< gameItemData >, flaggedAsSilent : Bool )
	{
		var addRecipeRequest : AddRecipeRequest;
		var craftingSystem : CraftingSystem;
		var recipeRecord : weak< ItemRecipe_Record >;
		var itemToAdd : weak< CraftingResult_Record >;
		if( itemData.HasTag( 'Recipe' ) )
		{
			craftingSystem = ( ( CraftingSystem )( GameInstance.GetScriptableSystemsContainer( player.GetGame() ).Get( 'CraftingSystem' ) ) );
			recipeRecord = TweakDBInterface.GetItemRecipeRecord( ItemID.GetTDBID( item ) );
			itemToAdd = recipeRecord.CraftingResult();
			addRecipeRequest = new AddRecipeRequest;
			addRecipeRequest.recipe = itemToAdd.Item().GetID();
			addRecipeRequest.amount = itemToAdd.Amount();
			if( recipeRecord.GetHideOnItemsAddedCount() > 0 )
			{
				recipeRecord.HideOnItemsAdded( addRecipeRequest.hideOnItemsAdded );
			}
			craftingSystem.QueueRequest( addRecipeRequest );
		}
	}

}

struct ItemRecipe
{
	persistent var targetItem : TweakDBID;
	persistent var hideOnItemsAdded : array< ItemID >;
	persistent var isHidden : Bool;
	persistent var amount : Int32;
}

enum CraftingCommands
{
	CraftingFinished = 0,
	DisassemblingFinished = 1,
	UpgradingFinished = 2,
	Failed = 3,
}

