--[[------------------------------------------------------------------ --SousChef.lua --Author: Wobin inspired by ingeniousclown's Research Assistant Thanks to Ayantir for the French translations, and sirinsidiator for the German ------------------------------------------------------------------]]-- SousChef = {} SousChef.Utility = {} SousChef.Media = {} SousChef.version = "2.14" local SousChef = SousChef local u = SousChef.Utility local LAM = LibStub:GetLibrary("LibAddonMenu-2.0") local BACKPACK = ZO_PlayerInventoryBackpack local BANK = ZO_PlayerBankBackpack local GUILD_BANK = ZO_GuildBankBackpack SousChef.Pantry = {} SousChef.Cookbook = {} SousChef.CookbookIndex = {} SousChef.ReverseCookbook = {} SousChef.settings = nil SousChef.slotLines = {} SousChef.hookedFunctions = {} SousChef.hookedDataFunction = nil SousChef.lang = GetCVar("Language.2") if SousChef.lang ~= "en" and SousChef.lang ~= "de" and SousChef.lang ~= "fr" then SousChef.lang = "en" end local rowHandler = {} local typeIconLookup = { -- en ["Grilled"] = 9, ["Bread and Pies"] = 10, ["Soup and Stew"] = 11, ["Beer"] = 12, ["Spirits"] = 13, ["Wine"] = 14, -- de ["Gegrillt"] = 9, ["Brot und Kuchen"] = 10, ["Suppen und Eintöpfe"] = 11, ["Bier"] = 12, ["Getränke"] = 13, ["Wein"] = 14, -- fr ["Grillades"] = 9, ["Pain et Tartes"] = 10, ["Soupe et Ragoût"] = 11, ["Bi\195\169re"] = 12, ["Spiritueux"] = 13, ["Vin"] = 14, } local colors = { ["green"] = "|c00ff00", ["blue"] = "|c0066ff", ["purple"] = "|c782ee6", ["white"] = "|cFFFFFF", ["ending"] = "|r", } -- FUNCTIONS -- AddRecipe(Cookbook, link) adds the linked recipe to the player cookbook if it isn't there already. local function AddRecipe(Cookbook, link) for _,v in pairs(Cookbook) do if v == link then return end end table.insert(Cookbook, link) end -- RefreshViews() incorporates changes to the rendered inventory if it is visible. function SousChef:RefreshViews() ZO_ScrollList_RefreshVisible(BACKPACK) ZO_ScrollList_RefreshVisible(BANK) ZO_ScrollList_RefreshVisible(GUILD_BANK) end -- ParseRecipes() goes through the player's known recipes and records their info. function SousChef:ParseRecipes() local lists = GetNumRecipeLists() for listIndex = 1, lists do local name, count = GetRecipeListInfo(listIndex) for recipeIndex = 1, count do if GetRecipeInfo(listIndex, recipeIndex) then -- Store the recipes known: local recipeName = u.CleanString((GetRecipeResultItemInfo(listIndex, recipeIndex))) -- in this character's cookbook SousChef.Cookbook[recipeName] = true -- and in the settings, so other characters can see what recipes this character knows if not SousChef.settings.Cookbook[recipeName] then SousChef.settings.Cookbook[recipeName] = {} end SousChef.settings.Cookbook[recipeName][GetUnitName("player")] = true -- now record information about the recipe's ingregients local _, _, ingredientCount, level, _, specialType = GetRecipeInfo(listIndex, recipeIndex) -- store the recipe's index numbers and number of ingredients local resultLink = GetRecipeResultItemLink(listIndex, recipeIndex) local plainName = GetItemLinkName(resultLink) local recipeColor = GetItemLinkQuality(resultLink) local coloredName if recipeColor == ITEM_QUALITY_MAGIC then -- green coloredName = colors.green .. zo_strformat("<<t:1>>", plainName) .. colors.ending elseif recipeColor == ITEM_QUALITY_ARCANE then -- blue coloredName = colors.blue .. zo_strformat("<<t:1>>", plainName) .. colors.ending elseif recipeColor == ITEM_QUALITY_ARTIFACT then -- purple coloredName = colors.purple .. zo_strformat("<<t:1>>", plainName) .. colors.ending else -- can't happen coloredName = zo_strformat("<<t:1>>", plainName) end SousChef.CookbookIndex[coloredName] = {listIndex = listIndex, recipeIndex = recipeIndex, numIngredients = ingredientCount} -- now, for every ingredient in the current recipe... for ingredientIndex = 1, ingredientCount do local link = u.GetItemID(GetRecipeIngredientItemLink(listIndex, recipeIndex, ingredientIndex, LINK_STYLE_DEFAULT)) -- Store the fact that the ingredient is used if ingredientIndex < 3 or not SousChef.settings.showSpecialIngredients then -- if this isn't a special ingredient, or if the user doesn't want special ingredients marked as special, just record the highest-tier recipe this ingredient appears in -- for this character, SousChef.Pantry[link] = math.max(level, SousChef.Pantry[link] or 0) -- and across characters SousChef.settings.Pantry[link] = math.max(level, SousChef.Pantry[link] or 0) else -- if this is a special ingredient, record: -- type icon number if user wants type icons, 7 if ingredient is a flavoring, 8 otherwise (ie, ingredient is a spice) SousChef.Pantry[link] = SousChef.settings.typeIcon and typeIconLookup[name] or specialType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FLAVORING and 7 or 8 SousChef.settings.Pantry[link] = SousChef.settings.typeIcon and typeIconLookup[name] or specialType == PROVISIONER_SPECIAL_INGREDIENT_TYPE_FLAVORING and 7 or 8 end -- Store the recipe it's used in to the character reverseCookbook if not SousChef.ReverseCookbook[link] then SousChef.ReverseCookbook[link] = {} end AddRecipe(SousChef.ReverseCookbook[link], coloredName) -- ...and to the account-wide reverseCookbook if not SousChef.settings.ReverseCookbook[link] then SousChef.settings.ReverseCookbook[link] = {} end AddRecipe(SousChef.settings.ReverseCookbook[link], coloredName) end end end end SousChef:RefreshViews() end -- SousChefCreateSettings() creates the configuration menu for the add-on local function SousChefCreateSettings() local str = SousChef.Strings[SousChef.lang] local panelData = { type = "panel", name = "Sous Chef", displayName = "Sous Chef", author = "Wobin & KatKat42 & CrazyDutchGuy", version = SousChef.version, registerForRefresh = true, slashCommand = "/souschef", } LAM:RegisterAddonPanel("SousChefSettings", panelData) local optionsMenu = { [1] = { type = "header", name = str.MENU_RECIPE_HEADER, width = "full", }, [2] = { type = "checkbox", name = str.MENU_PROCESS_RECIPES, tooltip = str.MENU_PROCESS_RECIPES_TOOLTIP, getFunc = function() return SousChef.settings.processRecipes end, setFunc = function(value) SousChef.settings.processRecipes = value end, width = "full", }, [3] = { type = "dropdown", name = str.MENU_MARK_IF_KNOWN, tooltip = str.MENU_MARK_IF_KNOWN_TOOLTIP, choices = {str.MENU_KNOWN, str.MENU_UNKNOWN}, getFunc = function() if SousChef.settings.checkKnown == "known" then return str.MENU_KNOWN elseif SousChef.settings.checkKnown == "unknown" then return str.MENU_UNKNOWN else -- can't happen d("Yikes! MENU_MARK_IF_KNOWN getter") return str.MENU_UNKNOWN end end, setFunc = function(valueString) if valueString == str.MENU_KNOWN then SousChef.settings.checkKnown = "known" elseif valueString == str.MENU_UNKNOWN then SousChef.settings.checkKnown = "unknown" else -- can't happen d("Oops! MENU_MARK_IF_KNOWN setter") SousChef.settings.checkKnown = "unknown" end end, disabled = function() return not SousChef.settings.processRecipes end, }, [4] = { type = "checkbox", name = str.MENU_MARK_IF_ALT_KNOWS, tooltip = str.MENU_MARK_IF_ALT_KNOWS_TOOLTIP, getFunc = function() return SousChef.settings.markAlt end, setFunc = function(value) SousChef.settings.markAlt = value SousChef:RefreshViews() end, disabled = function() return (not SousChef.settings.processRecipes) or (SousChef.settings.checkKnown == "known") end, }, [5] = { type = "checkbox", name = str.MENU_TOOLTIP_IF_ALT_KNOWS, tooltip = str.MENU_TOOLTIP_IF_ALT_KNOWS_TOOLTIP, getFunc = function() return SousChef.settings.showAltKnowledge end, setFunc = function(value) SousChef.settings.showAltKnowledge = value SousChef:RefreshViews() end, disabled = function() return not SousChef.settings.processRecipes end, }, [6] = { type = "checkbox", name = str.MENU_MATCHER, tooltip = str.MENU_MATCHER_TOOLTIP, getFunc = function() return SousChef.settings.experimentalMatch end, setFunc = function(value) SousChef.settings.experimentalMatch = value end, disabled = function() return not SousChef.settings.processRecipes end, }, [7] = { type = "checkbox", name = str.MENU_SORT_PROVISIONING, tooltip = str.MENU_SORT_PROVISIONING_TOOLTIP, getFunc = function() return SousChef.settings.sortProvisioningTable end, setFunc = function(value) SousChef.settings.sortProvisioningTable = value if value then SousChef:HookGetRecipeInfo() else SousChef:UnhookGetRecipeInfo() end end, }, [8] = { type = "header", name = str.MENU_TOOLTIP_HEADER, width = "full", }, [9] = { type = "checkbox", name = str.MENU_TOOLTIP_CLICK, tooltip = str.MENU_TOOLTIP_CLICK_TOOLTIP, warning = str.MENU_RELOAD, getFunc = function() return SousChef.settings.showOnClick end, setFunc = function(value) SousChef.settings.showOnClick = value end, }, [10] = { type = "checkbox", name = str.MENU_RESULT_COUNTS, tooltip = str.MENU_RESULT_COUNTS_TOOLTIP, getFunc = function() return SousChef.settings.showCounts end, setFunc = function(value) SousChef.settings.showCounts = value end, }, [11] = { type = "checkbox", name = str.MENU_ALT_USE, tooltip = str.MENU_ALT_USE_TOOLTIP, getFunc = function() return SousChef.settings.showAltIngredientKnowledge end, setFunc = function(value) SousChef.settings.showAltIngredientKnowledge = value SousChef:RefreshViews() end, }, [12] = { type = "header", name = str.MENU_INDICATOR_HEADER, width = "full", }, [13] = { type = "checkbox", name = str.MENU_ICON_SET, tooltip = str.MENU_ICON_SET_TOOLTIP, getFunc = function() return SousChef.settings.boldIcon end, setFunc = function(value) SousChef.settings.boldIcon = value SousChef:RefreshViews() end, }, [14] = { type = "checkbox", name = str.MENU_SPECIAL_ICONS, tooltip = str.MENU_SPECIAL_ICONS_TOOLTIP, getFunc = function() return SousChef.settings.showSpecialIngredients end, setFunc = function(value) SousChef.settings.showSpecialIngredients = value SousChef.ParseRecipes() end, }, [15] = { type = "checkbox", name = str.MENU_SPECIAL_TYPES, tooltip = str.MENU_SPECIAL_TYPES_TOOLTIP, getFunc = function() return SousChef.settings.typeIcon end, setFunc = function(value) SousChef.settings.typeIcon = value SousChef.ParseRecipes() SousChef:RefreshViews() end, disabled = function() return not SousChef.settings.showSpecialIngredients end, }, [16] = { type = "colorpicker", name = str.MENU_INDICATOR_COLOR, tooltip = str.MENU_INDICATOR_COLOR_TOOLTIP, getFunc = function() return SousChef.settings.colour[1], SousChef.settings.colour[2], SousChef.settings.colour[3] end, setFunc = function(r,g,b) SousChef.settings.colour[1] = r SousChef.settings.colour[2] = g SousChef.settings.colour[3] = b SousChef:RefreshViews() end, }, [17] = { type = "colorpicker", name = str.MENU_SHOPPING_COLOR, tooltip = str.MENU_SHOPPING_COLOR_TOOLTIP, getFunc = function() return SousChef.settings.shoppingColour[1], SousChef.settings.shoppingColour[2], SousChef.settings.shoppingColour[3] end, setFunc = function(r,g,b) SousChef.settings.shoppingColour[1] = r SousChef.settings.shoppingColour[2] = g SousChef.settings.shoppingColour[3] = b SousChef:RefreshViews() end, }, [18] = { type = "checkbox", name = str.MENU_ONLY_MARK_SHOPPING, tooltip = str.MENU_ONLY_MARK_SHOPPING_TOOLTIP, getFunc = function() return SousChef.settings.onlyShowShopping end, setFunc = function(value) SousChef.settings.onlyShowShopping = value SousChef:RefreshViews() end, }, [19] = { type = "checkbox", name = str.MENU_SORT_INGREDIENTS, tooltip = str.MENU_SORT_INGREDIENTS_TOOLTIP, getFunc = function() return SousChef.settings.sortKnownIngredients end, setFunc = function(value) SousChef.settings.sortKnownIngredients = not SousChef.settings.sortKnownIngredients if not SousChef.settings.sortKnownIngredients then SousChef.UnregisterSort() else SousChef.SetupSort() end end, }, } LAM:RegisterOptionControls("SousChefSettings", optionsMenu) end -- SousChef_Loaded(eventCode, addOnName) runs when the EVENT_ADD_ON_LOADED event fires. local function SousChef_Loaded(eventCode, addOnName) if(addOnName ~= "SousChef") then return end -- default config settings local defaults = { --watching = true, checkKnown = "unknown", markAlt = false, colour = {1, 1, 1}, shoppingColour = {0,1,1}, Cookbook = {}, Pantry = {}, ReverseCookbook = {}, showAltKnowledge = false, showAltIngredientKnowledge = false, boldIcon = false, typeIcon = true, experimentalMatch = false, processRecipes = true, showSpecialIngredients = false, ignoredRecipes = {}, showOnClick = false, showCounts = true, shoppingList = {}, onlyShowShopping = false, qualityChecked = false, sortProvisioningTable = true, sortKnownIngredients = false } local localized = SousChef.Strings[SousChef.lang] -- Fetch the saved variables SousChef.settings = ZO_SavedVars:NewAccountWide("SousChef_Settings", 10, SousChef.lang, defaults) -- define some slash commands SLASH_COMMANDS['/scstats'] = function() d(localized.SC_NUM_RECIPES_KNOWN.. NonContiguousCount(SousChef.settings.Cookbook)) d(localized.SC_NUM_INGREDIENTS_TRACKED..NonContiguousCount(SousChef.settings.Pantry)) end SLASH_COMMANDS['/sciadd'] = SousChef.AddRecipeToIgnoreList SLASH_COMMANDS['/sciremove'] = SousChef.RemoveRecipeFromIgnoreList SLASH_COMMANDS['/scilist'] = SousChef.ListIgnoredRecipes -- initialize the configuration menu SousChefCreateSettings() -- parse the recipes this character knows, in a second zo_callLater(SousChef.ParseRecipes, 1000) SousChef:UpdateProvisioningTable() SousChef:HookGetRecipeInfo() if SousChef.settings.sortKnownIngredients then SousChef.SetupSort() end ZO_CreateStringId("SI_BINDING_NAME_SC_MARK_RECIPE", localized.KEY_MARK) -- Now we register for some events, and hook into the function that sets the details on the inventory slot zo_callLater(SousChef.HookEvents, 3000) end -- HookEvents() registers the add-on for some events function SousChef.HookEvents() -- let us know if we're opening a trading house, so we can look at its contents EVENT_MANAGER:RegisterForEvent("SousChefTrading", EVENT_TRADING_HOUSE_RESPONSE_RECEIVED, SousChef.HookTrading) -- let us know if we've learned a new recipe, so we can integrate it into our cookbook EVENT_MANAGER:RegisterForEvent("SousChefLearnt", EVENT_RECIPE_LEARNED, SousChef.ParseRecipes) -- let us know when we open a crafting station, so we can sort the recipe tree EVENT_MANAGER:RegisterForEvent("SousChefProvi", EVENT_CRAFTING_STATION_INTERACT, function(...) SousChef:HookRecipeTree(...) end) EVENT_MANAGER:RegisterForEvent("SousChefProviEnd", EVENT_END_CRAFTING_STATION_INTERACT, function() SousChef:UnhookRecipeTree() end) -- and finally, hook the opening of the inventory, bank, guild bank, and loot windows so we can add icons and hook the tooltips SousChef.HookInventory() end EVENT_MANAGER:RegisterForEvent("SousChefLoaded", EVENT_ADD_ON_LOADED, SousChef_Loaded)