class CraftingLogicController extends CraftingMainLogicController { default m_maxIngredientCount = 5; private editable var m_ingredientsWeaponContainer : inkCompoundRef; private editable var m_itemPreviewContainer : inkWidgetRef; private editable var m_weaponPreviewContainer : inkWidgetRef; private editable var m_garmentPreviewContainer : inkWidgetRef; private editable var m_perkNotificationContainer : inkWidgetRef; private editable var m_perkNotificationText : inkTextRef; private var m_itemTooltipController : weak< AGenericTooltipController >; private var m_quickHackTooltipController : weak< AGenericTooltipController >; private var m_tooltipData : ATooltipData; private var m_ingredientWeaponController : weak< InventoryWeaponDisplayController >; private var m_ingredientClothingController : weak< InventoryWeaponDisplayController >; private var m_selectedItemGameData : gameItemData; private var m_quantityPickerPopupToken : inkGameNotificationToken; private var m_playerCraftBook : weak< CraftBook >; private var m_hasSpawnedQuickHackTooltip : Bool; private var m_timeUntilReset : Float; default m_timeUntilReset = 1; public override function Init( craftingGameController : weak< CraftingMainGameController > ) { super.Init( craftingGameController ); m_playerCraftBook = m_craftingSystem.GetPlayerCraftBook(); SetCraftingButton( "UI-Crafting-CraftItem" ); } private const function IsCurrentSelectedRecipeValid() : Bool { var data : array< IScriptable >; var i : Int32; data = m_dataSource.GetArray(); for( i = 0; i < data.Size(); i += 1 ) { if( ( ( RecipeData )( data[ i ] ) ).id == m_selectedRecipe.id ) { return true; } } return false; } public override function RefreshListViewContent( optional inventoryItemData : InventoryItemData ) { m_dataSource.Clear(); m_dataSource.Reset( GetRecipesList() ); if( !( IsCurrentSelectedRecipeValid() ) ) { m_selectedRecipe = NULL; } UpdateRecipePreviewPanel( m_selectedRecipe ); } protected override function SetupIngredientWidgets() { AsyncSpawnFromLocal( inkCompoundRef.Get( m_ingredientsWeaponContainer ), 'ingredientWeapon', this, 'OnWeaponControllerSpawned' ); AsyncSpawnFromLocal( inkCompoundRef.Get( m_ingredientsListContainer ), 'ingredientClothes', this, 'OnClothingControllerSpawned' ); inkCompoundRef.SetVisible( m_ingredientsWeaponContainer, false ); super.SetupIngredientWidgets(); } protected event OnWeaponControllerSpawned( widget : inkWidget, userData : IScriptable ) { var buttonController : weak< inkButtonController >; m_ingredientWeaponController = ( ( InventoryWeaponDisplayController )( widget.GetControllerByType( 'InventoryWeaponDisplayController' ) ) ); buttonController = ( ( inkButtonController )( m_ingredientWeaponController.GetRootWidget().GetControllerByType( 'inkButtonController' ) ) ); buttonController.SetEnabled( false ); } protected event OnClothingControllerSpawned( widget : inkWidget, userData : IScriptable ) { m_ingredientClothingController = ( ( InventoryWeaponDisplayController )( widget.GetControllerByType( 'InventoryWeaponDisplayController' ) ) ); } protected override function SetupFilters() { m_filters.PushBack( ( ( Int32 )( ItemFilterCategory.AllCount ) ) ); m_filters.PushBack( ( ( Int32 )( ItemFilterCategory.RangedWeapons ) ) ); m_filters.PushBack( ( ( Int32 )( ItemFilterCategory.MeleeWeapons ) ) ); m_filters.PushBack( ( ( Int32 )( ItemFilterCategory.Consumables ) ) ); m_filters.PushBack( ( ( Int32 )( ItemFilterCategory.Grenades ) ) ); m_filters.PushBack( ( ( Int32 )( ItemFilterCategory.Attachments ) ) ); m_filters.PushBack( ( ( Int32 )( ItemFilterCategory.Programs ) ) ); super.SetupFilters(); } protected override function UpdateItemPreview( craftableController : CraftableItemLogicController ) { var selectedRecipe : RecipeData; m_progressButtonController.Reset(); selectedRecipe = ( ( RecipeData )( ( ( IScriptable )( craftableController.GetData() ) ) ) ); UpdateRecipePreviewPanel( selectedRecipe ); } private function UpdateRecipePreviewPanel( selectedRecipe : RecipeData ) { var isWeapon : Bool; var previewEvent : CraftingItemPreviewEvent; var buttonState : EProgressBarState; m_selectedRecipe.isSelected = false; if( selectedRecipe == NULL ) { inkWidgetRef.SetVisible( m_itemDetailsContainer, false ); return; } inkWidgetRef.SetVisible( m_itemDetailsContainer, true ); DryMakeItem( selectedRecipe ); isWeapon = InventoryItemData.IsWeapon( m_selectedItemData ); inkWidgetRef.SetVisible( m_weaponPreviewContainer, isWeapon ); inkWidgetRef.SetVisible( m_itemPreviewContainer, !( isWeapon ) ); if( m_selectedRecipe.id != selectedRecipe.id ) { previewEvent = new CraftingItemPreviewEvent; previewEvent.itemID = ( ( isWeapon ) ? ( m_selectedItemGameData.GetID() ) : ( ItemID.None() ) ); QueueEvent( previewEvent ); } m_selectedRecipe = selectedRecipe; m_selectedRecipe.isSelected = true; SetupIngredients( m_craftingSystem.GetItemCraftingCost( m_selectedItemGameData ), 1 ); UpdateTooltipData(); SetQualityHeader(); m_playerCraftBook.SetRecipeInspected( m_selectedRecipe.id.GetID() ); m_isCraftable = m_craftingSystem.CanItemBeCrafted( m_selectedItemGameData ); buttonState = ( ( m_isCraftable ) ? ( EProgressBarState.Available ) : ( EProgressBarState.Blocked ) ); m_progressButtonController.SetAvaibility( buttonState ); inkTextRef.SetVisible( m_blockedText, !( m_isCraftable ) ); if( !( m_isCraftable ) ) { SetNotification( false ); } } private function DryMakeItem( selectedRecipe : RecipeData ) { var craftedItemID : ItemID; var itemData : gameItemData; var item : InventoryItemData; var player : weak< PlayerPuppet >; var itemModParams : ItemModParams; player = m_craftingGameController.GetPlayer(); craftedItemID = ItemID.FromTDBID( selectedRecipe.id.GetID() ); itemModParams.itemID = craftedItemID; itemModParams.quantity = 1; itemData = Inventory.CreateItemData( itemModParams, player ); CraftingSystem.SetItemLevel( player, itemData ); CraftingSystem.MarkItemAsCrafted( player, itemData ); itemData.SetDynamicTag( 'SkipActivityLog' ); item = m_craftingGameController.GetInventoryManager().GetInventoryItemDataForDryItem( itemData ); m_selectedItemGameData = itemData; m_selectedItemData = item; } private function GetMinimalInvetoryItemData() : MinimalItemTooltipData { var data : MinimalItemTooltipData; var statusManager : UIInventoryItemStatsManager; var itemRecord : weak< Item_Record >; var itemCategory : gamedataItemCategory; var itemType : gamedataItemType; data = m_inventoryManager.GetMinimalTooltipDataForInventoryItem( m_selectedItemData, false, NULL, false, false ); itemType = InventoryItemData.GetItemType( m_selectedItemData ); itemRecord = TweakDBInterface.GetItemRecord( ItemID.GetTDBID( InventoryItemData.GetID( m_selectedItemData ) ) ); itemCategory = itemRecord.ItemCategory().Type(); if( itemCategory != gamedataItemCategory.Weapon ) { statusManager = UIInventoryItemStatsManager.FromMinimalItemTooltipDataToTooltipStats( data ); data.GetStatsManager().SetTooltipsStats( statusManager.TooltipStats ); } if( RPGManager.IsScopeAttachment( itemType ) || RPGManager.IsMuzzleAttachment( itemType ) ) { HideMods( data ); } data.ammoCount = GameInstance.GetTransactionSystem( m_Game ).GetItemQuantity( m_Player, InventoryItemData.GetID( m_selectedItemData ) ); data.displayContext = InventoryTooltipDisplayContext.Crafting; return data; } private function HideMods( data : MinimalItemTooltipData ) { data.mods.Clear(); } private function UpdateTooltipData() { var isQuickHack : Bool; isQuickHack = IsQuickHackItem(); if( isQuickHack ) { if( ( m_quickHackTooltipController == NULL ) && !( m_hasSpawnedQuickHackTooltip ) ) { AsyncSpawnFromExternal( inkWidgetRef.Get( m_tooltipContainer ), R"base\gameplay\gui\common\tooltip\programtooltip.inkwidget", 'programTooltip', this, 'OnQuickHackTooltipSpawned' ); m_hasSpawnedQuickHackTooltip = true; return; } EnableQuickHackTooltip(); return; } if( ( m_itemTooltipController == NULL ) && !( m_hasSpawnedTooltip ) ) { SpawnItemTooltipAsync( inkWidgetRef.Get( m_tooltipContainer ), this, 'OnItemTooltipSpawned' ); m_hasSpawnedTooltip = true; return; } EnableMainTooltip(); } protected event OnItemTooltipSpawned( widget : inkWidget, userData : IScriptable ) { m_itemTooltipController = ( ( AGenericTooltipController )( widget.GetController() ) ); EnableMainTooltip(); } protected event OnQuickHackTooltipSpawned( widget : inkWidget, userData : IScriptable ) { m_quickHackTooltipController = ( ( AGenericTooltipController )( widget.GetController() ) ); EnableQuickHackTooltip(); } private function EnableQuickHackTooltip() { ToggleMainTooltip( false ); ToggleQuickHackTooltip( true ); } private function EnableMainTooltip() { ToggleMainTooltip( true ); ToggleQuickHackTooltip( false ); } private function ToggleMainTooltip( isEnabled : Bool ) { if( m_itemTooltipController != NULL ) { m_tooltipData = GetMinimalInvetoryItemData(); m_itemTooltipController.SetData( m_tooltipData ); m_itemTooltipController.GetRootWidget().SetVisible( isEnabled ); } } private function ToggleQuickHackTooltip( isEnabled : Bool ) { if( m_quickHackTooltipController != NULL ) { m_tooltipData = GetQuickHackTooltipData( m_selectedRecipe, m_selectedItemData, m_selectedItemGameData ); m_quickHackTooltipController.SetData( m_tooltipData ); m_quickHackTooltipController.GetRootWidget().SetVisible( isEnabled ); } } private function SetQualityHeader() { var rarityLabel, iconicLabel, plusLabel : String; var qualityName : CName; var isIconic : Bool; var isPlus : Float; var quality : gamedataQuality; var rarityItemType : RarityItemType; var itemData : weak< gameItemData >; iconicLabel = GetLocalizedText( UIItemsHelper.QualityToDefaultString( gamedataQuality.Iconic ) ); itemData = InventoryItemData.GetGameItemData( m_selectedItemData ); if( itemData.HasTag( 'ChimeraMod' ) ) { quality = gamedataQuality.Iconic; plusLabel = iconicLabel; } else { isIconic = RPGManager.IsItemIconic( itemData ); isPlus = RPGManager.GetItemPlus( itemData ); quality = GetQuality(); rarityItemType = UIItemsHelper.ItemTypeToRarity( InventoryItemData.GetItemType( m_selectedItemData ), itemData ); rarityLabel = GetLocalizedText( UIItemsHelper.QualityToDefaultString( quality, rarityItemType ) ); plusLabel = rarityLabel; if( isPlus >= 2.0 ) { plusLabel += "++"; } else if( isPlus >= 1.0 ) { plusLabel += "+"; } if( isIconic ) { plusLabel += ( " / " + iconicLabel ); } } inkTextRef.SetText( m_itemQuality, plusLabel ); qualityName = UIItemsHelper.QualityEnumToName( quality ); inkTextRef.SetState( m_itemQuality, qualityName ); inkTextRef.SetText( m_itemName, m_selectedRecipe.label ); inkTextRef.SetState( m_itemName, qualityName ); } private function SetNotification( isQuickHack : Bool ) { var levelParams : inkTextParams; var levelRequired : Int32; var playerLevel : Float; var quality : gamedataQuality; var hasAmmoCap : Bool; var hasEnoughIngredients : Bool; if( isQuickHack ) { inkTextRef.SetText( m_blockedText, "LocKey#78498" ); m_notificationType = UIMenuNotificationType.CraftingQuickhack; return; } quality = GetQuality(); levelRequired = GetMinimumLevelRequiredByQuality( quality ); playerLevel = m_craftingGameController.GetPlayerLevel(); if( playerLevel < ( ( Float )( levelRequired ) ) ) { levelParams = new inkTextParams; levelParams.AddNumber( "int_0", levelRequired ); inkTextRef.SetText( m_blockedText, "LocKey#87105", levelParams ); m_notificationType = UIMenuNotificationType.PlayerReqLevelToLow; return; } hasEnoughIngredients = m_craftingSystem.EnoughIngredientsForCrafting( InventoryItemData.GetGameItemData( m_selectedItemData ) ); if( !( hasEnoughIngredients ) ) { inkTextRef.SetText( m_blockedText, "LocKey#42797" ); m_notificationType = UIMenuNotificationType.CraftingNotEnoughMaterial; return; } hasAmmoCap = HasAmmoCap(); if( hasAmmoCap ) { inkTextRef.SetText( m_blockedText, "LocKey#81496" ); m_notificationType = UIMenuNotificationType.CraftingAmmoCap; return; } } private function HasAmmoCap() : Bool { var itemData : weak< gameItemData >; var maxCraftingAmount : Int32; itemData = InventoryItemData.GetGameItemData( m_selectedItemData ); maxCraftingAmount = m_craftingSystem.GetMaxCraftingAmount( itemData ); return maxCraftingAmount == 0; } private function GetQuality() : gamedataQuality { var qualityName : CName; qualityName = InventoryItemData.GetQuality( m_selectedItemData ); return UIItemsHelper.QualityNameToEnum( qualityName ); } private static function GetMinimumLevelRequiredByQuality( quality : gamedataQuality ) : Int32 { switch( quality ) { case gamedataQuality.Uncommon: return 1; case gamedataQuality.Rare: return 1; case gamedataQuality.Epic: return 1; case gamedataQuality.Legendary: return 1; default: return 1; } } private function SetupIngredients( const ingredient : ref< array< IngredientData > >, itemAmount : Int32 ) { var i, ingredientCount : Int32; var controller : weak< IngredientListItemLogicController >; var data : IngredientData; var itemData : InventoryItemData; var isInInventory : Bool; ingredientCount = ingredient.Size(); inkCompoundRef.SetVisible( m_ingredientsWeaponContainer, false ); m_ingredientClothingController.GetRootWidget().SetVisible( false ); for( i = 0; i < ingredientCount; i += 1 ) { data = ingredient[ i ]; itemData = GetInventoryItemDataFromRecord( data.id ); controller = m_ingredientsControllerList[ i ]; if( RPGManager.IsItemWeapon( InventoryItemData.GetID( itemData ) ) ) { inkCompoundRef.SetVisible( m_ingredientsWeaponContainer, true ); m_ingredientWeaponController.Setup( itemData ); controller.SetUnusedState(); isInInventory = RPGManager.HasItem( m_craftingGameController.GetPlayer(), ItemID.GetTDBID( InventoryItemData.GetID( itemData ) ) ); m_ingredientWeaponController.GetRootWidget().SetState( ( ( isInInventory ) ? ( 'Default' ) : ( 'Unavailable' ) ) ); continue; } if( RPGManager.IsItemClothing( InventoryItemData.GetID( itemData ) ) ) { m_ingredientClothingController.GetRootWidget().SetVisible( true ); m_ingredientClothingController.Setup( itemData ); isInInventory = RPGManager.HasItem( m_craftingGameController.GetPlayer(), ItemID.GetTDBID( InventoryItemData.GetID( itemData ) ) ); m_ingredientClothingController.GetRootWidget().SetState( ( ( isInInventory ) ? ( 'Default' ) : ( 'Unavailable' ) ) ); controller.SetUnusedState(); continue; } controller.SetupData( ingredient[ i ], m_tooltipsManager, itemAmount ); } for( i = ingredientCount; i < m_maxIngredientCount; i += 1 ) { controller = m_ingredientsControllerList[ i ]; controller.SetUnusedState(); } } protected event OnDisplayHoverOver( hoverOverEvent : ItemDisplayHoverOverEvent ) { var tooltipData : MaterialTooltipData; tooltipData = new MaterialTooltipData; if( hoverOverEvent.display.GetDisplayContext() == ItemDisplayContext.None ) { tooltipData.Title = GetLocalizedText( InventoryItemData.GetName( hoverOverEvent.itemData ) ); m_tooltipsManager.ShowTooltipAtWidget( 'materialTooltip', hoverOverEvent.widget, tooltipData, gameuiETooltipPlacement.RightTop, true ); } } public override function OnChangeTab( isCurrent : Bool ) { super.OnChangeTab( isCurrent ); m_quantityPickerPopupToken = NULL; m_selectedRecipe = NULL; } private function OpenQuantityPicker( const itemData : ref< InventoryItemData >, maxQuantity : Int32 ) { var data : QuantityPickerPopupData; data = new QuantityPickerPopupData; data.notificationName = 'base\gameplay\gui\widgets\notifications\item_quantity_picker.inkwidget'; data.isBlocking = true; data.useCursor = true; data.queueName = 'modal_popup'; data.maxValue = maxQuantity; data.gameItemData = itemData; data.actionType = QuantityPickerActionType.Craft; data.sendQuantityChangedEvent = true; m_quantityPickerPopupToken = m_craftingGameController.ShowGameNotification( data ); if( m_quantityPickerPopupToken ) { m_quantityPickerPopupToken.RegisterListener( this, 'OnQuantityPickerEvent' ); } m_buttonHintsController.Hide(); } protected event OnQuantityPickerEvent( data : inkGameNotificationData ) { var closeData : QuantityPickerPopupCloseData; var quantityData : PickerChoosenQuantityChangedEvent; closeData = ( ( QuantityPickerPopupCloseData )( data ) ); quantityData = ( ( PickerChoosenQuantityChangedEvent )( data ) ); if( closeData != NULL ) { m_quantityPickerPopupToken = NULL; if( closeData.choosenQuantity != -1 ) { CraftItem( m_selectedRecipe, closeData.choosenQuantity ); m_buttonHintsController.Show(); } } if( quantityData != NULL ) { SetupIngredients( m_craftingSystem.GetItemCraftingCost( m_selectedItemGameData ), quantityData.choosenQuantity ); } } protected event OnHoldFinished( evt : ProgressBarFinishedProccess ) { var quantity : Int32; if( !( m_isPanelOpen ) ) { return false; } PlaySound( 'Item', 'OnCrafted' ); PlayRumble( RumbleStrength.Heavy, RumbleType.Pulse, RumblePosition.Right ); if( ( ( m_selectedRecipe.id.TagsContains( 'Consumable' ) && !( m_selectedRecipe.id.TagsContains( 'Medical' ) ) ) || m_selectedRecipe.id.TagsContains( 'Ammo' ) ) || InventoryItemData.GetItemType( m_selectedRecipe.inventoryItem ) == gamedataItemType.Gen_CraftingMaterial ) { quantity = m_craftingSystem.GetMaxCraftingAmount( InventoryItemData.GetGameItemData( m_selectedItemData ) ); if( m_selectedRecipe.id.TagsContains( 'Ammo' ) && ( quantity == 0 ) ) { return false; } if( quantity > 1 ) { OpenQuantityPicker( m_selectedItemData, quantity ); return true; } } if( m_selectedRecipe.id.TagsContains( 'Ammo' ) ) { CraftItem( m_selectedRecipe, 1 ); } else { CraftItem( m_selectedRecipe, m_selectedRecipe.amount ); } } protected override function SetItemButtonHintsHoverOver( evt : inkPointerEvent ) { if( m_isCraftable ) { m_buttonHintsController.AddButtonHint( 'craft_item', GetLocalizedText( "UI-Crafting-hold_to_craft" ) ); } } private function GetRecipesList() : array< IScriptable > { var itemRecordList : array< weak< Item_Record > >; var itemRecord : weak< Item_Record >; var i : Int32; var recipeDataList : array< IScriptable >; var recipeData : RecipeData; m_playerCraftBook.HideRecipesForOwnedItems(); itemRecordList = m_playerCraftBook.GetCraftableItems(); for( i = 0; i < itemRecordList.Size(); i += 1 ) { itemRecord = itemRecordList[ i ]; if( itemRecord ) { recipeData = m_craftingSystem.GetRecipeData( itemRecord ); recipeData.isNew = m_playerCraftBook.IsRecipeNew( recipeData.id.GetID() ); recipeData.isCraftable = m_craftingSystem.CanItemBeCrafted( itemRecord ); recipeData.inventoryItem = m_inventoryManager.GetInventoryItemDataFromItemRecord( recipeData.id ); InventoryItemData.SetQuality( recipeData.inventoryItem, UIItemsHelper.QualityEnumToName( itemRecord.Quality().Type() ) ); m_inventoryManager.GetOrCreateInventoryItemSortData( recipeData.inventoryItem, m_craftingGameController.GetScriptableSystem() ); recipeDataList.PushBack( recipeData ); } } return recipeDataList; } private function GetInventoryItemDataFromRecord( itemRecord : Item_Record ) : InventoryItemData { var itemData : InventoryItemData; itemData = m_inventoryManager.GetInventoryItemDataFromItemRecord( itemRecord ); m_inventoryManager.GetOrCreateInventoryItemSortData( itemData, m_craftingGameController.GetScriptableSystem() ); return itemData; } private function GetQuickHackTooltipData( recipeData : RecipeData, inventoryItemData : InventoryItemData, gameData : gameItemData ) : ATooltipData { var tooltipData : InventoryTooltipData; tooltipData = InventoryTooltipData.FromRecipeAndItemData( m_craftingGameController.GetPlayer().GetGame(), recipeData, inventoryItemData, inventoryItemData, gameData ); InventoryItemData.SetGameItemData( tooltipData.inventoryItemData, gameData ); if( InventoryItemData.GetItemType( inventoryItemData ) == gamedataItemType.Prt_Program ) { tooltipData.quickhackData = m_inventoryManager.GetQuickhackTooltipData( ItemID.GetTDBID( InventoryItemData.GetID( inventoryItemData ) ) ); } return tooltipData; } private function IsQuickHackItem() : Bool { return m_selectedItemData.ItemType == gamedataItemType.Prt_Program; } private function CraftItem( selectedRecipe : RecipeData, amount : Int32 ) { var craftItemRequest : CraftItemRequest; if( selectedRecipe.label != "" ) { craftItemRequest = new CraftItemRequest; craftItemRequest.target = m_craftingGameController.GetPlayer(); craftItemRequest.itemRecord = selectedRecipe.id; craftItemRequest.amount = amount; if( selectedRecipe.id.TagsContains( 'Ammo' ) ) { craftItemRequest.bulletAmount = selectedRecipe.amount; } m_craftingSystem.QueueRequest( craftItemRequest ); } if( ( m_selectedRecipe.id.TagsContains( 'Medical' ) || m_selectedRecipe.id.TagsContains( 'Grenade' ) ) || ( m_selectedRecipe.id.TagsContains( 'CraftableIconic' ) && !( m_selectedRecipe.id.TagsContains( 'Haunted_Gun' ) ) ) ) { DelayedReset.CreateAndDispatch( this, m_Player, m_timeUntilReset ); } } public function ResetViewDelayed() { inkWidgetRef.SetVisible( m_itemDetailsContainer, false ); m_selectedRecipe = NULL; } protected event OnItemDisplayHoverOver( evt : ItemDisplayHoverOverEvent ) { if( !( InventoryItemData.IsEmpty( evt.itemData ) ) ) { m_playerCraftBook.SetRecipeInspected( ItemID.GetTDBID( InventoryItemData.GetID( evt.itemData ) ) ); } } protected event OnUninitialize() { if( m_selectedItemGameData ) { m_selectedItemGameData = NULL; } super.OnUninitialize(); } } class DelayedReset extends DelayCallback { private var m_controller : weak< CraftingLogicController >; public static function CreateAndDispatch( controller : weak< CraftingLogicController >, player : weak< PlayerPuppet >, time : Float ) { var callback : DelayedReset; callback = new DelayedReset; callback.m_controller = controller; GameInstance.GetDelaySystem( player.GetGame() ).DelayCallback( callback, time, false ); } public override function Call() { m_controller.ResetViewDelayed(); } }