From fc7ddc1ba3be8bcdb08bdce5469d6b9e6439cf71 Mon Sep 17 00:00:00 2001 From: Ade <923+ade@noreply.octowow.st> Date: Wed, 14 Oct 2026 11:48:22 +0000 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=B2=20=C2=AB?= =?UTF-8?q?/=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- recipes.lua | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++ scan.lua | 2 +- 2 files changed, 175 insertions(+), 1 deletion(-) create mode 100644 recipes.lua diff --git a/recipes.lua b/recipes.lua new file mode 100644 index 0000000..5aa37ea --- /dev/null +++ b/recipes.lua @@ -0,0 +1,174 @@ +-- Ade Alts: recipes (index over the bundled recipe database + known / missing lists) +local AA = AdeAlts + +local SPELLSRC = { A = "Learned automatically", Q = "Quest", T = "Trainer", W = "World object" } +local RECSRC = { + C = "Chest", E = "Crafted by an engineer", D = "Drop", F = "Fishing", + G = "Gift", P = "Pickpocketing", Q = "Quest", V = "Vendor", +} + +-- craft record: { spellId, name, skill, spellSources, resultItem, minCharLevel, { {recipeItem, quality, sources}, ... } } +function AA.RIndex() + if AA.ridx then return AA.ridx end + local idx = { byName = {}, byItem = {}, byAny = {} } + for prof, list in pairs(AA.RDATA) do + local bn = {} + idx.byName[prof] = bn + for _, cr in ipairs(list) do + local key = string.lower(cr[2]) + if not bn[key] then bn[key] = cr end + if not idx.byAny[key] then idx.byAny[key] = {} end + table.insert(idx.byAny[key], { prof = prof, c = cr }) + if cr[7] then + for _, rc in ipairs(cr[7]) do + if not idx.byItem[rc[1]] then idx.byItem[rc[1]] = {} end + table.insert(idx.byItem[rc[1]], { prof = prof, c = cr }) + end + end + end + end + AA.ridx = idx + return idx +end + +-- "Trainer", "Vendor, Quest", ... +function AA.CraftSource(cr) + local seen, out = {}, {} + local function add(txt) + if txt and not seen[txt] then + seen[txt] = true + table.insert(out, txt) + end + end + for ch in string.gfind(cr[4] or "", ".") do add(SPELLSRC[ch]) end + if cr[7] then + for _, rc in ipairs(cr[7]) do + for ch in string.gfind(rc[3] or "", ".") do add(RECSRC[ch]) end + end + end + if table.getn(out) == 0 then return "Unknown" end + return table.concat(out, ", ") +end + +-- known / missing list of one profession of one character +-- mode: "known" | "missing" sort: "level" | "name" +function AA.RecipeList(c, prof, mode, sort) + local idx = AA.RIndex() + local pr = c and c.prof and c.prof[prof] + local rec = (pr and pr.rec) or {} + local known = {} + for _, n in ipairs(rec) do known[string.lower(n)] = true end + local out = {} + if mode == "missing" then + local seen = {} + for _, cr in ipairs(AA.RDATA[prof] or {}) do + local key = string.lower(cr[2]) + if not known[key] and not seen[key] then + seen[key] = true + table.insert(out, { name = cr[2], skill = cr[3], cr = cr, prof = prof }) + end + end + else + local bn = idx.byName[prof] + for _, n in ipairs(rec) do + local cr = bn and bn[string.lower(n)] + table.insert(out, { name = n, skill = cr and cr[3] or 0, cr = cr, known = true, prof = prof }) + end + end + local function lv(e) if e.skill == 0 then return 9999 end return e.skill end + if sort == "name" then + table.sort(out, function(a, b) return a.name < b.name end) + else + table.sort(out, function(a, b) + local la, lb = lv(a), lv(b) + if la ~= lb then return la < lb end + return a.name < b.name + end) + end + return out +end + +-- number of known / missing recipes (nil when the recipe list was never scanned or no data exists) +function AA.RecipeCounts(c, prof) + local pr = c and c.prof and c.prof[prof] + if not pr or not pr.rec or not AA.RDATA[prof] then return nil end + local miss = table.getn(AA.RecipeList(c, prof, "missing", "name")) + return table.getn(pr.rec), miss +end + +-- colour of a recipe level: known recipes by distance to the current skill, missing ones by learnability +function AA.RecipeColor(e, rank) + if e.skill == 0 then return "|cff808080" end + rank = rank or 0 + if e.known then + local d = rank - e.skill + if d < 15 then return "|cffff8040" elseif d < 30 then return "|cffffff00" + elseif d < 45 then return "|cff40c040" end + return "|cff808080" + end + if e.skill > rank then return "|cffff4040" end + return "|cff40ff40" +end + +-- the recipe tooltip (known / missing lists) +function AA.RecipeTip(row) + local e = row.entry + if not e then return end + local c = AA.db.chars[AA.selKey or ""] + GameTooltip:SetOwner(row, "ANCHOR_RIGHT") + local cr = e.cr + local shown = false + if cr and cr[5] and cr[5] > 0 then + shown = pcall(GameTooltip.SetHyperlink, GameTooltip, "item:" .. cr[5]) and GameTooltip:NumLines() > 0 + end + if not shown then + GameTooltip:ClearLines() + GameTooltip:AddLine(e.name, 1, 1, 1) + end + GameTooltip:AddLine(" ") + local pr = c and c.prof and c.prof[e.prof] + local rank = pr and pr.r or 0 + if e.skill > 0 then + if e.skill > rank then + GameTooltip:AddLine("Requires " .. e.prof .. " (" .. e.skill .. ") - skill " .. rank, 1, 0.3, 0.3) + else + GameTooltip:AddLine("Requires " .. e.prof .. " (" .. e.skill .. ")", 0.4, 1, 0.4) + end + end + if cr and cr[6] and cr[6] > 0 then + GameTooltip:AddLine("Requires character level " .. cr[6], 1, 1, 1) + end + if cr then + GameTooltip:AddLine("Source: " .. AA.CraftSource(cr), 1, 0.82, 0) + if cr[7] then + for _, rc in ipairs(cr[7]) do + local nm, link + local ok, a, b = pcall(GetItemInfo, rc[1]) + if ok then nm, link = a, b end + GameTooltip:AddLine(" " .. (link or nm or ("recipe item #" .. rc[1])), 1, 1, 1) + end + end + end + -- what the other alts with this profession know + local lines = 0 + local key = string.lower(e.name) + for _, k in ipairs(AA.SortedAlts and AA.SortedAlts() or {}) do + local ch = AA.db.chars[k] + local p2 = ch and ch.prof and ch.prof[e.prof] + if p2 and p2.rec and lines < 12 then + local has = false + for _, n in ipairs(p2.rec) do if string.lower(n) == key then has = true; break end end + if lines == 0 then GameTooltip:AddLine(" ") end + lines = lines + 1 + local col = "|cff" .. AA.ClassHex(ch.class) + if has then + GameTooltip:AddLine(col .. ch.name .. "|r |cff40ff40knows it|r") + elseif e.skill > (p2.r or 0) then + GameTooltip:AddLine(col .. ch.name .. "|r |cffff6060needs " .. e.skill .. " (has " .. (p2.r or 0) .. ")|r") + else + GameTooltip:AddLine(col .. ch.name .. "|r |cffffd100can learn now|r") + end + end + end + GameTooltip:Show() +end diff --git a/scan.lua b/scan.lua index ac0f86c..40019e1 100644 --- a/scan.lua +++ b/scan.lua @@ -358,7 +358,7 @@ end local PROFN = { ["Alchemy"] = 1, ["Blacksmithing"] = 1, ["Enchanting"] = 1, ["Engineering"] = 1, ["Herbalism"] = 1, ["Leatherworking"] = 1, ["Mining"] = 1, ["Skinning"] = 1, ["Tailoring"] = 1, - ["Cooking"] = 1, ["First Aid"] = 1, ["Fishing"] = 1, ["Survival"] = 1, + ["Cooking"] = 1, ["First Aid"] = 1, ["Fishing"] = 1, ["Survival"] = 1, ["Jewelcrafting"] = 1, } local function ScanSkills() if not AA.me or not GetNumSkillLines then return false end