--[[------------------------------------------------------------------ --SousChef.lua --Author: Wobin --v0.0.1 inspired by ingeniousclown's Research Assistant ------------------------------------------------------------------]]-- local LAM = LibStub:GetLibrary("LibAddonMenu-1.0") local BACKPACK = ZO_PlayerInventoryBackpack local BANK = ZO_PlayerBankBackpack local GUILD_BANK = ZO_GuildBankBackpack local GUILD_SHOP = ZO_TradingHouse local COOKING_RANK_1 = [[SousChef\media\One.dds]] local COOKING_RANK_2 = [[SousChef\media\Two.dds]] local COOKING_RANK_3 = [[SousChef\media\Three.dds]] local COOKING_RANK_4 = [[SousChef\media\Four.dds]] local COOKING_RANK_5 = [[SousChef\media\Five.dds]] local COOKING_RANK_6 = [[SousChef\media\Six.dds]] local COOKING_RANK_1B = [[SousChef\media\One_flat.dds]] local COOKING_RANK_2B = [[SousChef\media\Two_flat.dds]] local COOKING_RANK_3B = [[SousChef\media\Three_flat.dds]] local COOKING_RANK_4B = [[SousChef\media\Four_flat.dds]] local COOKING_RANK_5B = [[SousChef\media\Five_flat.dds]] local COOKING_RANK_6B = [[SousChef\media\Six_flat.dds]] local COOKING = { COOKING_RANK_1, COOKING_RANK_2, COOKING_RANK_3, COOKING_RANK_4, COOKING_RANK_5, COOKING_RANK_6 } local COOKINGB = { COOKING_RANK_1B, COOKING_RANK_2B, COOKING_RANK_3B, COOKING_RANK_4B, COOKING_RANK_5B, COOKING_RANK_6B } local CANLEARN = [[/esoui/art/loot/loot_finesseitem.dds]] local containerHooks = { INVENTORY_BACKPACK, INVENTORY_BANK, INVENTORY_GUILD_BANK } local itemQuality = { ITEM_QUALITY_MAGIC = { 0, 0, 1 }, ITEM_QUALITY_NORMAL = {1,1,1}, ITEM_QUALITY_ARCANE = {1, 0, 1}} local Pantry = {} local Cookbook = {} local ReverseCookbook = {} local settings = nil local slotLines = {} local hookedFunctions = {} local hookedDataFunction local function GetItemID(link) return tonumber(string.match(string.match(link, "%d+:"), "%d+")) end function EndsWith(String,End) return End=='' or string.sub(String,-string.len(End))==End end local function MatchInCookbook(bag, slot) return Cookbook[GetItemName(bag, slot):lower():gsub(" ","")] end local function MatchInGlobalCookbook(bag, slot) return settings.Cookbook[GetItemName(bag,slot):lower():gsub(" ", "")] end rowClicked = {} local function AddDetails(row) if not row.dataEntry or not row.dataEntry.data or rowClicked[row] then return false end local bagId = row.dataEntry.data.bagId local slotIndex = row.dataEntry.data.slotIndex if ((GetItemCraftingInfo(bagId, slotIndex)) ~= CRAFTING_TYPE_PROVISIONING) then return false end local usableIngredient = ReverseCookbook[GetItemID(GetItemLink(bagId, slotIndex))] if settings.showAltKnowledge then usableIngredient = settings.ReverseCookbook[GetItemID(GetItemLink(bagId, slotIndex))] end if usableIngredient then ItemTooltip:AddLine("Used in:") for i,v in ipairs(usableIngredient) do ItemTooltip:AddLine(v) end rowClicked[row] = true end return false end local function getIcon(row) local rankIcon = slotLines[row:GetName()] if(not rankIcon) then rankIcon = WINDOW_MANAGER:CreateControl(row:GetName() .. "SousChef", row, CT_TEXTURE) slotLines[row:GetName()] = rankIcon if row:GetOwningWindow():GetName() ~= "ZO_TradingHouse" then ZO_PreHookHandler(row, "OnMouseDown", AddDetails) ZO_PreHookHandler(row, "OnMouseExit", function(self) rowClicked[self] = nil end ) end end return rankIcon end local rowHandler = {} local function AddRankToSlot(row) local bagId = row.dataEntry.data.bagId local slotIndex = row.dataEntry.data.slotIndex local rankIcon = getIcon(row) -- Allow for ingeniousclown's Inventory Grid View if row:GetWidth() - row:GetHeight() < 5 then -- if we're mostly square rankIcon:SetDimensions(20,20) rankIcon:SetAnchor(TOPLEFT, row, TOPLEFT, 2) else rankIcon:SetDimensions(30, 30) rankIcon:SetAnchor(CENTER, row, CENTER, 200) end rankIcon:SetHidden(true) if ((GetItemCraftingInfo(bagId, slotIndex)) == CRAFTING_TYPE_PROVISIONING) then local texture = Pantry[GetItemID(GetItemLink(bagId, slotIndex))] if settings.showAltKnowledge then texture = settings.Pantry[GetItemID(GetItemLink(bagId, slotIndex))] end if texture then rankIcon:SetColor(settings.colour[1], settings.colour[2], settings.colour[3]) rankIcon:SetHidden(false) if settings.boldIcon then rankIcon:SetTexture(COOKINGB[texture]) else rankIcon:SetTexture(COOKING[texture]) end end else if GetItemType(bagId, slotIndex) == ITEMTYPE_RECIPE then local match = MatchInCookbook(bagId, slotIndex) local gmatch = MatchInGlobalCookbook(bagId, slotIndex) if (match and settings.checkKnown == "known") or (not match and settings.checkKnown == "unknown")then rankIcon:SetTexture(CANLEARN) rankIcon:SetHidden(false) if not match and gmatch and settings.checkKnown == "unknown" and settings.markAlt then rankIcon:SetColor(1,1,1,0.2) else rankIcon:SetColor(1,1,1,1) end end end end end local function AddTradingSlot(row, result) local rankIcon = getIcon(row) rankIcon:SetHidden(true) if EndsWith(result.name, GetString(SI_ITEMTYPE29)) then local match = Cookbook[result.name:lower():gsub(" ","")] local gmatch = settings.Cookbook[result.name:lower():gsub(" ","")] if (match and settings.checkKnown == "known") or (not match and settings.checkKnown == "unknown")then rankIcon:SetDimensions(30, 30) rankIcon:SetAnchor(CENTER, row, CENTER, 230) rankIcon:SetTexture(CANLEARN) rankIcon:SetHidden(false) if not match and gmatch and settings.checkKnown == "unknown" and settings.markAlt then rankIcon:SetColor(1,1,1,0.2) else rankIcon:SetColor(1,1,1,1) end end end end local function AddRecipe(Cookbook, link) for _,v in pairs(Cookbook) do if v == link then return end end table.insert(Cookbook, link) end local function 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 Cookbook[(GetRecipeResultItemInfo(listIndex, recipeIndex)):gsub(" ",""):lower() .. "recipe"] = true settings.Cookbook[(GetRecipeResultItemInfo(listIndex, recipeIndex)):gsub(" ",""):lower() .. "recipe"] = true local _, _, ingredientCount, level = GetRecipeInfo(listIndex, recipeIndex) for ingredientIndex = 1, ingredientCount do local link = GetItemID(GetRecipeIngredientItemLink(listIndex, recipeIndex, ingredientIndex, LINK_STYLE_NORMAL)) -- Store the fact that the ingredient is used Pantry[link] = level settings.Pantry[link] = level -- Store the recipe it's used in if not ReverseCookbook[link] then ReverseCookbook[link] = {} end AddRecipe(ReverseCookbook[link], GetRecipeResultItemLink(listIndex, recipeIndex, LINK_STYLE_BRACKETS)) -- Store the global reference if not settings.ReverseCookbook[link] then settings.ReverseCookbook[link] = {} end AddRecipe(settings.ReverseCookbook[link], GetRecipeResultItemLink(listIndex, recipeIndex, LINK_STYLE_BRACKETS)) end end end end end local function SousChefCreateSettings() local panel = LAM:CreateControlPanel("SousChef", "Sous Chef") LAM:AddHeader(panel, "SousChef_General", "Settings") LAM:AddDropdown(panel, "markLearnt", "Mark if recipes are ", "How do you want Sous Chef to indicate your knowledge of a recipe?", {"known", "unknown"}, function() return settings.checkKnown end, function(valueString) settings.checkKnown = valueString end) LAM:AddCheckbox(panel, "markAltKnows", "Alternate Character Check", "Indicate if an alt knows the recipe on unknown recipes. Will only work if the above setting is set to 'unknown'", function() return settings.markAlt end, function(value) settings.markAlt = not settings.markAlt end) LAM:AddCheckbox(panel, "showAltKnows", "Alternate Character Recipe Knowledge", "Show rank indicators on alts for all recipe knowledge of all alternate characters", function() return settings.showAltKnowledge end, function(value) settings.showAltKnowledge = not settings.showAltKnowledge end) LAM:AddCheckbox(panel, "useBold", "Use bolder icons", "Swap out rank icon to a more flat display", function() return settings.boldIcon end, function(value) settings.boldIcon = not settings.boldIcon end) LAM:AddColorPicker(panel, "setColour", "Indicator colour", "Allows you to set the colour of the indicator", function() return settings.colour[1], settings.colour[2], settings.colour[3] end, function(r,g,b) settings.colour[1] = r; settings.colour[2] = g; settings.colour[3] = b end) end local function HookTrading(...) if hookedDataFunction then return end hookedDataFunction = ZO_TradingHouseItemPaneSearchResults.dataTypes[1].setupCallback ZO_TradingHouseItemPaneSearchResults.dataTypes[1].setupCallback = function(...) local row, data = ... hookedDataFunction(...) AddTradingSlot(row, data) end end local function SousChef_Loaded(eventCode, addOnName) if(addOnName ~= "SousChef") then return end local defaults = { watching = true, checkKnown = "unknown", markAlt = false, colour = {1, 1, 1}, Cookbook = {}, Pantry = {}, ReverseCookbook = {}, showAltKnowledge = false, boldIcon = false } settings = ZO_SavedVars:NewAccountWide("SousChef_Settings", 5, nil, defaults) SLASH_COMMANDS["/SCDebug"] = function() d("Debug mode on") SCCookbook = Cookbook SCRCookbook = ReverseCookbook SCPantry = Pantry SCslotList = slotLines SCsettings = settings end local function tablelength(T) local count = 0 for _ in pairs(T) do count = count + 1 end return count end SLASH_COMMANDS['/scstats'] = function() d("Number of recipes known: ".. tablelength(settings.Cookbook)) d("Number of ingredients tracked: "..tablelength(settings.Pantry)) end SousChefCreateSettings() ParseRecipes() -- Now we want to hook into the function that sets the details on the inventory slot for _,v in pairs(PLAYER_INVENTORY.inventories) do local listView = v.listView if listView and listView.dataTypes and listView.dataTypes[1] then hookedFunctions = listView.dataTypes[1].setupCallback listView.dataTypes[1].setupCallback = function(rowControl, slot) hookedFunctions(rowControl, slot) AddRankToSlot(rowControl) end end end ZO_ScrollList_RefreshVisible(BACKPACK) ZO_ScrollList_RefreshVisible(BANK) ZO_ScrollList_RefreshVisible(GUILD_BANK) EVENT_MANAGER:RegisterForEvent("SousChefTRading", EVENT_TRADING_HOUSE_RESPONSE_RECEIVED, HookTrading) end local function SousChef_Initialized() EVENT_MANAGER:RegisterForEvent("SousChefLoaded", EVENT_ADD_ON_LOADED, SousChef_Loaded) end SousChef_Initialized()