Mythic+ 30 and Updated Search functions and files

This commit is contained in:
merstrax
2022-01-15 04:55:43 -05:00
parent f354b79231
commit d9c6979f75
15 changed files with 12689 additions and 12912 deletions
+385 -366
View File
@@ -8,105 +8,106 @@ local ORANGE = "|cffFF8400";
local AL = LibStub("AceLocale-3.0"):GetLocale("AtlasLoot");
local modules = { "AtlasLoot_BurningCrusade", "AtlasLoot_Crafting", "AtlasLoot_OriginalWoW", "AtlasLoot_WorldEvents", "AtlasLoot_WrathoftheLichKing" };
currentPage = 1;
SearchResult = nil;
local currentPage = 1;
local SearchResult = nil;
-- Supported Operators
BINARYOPERATORS = { "&" };
OPERATORS = { "<>", "<=", ">=", "=", "<", ">" };
local OP_AND = "&"
local BINARYOPERATORS = { OP_AND };
-- multi-character patterns must come before single-character patterns
local RELATIONAL_OPERATORS = { ">=", "<=", "<>", "<", ">", "=", };
-- Supported Stat Filters
STATFILTERS = {
local STAT_FILTERS = {
-- 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",
["spr"] = "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",
["socketnocolor"] = "EMPTY_SOCKET_NO_COLOR",
["socketwhite"] = "EMPTY_SOCKET_NO_COLOR",
["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_SHORT",
["armourpenetration"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT",
["armorpen"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT",
["armourpen"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT",
["arp"] = "ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT",
["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",
["armour"] = "RESISTANCE0_NAME",
@@ -114,30 +115,37 @@ STATFILTERS = {
["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"
};
ITEMSOCKETSTATFILTERS = {
local SOCKET_FILTERS = {
["socket"] = true,
["sockets"] = true,
["gem"] = true,
["gems"] = true,
};
local SOCKET_TYPES = {
"EMPTY_SOCKET_BLUE",
"EMPTY_SOCKET_RED",
"EMPTY_SOCKET_YELLOW",
@@ -145,51 +153,336 @@ ITEMSOCKETSTATFILTERS = {
"EMPTY_SOCKET_NO_COLOR"
};
ITEMINFOFILTERS = {
["ilvl"] = "ilvl",
["minlvl"] = "minlvl",
["type"] = "type",
["subtype"] = "subtype",
["quality"] = "quality"
local INFO_FILTERS = {
["ilvl"] = true,
["minlvl"] = true,
--["type"] = true,
--["subtype"] = true,
};
ITEMLEVELGEAREQUIPFILTER = {
["INVTYPE_NON_EQUIP"] = "INVTYPE_NON_EQUIP",
["INVTYPE_BODY"] = "INVTYPE_BODY",
["INVTYPE_BAG"] = "INVTYPE_BAG",
["INVTYPE_AMMO"] = "INVTYPE_AMMO",
["INVTYPE_QUIVER"] = "INVTYPE_QUIVER"
local QUALITY_FILTERS = {
["poor"] = 0,
["common"] = 1,
["uncommon"] = 2,
["rare"] = 3,
["epic"] = 4,
["legendary"] = 5,
["artifact"] = 6,
["heirloom"] = 7
};
-- Slash command that prints out all used item filter keys
SLASH_ATLASLOOTITEMINFOFILTERS1 = "/atlaslootfilterkeys";
SlashCmdList["ATLASLOOTITEMINFOFILTERS"] = function(msg, editBox)
local sortedTable = { "socket", "sockets", "gem", "gems", "ilvl" };
for index, statItem in pairs(STATFILTERS) do
table.insert(sortedTable, index);
end
table.sort(sortedTable, function(a,b) return a < b; end)
local SLOT_FILTERS = {
["none"] = "INVTYPE_NON_EQUIP",
["head"] = "INVTYPE_HEAD",
["neck"] = "INVTYPE_NECK",
["shoulder"] = "INVTYPE_SHOULDER",
["body"] = "INVTYPE_BODY",
["chest"] = "INVTYPE_CHEST",
["waist"] = "INVTYPE_WAIST",
["legs"] = "INVTYPE_LEGS",
["feet"] = "INVTYPE_FEET",
["wrist"] = "INVTYPE_WRIST",
["hand"] = "INVTYPE_HAND",
["finger"] = "INVTYPE_FINGER",
["trinket"] = "INVTYPE_TRINKET",
["weapon"] = "INVTYPE_WEAPON",
["shield"] = "INVTYPE_SHIELD",
["ranged"] = "INVTYPE_RANGED",
["cloak"] = "INVTYPE_CLOAK",
["2hweapon"] = "INVTYPE_2HWEAPON",
["bag"] = "INVTYPE_BAG",
["tabard"] = "INVTYPE_TABARD",
["robe"] = "INVTYPE_ROBE",
["weaponmainhand"] = "INVTYPE_WEAPONMAINHAND",
["mainhand"] = "INVTYPE_WEAPONMAINHAND",
["weaponoffhand"] = "INVTYPE_WEAPONOFFHAND",
["offhand"] = "INVTYPE_WEAPONOFFHAND",
["holdable"] = "INVTYPE_HOLDABLE",
["ammo"] = "INVTYPE_AMMO",
["thrown"] = "INVTYPE_THROWN",
["rangedright"] = "INVTYPE_RANGEDRIGHT",
["quiver"] = "INVTYPE_QUIVER",
["relic"] = "INVTYPE_RELIC"
};
local filterKeys = "Filter keys: [ ";
for i, filterIndex in pairs(sortedTable) do
if i == 1 then
filterKeys = filterKeys..filterIndex;
else
filterKeys = filterKeys..", "..filterIndex;
end
end
filterKeys = filterKeys.." ]";
print(filterKeys);
local NON_EQUIPABLE_SLOTS = {
["INVTYPE_NON_EQUIP"] = true,
["INVTYPE_BODY"] = true,
["INVTYPE_BAG"] = true,
["INVTYPE_AMMO"] = true,
["INVTYPE_QUIVER"] = true,
};
SLASH_ATLASLOOTHELP1 = "/atlasloothelp";
SlashCmdList["ATLASLOOTHELP"] = function(msg, editBox)
local function show(caption, t)
local keys = {}
for key in pairs(t) do table.insert(keys, key) end
table.sort(keys, function(a,b) return a < b end)
print(caption..": ".. table.concat(keys, ", "))
end
show("stat", STAT_FILTERS)
show("socket", SOCKET_FILTERS)
show("slot", SLOT_FILTERS)
show("quality", QUALITY_FILTERS)
show("info", INFO_FILTERS)
print("\nExamples:")
print("gladiator")
print("str>40")
print("gladiator&str>40")
print("str>40&ilvl>=120&ilvl<140&int>0&socket>2");
print("sp>20&quality>=rare&quality<legendary&slot=finger");
print("stam>20&minlvl<=50")
end
-- Slash command that prints filter examples
SLASH_ATLASLOOTITEMINFOFILTEREXAMPLE1 = "/atlaslootfilterexample";
SlashCmdList["ATLASLOOTITEMINFOFILTEREXAMPLE"] = function(msg, editBox)
print("Single search example: str>40");
print("Multi search example: str>40&ilvl<140&ilvl>=120&int>0&socket>2");
SLASH_ATLASLOOTSEARCH1 = "/atlaslootsearch";
SLASH_ATLASLOOTSEARCH2 = "/als";
SlashCmdList["ATLASLOOTSEARCH"] = function(search, editBox)
AtlasLootDefaultFrame:Show()
if search and search ~= '' then
AtlasLootDefaultFrameSearchBox:SetText(search)
AtlasLootDefaultFrameSearchButton:Click()
end
end
-- split one string on another (delimiter can be more than one character)
local function SplitString(str, delimiter)
local result = {}
local start = 1
local len = #str
while start <= len do
local delimPos = str:find(delimiter, start, true)
if delimPos then
result[#result+1] = str:sub(start, delimPos-1) -- grab up to the delimeter
start = delimPos + #delimiter -- advance past the delimiter
else
result[#result+1] = str:sub(start) -- grab the rest of the string
break
end
end
return result
end
local function CompareNumbersByOperator(operator, left, right)
return left and right and (
(operator == "<>" and left ~= right)
or (operator == "<=" and left <= right)
or (operator == ">=" and left >= right)
or (operator == "=" and left == right)
or (operator == "<" and left < right)
or (operator == ">" and left > right)
)
end
local function ThrowQueryError(...)
error("Error: "..string.format(...))
end
local function IsItemStatMatch(term, stats)
local filterKey = STAT_FILTERS[term.left]
if not filterKey then
return
end
local statValue = tonumber(stats[filterKey])
if not statValue then
return
end
local searchedValue = tonumber(term.right)
if not searchedValue then
ThrowQueryError("'%s' requires a numeric argument", term.left)
end
return CompareNumbersByOperator(term.relational, statValue, searchedValue)
end
local function IsItemLevelFilterMatch(term, itemLvl, itemEquipLoc)
if term.left ~= "ilvl" then
return
end
local searchedValue = tonumber(term.right);
if not searchedValue then
ThrowQueryError("ilvl search requires a numeric argument")
end
return itemLvl ~= nil and itemLvl > 0 and CompareNumbersByOperator(term.relational, itemLvl, searchedValue)
end
local function IsItemQualityMatch(term, itemQuality)
if term.left ~= "quality" then
return
end
local searchedValue = QUALITY_FILTERS[term.right]
if not searchedValue then
ThrowQueryError("unrecognized quality value \"%s\"", term.right)
end
return CompareNumbersByOperator(term.relational, itemQuality, searchedValue)
end
local function IsItemSocketMatch(term, stats)
if not SOCKET_FILTERS[term.left] then
return
end
local searchedValue = tonumber(term.right)
if not searchedValue then
ThrowQueryError("'%s' requires a numeric argument", term.left)
end
local socketCount = 0;
for _, socketType in pairs(SOCKET_TYPES) do
local statValue = tonumber(stats[socketType]);
if statValue then
socketCount = socketCount + statValue;
end
end
return CompareNumbersByOperator(term.relational, socketCount, searchedValue)
end
local function IsMinLevelFilterMatch(term, minLvl)
if term.left ~= "minlvl" then
return
end
local searchedValue = tonumber(term.right);
if not searchedValue then
ThrowQueryError("minlvl search requires a numeric argument")
end
return minLvl ~= nil and minLvl > 0 and CompareNumbersByOperator(term.relational, minLvl, searchedValue)
end
local function IsItemSlotMatch(term, itemEquipLoc)
if term.left ~= "slot" then
return
end
if term.relational ~= "=" then
ThrowQueryError("slot searches should be in the form \"slot=[slotname]\"")
end
local slot = SLOT_FILTERS[term.right]
if not slot then
ThrowQueryError("unrecognized slot name: \"%s\"", term.right)
end
return slot == itemEquipLoc
end
local function nameMatches(name, searchText)
if AtlasLoot.db.profile.PartialMatching then
return string.find(string.lower(name), searchText);
else
return string.lower(name) == searchText;
end
end
local function ItemMatchesTerm(term, itemName, stats, itemLvl, minLvl, itemQuality, itemEquipLoc)
if term.relational then
return IsItemStatMatch(term, stats)
or IsItemSocketMatch(term, stats)
or IsItemLevelFilterMatch(term, itemLvl, itemEquipLoc)
or IsMinLevelFilterMatch(term, minLvl)
or IsItemSlotMatch(term, itemEquipLoc)
or IsItemQualityMatch(term, itemQuality)
else
return nameMatches(itemName, term.name)
end
end
local function ItemMatchesAllTerms(searchTerms, itemName, stats, itemLvl, minLvl, itemQuality, itemEquipLoc)
for _, term in ipairs(searchTerms) do
if not ItemMatchesTerm(term, itemName, stats, itemLvl, minLvl, itemQuality, itemEquipLoc) then
return false
end
end
return true
end
local function ParseTerm(termText)
for _, relational in ipairs(RELATIONAL_OPERATORS) do
local operands = SplitString(termText, relational)
if #operands == 2 then
return {
left = operands[1],
right = operands[2],
relational = relational
}
end
end
return { name = termText } -- simple name search
end
-- Parse search text into '&'-delimited search terms,
-- then parse each term on its relational operator, if present.
local function ParseQuery(searchText)
local terms = {}
for i, term in pairs(SplitString(searchText, OP_AND)) do
table.insert(terms, ParseTerm(term))
end
return terms
end
local function GetItemDetails(itemId, atlasName)
-- Name, Link, Quality(num), iLvl(num), minLvl(num), itemType(localized string), itemSubType(localized string), stackCount(num), itemEquipLoc(enum), texture(link to a local file), displayId(num)
local itemName, _, itemQuality, itemLvl, minLvl, _, _, _, itemEquipLoc = GetItemInfo(itemId);
if not itemName then itemName = gsub(atlasName, "=q%d=", "") end
return itemName, itemQuality, itemLvl, minLvl, itemEquipLoc, GetItemStats("item:"..itemId)
end
local function GetSpellName(itemId, atlasName)
local spellName = GetSpellInfo(string.sub(itemId, 2));
if spellName then
return spellName
elseif (string.sub(atlasName, 1, 2) == "=d") then
return gsub(atlasName, "=ds=", "");
else
return gsub(atlasName, "=q%d=", "");
end
end
local function DoSearch(searchText)
AtlasLootCharDB["SearchResult"] = {};
AtlasLootCharDB.LastSearchedText = Text;
local function AddItemToSearchResult(itemId, itemType, itemName, dataID)
local lootPage = AtlasLoot_TableNames[dataID] and AtlasLoot_TableNames[dataID][1] or "Argh!";
table.insert(AtlasLootCharDB["SearchResult"], { 0, itemId, itemType, itemName, lootPage, "", "", dataID.."|".."\"\"", [AtlasLoot_Difficulty.DIF_SEARCH] = 2});
end
local searchTerms = ParseQuery(searchText)
local equipableFilterOn = AtlasLoot.db.profile.EquipableFilter
local function IsItemEquipableMatch(itemEquipLoc)
return not equipableFilterOn or (itemEquipLoc and itemEquipLoc ~= '' and not NON_EQUIPABLE_SLOTS[itemEquipLoc])
end
for dataID, data in pairs(AtlasLoot_Data) do
for _, v in ipairs(data) do
local _, itemId, itemType, atlasName = unpack(v)
if type(itemId) == "number" and itemId > 0 then
local itemName, itemQuality, itemLvl, minLvl, itemEquipLoc, stats = GetItemDetails(itemId, atlasName);
if IsItemEquipableMatch(itemEquipLoc) and ItemMatchesAllTerms(searchTerms, itemName, stats, itemLvl, minLvl, itemQuality, itemEquipLoc) then
AddItemToSearchResult(itemId, itemType, itemName, dataID)
end
elseif not equipableFilterOn and itemId and itemId ~= "" and string.sub(itemId, 1, 1) == "s" then
local spellName = GetSpellName(itemId, atlasName)
if nameMatches(spellName, searchText) then
spellName = string.sub(atlasName, 1, 4)..spellName;
AddItemToSearchResult(itemId, itemType, spellName, dataID)
end
end
end
end
end
function AtlasLoot:ShowSearchResult()
AtlasLoot_ShowItemsFrame("SearchResult", "SearchResultPage"..currentPage, (AL["Search Result: %s"]):format(AtlasLootCharDB.LastSearchedText or ""), pFrame);
end
@@ -198,7 +491,7 @@ 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
@@ -210,7 +503,7 @@ function AtlasLoot:Search(Text)
end
end
if allDisabled then
DEFAULT_CHAT_FRAME:AddMessage(RED..AL["AtlasLoot"]..": "..WHITE..AL["You don't have any module selected to search on."]);
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
@@ -222,299 +515,18 @@ function AtlasLoot:Search(Text)
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 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
-- Region: Stat Filter
local function IsSocketTermInSearchText(searchText)
if string.find(searchText, "socket")
or string.find(searchText, "sockets")
or string.find(searchText, "gem")
or string.find(searchText, "gems")
then
return true;
end
return false;
end
local function IsSocketTermEqualsSearchText(searchText)
if searchText == "socket"
or searchText == "sockets"
or searchText == "gem"
or searchText == "gems"
then
return true;
end
return false;
end
local function FilterSockets(searchTextItem, stats, operator)
if stats then
if IsSocketTermInSearchText(searchTextItem) then
local searchedStatValue = tonumber(string.match(searchTextItem, "%d+"));
local searchTerm = string.gsub(searchTextItem, tostring(searchedStatValue), "");
searchTerm = string.gsub(searchTerm, operator, "");
if IsSocketTermEqualsSearchText(searchTerm) then
local socketCount = 0;
for _, socketType in pairs(ITEMSOCKETSTATFILTERS) do
if socketType then
local statValue = tonumber(stats[socketType]);
if statValue then
socketCount = socketCount + statValue;
end
end
end
if CompareNumbersByOperator(operator, socketCount, searchedStatValue) then
return true;
end
end
end
end
return false;
end
local function HaveStat (textValue)
for index, statItem in pairs(STATFILTERS) do
if textValue == index then
return STATFILTERS[index];
end
end
return nil;
end
local function IsItemStatMatch(searchTextItem, stats, operator)
if stats then
local searchedStat = tonumber(string.match(searchTextItem, "%d+"));
local searchTerm = searchTextItem.gsub(searchTextItem, tostring(searchedStat), "");
searchTerm = string.gsub(searchTerm, operator, "");
local statFilterFound = HaveStat(searchTerm);
if statFilterFound then
local statValue = tonumber(stats[statFilterFound]);
if CompareNumbersByOperator(operator, statValue, searchedStat) then
return true;
end
else
return FilterSockets(searchTextItem, stats, operator);
end
end
return false;
end
-- EndRegion
-- Region: Item Level Filter
local function HaveItemInfoFilter (textValue)
for index, itemInfoFilter in pairs(ITEMINFOFILTERS) do
if textValue == index then
return index;
end
end
return nil;
end
local function IsEquipableGear (textValue)
if textValue == nil or textValue == "" then
return false;
end
for index, equipLoc in ipairs(ITEMLEVELGEAREQUIPFILTER) do
if string.find(textValue, equipLoc) then
return false;
end
end
return true;
end
local function IsItemLevelFilter (textValue)
local itemLevelFilter = ITEMINFOFILTERS["ilvl"];
if string.match(textValue, itemLevelFilter) then
return true;
end
return false;
end
local function IsItemLevelFilterMatch(searchText, itemLvl, itemEquipLoc, operator)
local searchedItemLevel = tonumber(string.match(searchText, "%d+"));
local searchTerm = searchText.gsub(searchText, tostring(searchedItemLevel), "");
searchTerm = string.gsub(searchTerm, operator, "");
local itemInfoFilter = HaveItemInfoFilter(searchTerm);
if itemInfoFilter and itemLvl ~= nil and itemLvl > 0
--TODO Equipment filter patch
--and IsEquipableGear(itemEquipLoc)
and IsItemLevelFilter(itemInfoFilter)
then
if CompareNumbersByOperator(operator, itemLvl, searchedItemLevel) then
return true;
end
end
return false;
end
-- EndRegion
-- Add item to Search Result
local function AddItemToSearchResult(itemId, itemType, itemName, lootPage, dataId)
table.insert(AtlasLootCharDB["SearchResult"], { 0, itemId, itemType, itemName, lootPage, "", "", dataId.."|".."\"\"" });
end
-- Checks for Partial Matching
local partial = self.db.profile.PartialMatching;
-- Checks for Item Filters by searching for an Operator in the search text
local operator = HaveOperator(text);
for dataID, data in pairs(AtlasLoot_Data) do
for _, v in ipairs(data) do
if type(v[2]) == "number" and v[2] > 0 then
-- Name, Link, Quality(num), iLvl(num), minLvl(num), itemType(localized string), itemSubType(localized string), stackCount(num), itemEquipLoc(enum), texture(link to a local file), displayId(num)
local itemName, _, itemQuality, itemLvl, minLvl, _, _, _, itemEquipLoc = GetItemInfo(v[2]);
if not itemName then itemName = gsub(v[4], "=q%d=", "") end
local success, message = pcall(DoSearch, Text)
if operator ~= nil then
local stats = GetItemStats("item:"..tostring(v[2]));
-- Currently only supports "&"
local binaryOperator = HaveBinaryOperator(text);
if binaryOperator ~= nil then
local searchConditionsMet = true;
local searchItems = SplitString(text, binaryOperator);
if searchItems then
for _, searchTextItem in ipairs(searchItems) do
local localOperator = HaveOperator(searchTextItem);
if not localOperator
or not (
-- Stat Filter
IsItemStatMatch(searchTextItem, stats, localOperator)
-- Item Level Filter
or IsItemLevelFilterMatch(searchTextItem, itemLvl, itemEquipLoc, localOperator)
)
then
searchConditionsMet = false;
break;
end
end
if searchConditionsMet then
AddItemToSearchResult(v[2], v[3], itemName, lootpage, dataID);
end
end
else
-- Stat Filter
if IsItemStatMatch(text, stats, operator)
-- Item Level Filter
or IsItemLevelFilterMatch(text, itemLvl, itemEquipLoc, operator)
then
AddItemToSearchResult(v[2], v[3], itemName, lootpage, dataID);
end
-- TODO itemQuality
-- TODO minLvl
-- TODO itemEquipLoc
end
-- Stat Table Cleanup
if stats then
table.wipe(stats);
end
end
local found;
if partial then
local res = SplitString(text, " ");
for _, t in ipairs(res) do
found = string.find(string.lower(itemName), t);
if not found then
break;
end
end
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
if not success then
message = message:match("[^:]+: (.*)") or message -- strip stack location
DEFAULT_CHAT_FRAME:AddMessage(RED..AL["AtlasLoot"]..": "..WHITE..message);
elseif #AtlasLootCharDB["SearchResult"] == 0 then
local itemFilterErrorMessage = "";
if operator then
itemFilterErrorMessage = [[
Please check if you have a typo in the filter.
To check filter keys, type "/atlaslootfilterkeys".
To check filter examples, type "/atlaslootfilterexample".
For help, type "/atlasloothelp".
You might also have to query the server for item informations to load them into your client's Cache.]];
end
DEFAULT_CHAT_FRAME:AddMessage(RED..AL["AtlasLoot"]..": "..WHITE..AL["No match found for"].." \""..Text.."\"."..itemFilterErrorMessage);
@@ -577,6 +589,13 @@ function AtlasLoot:ShowSearchOptions(button)
"tooltipText", AL["If checked, AtlasLoot search item names for a partial match."],
"func", function() self.db.profile.PartialMatching = not self.db.profile.PartialMatching end
);
dewdrop:AddLine(
"text", "Only search equipable", -- TODO: put in AL
"checked", self.db.profile.EquipableFilter,
"tooltipTitle", "Equipable filter", -- TODO: put in AL
"tooltipText", "If checked, AtlasLoot only includes items that are euipable.", -- TODO: put in AL
"func", function() self.db.profile.EquipableFilter = not self.db.profile.EquipableFilter end
);
end;
dewdrop:Open(button,
'point', function(parent)
@@ -589,8 +608,8 @@ 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, nil, v[AtlasLoot_Difficulty.DIF_SEARCH]);
if v[2] == itemID then
AtlasLoot_ShowWishListDropDown(v[2], v[3], v[4], v[5], v[8], this, nil, v[AtlasLoot_Difficulty.DIF_SEARCH]);
end
end
end