TradeSkillMaster/LibTSM/Service/ItemFilter.lua

437 lines
12 KiB
Lua
Raw Permalink Normal View History

2020-11-13 14:13:12 -05:00
-- ------------------------------------------------------------------------------ --
-- 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