From 5030c2a48706402f95a32311b291b60c549c7bac Mon Sep 17 00:00:00 2001 From: John Pasula Date: Thu, 24 Mar 2011 07:35:47 -0600 Subject: [PATCH] core.lua -> Core.lua. This has been annoying me for ages. :) --- AckisRecipeList.toc | 2 +- Core.lua | 1466 +++++++++++++++++++++++++++++++++++++++++++++++++++ core.lua | 1466 --------------------------------------------------- 3 files changed, 1467 insertions(+), 1467 deletions(-) create mode 100644 Core.lua delete mode 100644 core.lua diff --git a/AckisRecipeList.toc b/AckisRecipeList.toc index cdbb959..0690634 100644 --- a/AckisRecipeList.toc +++ b/AckisRecipeList.toc @@ -65,7 +65,7 @@ locale.xml # Constants should be loaded first - many files use them in their main chunk. Constants.lua -core.lua +Core.lua Recipe.lua Config.lua Waypoint.lua diff --git a/Core.lua b/Core.lua new file mode 100644 index 0000000..0774586 --- /dev/null +++ b/Core.lua @@ -0,0 +1,1466 @@ +--[[ +************************************************************************ +core.lua +Core functions for Ackis Recipe List +************************************************************************ +File date: @file-date-iso@ +File hash: @file-abbreviated-hash@ +Project hash: @project-abbreviated-hash@ +Project version: @project-version@ +************************************************************************ +Please see http://www.wowace.com/addons/arl/ for more information. +************************************************************************ +This source code is released under All Rights Reserved. +************************************************************************ +--- Ackis Recipe List provides functionality to scan your professions. +-- It will determine which recipes you are missing. +-- @class file +-- @name core.lua +-- @release 2.0 +************************************************************************ +]] + +------------------------------------------------------------------------------- +-- Localized Lua globals. +------------------------------------------------------------------------------- +local _G = getfenv(0) + +-- Functions +local pairs, ipairs = _G.pairs, _G.ipairs +local select = _G.select +local tonumber, tostring = _G.tonumber, _G.tostring +local type = _G.type + +-- Libraries +local bit = _G.bit +local string = _G.string +local table = _G.table + +------------------------------------------------------------------------------- +-- AddOn namespace. +------------------------------------------------------------------------------- +local FOLDER_NAME, private = ... +private.addon_name = "Ackis Recipe List" + +local LibStub = _G.LibStub +local addon = LibStub("AceAddon-3.0"):NewAddon(private.addon_name, "AceConsole-3.0", "AceEvent-3.0") +_G.AckisRecipeList = addon + +--@alpha@ +_G.ARL = addon +--@end-alpha@ + +local L = LibStub("AceLocale-3.0"):GetLocale(private.addon_name) +local BFAC = LibStub("LibBabble-Faction-3.0"):GetLookupTable() + +local debugger = _G.tekDebug and _G.tekDebug:GetFrame(private.addon_name) + +private.build_num = select(2, _G.GetBuildInfo()) + +private.custom_list = {} +private.mob_list = {} +private.quest_list = {} +private.recipe_list = {} +private.reputation_list = {} +private.trainer_list = {} +private.seasonal_list = {} +private.vendor_list = {} +private.location_list = {} +private.acquire_list = {} + +------------------------------------------------------------------------------ +-- Constants. +------------------------------------------------------------------------------ +local PROFESSION_INIT_FUNCS = {} + +------------------------------------------------------------------------------ +-- Database tables +------------------------------------------------------------------------------ +local AllSpecialtiesTable = {} +local SpecialtyTable + +-- Filter flags and acquire types - defined in Constants.lua +local F = private.filter_flags +local A = private.acquire_types + +-- Global Frame Variables +addon.optionsFrame = {} + +------------------------------------------------------------------------------- +-- Check to see if we have mandatory libraries loaded. If not, notify the user +-- which are missing and return. +------------------------------------------------------------------------------- +local MissingLibraries +do + local REQUIRED_LIBS = { + "AceLocale-3.0", + "LibBabble-Boss-3.0", + "LibBabble-Faction-3.0", + "LibBabble-Zone-3.0", + } + function MissingLibraries() + local missing = false + + for idx, lib in ipairs(REQUIRED_LIBS) do + if not LibStub:GetLibrary(lib, true) then + missing = true + addon:Print(L["MISSING_LIBRARY"]:format(lib)) + end + end + return missing + end +end -- do + +if MissingLibraries() then + --@debug@ + addon:Print("You are using a development version of ARL. As per WowAce standards, externals are not set up. You will have to install all necessary libraries in order for the addon to function correctly.") + --@end-debug@ + _G.AckisRecipeList = nil + return +end + +------------------------------------------------------------------------------- +-- Define the static popups we're going to call when people haven't scanned or +-- when current filters are blocking all recipes from being displayed. +------------------------------------------------------------------------------- +_G.StaticPopupDialogs["ARL_NOTSCANNED"] = { + text = L["NOTSCANNED"], + button1 = _G.OKAY, + timeout = 0, + exclusive = 1, + whileDead = 1, + hideOnEscape = 1 +} + +_G.StaticPopupDialogs["ARL_ALLFILTERED"] = { + text = L["ALL_FILTERED"], + button1 = _G.OKAY, + timeout = 0, + exclusive = 1, + whileDead = 1, + hideOnEscape = 1 +} + +_G.StaticPopupDialogs["ARL_ALLKNOWN"] = { + text = L["ARL_ALLKNOWN"], + button1 = _G.OKAY, + timeout = 0, + exclusive = 1, + whileDead = 1, + hideOnEscape = 1 +} + +_G.StaticPopupDialogs["ARL_ALLEXCLUDED"] = { + text = L["ARL_ALLEXCLUDED"], + button1 = _G.OKAY, + timeout = 0, + exclusive = 1, + whileDead = 1, + hideOnEscape = 1 +} + +_G.StaticPopupDialogs["ARL_SEARCHFILTERED"] = { + text = L["ARL_SEARCHFILTERED"], + button1 = _G.OKAY, + timeout = 0, + exclusive = 1, + whileDead = 1, + hideOnEscape = 1 +} + +------------------------------------------------------------------------------- +-- Close all possible pop-up windows +------------------------------------------------------------------------------- +function addon:ClosePopups() + _G.StaticPopup_Hide("ARL_NOTSCANNED") + _G.StaticPopup_Hide("ARL_ALLFILTERED") + _G.StaticPopup_Hide("ARL_ALLKNOWN") + _G.StaticPopup_Hide("ARL_ALLEXCLUDED") + _G.StaticPopup_Hide("ARL_SEARCHFILTERED") +end + +------------------------------------------------------------------------------- +-- Functions common to most files in the AddOn. +------------------------------------------------------------------------------- +function private.SetTextColor(color_code, text) + return ("|cff%s%s|r"):format(color_code or "ffffff", text) +end + +------------------------------------------------------------------------------- +-- Debugger. +------------------------------------------------------------------------------- +function addon:Debug(...) + if debugger then + debugger:AddMessage(string.format(...)) + else + --@debug@ + self:Printf(...) + --@end-debug@ + end +end + +do + local output = {} + + function addon:DumpMembers(match) + table.wipe(output) + table.insert(output, "Addon Object members.\n") + + local count = 0 + + for key, value in pairs(self) do + local val_type = type(value) + + if not match or val_type == match then + table.insert(output, ("%s (%s)"):format(key, val_type)) + count = count + 1 + end + end + table.insert(output, ("\n%d found\n"):format(count)) + self:DisplayTextDump(nil, nil, table.concat(output, "\n")) + end +end -- do + +------------------------------------------------------------------------------- +-- Initialization functions +------------------------------------------------------------------------------- +function addon:OnInitialize() + -- Set default options, which are to include everything in the scan + local defaults = { + global = { + -- Saving alts tradeskills (needs to be global so all profiles can access it) + tradeskill = {}, + }, + profile = { + ------------------------------------------------------------------------------- + -- Frame options + ------------------------------------------------------------------------------- + frameopts = { + offsetx = 0, + offsety = 0, + anchorTo = "", + anchorFrom = "", + uiscale = 1, + small_list_font = true, + }, + + ------------------------------------------------------------------------------- + -- Tooltip Options + ------------------------------------------------------------------------------- + tooltip = { + scale = 1, + acquire_fontsize = 11, + }, + ------------------------------------------------------------------------------- + -- Sorting Options + ------------------------------------------------------------------------------- + sorting = "Ascending", + current_tab = 3, -- Name tab + skill_view = false, -- Sort the recipes by skill level instead of name? + + ------------------------------------------------------------------------------- + -- Display Options + ------------------------------------------------------------------------------- + includefiltered = false, + includeexcluded = false, + closeguionskillclose = false, + ignoreexclusionlist = false, + scanbuttonlocation = "TR", + spelltooltiplocation = "Right", + acquiretooltiplocation = "Right", + recipes_in_tooltips = true, + max_recipes_in_tooltips = 10, + hide_tooltip_hint = false, + hidepopup = false, + minimap = true, + worldmap = true, + autoscanmap = false, + scantrainers = false, + scanvendors = false, + autoloaddb = false, + maptrainer = false, + mapvendor = true, + mapmob = true, + mapquest = true, + + ------------------------------------------------------------------------------- + -- Text Dump Options + ------------------------------------------------------------------------------- + textdumpformat = "BBCode", + + ------------------------------------------------------------------------------- + -- Recipe Exclusion + ------------------------------------------------------------------------------- + exclusionlist = {}, + + ------------------------------------------------------------------------------- + -- Filter Options + ------------------------------------------------------------------------------- + filters = { + ------------------------------------------------------------------------------- + -- General Filters + ------------------------------------------------------------------------------- + general = { + faction = true, + specialty = false, + skill = true, + known = false, + unknown = true, + retired = false, + }, + ------------------------------------------------------------------------------- + -- Obtain Filters + ------------------------------------------------------------------------------- + obtain = { + trainer = true, + vendor = true, + instance = true, + raid = true, + seasonal = true, + quest = true, + pvp = true, + discovery = true, + worlddrop = true, + mobdrop = true, + achievement = true, + expansion0 = true, + expansion1 = true, + expansion2 = true, + expansion3 = true, + }, + ------------------------------------------------------------------------------- + -- Item Filters (Armor/Weapon) + ------------------------------------------------------------------------------- + item = { + armor = { + cloth = true, + leather = true, + mail = true, + plate = true, + trinket = true, + cloak = true, + ring = true, + necklace = true, + shield = true, + }, + weapon = { + onehand = true, + twohand = true, + axe = true, + sword = true, + mace = true, + polearm = true, + dagger = true, + fist = true, + staff = true, + wand = true, + thrown = true, + bow = true, + crossbow = true, + ammo = true, + gun = true, + }, + }, + ------------------------------------------------------------------------------- + -- Quality Filters + ------------------------------------------------------------------------------- + quality = { + common = true, + uncommon = true, + rare = true, + epic = true, + }, + ------------------------------------------------------------------------------- + -- Binding Filters + ------------------------------------------------------------------------------- + binding = { + itemboe = true, + itembop = true, + recipebop = true, + recipeboe = true, + }, + ------------------------------------------------------------------------------- + -- Player Role Filters + ------------------------------------------------------------------------------- + player = { + melee = true, + tank = true, + healer = true, + caster = true, + }, + ------------------------------------------------------------------------------- + -- Reputation Filters + ------------------------------------------------------------------------------- + rep = { + aldor = true, + scryer = true, + argentdawn = true, + ashtonguedeathsworn = true, + cenarioncircle = true, + cenarionexpedition = true, + consortium = true, + hellfire = true, + keepersoftime = true, + nagrand = true, + lowercity = true, + scaleofthesands = true, + shatar = true, + shatteredsun = true, + sporeggar = true, + thoriumbrotherhood = true, + timbermaw = true, + violeteye = true, + zandalar = true, + argentcrusade = true, + frenzyheart = true, + ebonblade = true, + kirintor = true, + sonsofhodir = true, + kaluak = true, + oracles = true, + wyrmrest = true, + wrathcommon1 = true, + wrathcommon2 = true, + wrathcommon3 = true, + wrathcommon4 = true, + wrathcommon5 = true, + ashenverdict = true, + catacommon1 = true, + catacommon2 = true, + guardiansofhyjal = true, + ramkahen = true, + earthenring = true, + therazane = true, + }, + ------------------------------------------------------------------------------- + -- Class Filters + ------------------------------------------------------------------------------- + classes = { + deathknight = true, + druid = true, + hunter = true, + mage = true, + paladin = true, + priest = true, + rogue = true, + shaman = true, + warlock = true, + warrior = true, + }, + } + } + } + self.db = LibStub("AceDB-3.0"):New("ARLDB2", defaults) + + if not self.db then + self:Print("Error: Database not loaded correctly. Please exit out of WoW and delete the ARL database file (AckisRecipeList.lua) found in: \\World of Warcraft\\WTF\\Account\\>\\SavedVariables\\") + return + end + local version = _G.GetAddOnMetadata("AckisRecipeList", "Version") + local debug_version = false + local alpha_version = false + + -- @debug@ + debug_version = true + -- @end-debug + + -- @alpha@ + alpha_version = true + -- @end-alpha@ + + version = debug_version and "Devel" or (alpha_version and version .. "-Alpha") or version + + self.version = version + + self:SetupOptions() + + -- Register slash commands + self:RegisterChatCommand("arl", "ChatCommand") + self:RegisterChatCommand("ackisrecipelist", "ChatCommand") + + ------------------------------------------------------------------------------- + -- Create the scan button + ------------------------------------------------------------------------------- + local scan_button = _G.CreateFrame("Button", nil, _G.UIParent, "UIPanelButtonTemplate") + scan_button:SetHeight(20) + + scan_button:RegisterForClicks("LeftButtonUp") + scan_button:SetScript("OnClick", + function(self, button, down) + local cur_profession = _G.GetTradeSkillLine() + local MainPanel = addon.Frame + local prev_profession + + if MainPanel then + prev_profession = MainPanel.prof_name or private.ordered_professions[MainPanel.profession] + end + + local shift_key = _G.IsShiftKeyDown() + local alt_key = _G.IsAltKeyDown() + local ctrl_key = _G.IsControlKeyDown() + + if shift_key and not alt_key and not ctrl_key then + addon:Scan(true) + elseif alt_key and not shift_key and not ctrl_key then + addon:ClearWaypoints() + elseif ctrl_key and not shift_key and not alt_key then + local current_prof = _G.GetTradeSkillLine() + addon:DumpProfession(current_prof) + elseif not shift_key and not alt_key and not ctrl_key then + if MainPanel and MainPanel:IsVisible() and prev_profession == cur_profession then + MainPanel:Hide() + else + addon:Scan(false) + addon:AddWaypoint() + end + end + end) + + scan_button:SetScript("OnEnter", + function(self) + local tooltip = _G.GameTooltip + + _G.GameTooltip_SetDefaultAnchor(tooltip, self) + tooltip:SetText(L["SCAN_RECIPES_DESC"]) + tooltip:Show() + end) + scan_button:SetScript("OnLeave", function() _G.GameTooltip:Hide() end) + scan_button:SetText(L["Scan"]) + + self.scan_button = scan_button + + ------------------------------------------------------------------------------- + -- Populate the profession initialization functions. + ------------------------------------------------------------------------------- + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51304)] = addon.InitAlchemy + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51300)] = addon.InitBlacksmithing + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51296)] = addon.InitCooking + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51313)] = addon.InitEnchanting + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51306)] = addon.InitEngineering + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(45542)] = addon.InitFirstAid + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51302)] = addon.InitLeatherworking + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(32606)] = addon.InitSmelting + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51309)] = addon.InitTailoring + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51311)] = addon.InitJewelcrafting + PROFESSION_INIT_FUNCS[_G.GetSpellInfo(45363)] = addon.InitInscription + PROFESSION_INIT_FUNCS[private.runeforging_name] = addon.InitRuneforging + + ------------------------------------------------------------------------------- + -- Hook GameTooltip so we can show information on mobs that drop/sell/train + ------------------------------------------------------------------------------- + _G.GameTooltip:HookScript("OnTooltipSetUnit", + function(self) + if not addon.db.profile.recipes_in_tooltips then + return + end + local name, unit = self:GetUnit() + + if not unit then + return + end + local guid = _G.UnitGUID(unit) + + if not guid then + return + end + local GUID = tonumber(string.sub(guid, -12, -9), 16) + local unit = private.mob_list[GUID] or private.vendor_list[GUID] or private.trainer_list[GUID] + + if not unit or not unit.item_list then + return + end + local player = private.Player + local recipe_list = private.recipe_list + local shifted = _G.IsShiftKeyDown() + local count = 0 + + for spell_id in pairs(unit.item_list) do + local recipe = recipe_list[spell_id] + local recipe_prof = _G.GetSpellInfo(recipe.profession) + local scanned = player.has_scanned[recipe_prof] + + if scanned then + local skill_level = player.professions[recipe_prof] + local has_level = skill_level and (type(skill_level) == "boolean" and true or skill_level >= recipe.skill_level) + + if ((not recipe:HasState("KNOWN") and has_level) or shifted) and player:HasRecipeFaction(recipe) then + local _, _, _, hex = _G.GetItemQualityColor(recipe.quality) + + self:AddLine(("%s: %s%s|r (%d)"):format(recipe.profession, hex, recipe.name, recipe.skill_level)) + count = count + 1 + end + end + + if count >= addon.db.profile.max_recipes_in_tooltips then + break + end + end + end) +end + +---Function run when the addon is enabled. Registers events and pre-loads certain variables. +function addon:OnEnable() + self:RegisterEvent("TRADE_SKILL_SHOW") -- Make addon respond to the tradeskill windows being shown + self:RegisterEvent("TRADE_SKILL_CLOSE") -- Addon responds to tradeskill windows being closed. + self:RegisterEvent("TRADE_SKILL_UPDATE") + + if addon.db.profile.scantrainers then + self:RegisterEvent("TRAINER_SHOW") + end + + if addon.db.profile.scanvendors then + self:RegisterEvent("MERCHANT_SHOW") + end + + ------------------------------------------------------------------------------- + -- Set the parent and scripts for addon.scan_button. + ------------------------------------------------------------------------------- + local scan_button = self.scan_button + + if _G.Skillet and _G.Skillet:IsActive() then + scan_button:SetParent(_G.SkilletFrame) + _G.Skillet:AddButtonToTradeskillWindow(scan_button) + scan_button:SetWidth(80) + elseif _G.MRTAPI then + _G.MRTAPI:RegisterHandler("TradeSkillWindowOnShow", + function() + scan_button:SetParent(_G.MRTSkillFrame) + scan_button:ClearAllPoints() + scan_button:SetPoint("RIGHT", _G.MRTSkillFrameCloseButton, "LEFT", 4, 0) + scan_button:SetWidth(scan_button:GetTextWidth() + 10) + scan_button:Show() + end) + elseif _G.ATSWFrame then + scan_button:SetParent(_G.ATSWFrame) + scan_button:ClearAllPoints() + + if _G.TradeJunkieMain and _G.TJ_OpenButtonATSW then + scan_button:SetPoint("RIGHT", _G.TJ_OpenButtonATSW, "LEFT", 0, 0) + else + scan_button:SetPoint("RIGHT", _G.ATSWOptionsButton, "LEFT", 0, 0) + end + scan_button:SetHeight(_G.ATSWOptionsButton:GetHeight()) + scan_button:SetWidth(_G.ATSWOptionsButton:GetWidth()) + elseif _G.CauldronFrame then + scan_button:SetParent(_G.CauldronFrame) + scan_button:ClearAllPoints() + scan_button:SetPoint("TOP", _G.CauldronFrame, "TOPRIGHT", -58, -52) + scan_button:SetWidth(90) + elseif _G.BPM_ShowTrainerFrame then + scan_button:SetParent(_G.BPM_ShowTrainerFrame) + scan_button:ClearAllPoints() + scan_button:SetPoint("RIGHT", _G.BPM_ShowTrainerFrame, "LEFT", 4, 0) + scan_button:SetWidth(scan_button:GetTextWidth() + 10) + scan_button:Show() + end + + local buttonparent = scan_button:GetParent() + local framelevel = buttonparent:GetFrameLevel() + local framestrata = buttonparent:GetFrameStrata() + + -- Set the frame level of the button to be 1 deeper than its parent + scan_button:SetFrameLevel(framelevel + 1) + scan_button:SetFrameStrata(framestrata) + scan_button:Enable() + + -- Add an option so that ARL will work with Manufac + if _G.Manufac then + _G.Manufac.options.args.ARLScan = { + type = 'execute', + name = L["Scan"], + desc = L["SCAN_RECIPES_DESC"], + func = function() addon:Scan(false) end, + order = 550, + } + end + private.Player:Initialize() + + ------------------------------------------------------------------------------- + -- Initialize the SpecialtyTable and AllSpecialtiesTable. + ------------------------------------------------------------------------------- + do + local AlchemySpec = { + [_G.GetSpellInfo(28674)] = 28674, + [_G.GetSpellInfo(28678)] = 28678, + [_G.GetSpellInfo(28676)] = 28676, + } + + local BlacksmithSpec = { + [_G.GetSpellInfo(9788)] = 9788, -- Armorsmith + [_G.GetSpellInfo(17041)] = 17041, -- Master Axesmith + [_G.GetSpellInfo(17040)] = 17040, -- Master Hammersmith + [_G.GetSpellInfo(17039)] = 17039, -- Master Swordsmith + [_G.GetSpellInfo(9787)] = 9787, -- Weaponsmith + } + + local EngineeringSpec = { + [_G.GetSpellInfo(20219)] = 20219, -- Gnomish + [_G.GetSpellInfo(20222)] = 20222, -- Goblin + } + + local LeatherworkSpec = { + [_G.GetSpellInfo(10657)] = 10657, -- Dragonscale + [_G.GetSpellInfo(10659)] = 10659, -- Elemental + [_G.GetSpellInfo(10661)] = 10661, -- Tribal + } + + local TailorSpec = { + [_G.GetSpellInfo(26797)] = 26797, -- Spellfire + [_G.GetSpellInfo(26801)] = 26801, -- Shadoweave + [_G.GetSpellInfo(26798)] = 26798, -- Primal Mooncloth + } + + SpecialtyTable = { + [_G.GetSpellInfo(51304)] = AlchemySpec, + [_G.GetSpellInfo(51300)] = BlacksmithSpec, + [_G.GetSpellInfo(51306)] = EngineeringSpec, + [_G.GetSpellInfo(51302)] = LeatherworkSpec, + [_G.GetSpellInfo(51309)] = TailorSpec, + } + + -- Populate the Specialty table with all Specialties, adding alchemy even though no recipes have alchemy filters + for i in pairs(AlchemySpec) do AllSpecialtiesTable[i] = true end + for i in pairs(BlacksmithSpec) do AllSpecialtiesTable[i] = true end + for i in pairs(EngineeringSpec) do AllSpecialtiesTable[i] = true end + for i in pairs(LeatherworkSpec) do AllSpecialtiesTable[i] = true end + for i in pairs(TailorSpec) do AllSpecialtiesTable[i] = true end + end -- do +end + +---Run when the addon is disabled. Ace3 takes care of unregistering events, etc. +function addon:OnDisable() + if addon.Frame then + addon.Frame:Hide() + end + + -- Remove the option from Manufac + if _G.Manufac then + _G.Manufac.options.args.ARLScan = nil + end +end + +------------------------------------------------------------------------------- +-- Event handling functions +------------------------------------------------------------------------------- + +---Event used for datamining when a trainer is shown. +function addon:TRAINER_SHOW() + self:ScanTrainerData(true) +end + +---Event used for datamining when a vendor is shown. +function addon:MERCHANT_SHOW() + self:ScanVendor() +end + +do + local GetTradeSkillListLink = _G.GetTradeSkillListLink + local UnitName = _G.UnitName + local GetRealmName = _G.GetRealmName + + function addon:TRADE_SKILL_SHOW() + local is_linked = _G.IsTradeSkillLinked() or _G.IsTradeSkillGuild() + local tradelink = GetTradeSkillListLink() + + local pname = UnitName("player") + local prealm = GetRealmName() + local tradename = _G.GetTradeSkillLine() + + -- Actual alt information saved here. -Torhal + addon.db.global.tradeskill = addon.db.global.tradeskill or {} + addon.db.global.tradeskill[prealm] = addon.db.global.tradeskill[prealm] or {} + addon.db.global.tradeskill[prealm][pname] = addon.db.global.tradeskill[prealm][pname] or {} + + -- If this is our own skill, save it. Otherwise, make sure it's gone. + addon.db.global.tradeskill[prealm][pname][tradename] = (not is_linked) and tradelink or nil + + local scan_button = self.scan_button + local scan_parent = scan_button:GetParent() + + if not scan_parent or scan_parent == _G.UIParent then + scan_button:SetParent(_G.TradeSkillFrame) + scan_parent = scan_button:GetParent() + end + + if scan_parent == _G.TradeSkillFrame then + scan_button:ClearAllPoints() + + local loc = addon.db.profile.scanbuttonlocation + + if loc == "TR" then + scan_button:SetPoint("RIGHT", _G.TradeSkillFrameCloseButton, "LEFT",4,0) + elseif loc == "TL" then + scan_button:SetPoint("LEFT", _G.TradeSkillFramePortrait, "RIGHT",2,12) + elseif loc == "BR" then + scan_button:SetPoint("TOP", _G.TradeSkillCancelButton, "BOTTOM",0,-5) + elseif loc == "BL" then + scan_button:SetPoint("TOP", _G.TradeSkillCreateAllButton, "BOTTOM",0,-5) + end + scan_button:SetWidth(scan_button:GetTextWidth() + 10) + end + scan_button:Show() + end +end + +function addon:TRADE_SKILL_CLOSE() + if self.Frame and addon.db.profile.closeguionskillclose then + self.Frame:Hide() + end + + if not _G.Skillet then + addon.scan_button:Hide() + end +end + +do + local last_update = 0 + local updater = _G.CreateFrame("Frame", nil, _G.UIParent) + + updater:Hide() + updater:SetScript("OnUpdate", + function(self, elapsed) + last_update = last_update + elapsed + + if last_update >= 0.5 then + local profession = _G.GetTradeSkillLine() + + if profession ~= "UNKNOWN" then + addon:Scan(false, true) + end + self:Hide() + end + end) + + function addon:TRADE_SKILL_UPDATE(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) + if not self.Frame or not self.Frame:IsVisible() then + return + end + + if not updater:IsVisible() then + last_update = 0 + updater:Show() + end + end +end + +------------------------------------------------------------------------------- +-- ARL Logic Functions +------------------------------------------------------------------------------- +function addon:InitializeProfession(profession) + if not profession then + --@alpha@ + addon:Print("nil profession passed to InitializeProfession()") + --@end-alpha@ + return + end + + if profession == private.professions["Smelting"] then + profession = private.mining_name + end + local func = PROFESSION_INIT_FUNCS[profession] + + if func then + func(addon) + PROFESSION_INIT_FUNCS[profession] = nil + end +end + +do + local fa = _G.GetSpellInfo(45542) + + -- Code snippet stolen from GearGuage by Torhal and butchered by Ackis + local function StrSplit(input) + if not input then return nil, nil end + local arg1, arg2, var1 + + arg1, var1 = input:match("^([^%s]+)%s*(.*)$") + arg1 = (arg1 and arg1:lower() or input:lower()) + + if var1 then + -- Small hack to get code to work with first aid. + if var1:lower() == fa:lower() then + arg2 = var1 + else + local var2 + arg2, var2 = var1:match("^([^%s]+)%s*(.*)$") + arg2 = (arg2 and arg2:lower() or var1:lower()) + end + end + return arg1, arg2 + end + + -- Determines what to do when the slash command is called. + function addon:ChatCommand(input) + + local arg1, arg2 = StrSplit(input) + + -- Open About panel if there's no parameters or if we do /arl about + if not arg1 or (arg1 and arg1:trim() == "") or arg1 == L["Sorting"]:lower() or arg1 == L["Sort"]:lower() or arg1 == _G.DISPLAY:lower() then + _G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame) + elseif arg1 == L["About"]:lower() then + if self.optionsFrame["About"] then + _G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame["About"]) + else + _G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame) + end + elseif arg1 == L["Profile"]:lower() then + _G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame["Profiles"]) + elseif arg1 == L["Documentation"]:lower() then + _G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame["Documentation"]) + elseif arg1 == L["Scan"]:lower() then + if not arg2 then + self:Print(L["COMMAND_LINE_SCAN"]) + else + _G.CastSpellByName(arg2) + + if self.Frame and self.Frame:IsVisible() then + self.Frame:Hide() + else + self:Scan(false, false) + end + end + elseif arg1 == "scanprof" then + self:ScanProfession("all") + elseif arg1 == "tradelinks" then + self:GenerateLinks() + else + -- What happens when we get here? + LibStub("AceConfigCmd-3.0"):HandleCommand("arl", "Ackis Recipe List", arg1) + end + end +end + +--- Public API function to initialize all of the lookup lists - self-nils once run. +-- @name AckisRecipeList:InitializeLookups() +-- @usage if AckisRecipeList.InitializeLookups then AckisRecipeList:InitializeLookups() end +function addon:InitializeLookups() + self:InitCustom(private.custom_list) + self:InitMob(private.mob_list) + self:InitQuest(private.quest_list) + self:InitReputation(private.reputation_list) + self:InitTrainer(private.trainer_list) + self:InitSeasons(private.seasonal_list) + self:InitVendor(private.vendor_list) + + self.InitializeLookups = nil +end + +------------------------------------------------------------------------------- +-- Recipe Scanning Functions +------------------------------------------------------------------------------- +do + -- List of tradeskill headers, used in addon:Scan() + local header_list = {} + + -- Toggles a recipe ot known state if it's your own + local function togglerecipe(recipe, is_linked) + if not is_linked then + recipe:AddState("KNOWN") + recipe:RemoveState("LINKED") + else + recipe:AddState("LINKED") + end + end + + --- Causes a scan of the tradeskill to be conducted. Function called when the scan button is clicked. Parses recipes and displays output + -- @name AckisRecipeList:Scan + -- @usage AckisRecipeList:Scan(true) + -- @param textdump Boolean indicating if we want the output to be a text dump, or if we want to use the ARL GUI + -- @return A frame with either the text dump, or the ARL frame + function addon:Scan(textdump, is_refresh) + local current_prof, prof_level = _G.GetTradeSkillLine() + + -- Bail if we haven't opened a tradeskill frame. + if current_prof == "UNKNOWN" then + self:Print(L["OpenTradeSkillWindow"]) + return + end + local player = private.Player + player:SetProfessions() + + -- Set the current profession level, and update the cached data. + private.current_profession_scanlevel = prof_level + + -- Make sure we're only updating a profession the character actually knows - this could be a scan from a tradeskill link. + local is_linked = _G.IsTradeSkillLinked() or _G.IsTradeSkillGuild() + + if not is_linked then + player.has_scanned[current_prof] = true + end + + -- Get the current profession Specialty + local specialty = SpecialtyTable[current_prof] + + for index = 1, 25, 1 do + local spell_name = _G.GetSpellBookItemName(index, _G.BOOKTYPE_SPELL) + + if not spell_name or index == 25 then + player["Specialty"] = nil + break + elseif specialty and specialty[spell_name] then + player["Specialty"] = specialty[spell_name] + break + end + end + + if self.InitializeLookups then + self:InitializeLookups() + end + addon:InitializeProfession(current_prof) + + ------------------------------------------------------------------------------- + -- Scan all recipes and mark the ones we know + ------------------------------------------------------------------------------- + table.wipe(header_list) + + -- Save the current state of the TradeSkillFrame so it can be restored after we muck with it. + local have_materials = _G.TradeSkillFrame.filterTbl.hasMaterials + local have_skillup = _G.TradeSkillFrame.filterTbl.hasSkillUp + local subclass = _G.TradeSkillFrame.filterTbl.subClassValue + local slot = _G.TradeSkillFrame.filterTbl.slotValue + + if _G.MRTAPI and _G.MRTAPI:PushFilterSelection() then + -- MrTrader saved the state for us + else + if not _G.Skillet and have_materials then + _G.TradeSkillFrame.filterTbl.hasMaterials = false + _G.TradeSkillOnlyShowMakeable(false) + end + if not _G.Skillet and have_skillup then + _G.TradeSkillFrame.filterTbl.hasSkillUp = false + _G.TradeSkillOnlyShowSkillUps(false) + end + --UIDropDownMenu_Initialize(TradeSkillFilterDropDown, TradeSkillInvSlotDropDown_Initialize) + --UIDropDownMenu_SetSelectedID(TradeSkillFilterDropDown, 1) + _G.SetTradeSkillInvSlotFilter(0, 1, 1) + _G.TradeSkillUpdateFilterBar() + _G.TradeSkillFrame_Update() + + -- Expand all headers so we can see all the recipes there are + for i = _G.GetNumTradeSkills(), 1, -1 do + local name, tradeType, _, isExpanded = _G.GetTradeSkillInfo(i) + + if tradeType == "header" and not isExpanded then + header_list[name] = true + _G.ExpandTradeSkillSubClass(i) + end + end + end + local recipe_list = private.recipe_list + local recipes_found = 0 + local SF = private.recipe_state_flags + local overwritemap = private.spell_overwrite_map + + for i = 1, _G.GetNumTradeSkills() do + local tradeName, tradeType = _G.GetTradeSkillInfo(i) + + if tradeType ~= "header" then + -- Get the trade skill link for the specified recipe + local spell_link = _G.GetTradeSkillRecipeLink(i) + -- Spell ID of the recipe being scanned. + local spell_string = spell_link:match("^|c%x%x%x%x%x%x%x%x|H%w+:(%d+)") + local spell_id = tonumber(spell_string) + local recipe = recipe_list[spell_id] + + if recipe then + -- Mark the first rank of the spell as known if we know rank 2 for certain recipes. + -- This is only done for recipes which when you learn the higher rank, you lose the + -- ability to learn the lower rank. + + -- If we have it in the mapping, set the lower rank spell to known + if overwritemap[spell_id] then + local overwriterecipe = recipe_list[overwritemap[spell_id]] + if overwriterecipe then + togglerecipe(overwriterecipe, is_linked) + else + self:Debug(tradeName .. " " .. overwritemap[spell_id] .. L["MissingFromDB"]) + end + end + -- Toggle spell to known + togglerecipe(recipe, is_linked) + recipes_found = recipes_found + 1 + else + self:Debug(tradeName .. " " .. spell_string .. L["MissingFromDB"]) + end + end + end + + -- Close all the headers we've opened + -- If Mr Trader is installed use that API + if _G.MRTAPI and _G.MRTAPI:PopFilterSelection() then + -- MrTrader restored the state for us + else + -- Collapse all headers that were collapsed before + for i = _G.GetNumTradeSkills(), 1, -1 do + local name, tradeType, _, isExpanded = _G.GetTradeSkillInfo(i) + + if header_list[name] then + _G.CollapseTradeSkillSubClass(i) + end + end + + -- Restore the state of the things we changed. + _G.TradeSkillFrame.filterTbl.hasMaterials = have_materials + _G.TradeSkillOnlyShowMakeable(have_materials) + _G.TradeSkillFrame.filterTbl.hasSkillUp = have_skillup + _G.TradeSkillOnlyShowSkillUps(have_skillup) + + _G.TradeSkillUpdateFilterBar() + _G.TradeSkillFrame_Update() + + end + player.prev_count = player.foundRecipes + player.foundRecipes = recipes_found + + if is_refresh and player.prev_count == recipes_found then + return + end + + ------------------------------------------------------------------------------- + -- Update the player's reputation levels. + ------------------------------------------------------------------------------- + player:UpdateReputations() + + ------------------------------------------------------------------------------- + -- Everything is ready - display the GUI or dump the list to text. + ------------------------------------------------------------------------------- + if textdump then + self:DisplayTextDump(recipe_list, current_prof) + else + if private.InitializeFrame then + private.InitializeFrame() + end + self.Frame:Display(current_prof, is_linked) + end + end +end + +------------------------------------------------------------------------------- +-- Text dumping functions +------------------------------------------------------------------------------- + +-------------------------------------------------------------------------------- +--- Creates a new frame with the contents of a text dump so you can copy and paste +-- Code borrowed from Antiarc (Chatter) with permission +-- @name AckisRecipeList:DisplayTextDump +-- @param RecipeDB The database (array) which you wish read data from. +-- @param profession Which profession are you displaying data for +-- @param text The text to be dumped +-------------------------------------------------------------------------------- +do + local copy_frame = _G.CreateFrame("Frame", "ARLCopyFrame", _G.UIParent) + copy_frame:SetBackdrop({ + bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], + edgeFile = [[Interface\DialogFrame\UI-DialogBox-Border]], + tile = true, + tileSize = 16, + edgeSize = 16, + insets = { + left = 3, + right = 3, + top = 5, + bottom = 3 + } + }) + copy_frame:SetBackdropColor(0, 0, 0, 1) + copy_frame:SetWidth(750) + copy_frame:SetHeight(400) + copy_frame:SetPoint("CENTER", _G.UIParent, "CENTER") + copy_frame:SetFrameStrata("DIALOG") + + table.insert(_G.UISpecialFrames, "ARLCopyFrame") + + local scrollArea = _G.CreateFrame("ScrollFrame", "ARLCopyScroll", copy_frame, "UIPanelScrollFrameTemplate") + scrollArea:SetPoint("TOPLEFT", copy_frame, "TOPLEFT", 8, -30) + scrollArea:SetPoint("BOTTOMRIGHT", copy_frame, "BOTTOMRIGHT", -30, 8) + + local edit_box = _G.CreateFrame("EditBox", nil, copy_frame) + edit_box:SetMultiLine(true) + edit_box:SetMaxLetters(0) + edit_box:EnableMouse(true) + edit_box:SetAutoFocus(true) + edit_box:SetFontObject("ChatFontNormal") + edit_box:SetWidth(650) + edit_box:SetHeight(270) + edit_box:SetScript("OnEscapePressed", + function() + copy_frame:Hide() + end) + edit_box:HighlightText(0) + + scrollArea:SetScrollChild(edit_box) + + local close = _G.CreateFrame("Button", nil, copy_frame, "UIPanelCloseButton") + close:SetPoint("TOPRIGHT", copy_frame, "TOPRIGHT") + + copy_frame:Hide() + + function addon:DisplayTextDump(RecipeDB, profession, text) + local text = (not RecipeDB and not profession) and text or self:GetTextDump(profession) + + if text ~= "" then + edit_box:SetText(text) + edit_box:HighlightText(0) + edit_box:SetCursorPosition(1) + copy_frame:Show() + end + end +end -- do + +do + ------------------------------------------------------------------------------- + -- Dumps recipe output in the format requested by the user + ------------------------------------------------------------------------------- + local text_table = {} + local acquire_list = {} + local ACQUIRE_NAMES = private.acquire_names + + local GetFilterNames + do + local LC = _G.LOCALIZED_CLASS_NAMES_MALE + local FILTER_NAMES + + function GetFilterNames() + if not FILTER_NAMES then + local is_alliance = (private.Player.faction == "Alliance") + + FILTER_NAMES = { + [1] = BFAC["Alliance"], + [2] = BFAC["Horde"], + [3] = L["Trainer"], + [4] = L["Vendor"], + [5] = _G.INSTANCE, + [6] = _G.RAID, + [7] = _G.EVENTS_LABEL, + [8] = L["Quest"], + [9] = _G.PVP, + [10] = L["World Drop"], + [11] = L["Mob Drop"], + [12] = L["Discovery"], + [13] = L["Retired"], + [21] = LC["DEATHKNIGHT"], + [22] = LC["DRUID"], + [23] = LC["HUNTER"], + [24] = LC["MAGE"], + [25] = LC["PALADIN"], + [26] = LC["PRIEST"], + [27] = LC["SHAMAN"], + [28] = LC["ROGUE"], + [29] = LC["WARLOCK"], + [30] = LC["WARRIOR"], + [36] = L["BOEFilter"], + [37] = L["BOPFilter"], + [38] = L["BOAFilter"], + [40] = L["RecipeBOEFilter"], + [41] = L["RecipeBOPFilter"], + [42] = L["RecipeBOAFilter"], + [51] = _G.MELEE, + [52] = _G.TANK, + [53] = _G.HEALER, + [54] = _G.DAMAGER, + [56] = L["Cloth"], + [57] = L["Leather"], + [58] = L["Mail"], + [59] = L["Plate"], + [60] = L["Cloak"], + [61] = L["Trinket"], + [62] = L["Ring"], + [63] = L["Necklace"], + [64] = L["Shield"], + [66] = L["One Hand"], + [67] = L["Two Hand"], + [68] = L["Axe"], + [69] = L["Sword"], + [70] = L["Mace"], + [71] = L["Polearm"], + [72] = L["Dagger"], + [73] = L["Staff"], + [74] = L["Wand"], + [75] = L["Thrown"], + [76] = L["Bow"], + [77] = L["Crossbow"], + [78] = L["Ammo"], + [79] = L["Fist"], + [80] = L["Gun"], + [96] = BFAC["Argent Dawn"], + [97] = BFAC["Cenarion Circle"], + [98] = BFAC["Thorium Brotherhood"], + [99] = BFAC["Timbermaw Hold"], + [100] = BFAC["Zandalar Tribe"], + [101] = BFAC["The Aldor"], + [102] = BFAC["Ashtongue Deathsworn"], + [103] = BFAC["Cenarion Expedition"], + [104] = (is_alliance and BFAC["Honor Hold"] or BFAC["Thrallmar"]), + [105] = BFAC["The Consortium"], + [106] = BFAC["Keepers of Time"], + [107] = BFAC["Lower City"], + [108] = (is_alliance and BFAC["Kurenai"] or BFAC["The Mag'har"]), + [109] = BFAC["The Scale of the Sands"], + [110] = BFAC["The Scryers"], + [111] = BFAC["The Sha'tar"], + [112] = BFAC["Shattered Sun Offensive"], + [113] = BFAC["Sporeggar"], + [114] = BFAC["The Violet Eye"], + [115] = BFAC["Argent Crusade"], + [116] = BFAC["Frenzyheart Tribe"], + [117] = BFAC["Knights of the Ebon Blade"], + [118] = BFAC["Kirin Tor"], + [119] = BFAC["The Sons of Hodir"], + [120] = BFAC["The Kalu'ak"], + [121] = BFAC["The Oracles"], + [122] = BFAC["The Wyrmrest Accord"], + [123] = (is_alliance and BFAC["The Silver Covenant"] or BFAC["The Sunreavers"]), + [124] = (is_alliance and BFAC["Explorers' League"] or BFAC["The Hand of Vengeance"]), + [125] = (is_alliance and BFAC["Valiance Expedition"] or BFAC["Warsong Offensive"]), + [126] = (is_alliance and BFAC["The Frostborn"] or BFAC["The Taunka"]), + [127] = (is_alliance and BFAC["Alliance Vanguard"] or BFAC["Horde Expedition"]), + [128] = BFAC["The Ashen Verdict"], + [129] = (is_alliance and BFAC["Wildhammer Clan"] or BFAC["Dragonmaw Clan"]), + [130] = (is_alliance and BFAC["Baradin's Wardens"] or BFAC["Hellscream's Reach"]), + [131] = BFAC["Guardians of Hyjal"], + [132] = BFAC["Ramkahen"], + [133] = BFAC["The Earthen Ring"], + [134] = BFAC["Therazane"], + } + end + return FILTER_NAMES + end + end -- do + + ---Dumps the recipe database in a format that is readable to humans (or machines) + function addon:GetTextDump(profession) + local output = addon.db.profile.textdumpformat + table.wipe(text_table) + + if not output or output == "Comma" then + table.insert(text_table, ("Ackis Recipe List Text Dump for %s's %s, in the form of Comma Separated Values.\n "):format(private.player_name, profession)) + table.insert(text_table, "Spell ID,Recipe Name,Skill Level,ARL Filter Flags,Acquire Methods,Known\n") + elseif output == "BBCode" then + table.insert(text_table, ("Ackis Recipe List Text Dump for %s's %s, in the form of BBCode.\n"):format(private.player_name, profession)) + elseif output == "XML" then + table.insert(text_table, "") + end + + local recipe_list = private.recipe_list + local SF = private.recipe_state_flags + + for recipe_id in pairs(recipe_list) do + local recipe = recipe_list[recipe_id] + local recipe_prof = _G.GetSpellInfo(recipe.profession) + local is_known = recipe:HasState("KNOWN") + + if recipe_prof == profession then + -- CSV + if not output or output == "Comma" then + -- Add Spell ID, Name and Skill Level to the list + table.insert(text_table, recipe_id) + table.insert(text_table, ",") + table.insert(text_table, recipe.name) + table.insert(text_table, ",") + table.insert(text_table, recipe.skill_level) + table.insert(text_table, ",\"") + -- BBCode + elseif output == "BBCode" then + -- Make the entry red + if not is_known then + table.insert(text_table, "[color=red]") + end + table.insert(text_table, "\n[b]" .. recipe_id .. "[/b] - " .. recipe.name .. " (" .. recipe.skill_level .. ")\n") + + -- Close Color tag + if not is_known then + table.insert(text_table, "[/color]\nRecipe Flags:\n[list]") + elseif is_known then + table.insert(text_table, "\nRecipe Flags:\n[list]") + end + --XML + elseif output == "XML" then + table.insert(text_table, "") + table.insert(text_table, " ..recipe_id..") + table.insert(text_table, " "..recipe.name.."") + table.insert(text_table, " ..recipe.skill_level..") + table.insert(text_table, " "..tostring(is_known).."") + table.insert(text_table, " ") + --Name + elseif output == "Name" then + table.insert(text_table, recipe.name) + end + + -- Add in all the filter flags + local filter_names = GetFilterNames() + local prev = false + + -- Find out which flags are set + for table_index, bits in ipairs(private.bit_flags) do + for flag_name, flag in pairs(bits) do + local bitfield = recipe.flags[private.flag_members[table_index]] + + if bitfield and bit.band(bitfield, flag) == flag then + if not output or output == "Comma" then + if prev then + table.insert(text_table, ",") + end + table.insert(text_table, filter_names[private.filter_flags[flag_name]]) + prev = true + -- BBCode + elseif output == "BBCode" then + table.insert(text_table, "[*]"..filter_names[private.filter_flags[flag_name]]) + elseif output == "XML" then + table.insert(text_table, " "..filter_names[private.filter_flags[flag_name]].."") + end + end + end + end + + if not output or output == "Comma" then + table.insert(text_table, "\",\"") + elseif output == "BBCode" then + table.insert(text_table, "[/list]\nAcquire Methods:\n[list]") + elseif output == "XML" then + table.insert(text_table, " ") + table.insert(text_table, " ") + end + + -- Find out which unique acquire methods we have + local acquire_data = recipe["acquire_data"] + table.wipe(acquire_list) + + for acquire_type in pairs(acquire_data) do + acquire_list[ACQUIRE_NAMES[acquire_type]] = true + end + + -- Add all the acquire methods in + prev = false + + for i in pairs(acquire_list) do + if not output or output == "Comma" then + if prev then + table.insert(text_table, ",") + end + table.insert(text_table, i) + prev = true + elseif output == "BBCode" then + table.insert(text_table, "[*] " .. i) + elseif output == "XML" then + table.insert(text_table, ""..i.."") + end + end + + if not output or output == "Comma" then + table.insert(text_table, "\","..tostring(is_known).."\n") + --if is_known then + -- table.insert(text_table, "\",true\n") + --else + -- table.insert(text_table, "\",false\n") + --end + elseif output == "BBCode" then + table.insert(text_table, "\n[/list]") + elseif output == "XML" then + table.insert(text_table, " ") + table.insert(text_table, "") + end + end + end -- for + return table.concat(text_table, "") + end +end diff --git a/core.lua b/core.lua deleted file mode 100644 index 0774586..0000000 --- a/core.lua +++ /dev/null @@ -1,1466 +0,0 @@ ---[[ -************************************************************************ -core.lua -Core functions for Ackis Recipe List -************************************************************************ -File date: @file-date-iso@ -File hash: @file-abbreviated-hash@ -Project hash: @project-abbreviated-hash@ -Project version: @project-version@ -************************************************************************ -Please see http://www.wowace.com/addons/arl/ for more information. -************************************************************************ -This source code is released under All Rights Reserved. -************************************************************************ ---- Ackis Recipe List provides functionality to scan your professions. --- It will determine which recipes you are missing. --- @class file --- @name core.lua --- @release 2.0 -************************************************************************ -]] - -------------------------------------------------------------------------------- --- Localized Lua globals. -------------------------------------------------------------------------------- -local _G = getfenv(0) - --- Functions -local pairs, ipairs = _G.pairs, _G.ipairs -local select = _G.select -local tonumber, tostring = _G.tonumber, _G.tostring -local type = _G.type - --- Libraries -local bit = _G.bit -local string = _G.string -local table = _G.table - -------------------------------------------------------------------------------- --- AddOn namespace. -------------------------------------------------------------------------------- -local FOLDER_NAME, private = ... -private.addon_name = "Ackis Recipe List" - -local LibStub = _G.LibStub -local addon = LibStub("AceAddon-3.0"):NewAddon(private.addon_name, "AceConsole-3.0", "AceEvent-3.0") -_G.AckisRecipeList = addon - ---@alpha@ -_G.ARL = addon ---@end-alpha@ - -local L = LibStub("AceLocale-3.0"):GetLocale(private.addon_name) -local BFAC = LibStub("LibBabble-Faction-3.0"):GetLookupTable() - -local debugger = _G.tekDebug and _G.tekDebug:GetFrame(private.addon_name) - -private.build_num = select(2, _G.GetBuildInfo()) - -private.custom_list = {} -private.mob_list = {} -private.quest_list = {} -private.recipe_list = {} -private.reputation_list = {} -private.trainer_list = {} -private.seasonal_list = {} -private.vendor_list = {} -private.location_list = {} -private.acquire_list = {} - ------------------------------------------------------------------------------- --- Constants. ------------------------------------------------------------------------------- -local PROFESSION_INIT_FUNCS = {} - ------------------------------------------------------------------------------- --- Database tables ------------------------------------------------------------------------------- -local AllSpecialtiesTable = {} -local SpecialtyTable - --- Filter flags and acquire types - defined in Constants.lua -local F = private.filter_flags -local A = private.acquire_types - --- Global Frame Variables -addon.optionsFrame = {} - -------------------------------------------------------------------------------- --- Check to see if we have mandatory libraries loaded. If not, notify the user --- which are missing and return. -------------------------------------------------------------------------------- -local MissingLibraries -do - local REQUIRED_LIBS = { - "AceLocale-3.0", - "LibBabble-Boss-3.0", - "LibBabble-Faction-3.0", - "LibBabble-Zone-3.0", - } - function MissingLibraries() - local missing = false - - for idx, lib in ipairs(REQUIRED_LIBS) do - if not LibStub:GetLibrary(lib, true) then - missing = true - addon:Print(L["MISSING_LIBRARY"]:format(lib)) - end - end - return missing - end -end -- do - -if MissingLibraries() then - --@debug@ - addon:Print("You are using a development version of ARL. As per WowAce standards, externals are not set up. You will have to install all necessary libraries in order for the addon to function correctly.") - --@end-debug@ - _G.AckisRecipeList = nil - return -end - -------------------------------------------------------------------------------- --- Define the static popups we're going to call when people haven't scanned or --- when current filters are blocking all recipes from being displayed. -------------------------------------------------------------------------------- -_G.StaticPopupDialogs["ARL_NOTSCANNED"] = { - text = L["NOTSCANNED"], - button1 = _G.OKAY, - timeout = 0, - exclusive = 1, - whileDead = 1, - hideOnEscape = 1 -} - -_G.StaticPopupDialogs["ARL_ALLFILTERED"] = { - text = L["ALL_FILTERED"], - button1 = _G.OKAY, - timeout = 0, - exclusive = 1, - whileDead = 1, - hideOnEscape = 1 -} - -_G.StaticPopupDialogs["ARL_ALLKNOWN"] = { - text = L["ARL_ALLKNOWN"], - button1 = _G.OKAY, - timeout = 0, - exclusive = 1, - whileDead = 1, - hideOnEscape = 1 -} - -_G.StaticPopupDialogs["ARL_ALLEXCLUDED"] = { - text = L["ARL_ALLEXCLUDED"], - button1 = _G.OKAY, - timeout = 0, - exclusive = 1, - whileDead = 1, - hideOnEscape = 1 -} - -_G.StaticPopupDialogs["ARL_SEARCHFILTERED"] = { - text = L["ARL_SEARCHFILTERED"], - button1 = _G.OKAY, - timeout = 0, - exclusive = 1, - whileDead = 1, - hideOnEscape = 1 -} - -------------------------------------------------------------------------------- --- Close all possible pop-up windows -------------------------------------------------------------------------------- -function addon:ClosePopups() - _G.StaticPopup_Hide("ARL_NOTSCANNED") - _G.StaticPopup_Hide("ARL_ALLFILTERED") - _G.StaticPopup_Hide("ARL_ALLKNOWN") - _G.StaticPopup_Hide("ARL_ALLEXCLUDED") - _G.StaticPopup_Hide("ARL_SEARCHFILTERED") -end - -------------------------------------------------------------------------------- --- Functions common to most files in the AddOn. -------------------------------------------------------------------------------- -function private.SetTextColor(color_code, text) - return ("|cff%s%s|r"):format(color_code or "ffffff", text) -end - -------------------------------------------------------------------------------- --- Debugger. -------------------------------------------------------------------------------- -function addon:Debug(...) - if debugger then - debugger:AddMessage(string.format(...)) - else - --@debug@ - self:Printf(...) - --@end-debug@ - end -end - -do - local output = {} - - function addon:DumpMembers(match) - table.wipe(output) - table.insert(output, "Addon Object members.\n") - - local count = 0 - - for key, value in pairs(self) do - local val_type = type(value) - - if not match or val_type == match then - table.insert(output, ("%s (%s)"):format(key, val_type)) - count = count + 1 - end - end - table.insert(output, ("\n%d found\n"):format(count)) - self:DisplayTextDump(nil, nil, table.concat(output, "\n")) - end -end -- do - -------------------------------------------------------------------------------- --- Initialization functions -------------------------------------------------------------------------------- -function addon:OnInitialize() - -- Set default options, which are to include everything in the scan - local defaults = { - global = { - -- Saving alts tradeskills (needs to be global so all profiles can access it) - tradeskill = {}, - }, - profile = { - ------------------------------------------------------------------------------- - -- Frame options - ------------------------------------------------------------------------------- - frameopts = { - offsetx = 0, - offsety = 0, - anchorTo = "", - anchorFrom = "", - uiscale = 1, - small_list_font = true, - }, - - ------------------------------------------------------------------------------- - -- Tooltip Options - ------------------------------------------------------------------------------- - tooltip = { - scale = 1, - acquire_fontsize = 11, - }, - ------------------------------------------------------------------------------- - -- Sorting Options - ------------------------------------------------------------------------------- - sorting = "Ascending", - current_tab = 3, -- Name tab - skill_view = false, -- Sort the recipes by skill level instead of name? - - ------------------------------------------------------------------------------- - -- Display Options - ------------------------------------------------------------------------------- - includefiltered = false, - includeexcluded = false, - closeguionskillclose = false, - ignoreexclusionlist = false, - scanbuttonlocation = "TR", - spelltooltiplocation = "Right", - acquiretooltiplocation = "Right", - recipes_in_tooltips = true, - max_recipes_in_tooltips = 10, - hide_tooltip_hint = false, - hidepopup = false, - minimap = true, - worldmap = true, - autoscanmap = false, - scantrainers = false, - scanvendors = false, - autoloaddb = false, - maptrainer = false, - mapvendor = true, - mapmob = true, - mapquest = true, - - ------------------------------------------------------------------------------- - -- Text Dump Options - ------------------------------------------------------------------------------- - textdumpformat = "BBCode", - - ------------------------------------------------------------------------------- - -- Recipe Exclusion - ------------------------------------------------------------------------------- - exclusionlist = {}, - - ------------------------------------------------------------------------------- - -- Filter Options - ------------------------------------------------------------------------------- - filters = { - ------------------------------------------------------------------------------- - -- General Filters - ------------------------------------------------------------------------------- - general = { - faction = true, - specialty = false, - skill = true, - known = false, - unknown = true, - retired = false, - }, - ------------------------------------------------------------------------------- - -- Obtain Filters - ------------------------------------------------------------------------------- - obtain = { - trainer = true, - vendor = true, - instance = true, - raid = true, - seasonal = true, - quest = true, - pvp = true, - discovery = true, - worlddrop = true, - mobdrop = true, - achievement = true, - expansion0 = true, - expansion1 = true, - expansion2 = true, - expansion3 = true, - }, - ------------------------------------------------------------------------------- - -- Item Filters (Armor/Weapon) - ------------------------------------------------------------------------------- - item = { - armor = { - cloth = true, - leather = true, - mail = true, - plate = true, - trinket = true, - cloak = true, - ring = true, - necklace = true, - shield = true, - }, - weapon = { - onehand = true, - twohand = true, - axe = true, - sword = true, - mace = true, - polearm = true, - dagger = true, - fist = true, - staff = true, - wand = true, - thrown = true, - bow = true, - crossbow = true, - ammo = true, - gun = true, - }, - }, - ------------------------------------------------------------------------------- - -- Quality Filters - ------------------------------------------------------------------------------- - quality = { - common = true, - uncommon = true, - rare = true, - epic = true, - }, - ------------------------------------------------------------------------------- - -- Binding Filters - ------------------------------------------------------------------------------- - binding = { - itemboe = true, - itembop = true, - recipebop = true, - recipeboe = true, - }, - ------------------------------------------------------------------------------- - -- Player Role Filters - ------------------------------------------------------------------------------- - player = { - melee = true, - tank = true, - healer = true, - caster = true, - }, - ------------------------------------------------------------------------------- - -- Reputation Filters - ------------------------------------------------------------------------------- - rep = { - aldor = true, - scryer = true, - argentdawn = true, - ashtonguedeathsworn = true, - cenarioncircle = true, - cenarionexpedition = true, - consortium = true, - hellfire = true, - keepersoftime = true, - nagrand = true, - lowercity = true, - scaleofthesands = true, - shatar = true, - shatteredsun = true, - sporeggar = true, - thoriumbrotherhood = true, - timbermaw = true, - violeteye = true, - zandalar = true, - argentcrusade = true, - frenzyheart = true, - ebonblade = true, - kirintor = true, - sonsofhodir = true, - kaluak = true, - oracles = true, - wyrmrest = true, - wrathcommon1 = true, - wrathcommon2 = true, - wrathcommon3 = true, - wrathcommon4 = true, - wrathcommon5 = true, - ashenverdict = true, - catacommon1 = true, - catacommon2 = true, - guardiansofhyjal = true, - ramkahen = true, - earthenring = true, - therazane = true, - }, - ------------------------------------------------------------------------------- - -- Class Filters - ------------------------------------------------------------------------------- - classes = { - deathknight = true, - druid = true, - hunter = true, - mage = true, - paladin = true, - priest = true, - rogue = true, - shaman = true, - warlock = true, - warrior = true, - }, - } - } - } - self.db = LibStub("AceDB-3.0"):New("ARLDB2", defaults) - - if not self.db then - self:Print("Error: Database not loaded correctly. Please exit out of WoW and delete the ARL database file (AckisRecipeList.lua) found in: \\World of Warcraft\\WTF\\Account\\>\\SavedVariables\\") - return - end - local version = _G.GetAddOnMetadata("AckisRecipeList", "Version") - local debug_version = false - local alpha_version = false - - -- @debug@ - debug_version = true - -- @end-debug - - -- @alpha@ - alpha_version = true - -- @end-alpha@ - - version = debug_version and "Devel" or (alpha_version and version .. "-Alpha") or version - - self.version = version - - self:SetupOptions() - - -- Register slash commands - self:RegisterChatCommand("arl", "ChatCommand") - self:RegisterChatCommand("ackisrecipelist", "ChatCommand") - - ------------------------------------------------------------------------------- - -- Create the scan button - ------------------------------------------------------------------------------- - local scan_button = _G.CreateFrame("Button", nil, _G.UIParent, "UIPanelButtonTemplate") - scan_button:SetHeight(20) - - scan_button:RegisterForClicks("LeftButtonUp") - scan_button:SetScript("OnClick", - function(self, button, down) - local cur_profession = _G.GetTradeSkillLine() - local MainPanel = addon.Frame - local prev_profession - - if MainPanel then - prev_profession = MainPanel.prof_name or private.ordered_professions[MainPanel.profession] - end - - local shift_key = _G.IsShiftKeyDown() - local alt_key = _G.IsAltKeyDown() - local ctrl_key = _G.IsControlKeyDown() - - if shift_key and not alt_key and not ctrl_key then - addon:Scan(true) - elseif alt_key and not shift_key and not ctrl_key then - addon:ClearWaypoints() - elseif ctrl_key and not shift_key and not alt_key then - local current_prof = _G.GetTradeSkillLine() - addon:DumpProfession(current_prof) - elseif not shift_key and not alt_key and not ctrl_key then - if MainPanel and MainPanel:IsVisible() and prev_profession == cur_profession then - MainPanel:Hide() - else - addon:Scan(false) - addon:AddWaypoint() - end - end - end) - - scan_button:SetScript("OnEnter", - function(self) - local tooltip = _G.GameTooltip - - _G.GameTooltip_SetDefaultAnchor(tooltip, self) - tooltip:SetText(L["SCAN_RECIPES_DESC"]) - tooltip:Show() - end) - scan_button:SetScript("OnLeave", function() _G.GameTooltip:Hide() end) - scan_button:SetText(L["Scan"]) - - self.scan_button = scan_button - - ------------------------------------------------------------------------------- - -- Populate the profession initialization functions. - ------------------------------------------------------------------------------- - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51304)] = addon.InitAlchemy - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51300)] = addon.InitBlacksmithing - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51296)] = addon.InitCooking - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51313)] = addon.InitEnchanting - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51306)] = addon.InitEngineering - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(45542)] = addon.InitFirstAid - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51302)] = addon.InitLeatherworking - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(32606)] = addon.InitSmelting - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51309)] = addon.InitTailoring - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(51311)] = addon.InitJewelcrafting - PROFESSION_INIT_FUNCS[_G.GetSpellInfo(45363)] = addon.InitInscription - PROFESSION_INIT_FUNCS[private.runeforging_name] = addon.InitRuneforging - - ------------------------------------------------------------------------------- - -- Hook GameTooltip so we can show information on mobs that drop/sell/train - ------------------------------------------------------------------------------- - _G.GameTooltip:HookScript("OnTooltipSetUnit", - function(self) - if not addon.db.profile.recipes_in_tooltips then - return - end - local name, unit = self:GetUnit() - - if not unit then - return - end - local guid = _G.UnitGUID(unit) - - if not guid then - return - end - local GUID = tonumber(string.sub(guid, -12, -9), 16) - local unit = private.mob_list[GUID] or private.vendor_list[GUID] or private.trainer_list[GUID] - - if not unit or not unit.item_list then - return - end - local player = private.Player - local recipe_list = private.recipe_list - local shifted = _G.IsShiftKeyDown() - local count = 0 - - for spell_id in pairs(unit.item_list) do - local recipe = recipe_list[spell_id] - local recipe_prof = _G.GetSpellInfo(recipe.profession) - local scanned = player.has_scanned[recipe_prof] - - if scanned then - local skill_level = player.professions[recipe_prof] - local has_level = skill_level and (type(skill_level) == "boolean" and true or skill_level >= recipe.skill_level) - - if ((not recipe:HasState("KNOWN") and has_level) or shifted) and player:HasRecipeFaction(recipe) then - local _, _, _, hex = _G.GetItemQualityColor(recipe.quality) - - self:AddLine(("%s: %s%s|r (%d)"):format(recipe.profession, hex, recipe.name, recipe.skill_level)) - count = count + 1 - end - end - - if count >= addon.db.profile.max_recipes_in_tooltips then - break - end - end - end) -end - ----Function run when the addon is enabled. Registers events and pre-loads certain variables. -function addon:OnEnable() - self:RegisterEvent("TRADE_SKILL_SHOW") -- Make addon respond to the tradeskill windows being shown - self:RegisterEvent("TRADE_SKILL_CLOSE") -- Addon responds to tradeskill windows being closed. - self:RegisterEvent("TRADE_SKILL_UPDATE") - - if addon.db.profile.scantrainers then - self:RegisterEvent("TRAINER_SHOW") - end - - if addon.db.profile.scanvendors then - self:RegisterEvent("MERCHANT_SHOW") - end - - ------------------------------------------------------------------------------- - -- Set the parent and scripts for addon.scan_button. - ------------------------------------------------------------------------------- - local scan_button = self.scan_button - - if _G.Skillet and _G.Skillet:IsActive() then - scan_button:SetParent(_G.SkilletFrame) - _G.Skillet:AddButtonToTradeskillWindow(scan_button) - scan_button:SetWidth(80) - elseif _G.MRTAPI then - _G.MRTAPI:RegisterHandler("TradeSkillWindowOnShow", - function() - scan_button:SetParent(_G.MRTSkillFrame) - scan_button:ClearAllPoints() - scan_button:SetPoint("RIGHT", _G.MRTSkillFrameCloseButton, "LEFT", 4, 0) - scan_button:SetWidth(scan_button:GetTextWidth() + 10) - scan_button:Show() - end) - elseif _G.ATSWFrame then - scan_button:SetParent(_G.ATSWFrame) - scan_button:ClearAllPoints() - - if _G.TradeJunkieMain and _G.TJ_OpenButtonATSW then - scan_button:SetPoint("RIGHT", _G.TJ_OpenButtonATSW, "LEFT", 0, 0) - else - scan_button:SetPoint("RIGHT", _G.ATSWOptionsButton, "LEFT", 0, 0) - end - scan_button:SetHeight(_G.ATSWOptionsButton:GetHeight()) - scan_button:SetWidth(_G.ATSWOptionsButton:GetWidth()) - elseif _G.CauldronFrame then - scan_button:SetParent(_G.CauldronFrame) - scan_button:ClearAllPoints() - scan_button:SetPoint("TOP", _G.CauldronFrame, "TOPRIGHT", -58, -52) - scan_button:SetWidth(90) - elseif _G.BPM_ShowTrainerFrame then - scan_button:SetParent(_G.BPM_ShowTrainerFrame) - scan_button:ClearAllPoints() - scan_button:SetPoint("RIGHT", _G.BPM_ShowTrainerFrame, "LEFT", 4, 0) - scan_button:SetWidth(scan_button:GetTextWidth() + 10) - scan_button:Show() - end - - local buttonparent = scan_button:GetParent() - local framelevel = buttonparent:GetFrameLevel() - local framestrata = buttonparent:GetFrameStrata() - - -- Set the frame level of the button to be 1 deeper than its parent - scan_button:SetFrameLevel(framelevel + 1) - scan_button:SetFrameStrata(framestrata) - scan_button:Enable() - - -- Add an option so that ARL will work with Manufac - if _G.Manufac then - _G.Manufac.options.args.ARLScan = { - type = 'execute', - name = L["Scan"], - desc = L["SCAN_RECIPES_DESC"], - func = function() addon:Scan(false) end, - order = 550, - } - end - private.Player:Initialize() - - ------------------------------------------------------------------------------- - -- Initialize the SpecialtyTable and AllSpecialtiesTable. - ------------------------------------------------------------------------------- - do - local AlchemySpec = { - [_G.GetSpellInfo(28674)] = 28674, - [_G.GetSpellInfo(28678)] = 28678, - [_G.GetSpellInfo(28676)] = 28676, - } - - local BlacksmithSpec = { - [_G.GetSpellInfo(9788)] = 9788, -- Armorsmith - [_G.GetSpellInfo(17041)] = 17041, -- Master Axesmith - [_G.GetSpellInfo(17040)] = 17040, -- Master Hammersmith - [_G.GetSpellInfo(17039)] = 17039, -- Master Swordsmith - [_G.GetSpellInfo(9787)] = 9787, -- Weaponsmith - } - - local EngineeringSpec = { - [_G.GetSpellInfo(20219)] = 20219, -- Gnomish - [_G.GetSpellInfo(20222)] = 20222, -- Goblin - } - - local LeatherworkSpec = { - [_G.GetSpellInfo(10657)] = 10657, -- Dragonscale - [_G.GetSpellInfo(10659)] = 10659, -- Elemental - [_G.GetSpellInfo(10661)] = 10661, -- Tribal - } - - local TailorSpec = { - [_G.GetSpellInfo(26797)] = 26797, -- Spellfire - [_G.GetSpellInfo(26801)] = 26801, -- Shadoweave - [_G.GetSpellInfo(26798)] = 26798, -- Primal Mooncloth - } - - SpecialtyTable = { - [_G.GetSpellInfo(51304)] = AlchemySpec, - [_G.GetSpellInfo(51300)] = BlacksmithSpec, - [_G.GetSpellInfo(51306)] = EngineeringSpec, - [_G.GetSpellInfo(51302)] = LeatherworkSpec, - [_G.GetSpellInfo(51309)] = TailorSpec, - } - - -- Populate the Specialty table with all Specialties, adding alchemy even though no recipes have alchemy filters - for i in pairs(AlchemySpec) do AllSpecialtiesTable[i] = true end - for i in pairs(BlacksmithSpec) do AllSpecialtiesTable[i] = true end - for i in pairs(EngineeringSpec) do AllSpecialtiesTable[i] = true end - for i in pairs(LeatherworkSpec) do AllSpecialtiesTable[i] = true end - for i in pairs(TailorSpec) do AllSpecialtiesTable[i] = true end - end -- do -end - ----Run when the addon is disabled. Ace3 takes care of unregistering events, etc. -function addon:OnDisable() - if addon.Frame then - addon.Frame:Hide() - end - - -- Remove the option from Manufac - if _G.Manufac then - _G.Manufac.options.args.ARLScan = nil - end -end - -------------------------------------------------------------------------------- --- Event handling functions -------------------------------------------------------------------------------- - ----Event used for datamining when a trainer is shown. -function addon:TRAINER_SHOW() - self:ScanTrainerData(true) -end - ----Event used for datamining when a vendor is shown. -function addon:MERCHANT_SHOW() - self:ScanVendor() -end - -do - local GetTradeSkillListLink = _G.GetTradeSkillListLink - local UnitName = _G.UnitName - local GetRealmName = _G.GetRealmName - - function addon:TRADE_SKILL_SHOW() - local is_linked = _G.IsTradeSkillLinked() or _G.IsTradeSkillGuild() - local tradelink = GetTradeSkillListLink() - - local pname = UnitName("player") - local prealm = GetRealmName() - local tradename = _G.GetTradeSkillLine() - - -- Actual alt information saved here. -Torhal - addon.db.global.tradeskill = addon.db.global.tradeskill or {} - addon.db.global.tradeskill[prealm] = addon.db.global.tradeskill[prealm] or {} - addon.db.global.tradeskill[prealm][pname] = addon.db.global.tradeskill[prealm][pname] or {} - - -- If this is our own skill, save it. Otherwise, make sure it's gone. - addon.db.global.tradeskill[prealm][pname][tradename] = (not is_linked) and tradelink or nil - - local scan_button = self.scan_button - local scan_parent = scan_button:GetParent() - - if not scan_parent or scan_parent == _G.UIParent then - scan_button:SetParent(_G.TradeSkillFrame) - scan_parent = scan_button:GetParent() - end - - if scan_parent == _G.TradeSkillFrame then - scan_button:ClearAllPoints() - - local loc = addon.db.profile.scanbuttonlocation - - if loc == "TR" then - scan_button:SetPoint("RIGHT", _G.TradeSkillFrameCloseButton, "LEFT",4,0) - elseif loc == "TL" then - scan_button:SetPoint("LEFT", _G.TradeSkillFramePortrait, "RIGHT",2,12) - elseif loc == "BR" then - scan_button:SetPoint("TOP", _G.TradeSkillCancelButton, "BOTTOM",0,-5) - elseif loc == "BL" then - scan_button:SetPoint("TOP", _G.TradeSkillCreateAllButton, "BOTTOM",0,-5) - end - scan_button:SetWidth(scan_button:GetTextWidth() + 10) - end - scan_button:Show() - end -end - -function addon:TRADE_SKILL_CLOSE() - if self.Frame and addon.db.profile.closeguionskillclose then - self.Frame:Hide() - end - - if not _G.Skillet then - addon.scan_button:Hide() - end -end - -do - local last_update = 0 - local updater = _G.CreateFrame("Frame", nil, _G.UIParent) - - updater:Hide() - updater:SetScript("OnUpdate", - function(self, elapsed) - last_update = last_update + elapsed - - if last_update >= 0.5 then - local profession = _G.GetTradeSkillLine() - - if profession ~= "UNKNOWN" then - addon:Scan(false, true) - end - self:Hide() - end - end) - - function addon:TRADE_SKILL_UPDATE(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10) - if not self.Frame or not self.Frame:IsVisible() then - return - end - - if not updater:IsVisible() then - last_update = 0 - updater:Show() - end - end -end - -------------------------------------------------------------------------------- --- ARL Logic Functions -------------------------------------------------------------------------------- -function addon:InitializeProfession(profession) - if not profession then - --@alpha@ - addon:Print("nil profession passed to InitializeProfession()") - --@end-alpha@ - return - end - - if profession == private.professions["Smelting"] then - profession = private.mining_name - end - local func = PROFESSION_INIT_FUNCS[profession] - - if func then - func(addon) - PROFESSION_INIT_FUNCS[profession] = nil - end -end - -do - local fa = _G.GetSpellInfo(45542) - - -- Code snippet stolen from GearGuage by Torhal and butchered by Ackis - local function StrSplit(input) - if not input then return nil, nil end - local arg1, arg2, var1 - - arg1, var1 = input:match("^([^%s]+)%s*(.*)$") - arg1 = (arg1 and arg1:lower() or input:lower()) - - if var1 then - -- Small hack to get code to work with first aid. - if var1:lower() == fa:lower() then - arg2 = var1 - else - local var2 - arg2, var2 = var1:match("^([^%s]+)%s*(.*)$") - arg2 = (arg2 and arg2:lower() or var1:lower()) - end - end - return arg1, arg2 - end - - -- Determines what to do when the slash command is called. - function addon:ChatCommand(input) - - local arg1, arg2 = StrSplit(input) - - -- Open About panel if there's no parameters or if we do /arl about - if not arg1 or (arg1 and arg1:trim() == "") or arg1 == L["Sorting"]:lower() or arg1 == L["Sort"]:lower() or arg1 == _G.DISPLAY:lower() then - _G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame) - elseif arg1 == L["About"]:lower() then - if self.optionsFrame["About"] then - _G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame["About"]) - else - _G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame) - end - elseif arg1 == L["Profile"]:lower() then - _G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame["Profiles"]) - elseif arg1 == L["Documentation"]:lower() then - _G.InterfaceOptionsFrame_OpenToCategory(self.optionsFrame["Documentation"]) - elseif arg1 == L["Scan"]:lower() then - if not arg2 then - self:Print(L["COMMAND_LINE_SCAN"]) - else - _G.CastSpellByName(arg2) - - if self.Frame and self.Frame:IsVisible() then - self.Frame:Hide() - else - self:Scan(false, false) - end - end - elseif arg1 == "scanprof" then - self:ScanProfession("all") - elseif arg1 == "tradelinks" then - self:GenerateLinks() - else - -- What happens when we get here? - LibStub("AceConfigCmd-3.0"):HandleCommand("arl", "Ackis Recipe List", arg1) - end - end -end - ---- Public API function to initialize all of the lookup lists - self-nils once run. --- @name AckisRecipeList:InitializeLookups() --- @usage if AckisRecipeList.InitializeLookups then AckisRecipeList:InitializeLookups() end -function addon:InitializeLookups() - self:InitCustom(private.custom_list) - self:InitMob(private.mob_list) - self:InitQuest(private.quest_list) - self:InitReputation(private.reputation_list) - self:InitTrainer(private.trainer_list) - self:InitSeasons(private.seasonal_list) - self:InitVendor(private.vendor_list) - - self.InitializeLookups = nil -end - -------------------------------------------------------------------------------- --- Recipe Scanning Functions -------------------------------------------------------------------------------- -do - -- List of tradeskill headers, used in addon:Scan() - local header_list = {} - - -- Toggles a recipe ot known state if it's your own - local function togglerecipe(recipe, is_linked) - if not is_linked then - recipe:AddState("KNOWN") - recipe:RemoveState("LINKED") - else - recipe:AddState("LINKED") - end - end - - --- Causes a scan of the tradeskill to be conducted. Function called when the scan button is clicked. Parses recipes and displays output - -- @name AckisRecipeList:Scan - -- @usage AckisRecipeList:Scan(true) - -- @param textdump Boolean indicating if we want the output to be a text dump, or if we want to use the ARL GUI - -- @return A frame with either the text dump, or the ARL frame - function addon:Scan(textdump, is_refresh) - local current_prof, prof_level = _G.GetTradeSkillLine() - - -- Bail if we haven't opened a tradeskill frame. - if current_prof == "UNKNOWN" then - self:Print(L["OpenTradeSkillWindow"]) - return - end - local player = private.Player - player:SetProfessions() - - -- Set the current profession level, and update the cached data. - private.current_profession_scanlevel = prof_level - - -- Make sure we're only updating a profession the character actually knows - this could be a scan from a tradeskill link. - local is_linked = _G.IsTradeSkillLinked() or _G.IsTradeSkillGuild() - - if not is_linked then - player.has_scanned[current_prof] = true - end - - -- Get the current profession Specialty - local specialty = SpecialtyTable[current_prof] - - for index = 1, 25, 1 do - local spell_name = _G.GetSpellBookItemName(index, _G.BOOKTYPE_SPELL) - - if not spell_name or index == 25 then - player["Specialty"] = nil - break - elseif specialty and specialty[spell_name] then - player["Specialty"] = specialty[spell_name] - break - end - end - - if self.InitializeLookups then - self:InitializeLookups() - end - addon:InitializeProfession(current_prof) - - ------------------------------------------------------------------------------- - -- Scan all recipes and mark the ones we know - ------------------------------------------------------------------------------- - table.wipe(header_list) - - -- Save the current state of the TradeSkillFrame so it can be restored after we muck with it. - local have_materials = _G.TradeSkillFrame.filterTbl.hasMaterials - local have_skillup = _G.TradeSkillFrame.filterTbl.hasSkillUp - local subclass = _G.TradeSkillFrame.filterTbl.subClassValue - local slot = _G.TradeSkillFrame.filterTbl.slotValue - - if _G.MRTAPI and _G.MRTAPI:PushFilterSelection() then - -- MrTrader saved the state for us - else - if not _G.Skillet and have_materials then - _G.TradeSkillFrame.filterTbl.hasMaterials = false - _G.TradeSkillOnlyShowMakeable(false) - end - if not _G.Skillet and have_skillup then - _G.TradeSkillFrame.filterTbl.hasSkillUp = false - _G.TradeSkillOnlyShowSkillUps(false) - end - --UIDropDownMenu_Initialize(TradeSkillFilterDropDown, TradeSkillInvSlotDropDown_Initialize) - --UIDropDownMenu_SetSelectedID(TradeSkillFilterDropDown, 1) - _G.SetTradeSkillInvSlotFilter(0, 1, 1) - _G.TradeSkillUpdateFilterBar() - _G.TradeSkillFrame_Update() - - -- Expand all headers so we can see all the recipes there are - for i = _G.GetNumTradeSkills(), 1, -1 do - local name, tradeType, _, isExpanded = _G.GetTradeSkillInfo(i) - - if tradeType == "header" and not isExpanded then - header_list[name] = true - _G.ExpandTradeSkillSubClass(i) - end - end - end - local recipe_list = private.recipe_list - local recipes_found = 0 - local SF = private.recipe_state_flags - local overwritemap = private.spell_overwrite_map - - for i = 1, _G.GetNumTradeSkills() do - local tradeName, tradeType = _G.GetTradeSkillInfo(i) - - if tradeType ~= "header" then - -- Get the trade skill link for the specified recipe - local spell_link = _G.GetTradeSkillRecipeLink(i) - -- Spell ID of the recipe being scanned. - local spell_string = spell_link:match("^|c%x%x%x%x%x%x%x%x|H%w+:(%d+)") - local spell_id = tonumber(spell_string) - local recipe = recipe_list[spell_id] - - if recipe then - -- Mark the first rank of the spell as known if we know rank 2 for certain recipes. - -- This is only done for recipes which when you learn the higher rank, you lose the - -- ability to learn the lower rank. - - -- If we have it in the mapping, set the lower rank spell to known - if overwritemap[spell_id] then - local overwriterecipe = recipe_list[overwritemap[spell_id]] - if overwriterecipe then - togglerecipe(overwriterecipe, is_linked) - else - self:Debug(tradeName .. " " .. overwritemap[spell_id] .. L["MissingFromDB"]) - end - end - -- Toggle spell to known - togglerecipe(recipe, is_linked) - recipes_found = recipes_found + 1 - else - self:Debug(tradeName .. " " .. spell_string .. L["MissingFromDB"]) - end - end - end - - -- Close all the headers we've opened - -- If Mr Trader is installed use that API - if _G.MRTAPI and _G.MRTAPI:PopFilterSelection() then - -- MrTrader restored the state for us - else - -- Collapse all headers that were collapsed before - for i = _G.GetNumTradeSkills(), 1, -1 do - local name, tradeType, _, isExpanded = _G.GetTradeSkillInfo(i) - - if header_list[name] then - _G.CollapseTradeSkillSubClass(i) - end - end - - -- Restore the state of the things we changed. - _G.TradeSkillFrame.filterTbl.hasMaterials = have_materials - _G.TradeSkillOnlyShowMakeable(have_materials) - _G.TradeSkillFrame.filterTbl.hasSkillUp = have_skillup - _G.TradeSkillOnlyShowSkillUps(have_skillup) - - _G.TradeSkillUpdateFilterBar() - _G.TradeSkillFrame_Update() - - end - player.prev_count = player.foundRecipes - player.foundRecipes = recipes_found - - if is_refresh and player.prev_count == recipes_found then - return - end - - ------------------------------------------------------------------------------- - -- Update the player's reputation levels. - ------------------------------------------------------------------------------- - player:UpdateReputations() - - ------------------------------------------------------------------------------- - -- Everything is ready - display the GUI or dump the list to text. - ------------------------------------------------------------------------------- - if textdump then - self:DisplayTextDump(recipe_list, current_prof) - else - if private.InitializeFrame then - private.InitializeFrame() - end - self.Frame:Display(current_prof, is_linked) - end - end -end - -------------------------------------------------------------------------------- --- Text dumping functions -------------------------------------------------------------------------------- - --------------------------------------------------------------------------------- ---- Creates a new frame with the contents of a text dump so you can copy and paste --- Code borrowed from Antiarc (Chatter) with permission --- @name AckisRecipeList:DisplayTextDump --- @param RecipeDB The database (array) which you wish read data from. --- @param profession Which profession are you displaying data for --- @param text The text to be dumped --------------------------------------------------------------------------------- -do - local copy_frame = _G.CreateFrame("Frame", "ARLCopyFrame", _G.UIParent) - copy_frame:SetBackdrop({ - bgFile = [[Interface\DialogFrame\UI-DialogBox-Background]], - edgeFile = [[Interface\DialogFrame\UI-DialogBox-Border]], - tile = true, - tileSize = 16, - edgeSize = 16, - insets = { - left = 3, - right = 3, - top = 5, - bottom = 3 - } - }) - copy_frame:SetBackdropColor(0, 0, 0, 1) - copy_frame:SetWidth(750) - copy_frame:SetHeight(400) - copy_frame:SetPoint("CENTER", _G.UIParent, "CENTER") - copy_frame:SetFrameStrata("DIALOG") - - table.insert(_G.UISpecialFrames, "ARLCopyFrame") - - local scrollArea = _G.CreateFrame("ScrollFrame", "ARLCopyScroll", copy_frame, "UIPanelScrollFrameTemplate") - scrollArea:SetPoint("TOPLEFT", copy_frame, "TOPLEFT", 8, -30) - scrollArea:SetPoint("BOTTOMRIGHT", copy_frame, "BOTTOMRIGHT", -30, 8) - - local edit_box = _G.CreateFrame("EditBox", nil, copy_frame) - edit_box:SetMultiLine(true) - edit_box:SetMaxLetters(0) - edit_box:EnableMouse(true) - edit_box:SetAutoFocus(true) - edit_box:SetFontObject("ChatFontNormal") - edit_box:SetWidth(650) - edit_box:SetHeight(270) - edit_box:SetScript("OnEscapePressed", - function() - copy_frame:Hide() - end) - edit_box:HighlightText(0) - - scrollArea:SetScrollChild(edit_box) - - local close = _G.CreateFrame("Button", nil, copy_frame, "UIPanelCloseButton") - close:SetPoint("TOPRIGHT", copy_frame, "TOPRIGHT") - - copy_frame:Hide() - - function addon:DisplayTextDump(RecipeDB, profession, text) - local text = (not RecipeDB and not profession) and text or self:GetTextDump(profession) - - if text ~= "" then - edit_box:SetText(text) - edit_box:HighlightText(0) - edit_box:SetCursorPosition(1) - copy_frame:Show() - end - end -end -- do - -do - ------------------------------------------------------------------------------- - -- Dumps recipe output in the format requested by the user - ------------------------------------------------------------------------------- - local text_table = {} - local acquire_list = {} - local ACQUIRE_NAMES = private.acquire_names - - local GetFilterNames - do - local LC = _G.LOCALIZED_CLASS_NAMES_MALE - local FILTER_NAMES - - function GetFilterNames() - if not FILTER_NAMES then - local is_alliance = (private.Player.faction == "Alliance") - - FILTER_NAMES = { - [1] = BFAC["Alliance"], - [2] = BFAC["Horde"], - [3] = L["Trainer"], - [4] = L["Vendor"], - [5] = _G.INSTANCE, - [6] = _G.RAID, - [7] = _G.EVENTS_LABEL, - [8] = L["Quest"], - [9] = _G.PVP, - [10] = L["World Drop"], - [11] = L["Mob Drop"], - [12] = L["Discovery"], - [13] = L["Retired"], - [21] = LC["DEATHKNIGHT"], - [22] = LC["DRUID"], - [23] = LC["HUNTER"], - [24] = LC["MAGE"], - [25] = LC["PALADIN"], - [26] = LC["PRIEST"], - [27] = LC["SHAMAN"], - [28] = LC["ROGUE"], - [29] = LC["WARLOCK"], - [30] = LC["WARRIOR"], - [36] = L["BOEFilter"], - [37] = L["BOPFilter"], - [38] = L["BOAFilter"], - [40] = L["RecipeBOEFilter"], - [41] = L["RecipeBOPFilter"], - [42] = L["RecipeBOAFilter"], - [51] = _G.MELEE, - [52] = _G.TANK, - [53] = _G.HEALER, - [54] = _G.DAMAGER, - [56] = L["Cloth"], - [57] = L["Leather"], - [58] = L["Mail"], - [59] = L["Plate"], - [60] = L["Cloak"], - [61] = L["Trinket"], - [62] = L["Ring"], - [63] = L["Necklace"], - [64] = L["Shield"], - [66] = L["One Hand"], - [67] = L["Two Hand"], - [68] = L["Axe"], - [69] = L["Sword"], - [70] = L["Mace"], - [71] = L["Polearm"], - [72] = L["Dagger"], - [73] = L["Staff"], - [74] = L["Wand"], - [75] = L["Thrown"], - [76] = L["Bow"], - [77] = L["Crossbow"], - [78] = L["Ammo"], - [79] = L["Fist"], - [80] = L["Gun"], - [96] = BFAC["Argent Dawn"], - [97] = BFAC["Cenarion Circle"], - [98] = BFAC["Thorium Brotherhood"], - [99] = BFAC["Timbermaw Hold"], - [100] = BFAC["Zandalar Tribe"], - [101] = BFAC["The Aldor"], - [102] = BFAC["Ashtongue Deathsworn"], - [103] = BFAC["Cenarion Expedition"], - [104] = (is_alliance and BFAC["Honor Hold"] or BFAC["Thrallmar"]), - [105] = BFAC["The Consortium"], - [106] = BFAC["Keepers of Time"], - [107] = BFAC["Lower City"], - [108] = (is_alliance and BFAC["Kurenai"] or BFAC["The Mag'har"]), - [109] = BFAC["The Scale of the Sands"], - [110] = BFAC["The Scryers"], - [111] = BFAC["The Sha'tar"], - [112] = BFAC["Shattered Sun Offensive"], - [113] = BFAC["Sporeggar"], - [114] = BFAC["The Violet Eye"], - [115] = BFAC["Argent Crusade"], - [116] = BFAC["Frenzyheart Tribe"], - [117] = BFAC["Knights of the Ebon Blade"], - [118] = BFAC["Kirin Tor"], - [119] = BFAC["The Sons of Hodir"], - [120] = BFAC["The Kalu'ak"], - [121] = BFAC["The Oracles"], - [122] = BFAC["The Wyrmrest Accord"], - [123] = (is_alliance and BFAC["The Silver Covenant"] or BFAC["The Sunreavers"]), - [124] = (is_alliance and BFAC["Explorers' League"] or BFAC["The Hand of Vengeance"]), - [125] = (is_alliance and BFAC["Valiance Expedition"] or BFAC["Warsong Offensive"]), - [126] = (is_alliance and BFAC["The Frostborn"] or BFAC["The Taunka"]), - [127] = (is_alliance and BFAC["Alliance Vanguard"] or BFAC["Horde Expedition"]), - [128] = BFAC["The Ashen Verdict"], - [129] = (is_alliance and BFAC["Wildhammer Clan"] or BFAC["Dragonmaw Clan"]), - [130] = (is_alliance and BFAC["Baradin's Wardens"] or BFAC["Hellscream's Reach"]), - [131] = BFAC["Guardians of Hyjal"], - [132] = BFAC["Ramkahen"], - [133] = BFAC["The Earthen Ring"], - [134] = BFAC["Therazane"], - } - end - return FILTER_NAMES - end - end -- do - - ---Dumps the recipe database in a format that is readable to humans (or machines) - function addon:GetTextDump(profession) - local output = addon.db.profile.textdumpformat - table.wipe(text_table) - - if not output or output == "Comma" then - table.insert(text_table, ("Ackis Recipe List Text Dump for %s's %s, in the form of Comma Separated Values.\n "):format(private.player_name, profession)) - table.insert(text_table, "Spell ID,Recipe Name,Skill Level,ARL Filter Flags,Acquire Methods,Known\n") - elseif output == "BBCode" then - table.insert(text_table, ("Ackis Recipe List Text Dump for %s's %s, in the form of BBCode.\n"):format(private.player_name, profession)) - elseif output == "XML" then - table.insert(text_table, "") - end - - local recipe_list = private.recipe_list - local SF = private.recipe_state_flags - - for recipe_id in pairs(recipe_list) do - local recipe = recipe_list[recipe_id] - local recipe_prof = _G.GetSpellInfo(recipe.profession) - local is_known = recipe:HasState("KNOWN") - - if recipe_prof == profession then - -- CSV - if not output or output == "Comma" then - -- Add Spell ID, Name and Skill Level to the list - table.insert(text_table, recipe_id) - table.insert(text_table, ",") - table.insert(text_table, recipe.name) - table.insert(text_table, ",") - table.insert(text_table, recipe.skill_level) - table.insert(text_table, ",\"") - -- BBCode - elseif output == "BBCode" then - -- Make the entry red - if not is_known then - table.insert(text_table, "[color=red]") - end - table.insert(text_table, "\n[b]" .. recipe_id .. "[/b] - " .. recipe.name .. " (" .. recipe.skill_level .. ")\n") - - -- Close Color tag - if not is_known then - table.insert(text_table, "[/color]\nRecipe Flags:\n[list]") - elseif is_known then - table.insert(text_table, "\nRecipe Flags:\n[list]") - end - --XML - elseif output == "XML" then - table.insert(text_table, "") - table.insert(text_table, " ..recipe_id..") - table.insert(text_table, " "..recipe.name.."") - table.insert(text_table, " ..recipe.skill_level..") - table.insert(text_table, " "..tostring(is_known).."") - table.insert(text_table, " ") - --Name - elseif output == "Name" then - table.insert(text_table, recipe.name) - end - - -- Add in all the filter flags - local filter_names = GetFilterNames() - local prev = false - - -- Find out which flags are set - for table_index, bits in ipairs(private.bit_flags) do - for flag_name, flag in pairs(bits) do - local bitfield = recipe.flags[private.flag_members[table_index]] - - if bitfield and bit.band(bitfield, flag) == flag then - if not output or output == "Comma" then - if prev then - table.insert(text_table, ",") - end - table.insert(text_table, filter_names[private.filter_flags[flag_name]]) - prev = true - -- BBCode - elseif output == "BBCode" then - table.insert(text_table, "[*]"..filter_names[private.filter_flags[flag_name]]) - elseif output == "XML" then - table.insert(text_table, " "..filter_names[private.filter_flags[flag_name]].."") - end - end - end - end - - if not output or output == "Comma" then - table.insert(text_table, "\",\"") - elseif output == "BBCode" then - table.insert(text_table, "[/list]\nAcquire Methods:\n[list]") - elseif output == "XML" then - table.insert(text_table, " ") - table.insert(text_table, " ") - end - - -- Find out which unique acquire methods we have - local acquire_data = recipe["acquire_data"] - table.wipe(acquire_list) - - for acquire_type in pairs(acquire_data) do - acquire_list[ACQUIRE_NAMES[acquire_type]] = true - end - - -- Add all the acquire methods in - prev = false - - for i in pairs(acquire_list) do - if not output or output == "Comma" then - if prev then - table.insert(text_table, ",") - end - table.insert(text_table, i) - prev = true - elseif output == "BBCode" then - table.insert(text_table, "[*] " .. i) - elseif output == "XML" then - table.insert(text_table, ""..i.."") - end - end - - if not output or output == "Comma" then - table.insert(text_table, "\","..tostring(is_known).."\n") - --if is_known then - -- table.insert(text_table, "\",true\n") - --else - -- table.insert(text_table, "\",false\n") - --end - elseif output == "BBCode" then - table.insert(text_table, "\n[/list]") - elseif output == "XML" then - table.insert(text_table, " ") - table.insert(text_table, "") - end - end - end -- for - return table.concat(text_table, "") - end -end -- 1.7.9.5