437 lines
12 KiB
Lua
437 lines
12 KiB
Lua
-- ------------------------------------------------------------------------------ --
|
|
-- TradeSkillMaster --
|
|
-- https://tradeskillmaster.com --
|
|
-- All Rights Reserved - Detailed license information included with addon. --
|
|
-- ------------------------------------------------------------------------------ --
|
|
|
|
local _, TSM = ...
|
|
local ItemFilter = TSM.Init("Service.ItemFilter")
|
|
local LibTSMClass = TSM.Include("LibTSMClass")
|
|
local L = TSM.Include("Locale").GetTable()
|
|
local Filter = LibTSMClass.DefineClass("ItemFilter")
|
|
local ItemClass = TSM.Include("Data.ItemClass")
|
|
local Money = TSM.Include("Util.Money")
|
|
local String = TSM.Include("Util.String")
|
|
local Vararg = TSM.Include("Util.Vararg")
|
|
local Log = TSM.Include("Util.Log")
|
|
local ItemInfo = TSM.Include("Service.ItemInfo")
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Module Functions
|
|
-- ============================================================================
|
|
|
|
function ItemFilter.New()
|
|
return Filter()
|
|
end
|
|
|
|
|
|
|
|
-- ============================================================================
|
|
-- Filter Class
|
|
-- ============================================================================
|
|
|
|
function Filter.__init(self)
|
|
self._isValid = nil
|
|
self._str = nil
|
|
self._escapedStr = nil
|
|
self._class = nil
|
|
self._subClass = nil
|
|
self._invSlotId = nil
|
|
self._minQuality = nil
|
|
self._maxQuality = nil
|
|
self._minLevel = nil
|
|
self._maxLevel = nil
|
|
self._minItemLevel = nil
|
|
self._maxItemLevel = nil
|
|
self._minPrice = nil
|
|
self._maxPrice = nil
|
|
self._maxQuantity = nil
|
|
self._uncollected = nil
|
|
self._usable = nil
|
|
self._upgrades = nil
|
|
self._unlearned = nil
|
|
self._canlearn = nil
|
|
self._exactOnly = nil
|
|
self._crafting = nil
|
|
self._disenchant = nil
|
|
self._item = nil
|
|
|
|
self:_Reset()
|
|
end
|
|
|
|
function Filter._Reset(self)
|
|
self._isValid = nil
|
|
self._str = ""
|
|
self._escapedStr = ""
|
|
self._class = nil
|
|
self._subClass = nil
|
|
self._invSlotId = nil
|
|
self._minQuality = -math.huge
|
|
self._maxQuality = math.huge
|
|
self._minLevel = 0
|
|
self._maxLevel = math.huge
|
|
self._minItemLevel = 0
|
|
self._maxItemLevel = math.huge
|
|
self._minPrice = 0
|
|
self._maxPrice = math.huge
|
|
self._maxQuantity = math.huge
|
|
self._uncollected = nil
|
|
self._usable = nil
|
|
self._upgrades = nil
|
|
self._unlearned = nil
|
|
self._canlearn = nil
|
|
self._exactOnly = nil
|
|
self._crafting = nil
|
|
self._disenchant = nil
|
|
self._item = nil
|
|
end
|
|
|
|
function Filter._ItemQualityToIndex(self, str)
|
|
for i = 0, 7 do
|
|
local text = _G["ITEM_QUALITY"..i.."_DESC"]
|
|
if strlower(str) == strlower(text) then
|
|
return i
|
|
end
|
|
end
|
|
end
|
|
|
|
function Filter.ParseStr(self, str)
|
|
self:_Reset()
|
|
local errMsg = nil
|
|
local numLevelParts, numItemLevelParts, numPriceParts, numQualityParts = 0, 0, 0, 0
|
|
self._isValid = nil
|
|
local hasNonCraftingPart = false
|
|
for i, part in Vararg.Iterator(strsplit("/", strtrim(str))) do
|
|
part = strtrim(part)
|
|
if self._isValid ~= nil then
|
|
-- already done iterating, but can't break / return out of a VarargIterator
|
|
if strmatch(part, "^[ip]:[0-9]+") then
|
|
-- request item info in case we failed due to not having it (for next time)
|
|
ItemInfo.FetchInfo(part)
|
|
end
|
|
elseif i == 1 then
|
|
-- first part must be a filter string or an item
|
|
if strmatch(part, "^[ip]:[0-9]+") then
|
|
local name = ItemInfo.GetName(part)
|
|
local level = ItemInfo.GetMinLevel(part)
|
|
local quality = ItemInfo.GetQuality(part)
|
|
if not name or not level or not quality then
|
|
errMsg = L["The specified item was not found."]
|
|
self._isValid = false
|
|
else
|
|
self._exactOnly = true
|
|
self._item = part
|
|
self._str = strlower(name)
|
|
self._escapedStr = String.Escape(self._str)
|
|
self._minQuality = quality
|
|
self._maxQuality = quality
|
|
self._minLevel = level
|
|
self._maxLevel = level
|
|
self._class = ItemInfo.GetClassId(self._item) or 0
|
|
self._subClass = ItemInfo.GetSubClassId(self._item) or 0
|
|
end
|
|
else
|
|
self._str = strlower(part)
|
|
self._escapedStr = String.Escape(self._str)
|
|
end
|
|
elseif part == "" then
|
|
-- ignore an empty part
|
|
elseif tonumber(part) then
|
|
if numLevelParts == 0 then
|
|
self._minLevel = tonumber(part)
|
|
elseif numLevelParts == 1 then
|
|
self._maxLevel = tonumber(part)
|
|
else
|
|
-- already have min / max level
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
numLevelParts = numLevelParts + 1
|
|
hasNonCraftingPart = true
|
|
elseif tonumber(strmatch(part, "^i(%d+)$")) then
|
|
if numItemLevelParts == 0 then
|
|
self._minItemLevel = tonumber(strmatch(part, "^i(%d+)$"))
|
|
elseif numItemLevelParts == 1 then
|
|
self._maxItemLevel = tonumber(strmatch(part, "^i(%d+)$"))
|
|
else
|
|
-- already have min / max item level
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
numItemLevelParts = numItemLevelParts + 1
|
|
hasNonCraftingPart = true
|
|
elseif ItemClass.GetClassIdFromClassString(part) then
|
|
self._class = ItemClass.GetClassIdFromClassString(part)
|
|
hasNonCraftingPart = true
|
|
elseif self._class and ItemClass.GetSubClassIdFromSubClassString(part, self._class) then
|
|
self._subClass = ItemClass.GetSubClassIdFromSubClassString(part, self._class)
|
|
hasNonCraftingPart = true
|
|
elseif ItemClass.GetInventorySlotIdFromInventorySlotString(part) then
|
|
self._invSlotId = ItemClass.GetInventorySlotIdFromInventorySlotString(part)
|
|
hasNonCraftingPart = true
|
|
elseif self:_ItemQualityToIndex(part) then
|
|
if numQualityParts == 0 then
|
|
self._minQuality = self:_ItemQualityToIndex(part)
|
|
elseif numQualityParts == 1 then
|
|
self._maxQuality = self:_ItemQualityToIndex(part)
|
|
else
|
|
-- already have min / max quality
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
numQualityParts = numQualityParts + 1
|
|
hasNonCraftingPart = true
|
|
elseif Money.FromString(part) then
|
|
if numPriceParts == 0 then
|
|
self._maxPrice = Money.FromString(part)
|
|
elseif numPriceParts == 1 then
|
|
self._minPrice = self._maxPrice
|
|
self._maxPrice = Money.FromString(part)
|
|
else
|
|
-- already have min / max price
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
numPriceParts = numPriceParts + 1
|
|
hasNonCraftingPart = true
|
|
elseif not TSM.IsWowClassic() and strlower(part) == "uncollected" then
|
|
if self._uncollected then
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
self._uncollected = true
|
|
hasNonCraftingPart = true
|
|
elseif strlower(part) == "usable" then
|
|
if self._usable then
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
self._usable = true
|
|
hasNonCraftingPart = true
|
|
elseif not TSM.IsWowClassic() and strlower(part) == "upgrades" then
|
|
if self._upgrades then
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
self._upgrades = true
|
|
hasNonCraftingPart = true
|
|
elseif strlower(part) == "unlearned" then
|
|
if self._unlearned then
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
if CanIMogIt and CanIMogIt.PlayerKnowsTransmog then
|
|
self._unlearned = true
|
|
else
|
|
Log.PrintUser(L["The unlearned filter was ignored because the CanIMogIt addon was not found."])
|
|
end
|
|
hasNonCraftingPart = true
|
|
elseif strlower(part) == "canlearn" then
|
|
if self._canlearn then
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
if CanIMogIt and CanIMogIt.CharacterCanLearnTransmog then
|
|
self._canlearn = true
|
|
else
|
|
Log.PrintUser(L["The canlearn filter was ignored because the CanIMogIt addon was not found."])
|
|
end
|
|
hasNonCraftingPart = true
|
|
elseif strlower(part) == "exact" then
|
|
if self._exactOnly then
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
self._exactOnly = true
|
|
hasNonCraftingPart = true
|
|
elseif tonumber(strmatch(part, "^x(%d+)$")) then
|
|
self._maxQuantity = tonumber(strmatch(part, "^x(%d+)$"))
|
|
if self._maxQuantity == 0 then
|
|
errMsg = L["The max quantity cannot be zero."]
|
|
self._isValid = false
|
|
end
|
|
elseif strlower(part) == "crafting" then
|
|
if self._crafting or self._disenchant then
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
self._crafting = true
|
|
elseif strlower(part) == "disenchant" then
|
|
if self._disenchant or self._crafting then
|
|
errMsg = L["The same filter was specified multiple times."]
|
|
self._isValid = false
|
|
end
|
|
self._disenchant = true
|
|
else
|
|
-- invalid part
|
|
errMsg = format(L["Unknown word (%s)."], part)
|
|
self._isValid = false
|
|
end
|
|
end
|
|
|
|
if (self._crafting or self._disenchant) and hasNonCraftingPart then
|
|
errMsg = L["Cannot use additional filters with /crafting or /disenchant."]
|
|
self._isValid = false
|
|
end
|
|
|
|
if self._isValid == nil then
|
|
self._isValid = true
|
|
end
|
|
return self._isValid, errMsg
|
|
end
|
|
|
|
function Filter.GetStr(self)
|
|
return self._str ~= "" and self._str or nil
|
|
end
|
|
|
|
function Filter.GetItem(self)
|
|
return self._item
|
|
end
|
|
|
|
function Filter.GetMinQuality(self)
|
|
return self._minQuality ~= -math.huge and self._minQuality or nil
|
|
end
|
|
|
|
function Filter.GetMaxQuality(self)
|
|
return self._maxQuality ~= math.huge and self._maxQuality or nil
|
|
end
|
|
|
|
function Filter.GetClass(self)
|
|
return self._class
|
|
end
|
|
|
|
function Filter.GetSubClass(self)
|
|
return self._subClass
|
|
end
|
|
|
|
function Filter.GetInvSlotId(self)
|
|
return self._invSlotId
|
|
end
|
|
|
|
function Filter.GetMinLevel(self)
|
|
return self._minLevel ~= 0 and self._minLevel or nil
|
|
end
|
|
|
|
function Filter.GetMaxLevel(self)
|
|
return self._maxLevel ~= math.huge and self._maxLevel or nil
|
|
end
|
|
|
|
function Filter.GetMinItemLevel(self)
|
|
return self._minItemLevel ~= 0 and self._minItemLevel or nil
|
|
end
|
|
|
|
function Filter.GetMaxItemLevel(self)
|
|
return self._maxItemLevel ~= math.huge and self._maxItemLevel or nil
|
|
end
|
|
|
|
function Filter.GetUncollected(self)
|
|
return self._uncollected
|
|
end
|
|
|
|
function Filter.GetUsableOnly(self)
|
|
return self._usable
|
|
end
|
|
|
|
function Filter.GetUpgrades(self)
|
|
return self._upgrades
|
|
end
|
|
|
|
function Filter.GetUnlearned(self)
|
|
return self._unlearned
|
|
end
|
|
|
|
function Filter.GetCanLearn(self)
|
|
return self._canlearn
|
|
end
|
|
|
|
function Filter.GetExactOnly(self)
|
|
return self._exactOnly
|
|
end
|
|
|
|
function Filter.GetMaxQuantity(self)
|
|
return self._maxQuantity ~= math.huge and self._maxQuantity or nil
|
|
end
|
|
|
|
function Filter.GetMinPrice(self)
|
|
return self._minPrice ~= 0 and self._minPrice or nil
|
|
end
|
|
|
|
function Filter.GetMaxPrice(self)
|
|
return self._maxPrice ~= math.huge and self._maxPrice or nil
|
|
end
|
|
|
|
function Filter.GetCrafting(self)
|
|
return self._crafting
|
|
end
|
|
|
|
function Filter.GetDisenchant(self)
|
|
return self._disenchant
|
|
end
|
|
|
|
function Filter.Matches(self, item, price)
|
|
if not self._isValid then
|
|
return false
|
|
end
|
|
|
|
-- check the name
|
|
local name = ItemInfo.GetName(item)
|
|
name = name and strlower(name)
|
|
if not name or not strfind(name, self._escapedStr) or (self._exactOnly and name ~= self._str) then
|
|
return false
|
|
end
|
|
|
|
-- check the quality
|
|
local quality = ItemInfo.GetQuality(item)
|
|
if not quality or quality < self._minQuality or quality > self._maxQuality then
|
|
return false
|
|
end
|
|
|
|
-- check the item level
|
|
local itemLevel = ItemInfo.GetItemLevel(item)
|
|
if not itemLevel or itemLevel < self._minItemLevel or itemLevel > self._maxItemLevel then
|
|
return false
|
|
end
|
|
|
|
-- check the required level
|
|
local level = ItemInfo.GetMinLevel(item)
|
|
if not level or level < self._minLevel or level > self._maxLevel then
|
|
return false
|
|
end
|
|
|
|
-- check the item class
|
|
if self._class and ItemInfo.GetClassId(item) ~= self._class then
|
|
return false
|
|
end
|
|
|
|
-- check the item subclass
|
|
if self._subClass and ItemInfo.GetSubClassId(item) ~= self._subClass then
|
|
return false
|
|
end
|
|
|
|
-- check the inventory slot
|
|
if self._invSlotId and ItemInfo.GetInvSlotId(item) ~= self._invSlotId then
|
|
return false
|
|
end
|
|
|
|
-- check unlearned
|
|
if self._unlearned and CanIMogIt:PlayerKnowsTransmog(ItemInfo.GetLink(item)) then
|
|
return false
|
|
end
|
|
|
|
-- check canlearn
|
|
if self._canlearn and CanIMogIt:CharacterCanLearnTransmog(ItemInfo.GetLink(item)) then
|
|
return false
|
|
end
|
|
|
|
-- check the price
|
|
price = price or 0
|
|
if price < self._minPrice or price > self._maxPrice then
|
|
return false
|
|
end
|
|
|
|
-- it passed!
|
|
return true
|
|
end
|