local GREY = "|cff999999"; local RED = "|cffff0000"; local WHITE = "|cffFFFFFF"; local GREEN = "|cff1eff00"; local PURPLE = "|cff9F3FFF"; local BLUE = "|cff0070dd"; local ORANGE = "|cffFF8400"; local AL = LibStub("AceLocale-3.0"):GetLocale("AtlasLoot"); local modules = { "AtlasLoot_BurningCrusade", "AtlasLoot_Crafting", "AtlasLoot_OriginalWoW", "AtlasLoot_WorldEvents", "AtlasLoot_WrathoftheLichKing" }; local currentPage = 1; local SearchResult = nil; -- Supported Operators local BINARYOPERATORS = { "&" }; local OPERATORS = { "<>", "<=", ">=", "=", "<", ">" }; -- Supported Stat Filters local STATFILTERS = { -- Base Stats ["stamina"] = "ITEM_MOD_STAMINA_SHORT", ["stam"] = "ITEM_MOD_STAMINA_SHORT", ["sta"] = "ITEM_MOD_STAMINA_SHORT", ["strength"] = "ITEM_MOD_STRENGTH_SHORT", ["str"] = "ITEM_MOD_STRENGTH_SHORT", ["agility"] = "ITEM_MOD_AGILITY_SHORT", ["agi"] = "ITEM_MOD_AGILITY_SHORT", ["intellect"] = "ITEM_MOD_INTELLECT_SHORT", ["int"] = "ITEM_MOD_INTELLECT_SHORT", ["spirit"] = "ITEM_MOD_SPIRIT_SHORT", ["spir"] = "ITEM_MOD_SPIRIT_SHORT", ["spi"] = "ITEM_MOD_SPIRIT_SHORT", ["health"] = "ITEM_MOD_HEALTH_SHORT", ["mana"] = "ITEM_MOD_MANA_SHORT", ["mp5"] = "ITEM_MOD_POWER_REGEN0_SHORT", ["mpr"] = "ITEM_MOD_POWER_REGEN0_SHORT", ["hp5"] = "ITEM_MOD_HEALTH_REGEN_SHORT", ["hpr"] = "ITEM_MOD_HEALTH_REGEN_SHORT", --Sockets ["socketblue"] = "EMPTY_SOCKET_BLUE", ["socketred"] = "EMPTY_SOCKET_RED", ["socketyellow"] = "EMPTY_SOCKET_YELLOW", ["socketmeta"] = "EMPTY_SOCKET_META", ["meta"] = "EMPTY_SOCKET_META", --Secondary Stats ["attackpowerferal"] = "ITEM_MOD_FERAL_ATTACK_POWER_SHORT", ["attackpowferal"] = "ITEM_MOD_FERAL_ATTACK_POWER_SHORT", ["apferal"] = "ITEM_MOD_FERAL_ATTACK_POWER_SHORT", ["attackpower"] = "ITEM_MOD_ATTACK_POWER_SHORT", ["attackpow"] = "ITEM_MOD_ATTACK_POWER_SHORT", ["ap"] = "ITEM_MOD_ATTACK_POWER_SHORT", ["spellpower"] = "ITEM_MOD_SPELL_POWER_SHORT", ["spellpow"] = "ITEM_MOD_SPELL_POWER_SHORT", ["sp"] = "ITEM_MOD_SPELL_POWER_SHORT", ["spellpenetration"] = "ITEM_MOD_SPELL_PENETRATION_SHORT", ["spellpen"] = "ITEM_MOD_SPELL_PENETRATION_SHORT", ["spp"] = "ITEM_MOD_SPELL_PENETRATION_SHORT", ["crit"] = "ITEM_MOD_CRIT_RATING_SHORT", ["haste"] = "ITEM_MOD_HASTE_RATING_SHORT", ["hit"] = "ITEM_MOD_HIT_RATING_SHORT", ["armorpenetration"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHOR", ["armorpen"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHOR", ["arp"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHOR", ["expertise"] = "ITEM_MOD_EXPERTISE_RATING_SHORT", ["exp"] = "ITEM_MOD_EXPERTISE_RATING_SHORT", ["dps"] = "ITEM_MOD_DAMAGE_PER_SECOND_SHORT", ["resilience"] = "ITEM_MOD_RESILIENCE_RATING", ["resil"] = "ITEM_MOD_RESILIENCE_RATING", ["res"] = "ITEM_MOD_RESILIENCE_RATING", ["defense"] = "ITEM_MOD_DEFENSE_SKILL_RATING_SHORT", ["def"] = "ITEM_MOD_DEFENSE_SKILL_RATING_SHORT", ["dodge"] = "ITEM_MOD_DODGE_RATING_SHORT", ["dod"] = "ITEM_MOD_DODGE_RATING_SHORT", ["block"] = "ITEM_MOD_BLOCK_RATING_SHORT", ["blockvalue"] = "ITEM_MOD_BLOCK_VALUE_SHORT", ["blockval"] = "ITEM_MOD_BLOCK_VALUE_SHORT", ["bv"] = "ITEM_MOD_BLOCK_VALUE_SHORT", ["parry"] = "ITEM_MOD_PARRY_RATING_SHORT", --Resistances ["armor"] = "RESISTANCE0_NAME", ["arm"] = "RESISTANCE0_NAME", ["resistancephysical"] = "RESISTANCE0_NAME", ["resistancephys"] = "RESISTANCE0_NAME", ["resphys"] = "RESISTANCE0_NAME", ["resistanceholy"] = "RESISTANCE1_NAME", ["resholy"] = "RESISTANCE1_NAME", ["resistancefire"] = "RESISTANCE2_NAME", ["resfire"] = "RESISTANCE2_NAME", ["resistancenature"] = "RESISTANCE3_NAME", ["resnature"] = "RESISTANCE3_NAME", ["resnat"] = "RESISTANCE3_NAME", ["resistanceforst"] = "RESISTANCE4_NAME", ["resfrost"] = "RESISTANCE4_NAME", ["resistanceshadow"] = "RESISTANCE5_NAME", ["resshadow"] = "RESISTANCE5_NAME", ["resshad"] = "RESISTANCE5_NAME", ["resistancearcane"] = "RESISTANCE6_NAME", ["resarcane"] = "RESISTANCE6_NAME", ["resarc"] = "RESISTANCE6_NAME", }; function AtlasLoot:ShowSearchResult() AtlasLoot_ShowItemsFrame("SearchResult", "SearchResultPage"..currentPage, (AL["Search Result: %s"]):format(AtlasLootCharDB.LastSearchedText or ""), pFrame); end function AtlasLoot:Search(Text) if not Text then return end Text = strtrim(Text); if Text == "" then return end -- Decide if we need load all modules or just specified ones local allDisabled = not self.db.profile.SearchOn.All; if allDisabled then for _, module in ipairs(modules) do if self.db.profile.SearchOn[module] == true then allDisabled = false; break; end end end if allDisabled then DEFAULT_CHAT_FRAME:AddMessage(RED..AL["AtlasLoot"]..": "..WHITE..AL["You don't have any module selected to search on."]); return; end if self.db.profile.SearchOn.All then AtlasLoot_LoadAllModules(); else for k, v in pairs(self.db.profile.SearchOn) do if k ~= "All" and v == true and not IsAddOnLoaded(k) and LoadAddOn(k) and self.db.profile.LoDNotify then DEFAULT_CHAT_FRAME:AddMessage(GREEN..AL["AtlasLoot"]..": "..ORANGE..k..WHITE.." "..AL["sucessfully loaded."]); end end end AtlasLootCharDB["SearchResult"] = {}; AtlasLootCharDB.LastSearchedText = Text; local text = string.lower(Text); --[[if not self.db.profile.SearchOn.All then local module = AtlasLoot_GetLODModule(dataSource); if not module or self.db.profile.SearchOn[module] ~= true then return end end]] local function HaveBinaryOperator (textValue) for index, operator in ipairs(BINARYOPERATORS) do if string.find(textValue, operator) then return operator; end end return nil; end local function HaveOperator (textValue) for index, operator in ipairs(OPERATORS) do if string.find(textValue, operator) then return operator; end end return nil; end local function SplitString(str, delimiter) result = {}; for match in (str..delimiter):gmatch("(.-)"..delimiter) do table.insert(result, match); end return result; end local function HaveStat (textValue) for index, statItem in pairs(STATFILTERS) do if string.find(textValue, index) then return STATFILTERS[index]; end end return nil; end local function CompareNumbersByOperator (operator, baseValue, valueToCompare) if baseValue ~= nil and valueToCompare ~= nil and ((operator == "<>") and (baseValue ~= valueToCompare) or (operator == "<=") and (baseValue <= valueToCompare) or (operator == ">=") and (baseValue >= valueToCompare) or (operator == "=") and (baseValue == valueToCompare) or (operator == "<") and (baseValue < valueToCompare) or (operator == ">") and (baseValue > valueToCompare)) then return true; end return false; end local function IsItemMatch(searchTextItem, stats, operator) if stats then local statFilterFound = HaveStat(searchTextItem); if statFilterFound then local statValue = tonumber(stats[statFilterFound]); local searchedStat = tonumber(string.match(searchTextItem, "%d+")); if CompareNumbersByOperator(operator, statValue, searchedStat) then return true; end end end return false; end local partial = self.db.profile.PartialMatching; for dataID, data in pairs(AtlasLoot_Data) do for _, v in ipairs(data) do if type(v[2]) == "number" and v[2] > 0 then local itemName = GetItemInfo(v[2]); if not itemName then itemName = gsub(v[4], "=q%d=", "") end -- Checks for Stat Filter by searching for an Operator in the search text local operator = HaveOperator(text); if operator ~= nil then local itemId = tostring(v[2]); -- Stat Filter local stats = GetItemStats("item:"..itemId); if stats then -- Currently only supports "&" local binaryOperator = HaveBinaryOperator(text); if binaryOperator ~= nil then local searchItems = SplitString(text, binaryOperator); local searchConditionsMet = true; for _, searchTextItem in ipairs(searchItems) do local localOperator = HaveOperator(searchTextItem); if not localOperator or not IsItemMatch(searchTextItem, stats, localOperator) then searchConditionsMet = false; end; end table.wipe(searchItems); if searchConditionsMet then table.insert(AtlasLootCharDB["SearchResult"], { 0, v[2], v[3], itemName, lootpage, "", "", dataID.."|".."\"\"" }); end elseif IsItemMatch(text, stats, operator) then table.insert(AtlasLootCharDB["SearchResult"], { 0, v[2], v[3], itemName, lootpage, "", "", dataID.."|".."\"\"" }); end table.wipe(stats); end end local found; if partial then found = string.find(string.lower(itemName), text); else found = string.lower(itemName) == text; end if found then local _, _, quality = string.find(v[4], "=q(%d)="); if quality then itemName = "=q"..quality.."="..itemName end if AtlasLoot_TableNames[dataID] then lootpage = AtlasLoot_TableNames[dataID][1]; else lootpage = "Argh!"; end table.insert(AtlasLootCharDB["SearchResult"], { 0, v[2], v[3], itemName, lootpage, "", "", dataID.."|".."\"\"" }); end elseif (v[2] ~= nil) and (v[2] ~= "") and (string.sub(v[2], 1, 1) == "s") then local spellName = GetSpellInfo(string.sub(v[2], 2)); if not spellName then if (string.sub(v[4], 1, 2) == "=d") then spellName = gsub(v[4], "=ds=", ""); else spellName = gsub(v[4], "=q%d=", ""); end end local found; if partial then found = string.find(string.lower(spellName), text); else found = string.lower(spellName) == text; end if found then spellName = string.sub(v[4], 1, 4)..spellName; if AtlasLoot_TableNames[dataID][1] then lootpage = AtlasLoot_TableNames[dataID][1]; else lootpage = "Argh!"; end table.insert(AtlasLootCharDB["SearchResult"], { 0, v[2], v[3], spellName, lootpage, "", "", dataID.."|".."\"\"" }); end end end end if #AtlasLootCharDB["SearchResult"] == 0 then DEFAULT_CHAT_FRAME:AddMessage(RED..AL["AtlasLoot"]..": "..WHITE..AL["No match found for"].." \""..Text.."\"."); else currentPage = 1; SearchResult = AtlasLoot_CategorizeWishList(AtlasLootCharDB["SearchResult"]); AtlasLoot_ShowItemsFrame("SearchResult", "SearchResultPage1", (AL["Search Result: %s"]):format(AtlasLootCharDB.LastSearchedText or ""), pFrame); end end function AtlasLoot:ShowSearchOptions(button) local dewdrop = AceLibrary("Dewdrop-2.0"); if dewdrop:IsOpen(button) then dewdrop:Close(1); else local setOptions = function() dewdrop:AddLine( "text", AL["Search on"], "isTitle", true, "notCheckable", true ); dewdrop:AddLine( "text", AL["All modules"], "checked", self.db.profile.SearchOn.All, "tooltipTitle", AL["All modules"], "tooltipText", AL["If checked, AtlasLoot will load and search across all the modules."], "func", function() self.db.profile.SearchOn.All = not self.db.profile.SearchOn.All; end ); for _, module in ipairs(modules) do if IsAddOnLoadOnDemand(module) then local title = GetAddOnMetadata(module, "title"); local notes = GetAddOnMetadata(module, "notes"); dewdrop:AddLine( "text", title, "checked", self.db.profile.SearchOn.All or self.db.profile.SearchOn[module], "disabled", self.db.profile.SearchOn.All, "tooltipTitle", title, "tooltipText", notes, "func", function() if self.db.profile.SearchOn[module] == nil then self.db.profile.SearchOn[module] = true; else self.db.profile.SearchOn[module] = nil; end end ); end end dewdrop:AddLine( "text", AL["Search options"], "isTitle", true, "notCheckable", true ); dewdrop:AddLine( "text", AL["Partial matching"], "checked", self.db.profile.PartialMatching, "tooltipTitle", AL["Partial matching"], "tooltipText", AL["If checked, AtlasLoot search item names for a partial match."], "func", function() self.db.profile.PartialMatching = not self.db.profile.PartialMatching end ); end; dewdrop:Open(button, 'point', function(parent) return "BOTTOMLEFT", "BOTTOMRIGHT"; end, "children", setOptions ); end end function AtlasLoot:GetOriginalDataFromSearchResult(itemID) for i, v in ipairs(AtlasLootCharDB["SearchResult"]) do if v[2] == itemID then AtlasLoot_ShowWishListDropDown(v[2], v[3], v[4], v[5], v[8], this); end end end -- Copied and modified from AtlasLoot_GetWishListPage function AtlasLoot:GetSearchResultPage(page) if not SearchResult then SearchResult = AtlasLoot_CategorizeWishList(AtlasLootCharDB["SearchResult"]) end -- Calc for maximal pages local pageMax = math.ceil(#SearchResult / 30); if page < 1 then page = 1 end if page > pageMax then page = pageMax end currentPage = page; -- Table copy local k=1; local result = {}; local start = (page - 1) * 30 + 1; for i = start, start + 29 do if not SearchResult[i] then break end SearchResult[i][1] = k; table.insert(result, SearchResult[i]); k=k+1; end return result, pageMax; end