local SousChef = SousChef local u = SousChef.Utility local m = SousChef.Media local str = SousChef.Strings[SousChef.lang] -- SousChef:UpdateProvisioningTable() adds the Quality checkbox to the provisioner window and overrides the filtering function to incorporate it function SousChef:UpdateProvisioningTable() local function OnFilterChanged() self.settings.qualityChecked = ZO_CheckButton_IsChecked(self.qualityCheckBox) PROVISIONER:DirtyRecipeList() end -- set up the quality checkbox self.qualityCheckBox = SousChef_ControllerOnlyQuality self.qualityCheckBox:SetParent(ZO_ProvisionerTopLevel) ZO_CheckButton_SetLabelText(self.qualityCheckBox, str.PROVISIONING_QUALITY) ZO_CheckButton_SetToggleFunction(self.qualityCheckBox, OnFilterChanged) ZO_CraftingUtils_ConnectCheckBoxToCraftingProcess(self.qualityCheckBox) ZO_CheckButton_SetCheckState(self.qualityCheckBox, self.settings.qualityChecked) -- make room for the checkbox if SousChef.lang == "fr" then -- the french strings are really long and need extra room ZO_ProvisionerTopLevelNavigationDivider:ClearAnchors() ZO_ProvisionerTopLevelNavigationDivider:SetAnchor(TOPLEFT, ZO_ProvisionerTopLevelMenuBarDivider, BOTTOMLEFT, 0, 62) self.qualityCheckBox:ClearAnchors() self.qualityCheckBox:SetAnchor(TOP, ZO_ProvisionerTopLevelHaveIngredientsLabel, BOTTOM, 0, 5) else ZO_ProvisionerTopLevelHaveSkills:ClearAnchors() ZO_ProvisionerTopLevelHaveSkills:SetAnchor( LEFT, ZO_ProvisionerTopLevelHaveIngredientsLabel, RIGHT, 20 ) end -- incorporate new checkbox into the filter SousChef.filter = ZO_SharedProvisioner.DoesRecipePassFilter ZO_SharedProvisioner.DoesRecipePassFilter = function(control, specialIngredientType, checkNumCreatable, numCreatable, checkSkills, provisionerLevelReq, qualityReq) if ZO_CheckButton_IsChecked(self.qualityCheckBox) and qualityReq < 2 then return false end return SousChef.filter(control, specialIngredientType, checkNumCreatable, numCreatable, checkSkills, provisionerLevelReq, qualityReq) end end -- this is our "Mark Recipe" button definition SousChef.ProvisioningButton= {{ name = str.KEY_MARK, keybind = "SC_MARK_RECIPE", control = self, callback = function(descriptor) SousChef:MarkRecipe() end, visible = function(descriptor) return PROVISIONER:GetSelectedRecipeIndex() ~= nil end, alignment = KEYBIND_STRIP_ALIGN_RIGHT, }} local bGroup = SousChef.ProvisioningButton -- SousChef:HookRecipeTreeFunction() adds the "Mark Recipe" button to the keybind bar, and sets the provisioning window to display checkmarks by marked recipes function SousChef:HookRecipeTreeFunction() -- now the keybind button if not KEYBIND_STRIP:HasKeybindButtonGroup(bGroup) then KEYBIND_STRIP:AddKeybindButtonGroup(bGroup) else KEYBIND_STRIP:UpdateKeybindButtonGroup(bGroup) end -- add a space for the checkmark, and hook the entry function to show/hide the checkmark as needed if not SousChef.hookedProvisioningFunction then local ref = PROVISIONER.recipeTree.templateInfo.ZO_ProvisionerNavigationEntry if ref then SousChef.hookedProvisioningFunction = ref.setupFunction ref.setupFunction = function(...) local node, control, data, open, userRequested, enabled = ... SousChef.hookedProvisioningFunction(...) local link = GetItemLinkName(GetRecipeResultItemLink(data.recipeListIndex, data.recipeIndex, LINK_STYLE_BRACKETS)) if link then SousChef:AddNotifier(control, type(SousChef.settings.shoppingList[link]) == "table" and u.TableKeyConcat(SousChef.settings.shoppingList[link])) end end end end PROVISIONER:DirtyRecipeList() end -- SousChef:getMarkedIcon(row, marked) adds the checkmark next to each marked line in the provisioning window function SousChef:getMarkedIcon(row, marked) local rankIcon = SousChef.slotLines[row:GetName()] -- first, if the control for the checkmark doesn't exist, create it if(not rankIcon) then rankIcon = WINDOW_MANAGER:CreateControl(row:GetName() .. "SousChef", row, CT_TEXTURE) SousChef.slotLines[row:GetName()] = rankIcon rankIcon:SetTexture(m.CANLEARN) rankIcon:SetDimensions(20, 20) rankIcon:SetAnchor(RIGHT, row, LEFT, -10) rankIcon:SetMouseEnabled(true) rankIcon:SetHandler("OnMouseExit", function() ClearTooltip(InformationTooltip) end) end -- then, if the recipe is marked by someone, show who, and set the checkmark's alpha accordingly if marked then rankIcon:SetHandler("OnMouseEnter", function() InitializeTooltip(InformationTooltip, rankIcon, RIGHT, -15, 0) InformationTooltip:AddLine(str.PROVISIONING_MARKED .. marked) end) if not marked:find(GetUnitName("player"), 1, true) then rankIcon:SetColor(1,1,1,0.2) else rankIcon:SetColor(1,1,1,1) end end return rankIcon end -- SousChef:AddNotifier(control, marked) shows or hides the checkmark next to each recipe according to whether it's marked by anyone function SousChef:AddNotifier(control, marked) local icon = self:getMarkedIcon(control, marked) if marked then icon:SetHidden(false) else icon:SetHidden(true) end end function SousChef:IsOnShoppingList(id) for i,v in ipairs(SousChef.settings.ReverseCookbook[id]) do if type(SousChef.settings.shoppingList[v]) == "table" and next(SousChef.settings.shoppingList[v]) then return SousChef.settings.shoppingList[v] end end return false end function SousChef:MarkRecipe() local link = GetItemLinkName(GetRecipeResultItemLink(PROVISIONER:GetSelectedRecipeListIndex(), PROVISIONER:GetSelectedRecipeIndex(), LINK_STYLE_BRACKETS)) if type(SousChef.settings.shoppingList[link]) ~= "table" then SousChef.settings.shoppingList[link] = {} end if not SousChef.settings.shoppingList[link][GetUnitName("player")] then SousChef.settings.shoppingList[link][GetUnitName("player")] = true -- we're now marked else SousChef.settings.shoppingList[link][GetUnitName("player")] = nil -- we're now unmarked -- if that was the last mark we just got rid of, then nil out the entire recipe entry if NonContiguousCount(SousChef.settings.shoppingList[link]) == 0 then SousChef.settings.shoppingList[link] = nil end end PROVISIONER:DirtyRecipeList() end function SousChef:HookRecipeTree(...) local eventId, craftingTable = ... if craftingTable ~= CRAFTING_TYPE_PROVISIONING then return end zo_callLater(function() SousChef:HookRecipeTreeFunction() end, 1000) end function SousChef:UnhookRecipeTree() if KEYBIND_STRIP:HasKeybindButtonGroup(bGroup) then KEYBIND_STRIP:RemoveKeybindButtonGroup(bGroup) end end function SousChef:HookGetRecipeInfo() -- first, add the pretty colors to the recipe tree if they aren't there already if SousChef.OldZO_ProvisionerRow_GetTextColor == nil then SousChef.OldZO_ProvisionerRow_GetTextColor = ZO_ProvisionerRow_GetTextColor ZO_ProvisionerRow_GetTextColor = function(self) return SousChef.ZO_ProvisionerRow_GetTextColor(self) end end if SousChef.settings.sortProvisioningTable then SousChef.OldRefreshRecipeList = ZO_Provisioner.RefreshRecipeList ZO_Provisioner.RefreshRecipeList = function() return SousChef.RefreshRecipeList(PROVISIONER) end end end function SousChef:UnhookGetRecipeInfo() if not SousChef.settings.sortProvisioningTable then if SousChef.OldRefreshRecipeList ~= nil then ZO_Provisioner.RefreshRecipeList = SousChef.OldRefreshRecipeList end end end local function SortRecipe(a, b) if a.provisionerLevelReq == b.provisionerLevelReq then if a.useLevelReq == b.useLevelReq then if a.qualityReq == b.qualityReq then if a.name == b.name then return a.recipeIndex < b.recipeIndex end return a.name < b.name end return a.qualityReq < b.qualityReq end return a.useLevelReq < b.useLevelReq end return a.provisionerLevelReq < b.provisionerLevelReq end local function CalculateHowManyCouldBeCreated(recipeListIndex, recipeIndex, numIngredients) local minCount for ingredientIndex = 1, numIngredients do local _, _, requiredQuantity = GetRecipeIngredientItemInfo(recipeListIndex, recipeIndex, ingredientIndex) local ingredientCount = GetCurrentRecipeIngredientCount(recipeListIndex, recipeIndex, ingredientIndex) minCount = zo_min(zo_floor(ingredientCount / requiredQuantity), minCount or math.huge) if minCount == 0 then return 0 end end return minCount or 0 end -- This is an almost direct clone of the existing function -- Except for two parts. -- 1) Storing the parent in the data (for each category of recipe) -- 2) Putting them all in a table first, then sorting, then adding them to the tree function SousChef:RefreshRecipeList() self.dirty = false self.recipeTree:Reset() local hasAnyRecipesInTab = false local hasRecipesWithFilter = false local checkNumCreatable = ZO_CheckButton_IsChecked(self.haveIngredientsCheckBox) local checkSkills = ZO_CheckButton_IsChecked(self.haveSkillsCheckBox) local RecipeLines = {} for recipeListIndex = 1, GetNumRecipeLists() do local recipeListName, numRecipes, upIcon, downIcon, overIcon, disabledIcon, createSound = GetRecipeListInfo(recipeListIndex) local parent for recipeIndex = 1, numRecipes do local known, recipeName, numIngredients, provisionerLevelReq, qualityReq, specialIngredientType = GetRecipeInfo(recipeListIndex, recipeIndex) local useLevelReq = GetItemLinkRequiredLevel(GetRecipeResultItemLink(recipeListIndex, recipeIndex)) if known and self.filterType == specialIngredientType then local numCreatable = self:CalculateHowManyCouldBeCreated(recipeListIndex, recipeIndex, numIngredients) if self:DoesRecipePassFilter(specialIngredientType, checkNumCreatable, numCreatable, checkSkills, provisionerLevelReq, qualityReq) then parent = parent or self.recipeTree:AddNode("ZO_IconHeader", { recipeListIndex = recipeListIndex, name = recipeListName, upIcon = upIcon, downIcon = downIcon, overIcon = overIcon, disabledIcon = disabledIcon }, nil, SOUNDS.PROVISIONING_BLADE_SELECTED) local data = { recipeListIndex = recipeListIndex, recipeIndex = recipeIndex, name = recipeName, provisionerLevelReq = provisionerLevelReq, qualityReq = qualityReq, useLevelReq = useLevelReq, specialIngredientType = specialIngredientType, numIngredients = numIngredients, numCreatable = numCreatable, createSound = createSound, parent = parent, } table.insert(RecipeLines, data) hasRecipesWithFilter = true end hasAnyRecipesInTab = true end end end table.sort(RecipeLines, SortRecipe) for i,data in ipairs(RecipeLines) do self.recipeTree:AddNode("ZO_ProvisionerNavigationEntry", data, data.parent, SOUNDS.PROVISIONING_ENTRY_SELECTED) end self.recipeTree:Commit() self.noRecipesLabel:SetHidden(hasRecipesWithFilter) ZO_CheckButton_SetEnableState(self.haveIngredientsCheckBox, hasAnyRecipesInTab) ZO_CheckButton_SetEnableState(self.haveSkillsCheckBox, hasAnyRecipesInTab) ZO_CheckButton_SetEnableState(SousChef.qualityCheckBox, hasAnyRecipesInTab) if not hasRecipesWithFilter then if hasAnyRecipesInTab then self.noRecipesLabel:SetText(GetString(SI_PROVISIONER_NO_MATCHING_RECIPES)) else self.noRecipesLabel:SetText(GetString(self.filterType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_SPICES and SI_PROVISIONER_NO_COOKING_RECIPES or SI_PROVISIONER_NO_BREWING_RECIPES)) ZO_CheckButton_SetChecked(self.haveIngredientsCheckBox) ZO_CheckButton_SetChecked(self.haveSkillsCheckBox) ZO_CheckButton_SetUnchecked(SousChef.qualityCheckBox) end self:RefreshRecipeDetails() end end local function Lighten(...) r, g, b = ... return r + 0.1, g + 0.1, b + 0.1 end local function Lightest(...) r, g, b = ... return r + 0.3, g + 0.3, b + 0.3 end function SousChef:ZO_ProvisionerRow_GetTextColor() if not self.enabled then return GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_DISABLED) end if self.selected then if self.data.qualityReq > 1 then return Lightest(GetInterfaceColor(INTERFACE_COLOR_TYPE_ITEM_QUALITY_COLORS, self.data.qualityReq + 1)) end return GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_SELECTED) end if self.mouseover then if self.data.qualityReq > 1 then return Lighten(GetInterfaceColor(INTERFACE_COLOR_TYPE_ITEM_QUALITY_COLORS, self.data.qualityReq + 1)) end return GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_HIGHLIGHT) end if self.meetsLevelReq and self.meetsQualityReq then if self.data.qualityReq > 1 then return GetInterfaceColor(INTERFACE_COLOR_TYPE_ITEM_QUALITY_COLORS, self.data.qualityReq + 1) end return GetInterfaceColor(INTERFACE_COLOR_TYPE_TEXT_COLORS, INTERFACE_TEXT_COLOR_NORMAL) end return ZO_ERROR_COLOR:UnpackRGBA() end