ZO_Provisioner = ZO_SharedProvisioner:Subclass() ZO_PROVISIONER_SLOT_ROW_WIDTH = 260 ZO_PROVISIONER_SLOT_ROW_HEIGHT = 58 ZO_PROVISIONER_SLOT_ICON_SIZE = 48 ZO_PROVISIONER_SLOT_PADDING_X = 5 function ZO_Provisioner:New(...) return ZO_SharedProvisioner.New(self, ...) end function ZO_Provisioner:Initialize(control) self.mainSceneName = "provisioner" ZO_SharedProvisioner.Initialize(self, control) self.resultTooltip = self.control:GetNamedChild("Tooltip") if IsChatSystemAvailableForCurrentPlatform() then local function OnTooltipMouseUp(control, button, upInside) if upInside and button == MOUSE_BUTTON_INDEX_RIGHT then ClearMenu() local function AddLink() local recipeListIndex, recipeIndex = self:GetSelectedRecipeListIndex(), self:GetSelectedRecipeIndex() local link = ZO_LinkHandler_CreateChatLink(GetRecipeResultItemLink, recipeListIndex, recipeIndex) ZO_LinkHandler_InsertLink(zo_strformat(SI_TOOLTIP_ITEM_NAME, link)) end AddMenuItem(GetString(SI_ITEM_ACTION_LINK_TO_CHAT), AddLink) ShowMenu(self) end end self.resultTooltip:SetHandler("OnMouseUp", OnTooltipMouseUp) self.resultTooltip:GetNamedChild("Icon"):SetHandler("OnMouseUp", OnTooltipMouseUp) end self.currentTabs = {} self.multiCraftContainer = self.control:GetNamedChild("MultiCraftContainer") self.multiCraftSpinner = ZO_MultiCraftSpinner:New(self.multiCraftContainer:GetNamedChild("Spinner")) self.multiCraftSpinner:RegisterCallback("OnValueChanged", function() self:RefreshRecipeDetails() end) ZO_CraftingUtils_ConnectSpinnerToCraftingProcess(self.multiCraftSpinner) self.filletPanel = ZO_FishFillet_Keyboard:New(self.control:GetNamedChild("FilletPanel"), self) self:InitializeTabs() self:InitializeSettings() self:InitializeFilters() self:InitializeKeybindStripDescriptors() self:InitializeRecipeTree() self:InitializeDetails() ZO_InventoryInfoBar_ConnectStandardBar(self.control:GetNamedChild("InfoBar")) local function OnAddOnLoaded(event, name) if name == "ZO_Ingame" then local defaults = { haveIngredientsChecked = true, haveSkillsChecked = true, questsOnlyChecked = false, } self.savedVars = ZO_SavedVars:New("ZO_Ingame_SavedVariables", 2, "Provisioner", defaults) ZO_CheckButton_SetCheckState(self.haveIngredientsCheckBox, self.savedVars.haveIngredientsChecked) ZO_CheckButton_SetCheckState(self.haveSkillsCheckBox, self.savedVars.haveSkillsChecked) ZO_CheckButton_SetCheckState(self.isQuestItemCheckbox, self.savedVars.questsOnlyChecked) self:DirtyRecipeList() self.control:UnregisterForEvent(EVENT_ADD_ON_LOADED) end end self.control:RegisterForEvent(EVENT_ADD_ON_LOADED, OnAddOnLoaded) PROVISIONER_FRAGMENT = ZO_FadeSceneFragment:New(control) PROVISIONER_FRAGMENT:RegisterCallback("StateChange", function(oldState, newState) if newState == SCENE_FRAGMENT_SHOWING then self:ResetMultiCraftNumIterations() SYSTEMS:GetObject("craftingResults"):SetCraftingTooltip(self.resultTooltip) KEYBIND_STRIP:AddKeybindButtonGroup(self.mainKeybindStripDescriptor) elseif newState == SCENE_FRAGMENT_SHOWN then self:RefreshRecipeDetails() elseif newState == SCENE_FRAGMENT_HIDDEN then SYSTEMS:GetObject("craftingResults"):SetCraftingTooltip(nil) KEYBIND_STRIP:RemoveKeybindButtonGroup(self.mainKeybindStripDescriptor) -- when we hide this fragment make sure to end the preview and toggle the camera back to normal, -- since we may still be staying in the crafting scene if ITEM_PREVIEW_KEYBOARD:IsInteractionCameraPreviewEnabled() then self:TogglePreviewMode() end end end) PROVISIONER_SCENE = self:CreateInteractScene(self.mainSceneName) PROVISIONER_SCENE:RegisterCallback("StateChange", function(oldState, newState) if newState == SCENE_SHOWING then self:ConfigureFromSettings(ZO_Provisioner.PROVISIONING_SETTINGS) local craftingType = GetCraftingInteractionType() local isCraftingTypeDifferent = self.oldCraftingType ~= craftingType self.filletPanel:SetCraftingType(craftingType, self.oldCraftingType, isCraftingTypeDifferent) if self.filterType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FILLET then TriggerTutorial(TUTORIAL_TRIGGER_FILLETING_OPENED) else TriggerTutorial(TUTORIAL_TRIGGER_PROVISIONING_OPENED) end if CRAFT_ADVISOR_MANAGER:HasActiveWrits() then SCENE_MANAGER:AddFragmentGroup(WRIT_ADVISOR_KEYBOARD_FRAGMENT_GROUP) end elseif newState == SCENE_HIDDEN then SCENE_MANAGER:RemoveFragmentGroup(WRIT_ADVISOR_KEYBOARD_FRAGMENT_GROUP) end end) CRAFT_ADVISOR_MANAGER:RegisterCallback("QuestMasterListUpdated", function() if PROVISIONER_SCENE:IsShowing() then if CRAFT_ADVISOR_MANAGER:HasActiveWrits() then SCENE_MANAGER:AddFragmentGroup(WRIT_ADVISOR_KEYBOARD_FRAGMENT_GROUP) else SCENE_MANAGER:RemoveFragmentGroup(WRIT_ADVISOR_KEYBOARD_FRAGMENT_GROUP) end end end) self.skillInfoHeader = self.control:GetNamedChild("SkillInfo") ZO_Skills_TieSkillInfoHeaderToCraftingSkill(self.skillInfoHeader, CRAFTING_TYPE_PROVISIONING) end --Settings ZO_Provisioner.PROVISIONING_SETTINGS = { tabsOffsetY = 0, selectedTabLabelFont = "ZoFontHeader4", selectedTabLabelOffsetY = 7, showProvisionerSkillLevel = true, } ZO_Provisioner.EMBEDDED_SETTINGS = { tabsOffsetY = 58, selectedTabLabelFont = "ZoFontHeader2", selectedTabLabelOffsetY = 0, showProvisionerSkillLevel = false, } function ZO_Provisioner:InitializeSettings() local function GenerateTab(filterType, normal, pressed, highlight, disabled) local name = GetString("SI_PROVISIONERSPECIALINGREDIENTTYPE", filterType) return { activeTabText = name, categoryName = name, descriptor = filterType, normal = normal, pressed = pressed, highlight = highlight, disabled = disabled, callback = function(tabData) self:OnTabFilterChanged(tabData) end, } end local provisioningSettings = ZO_Provisioner.PROVISIONING_SETTINGS local filletTab = GenerateTab(PROVISIONER_SPECIAL_INGREDIENT_TYPE_FILLET, "EsoUI/Art/Crafting/provisioner_indexIcon_fillet_up.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_fillet_down.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_fillet_over.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_fillet_disabled.dds") local foodTab = GenerateTab(PROVISIONER_SPECIAL_INGREDIENT_TYPE_SPICES, "EsoUI/Art/Crafting/provisioner_indexIcon_meat_up.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_meat_down.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_meat_over.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_meat_disabled.dds") local drinkTab = GenerateTab(PROVISIONER_SPECIAL_INGREDIENT_TYPE_FLAVORING, "EsoUI/Art/Crafting/provisioner_indexIcon_beer_up.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_beer_down.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_beer_over.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_beer_disabled.dds") local furnishingsTab = GenerateTab(PROVISIONER_SPECIAL_INGREDIENT_TYPE_FURNISHING, "EsoUI/Art/Crafting/provisioner_indexIcon_furnishings_up.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_furnishings_down.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_furnishings_over.dds", "EsoUI/Art/Crafting/provisioner_indexIcon_furnishings_disabled.dds") provisioningSettings.tabs = {} table.insert(provisioningSettings.tabs, filletTab) table.insert(provisioningSettings.tabs, foodTab) table.insert(provisioningSettings.tabs, drinkTab) table.insert(provisioningSettings.tabs, furnishingsTab) local embeddedSettings = ZO_Provisioner.EMBEDDED_SETTINGS embeddedSettings.tabs = {} table.insert(embeddedSettings.tabs, furnishingsTab) end function ZO_Provisioner:ConfigureFromSettings(settings) if self.settings ~= settings then self.settings = settings self.skillInfoHeader:SetHidden(not settings.showProvisionerSkillLevel) self.tabs:SetAnchor(TOPRIGHT, ZO_SharedRightPanelBackground, TOPRIGHT, -33, settings.tabsOffsetY) local selectedTabLabel = self.tabs:GetNamedChild("Label") selectedTabLabel:SetFont(settings.selectedTabLabelFont) selectedTabLabel:SetAnchor(RIGHT, nil, LEFT, -25, settings.selectedTabLabelOffsetY) ZO_MenuBar_ClearButtons(self.tabs) ZO_ClearTable(self.currentTabs) for _, tab in ipairs(settings.tabs) do table.insert(self.currentTabs, ZO_MenuBar_AddButton(self.tabs, tab)) end ZO_MenuBar_SelectDescriptor(self.tabs, settings.tabs[1].descriptor) end end function ZO_Provisioner:EmbedInCraftingScene() self:ConfigureFromSettings(ZO_Provisioner.EMBEDDED_SETTINGS) SCENE_MANAGER:AddFragment(PROVISIONER_FRAGMENT) self:DirtyRecipeList() self:UpdateQuestPins() end function ZO_Provisioner:RemoveFromCraftingScene() SCENE_MANAGER:RemoveFragment(PROVISIONER_FRAGMENT) end function ZO_Provisioner:ShouldShowForControlScheme() return not IsInGamepadPreferredMode() end function ZO_Provisioner:InitializeTabs() self.tabs = self.control:GetNamedChild("Tabs") self.activeTab = self.control:GetNamedChild("TabsLabel") ZO_CraftingUtils_ConnectMenuBarToCraftingProcess(self.tabs) end function ZO_Provisioner:OnTabFilterChanged(filterData) -- we are switching from the furnishing tab to another tab, make sure the end the preview if there is one if self.filterType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FURNISHING then if SYSTEMS:GetObject("itemPreview"):IsInteractionCameraPreviewEnabled() then self:TogglePreviewMode() end end self.activeTab:SetText(filterData.activeTabText) self.filterType = filterData.descriptor if self.filterType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FILLET then self.provisioningFiltersControl:SetHidden(true) self.detailsPane:SetHidden(true) self.detailsDivider:SetHidden(true) self.navigationContainer:SetHidden(true) self:SetMultiCraftHidden(true) self.resultTooltip:SetHidden(true) self.filletPanel.control:SetHidden(false) TriggerTutorial(TUTORIAL_TRIGGER_FILLETING_OPENED) else self.provisioningFiltersControl:SetHidden(false) self.detailsPane:SetHidden(false) self.detailsDivider:SetHidden(false) self.navigationContainer:SetHidden(false) self.resultTooltip:SetHidden(false) self.filletPanel.control:SetHidden(true) self:SetMultiCraftHidden(false) if self.savedVars then ZO_CheckButton_SetCheckState(self.haveIngredientsCheckBox, self.savedVars.haveIngredientsChecked) ZO_CheckButton_SetCheckState(self.haveSkillsCheckBox, self.savedVars.haveSkillsChecked) ZO_CheckButton_SetCheckState(self.isQuestItemCheckbox, self.savedVars.questsOnlyChecked) end self:ResetMultiCraftNumIterations() self:DirtyRecipeList() TriggerTutorial(TUTORIAL_TRIGGER_PROVISIONING_OPENED) end end function ZO_Provisioner:InitializeFilters() self.provisioningFiltersControl = self.control:GetNamedChild("ProvisioningFilters") self.haveIngredientsCheckBox = self.provisioningFiltersControl:GetNamedChild("HaveIngredients") self.haveSkillsCheckBox = self.provisioningFiltersControl:GetNamedChild("HaveSkills") self.isQuestItemCheckbox = self.provisioningFiltersControl:GetNamedChild("IsQuestItem") local function OnFilterChanged() self.savedVars.haveIngredientsChecked = ZO_CheckButton_IsChecked(self.haveIngredientsCheckBox) self.savedVars.haveSkillsChecked = ZO_CheckButton_IsChecked(self.haveSkillsCheckBox) self.savedVars.questsOnlyChecked = ZO_CheckButton_IsChecked(self.isQuestItemCheckbox) self:DirtyRecipeList() end ZO_CheckButton_SetToggleFunction(self.haveIngredientsCheckBox, OnFilterChanged) ZO_CheckButton_SetToggleFunction(self.haveSkillsCheckBox, OnFilterChanged) ZO_CheckButton_SetToggleFunction(self.isQuestItemCheckbox, OnFilterChanged) ZO_CheckButton_SetLabelText(self.haveIngredientsCheckBox, GetString(SI_PROVISIONER_HAVE_INGREDIENTS)) local FILTER_SPACING = 20 self.haveSkillsCheckBox:SetAnchor(LEFT, self.haveIngredientsCheckBox.label, RIGHT, FILTER_SPACING, 0) ZO_CheckButton_SetLabelText(self.haveSkillsCheckBox, GetString(SI_PROVISIONER_HAVE_SKILLS)) self.isQuestItemCheckbox:SetAnchor(LEFT, self.haveSkillsCheckBox.label, RIGHT, FILTER_SPACING, 0) ZO_CheckButton_SetLabelText(self.isQuestItemCheckbox, GetString(SI_SMITHING_IS_QUEST_ITEM)) ZO_CraftingUtils_ConnectCheckBoxToCraftingProcess(self.haveIngredientsCheckBox) ZO_CraftingUtils_ConnectCheckBoxToCraftingProcess(self.haveSkillsCheckBox) ZO_CraftingUtils_ConnectCheckBoxToCraftingProcess(self.isQuestItemCheckbox) end function ZO_Provisioner:InitializeKeybindStripDescriptors() self.mainKeybindStripDescriptor = { alignment = KEYBIND_STRIP_ALIGN_CENTER, -- Perform craft { name = function() if self.filterType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FILLET then local action = self.filletPanel:IsMultiFillet() and "SI_DECONSTRUCTACTIONNAME_PERFORMMULTIPLE" or "SI_DECONSTRUCTACTIONNAME" return GetString(action, DECONSTRUCT_ACTION_NAME_FILLET) else local cost = GetCostToCraftProvisionerItem(self:GetSelectedRecipeListIndex(), self:GetSelectedRecipeIndex()) return ZO_CraftingUtils_GetCostToCraftString(cost) end end, keybind = "UI_SHORTCUT_SECONDARY", callback = function() if self.filterType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FILLET then self.filletPanel:ConfirmFillet() else ZO_KeyboardCraftingUtils_RequestCraftingCreate(self, self:GetMultiCraftNumIterations()) end end, enabled = function() if self.filterType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FILLET then return self.filletPanel:HasSelections() end return self:ShouldCraftButtonBeEnabled() end, }, -- Clear selections { name = GetString(SI_CRAFTING_CLEAR_SELECTIONS), keybind = "UI_SHORTCUT_NEGATIVE", callback = function() self.filletPanel:ClearSelections() end, visible = function() if self.filterType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FILLET then return self.filletPanel:HasSelections() end return false end, }, --Toggle Preview { name = function() if not ITEM_PREVIEW_KEYBOARD:IsInteractionCameraPreviewEnabled() then return GetString(SI_CRAFTING_ENTER_PREVIEW_MODE) else return GetString(SI_CRAFTING_EXIT_PREVIEW_MODE) end end, keybind = "UI_SHORTCUT_QUATERNARY", callback = function() self:TogglePreviewMode() end, visible = function() return self:CanPreviewRecipe(self:GetRecipeData()) end, }, } ZO_CraftingUtils_ConnectKeybindButtonGroupToCraftingProcess(self.mainKeybindStripDescriptor) end function ZO_Provisioner:InitializeRecipeTree() self.navigationContainer = self.control:GetNamedChild("NavigationContainer") self.recipeTree = ZO_Tree:New(self.navigationContainer:GetNamedChild("ScrollChild"), 74, -10, 535) local function TreeHeaderSetup(node, control, data, open, userRequested, enabled) control.text:SetModifyTextType(MODIFY_TEXT_TYPE_UPPERCASE) control.text:SetDimensionConstraints(0, 0, 260, 0) control.text:SetText(data.name) local shouldHide = self.questRecipeLists[data.recipeListIndex] ~= true control.questPin:SetHidden(shouldHide) if not enabled then control.icon:SetDesaturation(1) control.icon:SetTexture(data.upIcon) elseif open then control.icon:SetDesaturation(0) control.icon:SetTexture(data.downIcon) else control.icon:SetDesaturation(0) control.icon:SetTexture(data.upIcon) end control.iconHighlight:SetTexture(data.overIcon) ZO_IconHeader_Setup(control, open, enabled) end local function TreeHeaderEquality(left, right) return left.recipeListIndex == right.recipeListIndex end self.recipeTree:AddTemplate("ZO_ProvisionerNavigationHeader", TreeHeaderSetup, nil, TreeHeaderEquality, nil, 0) local function TreeEntrySetup(node, control, data, open, userRequested, enabled) control.data = data control.meetsLevelReq = self:PassesTradeskillLevelReqs(data.tradeskillsLevelReqs) control.meetsQualityReq = self:PassesQualityLevelReq(data.qualityReq) control.enabled = enabled local shouldHideQuestPin = self.questRecipes[data.resultItemId] ~= true control.questPin:SetHidden(shouldHideQuestPin) if data.maxIterationsForIngredients > 0 and enabled then control:SetText(zo_strformat(SI_PROVISIONER_RECIPE_NAME_COUNT, data.name, data.maxIterationsForIngredients)) else control:SetText(zo_strformat(SI_PROVISIONER_RECIPE_NAME_COUNT_NONE, data.name)) end control:SetEnabled(enabled) control:SetSelected(node:IsSelected()) if WINDOW_MANAGER:GetMouseOverControl() == control then zo_callHandler(control, enabled and "OnMouseEnter" or "OnMouseExit") end end local function TreeEntryOnSelected(control, data, selected, reselectingDuringRebuild) control:SetSelected(selected) if selected then self:RefreshRecipeDetails() end end local function TreeEntryEquality(left, right) return left.recipeListIndex == right.recipeListIndex and left.recipeIndex == right.recipeIndex and left.name == right.name end self.recipeTree:AddTemplate("ZO_ProvisionerNavigationEntry", TreeEntrySetup, TreeEntryOnSelected, TreeEntryEquality) self.recipeTree:SetExclusive(true) self.recipeTree:SetOpenAnimation("ZO_TreeOpenAnimation") ZO_CraftingUtils_ConnectTreeToCraftingProcess(self.recipeTree) self.noRecipesLabel = self.navigationContainer:GetNamedChild("NoRecipesLabel") self:DirtyRecipeList() end function ZO_Provisioner:InitializeDetails() self.detailsPane = self.control:GetNamedChild("Details") self.detailsDivider = self.control:GetNamedChild("DetailsDivider") self.ingredientRowsContainer = self.detailsPane:GetNamedChild("Ingredients") self.ingredientRows = {} local ingredientAnchor = ZO_Anchor:New(TOPLEFT, self.ingredientRowsContainer, TOPLEFT, 0, 0) local NUM_INGREDIENTS_PER_ROW = 2 local INGREDIENT_PAD_X = 15 local INGREDIENT_PAD_Y = 15 local INGREDIENT_INITIAL_OFFSET_X = 0 local INGREDIENT_INITIAL_OFFSET_Y = 0 for i = 1, GetMaxRecipeIngredients() do local control = CreateControlFromVirtual("$(parent)Slot", self.ingredientRowsContainer, "ZO_ProvisionerSlotRow", i) table.insert(self.ingredientRows, ZO_ProvisionerRow:New(self, control)) ZO_Anchor_BoxLayout(ingredientAnchor, control, i - 1, NUM_INGREDIENTS_PER_ROW, INGREDIENT_PAD_X, INGREDIENT_PAD_Y, ZO_PROVISIONER_SLOT_ROW_WIDTH, ZO_PROVISIONER_SLOT_ROW_HEIGHT, INGREDIENT_INITIAL_OFFSET_X, INGREDIENT_INITIAL_OFFSET_Y) end end function ZO_Provisioner:ResetSelectedTab() self.settings = nil end function ZO_Provisioner:OnFilletSlotChanged() KEYBIND_STRIP:UpdateKeybindButtonGroup(self.mainKeybindStripDescriptor) end function ZO_Provisioner:SetDetailsEnabled(enabled) for ingredientIndex, ingredientSlot in ipairs(self.ingredientRows) do ingredientSlot:SetEnabled(enabled) end end function ZO_Provisioner:RefreshRecipeList() self.recipeTree:Reset() local knowAnyRecipesInTab = false local hasRecipesWithFilter = false local requireIngredients = ZO_CheckButton_IsChecked(self.haveIngredientsCheckBox) local requireSkills = ZO_CheckButton_IsChecked(self.haveSkillsCheckBox) local requireQuests = ZO_CheckButton_IsChecked(self.isQuestItemCheckbox) local craftingInteractionType = GetCraftingInteractionType() local recipeLists = PROVISIONER_MANAGER:GetRecipeListData(craftingInteractionType) for _, recipeList in pairs(recipeLists) do local parent for _, recipe in ipairs(recipeList.recipes) do if recipe.requiredCraftingStationType == craftingInteractionType and self.filterType == recipe.specialIngredientType then knowAnyRecipesInTab = true if self:DoesRecipePassFilter(recipe.specialIngredientType, requireIngredients, recipe.maxIterationsForIngredients, requireSkills, recipe.tradeskillsLevelReqs, recipe.qualityReq, craftingInteractionType, recipe.requiredCraftingStationType, requireQuests, recipe.resultItemId) then parent = parent or self.recipeTree:AddNode("ZO_ProvisionerNavigationHeader", { recipeListIndex = recipeList.recipeListIndex, name = recipeList.recipeListName, upIcon = recipeList.upIcon, downIcon = recipeList.downIcon, overIcon = recipeList.overIcon, }) self.recipeTree:AddNode("ZO_ProvisionerNavigationEntry", recipe, parent) hasRecipesWithFilter = true end end end end self.recipeTree:Commit() self.noRecipesLabel:SetHidden(hasRecipesWithFilter) if not hasRecipesWithFilter then if knowAnyRecipesInTab then self.noRecipesLabel:SetText(GetString(SI_PROVISIONER_NONE_MATCHING_FILTER)) else --If there are no recipes all the types show the same message. self.noRecipesLabel:SetText(GetString(SI_PROVISIONER_NO_RECIPES)) ZO_CheckButton_SetChecked(self.haveIngredientsCheckBox) ZO_CheckButton_SetChecked(self.haveSkillsCheckBox) ZO_CheckButton_SetUnchecked(self.isQuestItemCheckbox) end self:RefreshRecipeDetails() end ZO_CheckButton_SetEnableState(self.haveIngredientsCheckBox, knowAnyRecipesInTab) ZO_CheckButton_SetEnableState(self.haveSkillsCheckBox, knowAnyRecipesInTab) ZO_CheckButton_SetEnableState(self.isQuestItemCheckbox, knowAnyRecipesInTab) end function ZO_Provisioner:GetRecipeData() if self.filterType ~= PROVISIONER_SPECIAL_INGREDIENT_TYPE_FILLET then return self.recipeTree:GetSelectedData() end return nil end function ZO_Provisioner:GetSelectedRecipeListIndex() local recipeData = self:GetRecipeData() if recipeData then return recipeData.recipeListIndex end end function ZO_Provisioner:GetSelectedRecipeIndex() local recipeData = self:GetRecipeData() if recipeData then return recipeData.recipeIndex end end function ZO_Provisioner:RefreshRecipeDetails() local recipeData = self:GetRecipeData() if recipeData then if not ITEM_PREVIEW_KEYBOARD:IsInteractionCameraPreviewEnabled() then self.resultTooltip:SetHidden(false) end local recipeListIndex, recipeIndex = self:GetSelectedRecipeListIndex(), self:GetSelectedRecipeIndex() self.resultTooltip:ClearLines() self.resultTooltip:SetProvisionerResultItem(recipeListIndex, recipeIndex) local numIngredients = recipeData.numIngredients for ingredientIndex, ingredientSlot in ipairs(self.ingredientRows) do if ingredientIndex > numIngredients then ingredientSlot:ClearItem() else local name, icon, requiredQuantity, _, displayQuality = GetRecipeIngredientItemInfo(recipeListIndex, recipeIndex, ingredientIndex) -- Scale the recipe ingredients to what will actually be used when you hit craft. -- If numIterations is 0 we should just show what ingredients you would need to craft once, instead. local numIterations = self:GetMultiCraftNumIterations() if numIterations > 1 then requiredQuantity = requiredQuantity * numIterations end local ingredientCount = GetCurrentRecipeIngredientCount(recipeListIndex, recipeIndex, ingredientIndex) ingredientSlot:SetItem(name, icon, ingredientCount, displayQuality, requiredQuantity) ingredientSlot:SetItemIndices(recipeListIndex, recipeIndex, ingredientIndex) end end if self.filletPanel.control:IsHidden() then CRAFTING_RESULTS:SetTooltipAnimationSounds(recipeData.createSound) end if ITEM_PREVIEW_KEYBOARD:IsInteractionCameraPreviewEnabled() and self:CanPreviewRecipe(recipeData) then self:PreviewRecipe(recipeData) end else self.resultTooltip:SetHidden(true) for ingredientIndex, ingredientSlot in ipairs(self.ingredientRows) do ingredientSlot:ClearItem() end end self:UpdateMultiCraft() KEYBIND_STRIP:UpdateKeybindButtonGroup(self.mainKeybindStripDescriptor) end function ZO_Provisioner:UpdateQuestPins() --Determine whether or not we need quest pins on each tab for _, tab in ipairs(self.currentTabs) do local data = tab.m_object.m_buttonData local shouldHide = self.questCategories[data.descriptor] ~= true tab.questPin:SetHidden(shouldHide) end end function ZO_Provisioner:TogglePreviewMode() ITEM_PREVIEW_KEYBOARD:ToggleInteractionCameraPreview(FRAME_TARGET_CRAFTING_FRAGMENT, FRAME_PLAYER_ON_SCENE_HIDDEN_FRAGMENT, CRAFTING_PREVIEW_OPTIONS_FRAGMENT) if ITEM_PREVIEW_KEYBOARD:IsInteractionCameraPreviewEnabled() then self.resultTooltip:SetHidden(true) self:SetMultiCraftHidden(true) self:PreviewRecipe(self:GetRecipeData()) else self.resultTooltip:SetHidden(false) self:SetMultiCraftHidden(false) end KEYBIND_STRIP:UpdateKeybindButtonGroup(self.mainKeybindStripDescriptor) end function ZO_Provisioner:SetMultiCraftHidden(shouldBeHidden) self.multiCraftContainer:SetHidden(shouldBeHidden) self:RefreshRecipeDetails() end function ZO_Provisioner:GetMultiCraftNumIterations() -- while spinner is hidden, hard cap the iteration count at 1, so the player doesn't accidentally perform a multicraft without a visual cue that it will happen if self.multiCraftContainer:IsControlHidden() then return 1 end return self.multiCraftSpinner:GetValue() end function ZO_Provisioner:ResetMultiCraftNumIterations() self.multiCraftSpinner:SetValue(1) end function ZO_Provisioner:UpdateMultiCraft() self.multiCraftSpinner:SetMinMax(1, self:GetMultiCraftMaxIterations()) self.multiCraftSpinner:UpdateButtons() end ZO_ProvisionerRow = ZO_Object:Subclass() function ZO_ProvisionerRow:New(...) local provisionerSlot = ZO_Object.New(self) provisionerSlot:Initialize(...) return provisionerSlot end function ZO_ProvisionerRow:Initialize(owner, control) self.owner = owner self.control = control self.enabled = true self.icon = control:GetNamedChild("Icon") self.nameLabel = control:GetNamedChild("Name") self.countControl = control:GetNamedChild("Count") local DIVIDER_THICKNESS = 2 self.countFractionDisplay = ZO_FractionDisplay:New(self.countControl, "ZoFontWinH4", DIVIDER_THICKNESS) self.countFractionDisplay:SetHorizontalAlignment(TEXT_ALIGN_RIGHT) self.countDividerTexture = self.countControl:GetNamedChild("Divider") end function ZO_ProvisionerRow:SetItemIndices(recipeListIndex, recipeIndex, ingredientIndex) self.control.recipeListIndex = recipeListIndex self.control.recipeIndex = recipeIndex self.control.ingredientIndex = ingredientIndex end function ZO_ProvisionerRow:SetItem(name, icon, ingredientCount, displayQuality, requiredQuantity) self.ingredientCount = ingredientCount self.requiredQuantity = requiredQuantity self.displayQuality = displayQuality -- self.quality is deprecated, included here for addon backwards compatibility self.quality = displayQuality self.nameLabel:SetText(zo_strformat(SI_TOOLTIP_ITEM_NAME, name)) self.icon:SetTexture(icon) self.countFractionDisplay:SetValues(ingredientCount, requiredQuantity) --The name label takes the remaining width which is the full row minus padding, icon, padding, padding, count, padding. self.nameLabel:SetWidth(ZO_PROVISIONER_SLOT_ROW_WIDTH - ZO_PROVISIONER_SLOT_ICON_SIZE - ZO_PROVISIONER_SLOT_PADDING_X * 4 - self.countControl:GetWidth()) self:UpdateColors() self:SetHidden(false) self.hasItem = true end function ZO_ProvisionerRow:ClearItem() self.control.recipeListIndex = nil self.control.recipeIndex = nil self.control.ingredientIndex = nil self:SetHidden(true) self.hasItem = false end function ZO_ProvisionerRow:SetHidden(hidden) self.nameLabel:SetHidden(hidden) self.icon:SetHidden(hidden) self.countControl:SetHidden(hidden) end function ZO_ProvisionerRow:SetEnabled(enabled) if self.enabled ~= enabled then self.enabled = enabled self:UpdateEnabledState() end end function ZO_ProvisionerRow:UpdateColors() local ingredientCount = self.ingredientCount local requiredQuantity = self.requiredQuantity if ingredientCount >= requiredQuantity then -- self.quality is deprecated, included here for addon backwards compatibility local displayQuality = self.displayQuality or self.quality local r, g, b = GetInterfaceColor(INTERFACE_COLOR_TYPE_ITEM_QUALITY_COLORS, displayQuality) self.nameLabel:SetColor(r, g, b, 1) else self.nameLabel:SetColor(ZO_ERROR_COLOR:UnpackRGBA()) end if self.enabled then if ingredientCount >= requiredQuantity then self.icon:SetColor(ZO_SELECTED_TEXT:UnpackRGBA()) else self.icon:SetColor(ZO_ERROR_COLOR:UnpackRGBA()) end else local DISABLED = true ZO_ItemSlot_SetupIconUsableAndLockedColor(self.icon, MEETS_USAGE_REQUIREMENTS, DISABLED) end --Despite the name these only touch the label alpha local MEETS_USAGE_REQUIREMENTS = true ZO_ItemSlot_SetupTextUsableAndLockedColor(self.nameLabel, MEETS_USAGE_REQUIREMENTS, not self.enabled) ZO_ItemSlot_SetupTextUsableAndLockedColor(self.haveLabel, MEETS_USAGE_REQUIREMENTS, not self.enabled) ZO_ItemSlot_SetupTextUsableAndLockedColor(self.countControl, MEETS_USAGE_REQUIREMENTS, not self.enabled) end function ZO_ProvisionerRow:UpdateEnabledState() if self.hasItem then self:UpdateColors() end end function ZO_Provisioner_Initialize(control) PROVISIONER = ZO_Provisioner:New(control) end function ZO_Provisioner_HaveIngredientsOnMouseEnter(control) InitializeTooltip(InformationTooltip, control, BOTTOM, 0, -10) SetTooltipText(InformationTooltip, GetString(SI_CRAFTING_HAVE_INGREDIENTS_TOOLTIP)) end function ZO_Provisioner_HaveSkillsOnMouseEnter(control) InitializeTooltip(InformationTooltip, control, BOTTOM, 0, -10) SetTooltipText(InformationTooltip, GetString(SI_CRAFTING_HAVE_SKILLS_TOOLTIP)) end function ZO_Provisioner_IsQuestItemOnMouseEnter(control) InitializeTooltip(InformationTooltip, control, BOTTOM, 0, -10) SetTooltipText(InformationTooltip, GetString(SI_CRAFTING_IS_QUEST_ITEM_TOOLTIP)) end function ZO_Provisioner_FilterOnMouseExit(control) ClearTooltip(InformationTooltip) end function ZO_ProvisionerRow_GetTextColor(self) if not self.enabled then return GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_DISABLED) elseif self.selected then return GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED) elseif self.mouseover then return GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_HIGHLIGHT) elseif self.meetsLevelReq and self.meetsQualityReq then return GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_NORMAL) end return ZO_ERROR_COLOR:UnpackRGBA() end function ZO_ProvisionerNavigationEntry_OnMouseEnter(self) ZO_SelectableLabel_OnMouseEnter(self) if self.enabled and (not self.meetsLevelReq or not self.meetsQualityReq) then InitializeTooltip(InformationTooltip, self, RIGHT, -15, 0) --loop over tradeskills if not self.meetsLevelReq then for tradeskill, levelReq in pairs(self.data.tradeskillsLevelReqs) do local level = GetNonCombatBonus(GetNonCombatBonusLevelTypeForTradeskillType(tradeskill)) if level < levelReq then local levelPassiveAbilityId = GetTradeskillLevelPassiveAbilityId(tradeskill) local levelPassiveAbilityName = GetAbilityName(levelPassiveAbilityId) InformationTooltip:AddLine(zo_strformat(SI_RECIPE_REQUIRES_LEVEL_PASSIVE, levelPassiveAbilityName, levelReq), "", ZO_ERROR_COLOR:UnpackRGBA()) end end end if not self.meetsQualityReq then InformationTooltip:AddLine(zo_strformat(SI_PROVISIONER_REQUIRES_RECIPE_QUALITY, self.data.qualityReq), "", ZO_ERROR_COLOR:UnpackRGBA()) end end end function ZO_ProvisionerNavigationEntry_OnMouseExit(self) ZO_SelectableLabel_OnMouseExit(self) ClearTooltip(InformationTooltip) end function ZO_ProvisionerTabs_OnInitialized(control) ZO_MenuBar_OnInitialized(control) local barData = { buttonPadding = 20, normalSize = 51, downSize = 64, animationDuration = DEFAULT_SCENE_TRANSITION_TIME, buttonTemplate = "ZO_ProvisionerTabButton", } ZO_MenuBar_SetData(control, barData) end