diff --git a/AtlasLoot/Core/Search.lua b/AtlasLoot/Core/Search.lua index 7f75e39..1ad7f30 100644 --- a/AtlasLoot/Core/Search.lua +++ b/AtlasLoot/Core/Search.lua @@ -7,259 +7,257 @@ 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 modules = {"AtlasLoot_BurningCrusade", "AtlasLoot_Crafting", "AtlasLoot_OriginalWoW", "AtlasLoot_WorldEvents", "AtlasLoot_WrathoftheLichKing"}; local currentPage = 1; local SearchResult = nil; -- Supported Operators local OP_AND = "&" -local BINARYOPERATORS = { OP_AND }; - -- multi-character patterns must come before single-character patterns -local RELATIONAL_OPERATORS = { ">=", "<=", "<>", "<", ">", "=", }; +local BINARYOPERATORS = {OP_AND}; +-- multi-character patterns must come before single-character patterns +local RELATIONAL_OPERATORS = {">=", "<=", "<>", "<", ">", "="}; -- Supported Stat Filters local STAT_FILTERS = { - -- Base Stats - ["stamina"] = "ITEM_MOD_STAMINA_SHORT", - ["stam"] = "ITEM_MOD_STAMINA_SHORT", - ["sta"] = "ITEM_MOD_STAMINA_SHORT", + -- 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", + ["strength"] = "ITEM_MOD_STRENGTH_SHORT", + ["str"] = "ITEM_MOD_STRENGTH_SHORT", - ["agility"] = "ITEM_MOD_AGILITY_SHORT", - ["agi"] = "ITEM_MOD_AGILITY_SHORT", + ["agility"] = "ITEM_MOD_AGILITY_SHORT", + ["agi"] = "ITEM_MOD_AGILITY_SHORT", - ["intellect"] = "ITEM_MOD_INTELLECT_SHORT", - ["int"] = "ITEM_MOD_INTELLECT_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", + ["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", + ["health"] = "ITEM_MOD_HEALTH_SHORT", + ["mana"] = "ITEM_MOD_MANA_SHORT", - ["mp5"] = "ITEM_MOD_POWER_REGEN0_SHORT", - ["mpr"] = "ITEM_MOD_POWER_REGEN0_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", + ["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", + -- Sockets + ["socketblue"] = "EMPTY_SOCKET_BLUE", + ["socketred"] = "EMPTY_SOCKET_RED", + ["socketyellow"] = "EMPTY_SOCKET_YELLOW", - ["socketnocolor"] = "EMPTY_SOCKET_NO_COLOR", - ["socketwhite"] = "EMPTY_SOCKET_NO_COLOR", + ["socketnocolor"] = "EMPTY_SOCKET_NO_COLOR", + ["socketwhite"] = "EMPTY_SOCKET_NO_COLOR", - ["socketmeta"] = "EMPTY_SOCKET_META", - ["meta"] = "EMPTY_SOCKET_META", + ["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", + -- 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", + ["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", + ["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", + ["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", + ["crit"] = "ITEM_MOD_CRIT_RATING_SHORT", + ["haste"] = "ITEM_MOD_HASTE_RATING_SHORT", - ["hit"] = "ITEM_MOD_HIT_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", + ["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", + ["expertise"] = "ITEM_MOD_EXPERTISE_RATING_SHORT", + ["exp"] = "ITEM_MOD_EXPERTISE_RATING_SHORT", - ["dps"] = "ITEM_MOD_DAMAGE_PER_SECOND_SHORT", + ["dps"] = "ITEM_MOD_DAMAGE_PER_SECOND_SHORT", - ["resilience"] = "ITEM_MOD_RESILIENCE_RATING", - ["resil"] = "ITEM_MOD_RESILIENCE_RATING", - ["res"] = "ITEM_MOD_RESILIENCE_RATING", + ["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", + ["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", + ["dodge"] = "ITEM_MOD_DODGE_RATING_SHORT", + ["dod"] = "ITEM_MOD_DODGE_RATING_SHORT", - ["block"] = "ITEM_MOD_BLOCK_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", + ["blockvalue"] = "ITEM_MOD_BLOCK_VALUE_SHORT", + ["blockval"] = "ITEM_MOD_BLOCK_VALUE_SHORT", + ["bv"] = "ITEM_MOD_BLOCK_VALUE_SHORT", - ["parry"] = "ITEM_MOD_PARRY_RATING_SHORT", + ["parry"] = "ITEM_MOD_PARRY_RATING_SHORT", - --Resistances - ["armor"] = "RESISTANCE0_NAME", - ["armour"] = "RESISTANCE0_NAME", - ["arm"] = "RESISTANCE0_NAME", - ["resistancephysical"] = "RESISTANCE0_NAME", - ["resistancephys"] = "RESISTANCE0_NAME", - ["resphys"] = "RESISTANCE0_NAME", + -- Resistances + ["armor"] = "RESISTANCE0_NAME", + ["armour"] = "RESISTANCE0_NAME", + ["arm"] = "RESISTANCE0_NAME", + ["resistancephysical"] = "RESISTANCE0_NAME", + ["resistancephys"] = "RESISTANCE0_NAME", + ["resphys"] = "RESISTANCE0_NAME", - ["resistanceholy"] = "RESISTANCE1_NAME", - ["resholy"] = "RESISTANCE1_NAME", + ["resistanceholy"] = "RESISTANCE1_NAME", + ["resholy"] = "RESISTANCE1_NAME", - ["resistancefire"] = "RESISTANCE2_NAME", - ["resfire"] = "RESISTANCE2_NAME", + ["resistancefire"] = "RESISTANCE2_NAME", + ["resfire"] = "RESISTANCE2_NAME", - ["resistancenature"] = "RESISTANCE3_NAME", - ["resnature"] = "RESISTANCE3_NAME", - ["resnat"] = "RESISTANCE3_NAME", + ["resistancenature"] = "RESISTANCE3_NAME", + ["resnature"] = "RESISTANCE3_NAME", + ["resnat"] = "RESISTANCE3_NAME", - ["resistanceforst"] = "RESISTANCE4_NAME", - ["resfrost"] = "RESISTANCE4_NAME", + ["resistanceforst"] = "RESISTANCE4_NAME", + ["resfrost"] = "RESISTANCE4_NAME", - ["resistanceshadow"] = "RESISTANCE5_NAME", - ["resshadow"] = "RESISTANCE5_NAME", - ["resshad"] = "RESISTANCE5_NAME", + ["resistanceshadow"] = "RESISTANCE5_NAME", + ["resshadow"] = "RESISTANCE5_NAME", + ["resshad"] = "RESISTANCE5_NAME", - ["resistancearcane"] = "RESISTANCE6_NAME", - ["resarcane"] = "RESISTANCE6_NAME", - ["resarc"] = "RESISTANCE6_NAME" + ["resistancearcane"] = "RESISTANCE6_NAME", + ["resarcane"] = "RESISTANCE6_NAME", + ["resarc"] = "RESISTANCE6_NAME" }; local SOCKET_FILTERS = { ["socket"] = true, ["sockets"] = true, ["gem"] = true, - ["gems"] = true, + ["gems"] = true }; -local SOCKET_TYPES = { - "EMPTY_SOCKET_BLUE", - "EMPTY_SOCKET_RED", - "EMPTY_SOCKET_YELLOW", - "EMPTY_SOCKET_META", - "EMPTY_SOCKET_NO_COLOR" -}; +local SOCKET_TYPES = {"EMPTY_SOCKET_BLUE", "EMPTY_SOCKET_RED", "EMPTY_SOCKET_YELLOW", "EMPTY_SOCKET_META", "EMPTY_SOCKET_NO_COLOR"}; local INFO_FILTERS = { - ["ilvl"] = true, - ["minlvl"] = true, - --["type"] = true, - --["subtype"] = true, + ["ilvl"] = true, + ["minlvl"] = true + -- ["type"] = true, + -- ["subtype"] = true, }; local QUALITY_FILTERS = { - ["poor"] = 0, - ["common"] = 1, - ["uncommon"] = 2, - ["rare"] = 3, - ["epic"] = 4, - ["legendary"] = 5, - ["artifact"] = 6, - ["heirloom"] = 7 + ["poor"] = 0, + ["common"] = 1, + ["uncommon"] = 2, + ["rare"] = 3, + ["epic"] = 4, + ["legendary"] = 5, + ["artifact"] = 6, + ["heirloom"] = 7 }; 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", - ["2h"] = "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", + ["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", + ["2h"] = "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 TYPE_FILTERS = { - ["cloth"] = "Cloth", - ["leather"] = "Leather", - ["mail"] = "Mail", - ["plate"] = "Plate", - ["shield"] = "Shields", - ["libram"] = "Librams", - ["idol"] = "Idols", - ["totem"] = "Totems", - ["sigil"] = "Sigils", + ["cloth"] = "Cloth", + ["leather"] = "Leather", + ["mail"] = "Mail", + ["plate"] = "Plate", + ["shield"] = "Shields", + ["libram"] = "Librams", + ["idol"] = "Idols", + ["totem"] = "Totems", + ["sigil"] = "Sigils", - ["axe1h"] = "One-Handed Axes", - ["axe2h"] = "Two-Handed Axes", - ["bows"] = "Bows", - ["bow"] = "Bows", - ["guns"] = "Guns", - ["gun"] = "Guns", - ["mace1h"] = "One-Handed Maces", - ["mace2h"] = "Two-Handed Maces", - ["polearm"] = "Polearms", - ["sword1h"] = "One-Handed Swords", - ["sword2h"] = "Two-Handed Swords", - ["staff"] = "Staves", - ["fist"] = "Fist Weapons", - ["generic"] = "", - ["dagger"] = "Daggers", - ["thrown"] = "Thrown", - ["crossbows"] = "Crossbows", - ["crossbow"] = "Crossbows", - ["wand"] = "Wands", - ["fishingpole"] = "Fishing Poles", + ["axe1h"] = "One-Handed Axes", + ["axe2h"] = "Two-Handed Axes", + ["bows"] = "Bows", + ["bow"] = "Bows", + ["guns"] = "Guns", + ["gun"] = "Guns", + ["mace1h"] = "One-Handed Maces", + ["mace2h"] = "Two-Handed Maces", + ["polearm"] = "Polearms", + ["sword1h"] = "One-Handed Swords", + ["sword2h"] = "Two-Handed Swords", + ["staff"] = "Staves", + ["fist"] = "Fist Weapons", + ["generic"] = "", + ["dagger"] = "Daggers", + ["thrown"] = "Thrown", + ["crossbows"] = "Crossbows", + ["crossbow"] = "Crossbows", + ["wand"] = "Wands", + ["fishingpole"] = "Fishing Poles" } local NON_EQUIPABLE_SLOTS = { - ["INVTYPE_NON_EQUIP"] = true, - ["INVTYPE_BODY"] = true, - ["INVTYPE_BAG"] = true, - ["INVTYPE_AMMO"] = true, - ["INVTYPE_QUIVER"] = true, + ["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, ", ")) + 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("stat", STAT_FILTERS) + show("socket", SOCKET_FILTERS) + show("slot", SLOT_FILTERS) show("quality", QUALITY_FILTERS) - show("info", INFO_FILTERS) + show("info", INFO_FILTERS) print("\nExamples:") print("gladiator") @@ -288,10 +286,10 @@ local function SplitString(str, delimiter) 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 + 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 + result[#result + 1] = str:sub(start) -- grab the rest of the string break end end @@ -299,18 +297,13 @@ local function SplitString(str, delimiter) 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) - ) + 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(...)) + error("Error: " .. string.format(...)) end local function IsItemStatMatch(term, stats) @@ -332,7 +325,7 @@ local function IsItemStatMatch(term, stats) return CompareNumbersByOperator(term.relational, statValue, searchedValue) end -local function IsItemLevelFilterMatch(term, itemLvl, itemEquipLoc) +local function IsItemLevelFilterMatch(term, itemLvl) if term.left ~= "ilvl" then return end @@ -439,51 +432,197 @@ local function IsItemDifficulty(term, itemName) ThrowQueryError("difficulty should be a number: 1 - %i", #AtlasLoot_Difficulty.MythicPlus + 4) end - local _, hasDifficulty = AL_FindId(itemName, tonumber(term.right)); - + local _, hasDifficulty = AL_FindId(itemName, tonumber(term.right)); + return hasDifficulty; end local function nameMatches(name, searchText) if AtlasLoot.db.profile.PartialMatching then - return string.find(string.lower(name), searchText); + return string.find(string.lower(name), string.lower(searchText)); else - return string.lower(name) == searchText; + return string.lower(name) == string.lower(searchText); end end -local function ItemMatchesTerm(term, itemName, stats, itemLvl, minLvl, itemQuality, itemEquipLoc, itemType) +local RelationalFunctions = { + ["ilv"] = {IsItemLevelFilterMatch, 3}, + ["minlvl"] = {IsMinLevelFilterMatch, 4}, + ["type"] = {IsItemTypeMatch, 6}, + ["slot"] = {IsItemSlotMatch, 5}, + ["quality"] = {IsItemQualityMatch, 2}, + + ["gem"] = {IsItemSocketMatch, 7}, + ["gems"] = {IsItemSocketMatch, 7}, + ["socket"] = {IsItemSocketMatch, 7}, + ["sockets"] = {IsItemSocketMatch, 7}, + + -- Base Stats + ["stamina"] = {IsItemStatMatch, 7}, + ["stam"] = {IsItemStatMatch, 7}, + ["sta"] = {IsItemStatMatch, 7}, + + ["strength"] = {IsItemStatMatch, 7}, + ["str"] = {IsItemStatMatch, 7}, + + ["agility"] = {IsItemStatMatch, 7}, + ["agi"] = {IsItemStatMatch, 7}, + + ["intellect"] = {IsItemStatMatch, 7}, + ["int"] = {IsItemStatMatch, 7}, + + ["spirit"] = {IsItemStatMatch, 7}, + ["spir"] = {IsItemStatMatch, 7}, + ["spi"] = {IsItemStatMatch, 7}, + + ["health"] = {IsItemStatMatch, 7}, + ["mana"] = {IsItemStatMatch, 7}, + + ["mp5"] = {IsItemStatMatch, 7}, + ["mpr"] = {IsItemStatMatch, 7}, + + ["hp5"] = {IsItemStatMatch, 7}, + ["hpr"] = {IsItemStatMatch, 7}, + + -- Sockets + ["socketblue"] = {IsItemStatMatch, 7}, + ["socketred"] = {IsItemStatMatch, 7}, + ["socketyellow"] = {IsItemStatMatch, 7}, + + ["socketnocolor"] = {IsItemStatMatch, 7}, + ["socketwhite"] = {IsItemStatMatch, 7}, + + ["socketmeta"] = {IsItemStatMatch, 7}, + ["meta"] = {IsItemStatMatch, 7}, + + -- Secondary Stats + ["attackpowerferal"] = {IsItemStatMatch, 7}, + ["attackpowferal"] = {IsItemStatMatch, 7}, + ["apferal"] = {IsItemStatMatch, 7}, + + ["attackpower"] = {IsItemStatMatch, 7}, + ["attackpow"] = {IsItemStatMatch, 7}, + ["ap"] = {IsItemStatMatch, 7}, + + ["spellpower"] = {IsItemStatMatch, 7}, + ["spellpow"] = {IsItemStatMatch, 7}, + ["sp"] = {IsItemStatMatch, 7}, + + ["spellpenetration"] = {IsItemStatMatch, 7}, + ["spellpen"] = {IsItemStatMatch, 7}, + ["spp"] = {IsItemStatMatch, 7}, + + ["crit"] = {IsItemStatMatch, 7}, + ["haste"] = {IsItemStatMatch, 7}, + + ["hit"] = {IsItemStatMatch, 7}, + + ["armorpenetration"] = {IsItemStatMatch, 7}, + ["armourpenetration"] = {IsItemStatMatch, 7}, + ["armorpen"] = {IsItemStatMatch, 7}, + ["armourpen"] = {IsItemStatMatch, 7}, + ["arp"] = {IsItemStatMatch, 7}, + + ["expertise"] = {IsItemStatMatch, 7}, + ["exp"] = {IsItemStatMatch, 7}, + + ["dps"] = {IsItemStatMatch, 7}, + + ["resilience"] = {IsItemStatMatch, 7}, + ["resil"] = {IsItemStatMatch, 7}, + ["res"] = {IsItemStatMatch, 7}, + + ["defense"] = {IsItemStatMatch, 7}, + ["def"] = {IsItemStatMatch, 7}, + + ["dodge"] = {IsItemStatMatch, 7}, + ["dod"] = {IsItemStatMatch, 7}, + + ["block"] = {IsItemStatMatch, 7}, + + ["blockvalue"] = {IsItemStatMatch, 7}, + ["blockval"] = {IsItemStatMatch, 7}, + ["bv"] = {IsItemStatMatch, 7}, + + ["parry"] = {IsItemStatMatch, 7}, + + -- Resistances + ["armor"] = {IsItemStatMatch, 7}, + ["armour"] = {IsItemStatMatch, 7}, + ["arm"] = {IsItemStatMatch, 7}, + ["resistancephysical"] = {IsItemStatMatch, 7}, + ["resistancephys"] = {IsItemStatMatch, 7}, + ["resphys"] = {IsItemStatMatch, 7}, + + ["resistanceholy"] = {IsItemStatMatch, 7}, + ["resholy"] = {IsItemStatMatch, 7}, + + ["resistancefire"] = {IsItemStatMatch, 7}, + ["resfire"] = {IsItemStatMatch, 7}, + + ["resistancenature"] = {IsItemStatMatch, 7}, + ["resnature"] = {IsItemStatMatch, 7}, + ["resnat"] = {IsItemStatMatch, 7}, + + ["resistanceforst"] = {IsItemStatMatch, 7}, + ["resfrost"] = {IsItemStatMatch, 7}, + + ["resistanceshadow"] = {IsItemStatMatch, 7}, + ["resshadow"] = {IsItemStatMatch, 7}, + ["resshad"] = {IsItemStatMatch, 7}, + + ["resistancearcane"] = {IsItemStatMatch, 7}, + ["resarcane"] = {IsItemStatMatch, 7}, + ["resarc"] = {IsItemStatMatch, 7}, + + ["dif"] = {IsItemDifficulty, 1} +} + +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, _, itemSubType, _, itemEquipLoc = GetItemInfo(itemId); + if not itemName then + itemName = gsub(atlasName, "=q%d=", "") + end + return itemName, itemQuality, itemLvl, minLvl, itemEquipLoc, itemSubType, GetItemStats("item:" .. itemId) +end + +local function ItemMatchesTerm(term, itemDetails) 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) - or IsItemTypeMatch(term, itemType) - or IsItemDifficulty(term, itemName) + local func, arg = unpack(RelationalFunctions[term.left]); + if func then + return func(term, itemDetails[arg]); + end + return false; else - return nameMatches(itemName, term.name) + return nameMatches(itemDetails[1], term.name); end end -local function ItemMatchesAllTerms(searchTerms, itemName, stats, itemLvl, minLvl, itemQuality, itemEquipLoc, itemType) +local function ItemMatchesAllTerms(searchTerms, itemDetails) + local function IsItemEquipableMatch(itemEquipLoc) + return not AtlasLoot.db.profile.EquipableFilter or ((itemEquipLoc and itemEquipLoc ~= '' and not NON_EQUIPABLE_SLOTS[itemEquipLoc])) + end + for _, term in ipairs(searchTerms) do - if not ItemMatchesTerm(term, itemName, stats, itemLvl, minLvl, itemQuality, itemEquipLoc, itemType) then + if not ItemMatchesTerm(term, itemDetails) then return false end end - return true + + return true and IsItemEquipableMatch(itemDetails[5]) end local function TermsContainDifficulty(searchTerms) - for _, term in ipairs(searchTerms) do - if term.relational then - if term.left == "dif" then return tonumber(term.right) end - end - end + for _, term in ipairs(searchTerms) do + if term.relational then + if term.left == "dif" then + return tonumber(term.right) + end + end + end - return AtlasLoot_Difficulty.Normal; + return AtlasLoot_Difficulty.Normal; end local function ParseTerm(termText) @@ -497,26 +636,21 @@ local function ParseTerm(termText) } end end - return { name = termText } -- simple name search + return { + name = termText + } 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)) + for _, 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, _, itemSubType, _, itemEquipLoc = GetItemInfo(itemId); - if not itemName then itemName = gsub(atlasName, "=q%d=", "") end - return itemName, itemQuality, itemLvl, minLvl, itemEquipLoc, itemSubType, GetItemStats("item:"..itemId) -end - local function GetSpellName(itemId, atlasName) local spellName = GetSpellInfo(string.sub(itemId, 2)); if spellName then @@ -530,38 +664,40 @@ end local function DoSearch(searchText) AtlasLootCharDB["SearchResult"] = {}; - AtlasLootCharDB.LastSearchedText = searchText; + AtlasLootCharDB.LastSearchedText = searchText; - local function AddItemToSearchResult(itemId, itemType, itemName, dataID, difficulty) + 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.."|".."\"\""}); + table.insert(AtlasLootCharDB["SearchResult"], {0, itemId, itemType, itemName, lootPage, "", "", dataID .. "|" .. "\"\""}); end local searchTerms = ParseQuery(searchText); local equipableFilterOn = AtlasLoot.db.profile.EquipableFilter; - local difficulty = TermsContainDifficulty(searchTerms); - local function IsItemEquipableMatch(itemEquipLoc) - return not equipableFilterOn or ((itemEquipLoc and itemEquipLoc ~= '' and not NON_EQUIPABLE_SLOTS[itemEquipLoc])) - end - + local difficulty = TermsContainDifficulty(searchTerms); + for dataID, data in pairs(AtlasLoot_Data) do for _, v in ipairs(data) do local _, itemId, itemType, atlasName = unpack(v) - if (string.sub(itemId, 1, 1) ~= "s") then - itemId = AL_FindId(string.sub(atlasName, 5), difficulty) or itemId; - itemId = tonumber(itemId); - end - if type(itemId) == "number" and itemId > 0 then - local itemName, itemQuality, itemLvl, minLvl, itemEquipLoc, itemSubType, stats = GetItemDetails(itemId, atlasName); - if IsItemEquipableMatch(itemEquipLoc) and ItemMatchesAllTerms(searchTerms, itemName, stats, itemLvl, minLvl, itemQuality, itemEquipLoc, itemSubType) then - AddItemToSearchResult(itemId, itemType, itemName, dataID, difficulty); + if difficulty ~= 2 then + itemId = AL_FindId(string.sub(atlasName, 5), difficulty) or itemId; + end + + local itemDetails = {GetItemDetails(itemId, atlasName)}; + itemDetails[8] = difficulty; + + if #searchTerms == 1 and searchTerms[1].name then + if nameMatches(atlasName, searchTerms[1].name) then + AddItemToSearchResult(itemId, itemType, atlasName, dataID); + end + elseif ItemMatchesAllTerms(searchTerms, itemDetails) then + AddItemToSearchResult(itemId, itemType, atlasName, 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; + spellName = string.sub(atlasName, 1, 4) .. spellName; AddItemToSearchResult(itemId, itemType, spellName, dataID) end end @@ -569,156 +705,141 @@ local function DoSearch(searchText) end end - function AtlasLoot:ShowSearchResult() - AtlasLoot_ShowItemsFrame("SearchResult", "SearchResultPage"..currentPage, (AL["Search Result: %s"]):format(AtlasLootCharDB.LastSearchedText or ""), pFrame); + 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 + 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 + -- 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 local success, message = pcall(DoSearch, Text) if not success then message = message:match("[^:]+: (.*)") or message -- strip stack location - DEFAULT_CHAT_FRAME:AddMessage(RED..AL["AtlasLoot"]..": "..WHITE..message); + DEFAULT_CHAT_FRAME:AddMessage(RED .. AL["AtlasLoot"] .. ": " .. WHITE .. message); elseif #AtlasLootCharDB["SearchResult"] == 0 then - local itemFilterErrorMessage = ""; - if operator then - itemFilterErrorMessage = [[ + local itemFilterErrorMessage = ""; + if operator then + itemFilterErrorMessage = [[ Please check if you have a typo in the filter. 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); - else - currentPage = 1; - SearchResult = AtlasLoot_CategorizeWishList(AtlasLootCharDB["SearchResult"]); - AtlasLoot_ShowItemsFrame("SearchResult", "SearchResultPage1", (AL["Search Result: %s"]):format(AtlasLootCharDB.LastSearchedText or ""), pFrame); - end + end + DEFAULT_CHAT_FRAME:AddMessage(RED .. AL["AtlasLoot"] .. ": " .. WHITE .. AL["No match found for"] .. " \"" .. Text .. "\"." .. itemFilterErrorMessage); + 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 - ); - 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) - return "BOTTOMLEFT", "BOTTOMRIGHT"; - end, - "children", setOptions - ); - end + 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); + 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) + 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 + 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]); end - 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; + 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 + -- 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; + table.insert(result, SearchResult[i]); + k = k + 1; + end + return result, pageMax; end