You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1477 lines
56 KiB
1477 lines
56 KiB
local _, S = ...
|
|
local pairs, ipairs, string, type, time = pairs, ipairs, string, type, time
|
|
|
|
-- Use new APIs, keeping compatibility with Classic
|
|
local useNewContainerAPI = false
|
|
local ContainerIDToInventoryID, GetContainerItemInfo, PickupContainerItem = ContainerIDToInventoryID, GetContainerItemInfo, PickupContainerItem
|
|
if C_Container then
|
|
if C_Container.ContainerIDToInventoryID then ContainerIDToInventoryID = C_Container.ContainerIDToInventoryID end
|
|
if C_Container.GetContainerItemInfo then useNewContainerAPI = true; GetContainerItemInfo = C_Container.GetContainerItemInfo end
|
|
if C_Container.PickupContainerItem then PickupContainerItem = C_Container.PickupContainerItem end
|
|
end
|
|
local GetCurrencyListLink = GetCurrencyListLink
|
|
if C_CurrencyInfo then
|
|
if C_CurrencyInfo.GetCurrencyListLink then GetCurrencyListLink = C_CurrencyInfo.GetCurrencyListLink end
|
|
end
|
|
local GetItemInfoInstant, GetItemInfo, GetItemClassInfo, GetItemSubClassInfo, GetDetailedItemLevelInfo, IsEquippableItem = GetItemInfoInstant, GetItemInfo, GetItemClassInfo, GetItemSubClassInfo, GetDetailedItemLevelInfo, IsEquippableItem
|
|
if C_Item then
|
|
GetItemInfoInstant, GetItemInfo, GetItemClassInfo, GetItemSubClassInfo, GetDetailedItemLevelInfo, IsEquippableItem = C_Item.GetItemInfoInstant, C_Item.GetItemInfo, C_Item.GetItemClassInfo, C_Item.GetItemSubClassInfo, C_Item.GetDetailedItemLevelInfo, C_Item.IsEquippableItem
|
|
end
|
|
|
|
S.Data = {}
|
|
|
|
S.DataTooltip = CreateFrame("GameTooltip", "SortedDataTooltip", nil, "GameTooltipTemplate")
|
|
S.DataTooltip:SetOwner(WorldFrame, "ANCHOR_NONE")
|
|
|
|
local playerGUID = UnitGUID("player")
|
|
local totalMoney = {}
|
|
function S.Data.GetTotalMoney()
|
|
return totalMoney
|
|
end
|
|
|
|
local INVENTORY_IDS_TO_UPDATE = {}
|
|
local BANK_INVENTORY_IDS = {}
|
|
for _, containerID in pairs(S.Utils.ContainersOfType("ALL")) do
|
|
if containerID ~= BACKPACK_CONTAINER and containerID ~= BANK_CONTAINER and containerID ~= REAGENTBANK_CONTAINER and containerID ~= KEYRING_CONTAINER then
|
|
table.insert(INVENTORY_IDS_TO_UPDATE, ContainerIDToInventoryID(containerID))
|
|
end
|
|
end
|
|
for _, containerID in pairs(S.Utils.ContainersOfType("BANK")) do
|
|
if containerID ~= BANK_CONTAINER then
|
|
BANK_INVENTORY_IDS[ContainerIDToInventoryID(containerID)] = true
|
|
end
|
|
end
|
|
|
|
-- Converts item link into a key for the data table
|
|
function S.Data.ItemKey(itemLink, speciesID)
|
|
-- Battle pets
|
|
if speciesID then
|
|
return "BattlePet:"..speciesID
|
|
else
|
|
if string.find(itemLink, "|Hitem") then
|
|
local a,b = string.match(itemLink, "|Hitem:(%d*:)[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:(.-)|h")
|
|
return a..b
|
|
else
|
|
local a = string.match(itemLink, "|H(.-)|h")
|
|
return a
|
|
end
|
|
end
|
|
end
|
|
local ItemKey = S.Data.ItemKey
|
|
|
|
|
|
|
|
-- One data table to hold them all, one table to find them, one table to bring them all, and in the darkness bind them.
|
|
Sorted_Data = {}
|
|
local sortedData = Sorted_Data -- Make local for performance. This table gets used a lot
|
|
|
|
|
|
-- Table for account-wide data
|
|
Sorted_AccountData = {
|
|
["containers"] = {},
|
|
["containerNumSlots"] = {},
|
|
["bankTabData"] = {},
|
|
}
|
|
|
|
|
|
-- Player selection
|
|
local selectedCharacterGUID = UnitGUID("player")
|
|
function S.GetSelectedCharacter()
|
|
return selectedCharacterGUID
|
|
end
|
|
function S.SelectCharacter(guid)
|
|
if selectedCharacterGUID ~= guid then
|
|
selectedCharacterGUID = guid
|
|
S.Utils.TriggerEvent("CharacterSelected")
|
|
end
|
|
end
|
|
function S.IsPlayingCharacterSelected()
|
|
return selectedCharacterGUID == UnitGUID("player")
|
|
end
|
|
|
|
-- Equipment set selection
|
|
local selectedEquipmentSetID = -1 -- -1 for no selection, -2 to filter items not in any equipment set
|
|
function S.GetSelectedEquipmentSet()
|
|
return selectedEquipmentSetID
|
|
end
|
|
function S.SelectEquipmentSet(id)
|
|
selectedEquipmentSetID = id
|
|
S.Utils.TriggerEvent("EquipmentSetSelected")
|
|
end
|
|
|
|
|
|
-- Return the data table for a player
|
|
local function GetData(guid)
|
|
if not guid then
|
|
return sortedData[selectedCharacterGUID]
|
|
else
|
|
return sortedData[guid]
|
|
end
|
|
end
|
|
function S.GetData(guid)
|
|
return GetData(guid)
|
|
end
|
|
|
|
function S.Data.DeleteCharacter(guid)
|
|
if S.GetSelectedCharacter() == guid then
|
|
S.SelectCharacter(UnitGUID("player"))
|
|
end
|
|
sortedData[guid] = nil
|
|
end
|
|
|
|
-- On login, creates the data table if the current player is new
|
|
local function InitialiseData()
|
|
if not sortedData[playerGUID] then
|
|
sortedData[playerGUID] = {}
|
|
sortedData[playerGUID].bankNotCached = true
|
|
sortedData[playerGUID].containers = {}
|
|
sortedData[playerGUID].favoritedItems = {}
|
|
end
|
|
-- Check these fields individually for characters which last loaded an older version of the addon
|
|
if not sortedData[playerGUID].trashItems then
|
|
sortedData[playerGUID].trashItems = {}
|
|
end
|
|
if not sortedData[playerGUID].currencies then
|
|
sortedData[playerGUID].currencies = {}
|
|
end
|
|
if not sortedData[playerGUID].favoritedCurrencies then
|
|
sortedData[playerGUID].favoritedCurrencies = {}
|
|
end
|
|
if not sortedData[playerGUID].timeItemsAdded then
|
|
sortedData[playerGUID].timeItemsAdded = {}
|
|
end
|
|
if not sortedData[playerGUID].newItems then
|
|
sortedData[playerGUID].newItems = {}
|
|
end
|
|
if not sortedData[playerGUID].equipSets then
|
|
sortedData[playerGUID].equipSets = {}
|
|
end
|
|
if not sortedData[playerGUID].containerNumSlots then
|
|
sortedData[playerGUID].containerNumSlots = {}
|
|
end
|
|
if not sortedData[playerGUID].inventoryItems then
|
|
sortedData[playerGUID].inventoryItems = {}
|
|
end
|
|
end
|
|
-- Updates any info available on login
|
|
local function UpdatePlayerData()
|
|
local playerData = sortedData[playerGUID]
|
|
playerData.lastLogged = time()
|
|
playerData.name = UnitName("player")
|
|
playerData.level = UnitLevel("player")
|
|
_, _, playerData.race = UnitRace("player")
|
|
playerData.faction = UnitFactionGroup("player")
|
|
playerData.realm = GetRealmName()
|
|
_, playerData.class = UnitClass("player")
|
|
if S.WoWVersion() >= 6 and not IsReagentBankUnlocked() then
|
|
playerData.reagentNotUnlocked = true
|
|
else
|
|
playerData.reagentNotUnlocked = nil
|
|
end
|
|
end
|
|
|
|
local updatedCurrencies = {} -- Keep track of which currencies have been updated so far this session
|
|
-- Sorted updates each currency once per session (in case of changes) and then only updates the quantities after
|
|
local function UpdateCurrencies()
|
|
if S.WoWVersion() > 1 then
|
|
local i = 1
|
|
local headingInfo
|
|
local currenciesTable = GetData(playerGUID).currencies
|
|
|
|
-- Classic doesn't use the new C_CurrencyInfo namespace
|
|
if not C_CurrencyInfo.GetCurrencyListSize then
|
|
-- Iterate through the currency list, updating the currency table in sortedData
|
|
while i <= GetCurrencyListSize() do
|
|
local name, isHeader, isExpanded, isUnused, isWatched, count, icon, maximum, hasWeeklyLimit, currentWeeklyAmount, unknown, currencyID = GetCurrencyListInfo(i)
|
|
if isHeader then
|
|
if not isExpanded then
|
|
ExpandCurrencyList(i, true)
|
|
end
|
|
headingInfo = name
|
|
else
|
|
if not currenciesTable[currencyID] then
|
|
currenciesTable[currencyID] = {}
|
|
end
|
|
|
|
local data = currenciesTable[currencyID]
|
|
if not updatedCurrencies[currencyID] then -- Do a full update
|
|
data.id = currencyID
|
|
data.name = name
|
|
data.link = GetCurrencyListLink(i)
|
|
data.texture = icon
|
|
data.quality = 1
|
|
data.maxQuantity = maximum
|
|
data.canEarnPerWeek = hasWeeklyLimit
|
|
data.maxWeeklyQuantity = maxWeeklyQuantity
|
|
data.heading = headingInfo
|
|
data.tooltip = S.Utils.GetCurrencyTooltipByID(currencyID)
|
|
|
|
updatedCurrencies[currencyID] = true
|
|
end
|
|
data.count = count
|
|
data.quantityEarnedThisWeek = currentWeeklyAmount
|
|
end
|
|
i = i + 1
|
|
end
|
|
|
|
|
|
-- Retail
|
|
else
|
|
-- Iterate through the currency list, updating the currency table in sortedData
|
|
while i <= C_CurrencyInfo.GetCurrencyListSize() do
|
|
local currencyInfo = C_CurrencyInfo.GetCurrencyListInfo(i)
|
|
if currencyInfo.isHeader then -- It's a header, so make sure it's expanded before continuing through the list
|
|
if not currencyInfo.isHeaderExpanded then
|
|
C_CurrencyInfo.ExpandCurrencyList(i, true)
|
|
end
|
|
headingInfo = currencyInfo
|
|
else -- It's not a header, so it's actually a currency! Update the data table, using the currencyID as the table key
|
|
local currencyID = currencyInfo.currencyID
|
|
if not currenciesTable[currencyID] then
|
|
currenciesTable[currencyID] = {}
|
|
end
|
|
local data = currenciesTable[currencyID]
|
|
|
|
if not updatedCurrencies[currencyID] then -- Do a full update
|
|
data.id = currencyID
|
|
data.name = currencyInfo.name
|
|
data.link = C_CurrencyInfo.GetCurrencyListLink(i)
|
|
data.texture = currencyInfo.iconFileID
|
|
data.quality = currencyInfo.quality
|
|
data.maxQuantity = currencyInfo.maxQuantity
|
|
data.canEarnPerWeek = currencyInfo.canEarnPerWeek
|
|
data.maxWeeklyQuantity = currencyInfo.maxWeeklyQuantity
|
|
data.heading = headingInfo.name
|
|
data.tooltip = S.Utils.GetCurrencyTooltipByID(currencyID)
|
|
|
|
updatedCurrencies[currencyID] = true
|
|
end
|
|
data.count = currencyInfo.quantity
|
|
data.quantityEarnedThisWeek = currencyInfo.quantityEarnedThisWeek
|
|
end
|
|
i = i + 1
|
|
end
|
|
end
|
|
end
|
|
S.Utils.TriggerEvent("CurrenciesUpdated")
|
|
end
|
|
function S.Data.GetCurrency(currencyID)
|
|
local data = GetData()
|
|
if data.currencies then
|
|
if data.currencies[currencyID] then
|
|
return data.currencies[currencyID]
|
|
end
|
|
end
|
|
end
|
|
|
|
local function UpdateTimeItemsAdded()
|
|
local time = time()
|
|
local data = GetData(playerGUID)
|
|
-- Make a table of every item in the player's bags
|
|
local items = {}
|
|
for _, bag in pairs(S.Utils.ContainersOfType("ALL")) do
|
|
for slot = 1, S.Utils.GetContainerMaxSlots(bag) do
|
|
local itemData = S.Data.GetItem(bag, slot, playerGUID)
|
|
if itemData.link then
|
|
local key = itemData.key
|
|
if not items[key] then
|
|
items[key] = {}
|
|
items[key].time = time
|
|
items[key].count = itemData.count
|
|
else
|
|
items[key].count = items[key].count + itemData.count
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- Include equipment slots
|
|
for invID = 1, 23 do
|
|
local link = GetInventoryItemLink("player", invID)
|
|
if link then
|
|
local key = S.Data.ItemKey(link)
|
|
if not items[key] then
|
|
items[key] = {}
|
|
items[key].time = time
|
|
items[key].count = 1
|
|
else
|
|
items[key].count = items[key].count + 1
|
|
end
|
|
end
|
|
end
|
|
-- Replace times with any times from the existing table
|
|
if data.timeItemsAdded then
|
|
for key, timeItemAdded in pairs(data.timeItemsAdded) do
|
|
if items[key] and items[key].count <= timeItemAdded.count then
|
|
items[key].time = timeItemAdded.time
|
|
end
|
|
end
|
|
end
|
|
-- Replace with new table
|
|
data.timeItemsAdded = items
|
|
end
|
|
function S.Data.GetItemAge(itemData)
|
|
local key = itemData.key
|
|
local timeItemAdded = GetData().timeItemsAdded[key]
|
|
if timeItemAdded then
|
|
return time() - timeItemAdded.time
|
|
end
|
|
end
|
|
|
|
local function UpdateEquipmentSets()
|
|
if S.WoWVersion() >= 3 then
|
|
local data = GetData(playerGUID)
|
|
for id, _ in pairs(data.equipSets) do
|
|
data.equipSets[id].deleted = true
|
|
end
|
|
for _, id in pairs(C_EquipmentSet.GetEquipmentSetIDs()) do
|
|
if not data.equipSets[id] then
|
|
data.equipSets[id] = {}
|
|
data.equipSets[id].locations = {}
|
|
end
|
|
data.equipSets[id].deleted = nil
|
|
data.equipSets[id].name, data.equipSets[id].icon = C_EquipmentSet.GetEquipmentSetInfo(id)
|
|
-- Clear current locations table, ignoring the bank if the player doesn't have it opened
|
|
local toClear = {}
|
|
for k,v in pairs(data.equipSets[id].locations) do
|
|
if S.IsBankOpened() or not v.bag or v.bag <= NUM_BAG_SLOTS then
|
|
table.insert(toClear, k)
|
|
end
|
|
end
|
|
for _,k in pairs(toClear) do
|
|
data.equipSets[id].locations[k] = nil
|
|
end
|
|
-- Populate locations table
|
|
local itemLocations = C_EquipmentSet.GetItemLocations(id)
|
|
if itemLocations then
|
|
for _, location in pairs(itemLocations) do
|
|
local player, bank, bags, voidStorage, slot, bag
|
|
if S.WoWVersion() == 3 then
|
|
player, bank, bags, slot, bag = EquipmentManager_UnpackLocation(location)
|
|
else
|
|
player, bank, bags, voidStorage, slot, bag = EquipmentManager_UnpackLocation(location)
|
|
end
|
|
if (bags or bank) and bag ~= nil then
|
|
table.insert(data.equipSets[id].locations, {
|
|
["bag"] = bag,
|
|
["slot"] = slot
|
|
})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- Clear deleted equipment sets
|
|
local toClear = {}
|
|
for id, equipSet in pairs(data.equipSets) do
|
|
if equipSet.deleted then
|
|
table.insert(toClear, id)
|
|
end
|
|
end
|
|
for _, id in pairs(toClear) do
|
|
data.equipSets[id] = nil
|
|
end
|
|
-- Toggle the equipment sets dropdown button
|
|
--SortedEquipmentSetsDropdownButton_Update()
|
|
end
|
|
S.Utils.TriggerEvent("EquipmentSetsUpdated")
|
|
end
|
|
|
|
local function UpdateBagContents(container)
|
|
-- Bags
|
|
for k, bagID in pairs(S.Utils.ContainersOfType("BAGS")) do
|
|
if not container or bagID == container then
|
|
for slotID = 1, S.Utils.MaxBagSlots() do
|
|
S.Data.UpdateItem(bagID, slotID)
|
|
end
|
|
end
|
|
end
|
|
-- Container buttons
|
|
--[[for i = 1, NUM_BAG_SLOTS do
|
|
local slotID = -NUM_BAG_SLOTS + i
|
|
S.Data.UpdateItem(0, slotID)
|
|
end]]
|
|
|
|
-- Bank
|
|
if S.IsBankOpened() then
|
|
GetData(playerGUID).bankNotCached = nil
|
|
for k, bagID in pairs(S.Utils.ContainersOfType("BANK")) do
|
|
if not container or bagID == container then
|
|
for slotID = 1, S.Utils.MaxBagSlots() do
|
|
S.Data.UpdateItem(bagID, slotID)
|
|
end
|
|
end
|
|
end
|
|
-- Container buttons
|
|
for slotID = 1, NUM_BANKBAGSLOTS do
|
|
S.Data.UpdateItem(-4, slotID)
|
|
end
|
|
end
|
|
|
|
-- Reagent bank
|
|
if S.WoWVersion() >= 6 and S.IsBankOpened() and IsReagentBankUnlocked() then
|
|
GetData(playerGUID).reagentNotUnlocked = nil
|
|
if not container or REAGENTBANK_CONTAINER == container then
|
|
for slotID = 1, 98 do
|
|
S.Data.UpdateItem(REAGENTBANK_CONTAINER, slotID)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Account bank
|
|
if S.WoWVersion() >= 11 and S.IsBankOpened() and C_PlayerInfo.HasAccountInventoryLock() then
|
|
for k, bagID in pairs(S.Utils.ContainersOfType("ACCOUNT")) do
|
|
if not container or bagID == container then
|
|
for slotID = 1, 98 do
|
|
S.Data.UpdateItem(bagID, slotID)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Keyring
|
|
if S.WoWVersion() <= 3 then
|
|
if not container or KEYRING_CONTAINER == container then
|
|
for slotID = 1,32 do
|
|
S.Data.UpdateItem(KEYRING_CONTAINER, slotID)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Inventory items
|
|
for _, inventoryID in pairs(INVENTORY_IDS_TO_UPDATE) do
|
|
if not BANK_INVENTORY_IDS[inventoryID] or S.IsBankOpened() then
|
|
S.Data.UpdateInventoryItem(inventoryID)
|
|
end
|
|
end
|
|
|
|
-- Update number of slots
|
|
for k, bagID in pairs(S.Utils.ContainersOfType("ALL")) do
|
|
if S.IsBankOpened() or not (S.Utils.ContainerIsType(bagID, "BANK") or S.Utils.ContainerIsType(bagID, "REAGENT") or S.Utils.ContainerIsType(bagID, "ACCOUNT")) then
|
|
if S.Utils.ContainerIsType(bagID, "ACCOUNT") then
|
|
Sorted_AccountData.containerNumSlots[bagID] = {
|
|
["numSlots"] = S.Utils.GetContainerNumSlots(bagID),
|
|
["numFreeSlots"] = S.Utils.GetContainerNumFreeSlots(bagID)
|
|
}
|
|
else
|
|
sortedData[playerGUID].containerNumSlots[bagID] = {
|
|
["numSlots"] = S.Utils.GetContainerNumSlots(bagID),
|
|
["numFreeSlots"] = S.Utils.GetContainerNumFreeSlots(bagID)
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
UpdateEquipmentSets()
|
|
|
|
UpdateTimeItemsAdded()
|
|
|
|
S.Utils.TriggerEvent("BagsUpdated")
|
|
end
|
|
S.Data.UpdateBagContents = UpdateBagContents
|
|
|
|
|
|
local itemUpdateMethods = {}
|
|
local columnItemUpdateMethod = {}
|
|
function S.Data.AddDataToItem(func, columnKey)
|
|
table.insert(itemUpdateMethods, func)
|
|
if columnKey then
|
|
columnItemUpdateMethod[columnKey] = func
|
|
end
|
|
end
|
|
|
|
local function UpdateItemColumn(bag, slot, columnKey)
|
|
columnItemUpdateMethod[columnKey](S.Data.GetItem(bag, slot, playerGUID))
|
|
end
|
|
function S.Data.UpdateColumn(columnKey)
|
|
-- Bags
|
|
for k, bagID in pairs(S.Utils.ContainersOfType("BAGS")) do
|
|
if not container or bagID == container then
|
|
for slotID = 1, S.Utils.MaxBagSlots() do
|
|
UpdateItemColumn(bagID, slotID, columnKey)
|
|
end
|
|
end
|
|
end
|
|
-- Bank
|
|
for k, bagID in pairs(S.Utils.ContainersOfType("BANK")) do
|
|
if not container or bagID == container then
|
|
for slotID = 1, S.Utils.MaxBagSlots() do
|
|
UpdateItemColumn(bagID, slotID, columnKey)
|
|
end
|
|
end
|
|
end
|
|
-- Reagent bank
|
|
if S.WoWVersion() >= 6 then
|
|
if not container or REAGENTBANK_CONTAINER == container then
|
|
for slotID = 1, 98 do
|
|
UpdateItemColumn(REAGENTBANK_CONTAINER, slotID, columnKey)
|
|
end
|
|
end
|
|
end
|
|
-- Account bank
|
|
if S.WoWVersion() >= 11 then
|
|
for k, bagID in pairs(S.Utils.ContainersOfType("ACCOUNT")) do
|
|
if not container or bagID == container then
|
|
for slotID = 1, 98 do
|
|
UpdateItemColumn(bagID, slotID, columnKey)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- Keyring
|
|
if S.WoWVersion() <= 3 then
|
|
if not container or KEYRING_CONTAINER == container then
|
|
for slotID = 1,32 do
|
|
UpdateItemColumn(KEYRING_CONTAINER, slotID, columnKey)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local guildTooltipInfoFields = {
|
|
["id"] = {"itemID", "intVal"},
|
|
["battlePetSpeciesID"] = {"speciesID", "intVal"},
|
|
["battlePetLevel"] = {"effectiveILvl", "intVal"},
|
|
["battlePetName"] = {"speciesName", "stringVal"},
|
|
["battlePetBreedQuality"] = {"quality", "intVal"},
|
|
}
|
|
local updatedItems = {
|
|
["INVENTORY"] = {},
|
|
["GUILD"] = {},
|
|
["VOID"] = {},
|
|
["BAGS"] = {}
|
|
}
|
|
local function OnDataAvailable(bag, slot, inventory, guild, void)
|
|
local self, newLink
|
|
if inventory then
|
|
self = S.Data.GetInventoryItem(bag, playerGUID)
|
|
self.texture, self.count, self.quality, newLink, self.hasNoValue, self.itemID =
|
|
GetInventoryItemTexture("player", bag),
|
|
GetInventoryItemCount("player", bag),
|
|
GetInventoryItemQuality("player", bag),
|
|
GetInventoryItemLink("player", bag),
|
|
false,
|
|
GetInventoryItemID("player", bag)
|
|
elseif guild then
|
|
if not S.IsGuildBankAvailable() then
|
|
return
|
|
end
|
|
self = S.Data.GetGuildItem(bag, slot, playerGUID)
|
|
self.texture, self.count, _, _, self.quality = GetGuildBankItemInfo(bag, slot)
|
|
newLink = GetGuildBankItemLink(bag, slot)
|
|
self.itemID = GetItemInfoInstant(newLink)
|
|
elseif void then
|
|
if not S.IsVoidStorageAvailable() then
|
|
return
|
|
end
|
|
self = S.Data.GetVoidItem(bag, slot, playerGUID)
|
|
self.itemID, self.texture, _, _, _, self.quality = GetVoidItemInfo(bag, slot)
|
|
newLink = GetVoidItemHyperlinkString((bag - 1) * 80 + slot)
|
|
self.count = 1
|
|
else
|
|
self = S.Data.GetItem(bag, slot, playerGUID)
|
|
if S.WoWVersion() >= 4 or bag ~= KEYRING_CONTAINER then
|
|
if useNewContainerAPI then
|
|
local t = GetContainerItemInfo(bag, slot)
|
|
if t then
|
|
self.texture = t.iconFileID
|
|
self.count = t.stackCount
|
|
self.quality = t.quality
|
|
newLink = t.hyperlink
|
|
self.hasNoValue = t.hasNoValue
|
|
self.itemID = t.itemID
|
|
else
|
|
self.texture, self.count, self.quality, newLink, self.hasNoValue, self.itemID =
|
|
nil, nil, nil, nil, nil, nil
|
|
end
|
|
else
|
|
self.texture, self.count, _, self.quality, _, _,
|
|
newLink, _, self.hasNoValue, self.itemID = GetContainerItemInfo(bag, slot)
|
|
end
|
|
else
|
|
local invSlotID = KeyRingButtonIDToInvSlotID(slot)
|
|
self.texture, self.count, self.quality, newLink, self.hasNoValue, self.itemID =
|
|
GetInventoryItemTexture("player", invSlotID),
|
|
GetInventoryItemCount("player", invSlotID),
|
|
GetInventoryItemQuality("player", invSlotID),
|
|
GetInventoryItemLink("player", invSlotID),
|
|
false,
|
|
GetInventoryItemID("player", invSlotID)
|
|
end
|
|
end
|
|
|
|
-- Make sure that, after reloading, each item updates at least once, even if the link hasn't changed
|
|
local itemHasUpdated
|
|
if inventory then
|
|
itemHasUpdated = updatedItems["INVENTORY"][bag]
|
|
updatedItems["INVENTORY"][bag] = true
|
|
elseif guild then
|
|
if not updatedItems["GUILD"][bag] then
|
|
updatedItems["GUILD"][bag] = {}
|
|
end
|
|
itemHasUpdated = updatedItems["GUILD"][bag][slot]
|
|
updatedItems["GUILD"][bag][slot] = true
|
|
elseif void then
|
|
if not updatedItems["VOID"][bag] then
|
|
updatedItems["VOID"][bag] = {}
|
|
end
|
|
itemHasUpdated = false --updatedItems["VOID"][bag][slot] DISABLED WHILE VOID STORAGE TAB IS HAVING ISSUES
|
|
updatedItems["VOID"][bag][slot] = true
|
|
else
|
|
if not updatedItems["BAGS"][bag] then
|
|
updatedItems["BAGS"][bag] = {}
|
|
end
|
|
itemHasUpdated = updatedItems["BAGS"][bag][slot]
|
|
updatedItems["BAGS"][bag][slot] = true
|
|
end
|
|
|
|
-- Only update when the item changes, or if this is the first time this item has been updated since the last reload
|
|
if self.link ~= newLink or not itemHasUpdated then
|
|
self.link = newLink
|
|
|
|
if not self.categories then
|
|
self.categories = {}
|
|
end
|
|
|
|
if self.link then
|
|
-- Run any methods to add data provided by plugins
|
|
for _, func in pairs(itemUpdateMethods) do
|
|
func(self)
|
|
end
|
|
|
|
if guild then
|
|
-- Get info out of the C_TooltipInfo api
|
|
local args = C_TooltipInfo.GetGuildBankItem(bag, slot)
|
|
if args then
|
|
if args.args then
|
|
-- Pre 10.1 version
|
|
args = args.args
|
|
local t = {}
|
|
for _, arg in pairs(args) do
|
|
local fields = guildTooltipInfoFields[arg.field]
|
|
if fields then
|
|
self[fields[1]] = arg[fields[2]]
|
|
end
|
|
end
|
|
|
|
else
|
|
-- Post 10.1 version
|
|
for field, arg in pairs(args) do
|
|
local fields = guildTooltipInfoFields[field]
|
|
if fields then
|
|
self[fields[1]] = arg
|
|
end
|
|
end
|
|
self.tooltip = {{}, {}}
|
|
for k,v in pairs(args.lines) do
|
|
self.tooltip[1][k] = v.leftText
|
|
self.tooltip[2][k] = v.rightText
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Replaced with self.invSlotID
|
|
self.equipLoc = nil
|
|
|
|
|
|
-- Pet cages
|
|
if self.itemID == 82800 then
|
|
_, _, _, _, self.minLevel, _, _, self.stackCount, _,
|
|
_, self.value, self.classID, self.subClassID, self.bindType, self.expacID = GetItemInfo(82800)
|
|
self.invSlotID = nil
|
|
if not guild then
|
|
-- Guild items already have this data extracted from C_TooltipInfo
|
|
self.speciesID, self.level, self.quality, _, _, _, self.speciesName = BattlePetToolTip_UnpackBattlePetLink(self.link)
|
|
self.speciesName = self.speciesName:gsub("[%[%]]", "") -- Remove square brackets around name
|
|
self.effectiveILvl = self.level
|
|
end
|
|
self.name = string.format(S.Localize("ITEM_PET_CAGED"), self.speciesName)
|
|
else
|
|
self.speciesName, self.speciesID, self.cageName = nil, nil, nil
|
|
if S.WoWVersion() >= 5 then
|
|
_, _, _, _, _, _, _, _, _, _, _, _, self.speciesID = C_PetJournal.GetPetInfoByItemID(self.itemID)
|
|
end
|
|
|
|
-- Mythic Keystones
|
|
if S.WoWVersion() >= 7 and self.itemID and C_Item.IsItemKeystoneByID(self.itemID) then -- Mythic Keystone
|
|
self.minLevel = 60
|
|
self.value = 0
|
|
self.classID = Enum.ItemClass.Miscellaneous
|
|
self.subClassID = Enum.ItemMiscellaneousSubclass.Reagent
|
|
self.bindType = 1
|
|
self.expacID = S.WoWVersion() - 1
|
|
self.quality = 8
|
|
self.invSlotID = nil
|
|
if not guid then
|
|
self.level = C_MythicPlus.GetOwnedKeystoneLevel()
|
|
local mapID = C_MythicPlus.GetOwnedKeystoneChallengeMapID()
|
|
if (not mapID) then
|
|
mapID = C_MythicPlus.GetOwnedKeystoneMapID()
|
|
end
|
|
if (mapID) then
|
|
local name, id, timeLimit, texture, backgroundTexture = C_ChallengeMode.GetMapUIInfo(mapID)
|
|
if (name) then
|
|
self.name = string.format(S.Localize("ITEM_MYTHIC_KEYSTONE"), name.." ("..self.level..")")
|
|
else
|
|
self.name = S.Localize("ITEM_UNKNOWN_KEYSTONE")
|
|
end
|
|
else
|
|
self.name = S.Localize("ITEM_UNKNOWN_KEYSTONE")
|
|
end
|
|
else
|
|
self.level = 1
|
|
self.name = S.Localize("ITEM_UNKNOWN_KEYSTONE")
|
|
end
|
|
self.effectiveILvl = self.level
|
|
else
|
|
self.name = nil
|
|
|
|
-- Get more info from the link using GetItemInfo
|
|
self.name, _, self.quality, self.level, self.minLevel, _, _, self.stackCount, _,
|
|
_, self.value, self.classID, self.subClassID, self.bindType, self.expacID = GetItemInfo(self.link)
|
|
|
|
-- If that didn't work, try using the itemID instead
|
|
if not self.name then
|
|
self.name, _, self.quality, self.level, self.minLevel, _, _, self.stackCount, _,
|
|
_, self.value, self.classID, self.subClassID, self.bindType, self.expacID = GetItemInfo(self.itemID)
|
|
self.effectiveILvl = self.level
|
|
else
|
|
-- Get the actual item level, after any scaling is applied
|
|
self.effectiveILvl = GetDetailedItemLevelInfo(self.link)
|
|
end
|
|
|
|
self.invSlotID = C_Item.GetItemInventoryTypeByID(self.link)
|
|
|
|
if not self.expacID then
|
|
self.expacID = 0
|
|
elseif self.expacID > 253 then
|
|
self.expacID = self.expacID - 254
|
|
end
|
|
--[[if S.WoWVersion() >= 9 and self.link then
|
|
if C_Soulbinds.IsItemConduitByItemInfo(self.link) then
|
|
self.subClassID = S.CONDUIT_SUBCLASSID
|
|
end
|
|
end]]
|
|
end
|
|
end
|
|
self.type = nil
|
|
|
|
self.isEquippable = IsEquippableItem(self.link)
|
|
|
|
-- Get soulbinding
|
|
if guild then
|
|
self.bound = false
|
|
else
|
|
if void then
|
|
self.bound = true
|
|
else
|
|
local item
|
|
if inventory then
|
|
item = ItemLocation:CreateFromEquipmentSlot(bag)
|
|
else
|
|
item = ItemLocation:CreateFromBagAndSlot(bag, slot)
|
|
end
|
|
self.bound = C_Item.IsBound(item)
|
|
|
|
-- Warbinding
|
|
if S.WoWVersion() >= 11 then
|
|
if self.bindType == 2 then -- Bind on equip
|
|
self.accountBound = C_Item.IsBoundToAccountUntilEquip(item)
|
|
else
|
|
self.accountBound = C_Bank.IsItemAllowedInBankType(Enum.BankType.Account, item)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if self.speciesID then
|
|
|
|
end
|
|
|
|
-- Get tooltip text
|
|
if not guild then -- Guild items already have their tooltip info
|
|
if C_TooltipInfo then -- C_TooltipInfo currently isn't available in Classic
|
|
self.tooltip = {{}, {}}
|
|
local tooltipInfo
|
|
if void then
|
|
tooltipInfo = C_TooltipInfo.GetVoidItem(bag, slot)
|
|
elseif not inventory then
|
|
tooltipInfo = C_TooltipInfo.GetBagItem(bag, slot)
|
|
else
|
|
tooltipInfo = C_TooltipInfo.GetInventoryItem("player", bag)
|
|
end
|
|
if tooltipInfo then
|
|
for k,v in pairs(tooltipInfo.lines) do
|
|
self.tooltip[1][k] = v.leftText
|
|
self.tooltip[2][k] = v.rightText
|
|
end
|
|
end
|
|
elseif void then
|
|
self.tooltip = S.Utils.GetVoidItemTooltip(bag, slot)
|
|
elseif not inventory then
|
|
self.tooltip = S.Utils.GetBagItemTooltip(bag, slot)
|
|
else
|
|
self.tooltip = S.Utils.GetInventoryItemTooltip(bag)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Item is gone (or something has gone wrong), clear the data
|
|
if not self.link or not self.itemID or not self.quality or not self.subClassID or not self.bindType then
|
|
for k, _ in pairs(self) do
|
|
if k ~= "bag" and k ~= "slot" and k ~= "tab" then
|
|
self[k] = nil
|
|
end
|
|
end
|
|
else
|
|
self.key = ItemKey(self.link, self.speciesID) -- Generate item key which ignores certain parts of the item link. Used to determine if two items are the same
|
|
end
|
|
end
|
|
return self.itemID
|
|
end
|
|
|
|
function S.Data.UpdateItem(bag, slot)
|
|
local item = Item:CreateFromBagAndSlot(bag, slot)
|
|
if item:IsItemDataCached() then
|
|
OnDataAvailable(bag, slot)
|
|
else
|
|
item:ContinueOnItemLoad(function()
|
|
local itemID = OnDataAvailable(bag, slot)
|
|
end)
|
|
end
|
|
end
|
|
function S.Data.UpdateInventoryItem(inventoryID)
|
|
local item = Item:CreateFromEquipmentSlot(inventoryID)
|
|
if item:IsItemDataCached() then
|
|
OnDataAvailable(inventoryID, nil, true)
|
|
else
|
|
item:ContinueOnItemLoad(function()
|
|
local itemID = OnDataAvailable(inventoryID, nil, true)
|
|
end)
|
|
end
|
|
end
|
|
|
|
-- Returns a reference to a table with elements: texture, count, quality, link, hasNoValue, itemID, key, bag, slot
|
|
function S.Data.GetItem(bag, slot, guid)
|
|
local data
|
|
if S.Utils.ContainerIsType(bag, S.CONTAINER_TYPES.ACCOUNT) then
|
|
data = Sorted_AccountData
|
|
else
|
|
data = GetData(guid)
|
|
end
|
|
if not data.containers[bag] then
|
|
data.containers[bag] = {}
|
|
end
|
|
if not data.containers[bag][slot] then
|
|
data.containers[bag][slot] = {}
|
|
end
|
|
local itemData = data.containers[bag][slot]
|
|
itemData.bag = bag
|
|
itemData.slot = slot
|
|
if not itemData.key and itemData.link then
|
|
itemData.key = ItemKey(itemData.link)
|
|
end
|
|
return itemData
|
|
end
|
|
|
|
-- Returns a reference to a table with elements: texture, count, quality, link, hasNoValue, itemID, key, bag, slot
|
|
function S.Data.GetInventoryItem(inventoryID, guid)
|
|
local data = GetData(guid)
|
|
if not data.inventoryItems then
|
|
data.inventoryItems = {}
|
|
end
|
|
if not data.inventoryItems[inventoryID] then
|
|
data.inventoryItems[inventoryID] = {}
|
|
end
|
|
local itemData = data.inventoryItems[inventoryID]
|
|
if not itemData.key and itemData.link then
|
|
itemData.key = ItemKey(itemData.link)
|
|
end
|
|
return itemData
|
|
end
|
|
|
|
-- Returns two numbers, number of filled slots of the given type, and total number available
|
|
function S.Data.GetNumSlots(type, guid)
|
|
local data = GetData(guid)
|
|
if not data then return 0,0 end
|
|
return data[type:lower().."UsedSlots"], data[type:lower().."NumSlots"]
|
|
end
|
|
|
|
-- ACCOUNT BANK FUNCTIONS
|
|
function S.Data.UpdateAccountBankTabs()
|
|
local bankTabData = C_Bank.FetchPurchasedBankTabData(2)
|
|
S.Utils.CopyTable(bankTabData, Sorted_AccountData.bankTabData)
|
|
S.Utils.TriggerEvent("BankTabsUpdated")
|
|
end
|
|
|
|
-- GUILD BANK FUNCTIONS
|
|
function S.Data.UpdateGuildInfo()
|
|
local data = GetData(playerGUID)
|
|
if not IsInGuild() then
|
|
data.guild = nil
|
|
else
|
|
-- Initialise guild table
|
|
if not data.guild then
|
|
data.guild = {}
|
|
data.guild.tabs = {}
|
|
for i = 1, 8 do
|
|
data.guild.tabs[i] = {}
|
|
data.guild.tabs[i].slots = {}
|
|
for slot = 1, 98 do
|
|
data.guild.tabs[i].slots[slot] = {
|
|
["isGuild"] = true,
|
|
["bag"] = i,
|
|
["slot"] = slot
|
|
}
|
|
end
|
|
end
|
|
end
|
|
-- Update guild info
|
|
data.guild.name, data.guild.rank, data.guild.rankID = GetGuildInfo("player")
|
|
end
|
|
end
|
|
function S.Data.UpdateGuildMoney()
|
|
local data = GetData(playerGUID)
|
|
if data.guild then
|
|
data.guild.money = GetGuildBankMoney()
|
|
data.guild.withdrawLimit = GetGuildBankWithdrawMoney()
|
|
end
|
|
end
|
|
local defaultTabIcon = "Interface\\Icons\\INV_Misc_QuestionMark"
|
|
local defaultTabNames = {"Tab 1","Tab 2","Tab 3","Tab 4","Tab 5","Tab 6","Tab 7","Tab 8"}
|
|
function S.Data.UpdateGuildBankTabs()
|
|
local data = GetData(playerGUID)
|
|
if data.guild then
|
|
local guild = data.guild
|
|
|
|
for i = 1, 8 do
|
|
local name, icon, canView, canDeposit, numWithdrawals, remainingWithdrawals, filtered = GetGuildBankTabInfo(i)
|
|
local tab = guild.tabs[i]
|
|
-- Only update name and icon if the info is available
|
|
if name == defaultTabNames[i] and icon == defaultTabIcon then
|
|
if not tab.name then
|
|
-- Tab doesn't have a name or icon set anyway, so set them to the default values
|
|
tab.name, tab.icon = name, icon
|
|
end
|
|
tab.canView, tab.canDeposit, tab.numWithdrawals, tab.remainingWithdrawals, tab.filtered = canView, canDeposit, numWithdrawals, remainingWithdrawals, filtered
|
|
else
|
|
-- All info is available, update all of the tab data
|
|
tab.name, tab.icon, tab.canView, tab.canDeposit, tab.numWithdrawals, tab.remainingWithdrawals, tab.filtered =
|
|
name, icon, canView, canDeposit, numWithdrawals, remainingWithdrawals, filtered
|
|
end
|
|
end
|
|
end
|
|
S.Utils.TriggerEvent("GuildBankTabsUpdated")
|
|
end
|
|
|
|
function S.Data.UpdateGuildItem(tab, slot, link)
|
|
if link then
|
|
local item = Item:CreateFromItemLink(link)
|
|
if item:IsItemDataCached() then
|
|
OnDataAvailable(tab, slot, false, true)
|
|
else
|
|
item:ContinueOnItemLoad(function()
|
|
OnDataAvailable(tab, slot, false, true)
|
|
end)
|
|
end
|
|
else
|
|
-- There's no item in this slot, so clear anything existing
|
|
local data = S.Data.GetGuildItem(tab, slot, playerGUID)
|
|
if data.link then
|
|
GetData(playerGUID).guild.tabs[tab].slots[slot] = {
|
|
["isGuild"] = true,
|
|
["bag"] = tab,
|
|
["slot"] = slot
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Updating the guild bank completely requires querying the server. Don't do this too often.
|
|
function S.Data.UpdateGuildBank(tab)
|
|
local data = GetData(playerGUID)
|
|
|
|
if data.guild then
|
|
local guild = data.guild
|
|
|
|
|
|
-- Update one specific tab
|
|
if tab then
|
|
if guild.tabs[tab].canView then
|
|
QueryGuildBankTab(tab)
|
|
end
|
|
|
|
|
|
local count = 0
|
|
if guild.tabs[tab].canView then
|
|
|
|
-- Figure out if tab is empty, or if the data isn't available yet
|
|
local dataUnavailable = true
|
|
local slot = 1
|
|
while dataUnavailable and slot <= 98 do
|
|
if GetGuildBankItemLink(tab, slot) then
|
|
dataUnavailable = false
|
|
end
|
|
slot = slot + 1
|
|
end
|
|
if dataUnavailable then
|
|
-- No items found
|
|
-- Count the number of times the tab has updated and been empty
|
|
if not guild.tabs[tab].emptyUpdates then
|
|
guild.tabs[tab].emptyUpdates = 1
|
|
else
|
|
guild.tabs[tab].emptyUpdates = guild.tabs[tab].emptyUpdates + 1
|
|
end
|
|
-- If it's still empty after several (3) updates, give in, let it update already
|
|
if guild.tabs[tab].emptyUpdates > 3 then
|
|
guild.tabs[tab].emptyUpdates = nil
|
|
dataUnavailable = false
|
|
end
|
|
end
|
|
|
|
-- Update data
|
|
if not dataUnavailable then
|
|
for slot = 1, 98 do
|
|
local link = GetGuildBankItemLink(tab, slot)
|
|
S.Data.UpdateGuildItem(tab, slot, link)
|
|
if link then
|
|
count = count + 1
|
|
end
|
|
end
|
|
guild.tabs[tab].count = count
|
|
end
|
|
|
|
else
|
|
-- Can't be viewed
|
|
guild.tabs[tab].count = 0
|
|
end
|
|
|
|
|
|
-- Update everything
|
|
else
|
|
for tab = 1, 8 do
|
|
if guild.tabs[tab].canView then
|
|
QueryGuildBankTab(tab)
|
|
end
|
|
|
|
local count = 0
|
|
if guild.tabs[tab].canView then
|
|
for slot = 1, 98 do
|
|
local link = GetGuildBankItemLink(tab, slot)
|
|
S.Data.UpdateGuildItem(tab, slot, link)
|
|
if link then
|
|
count = count + 1
|
|
end
|
|
end
|
|
end
|
|
guild.tabs[tab].count = count
|
|
end
|
|
end
|
|
end
|
|
end
|
|
function S.Data.GetGuildItem(tab, slot, guid)
|
|
local guild = GetData(guid).guild
|
|
if not guild then
|
|
return {}
|
|
else
|
|
return guild.tabs[tab].slots[slot]
|
|
end
|
|
end
|
|
|
|
-- VOID STORAGE FUNCTIONS
|
|
function S.Data.UpdateVoidItem(tab, slot)
|
|
OnDataAvailable(tab, slot, nil, nil, true)
|
|
end
|
|
function S.Data.GetVoidItem(tab, slot, guid)
|
|
local void = GetData(guid).voidStorage
|
|
if not void then
|
|
return {}
|
|
else
|
|
return void.tabs[tab].slots[slot]
|
|
end
|
|
end
|
|
local function UpdateVoidContents()
|
|
for tab = 1, 2 do
|
|
for slot = 1, 80 do
|
|
S.Data.UpdateVoidItem(tab, slot)
|
|
end
|
|
end
|
|
S.Utils.TriggerEvent("VoidStorageUpdated")
|
|
end
|
|
function S.Data.UpdateVoidContents()
|
|
if S.IsVoidStorageAvailable() then
|
|
local data = GetData(playerGUID)
|
|
if not data.voidStorage then
|
|
data.voidStorage = {}
|
|
data.voidStorage.tabs = {}
|
|
for tab = 1, 2 do
|
|
data.voidStorage.tabs[tab] = {}
|
|
data.voidStorage.tabs[tab].slots = {}
|
|
for slot = 1, 80 do
|
|
data.voidStorage.tabs[tab].slots[slot] = {
|
|
["isVoid"] = true,
|
|
["bag"] = tab,
|
|
["slot"] = slot
|
|
}
|
|
end
|
|
end
|
|
end
|
|
-- Just make sure that the void storage item info is available
|
|
for tab = 1,2 do
|
|
for slot = 1,80 do
|
|
local itemID = GetVoidItemInfo(tab, slot)
|
|
if itemID then
|
|
C_Item.RequestLoadItemDataByID(itemID)
|
|
end
|
|
end
|
|
end
|
|
C_Timer.After(0.01, UpdateVoidContents)
|
|
end
|
|
end
|
|
|
|
|
|
-- ITEM DATA FUNCTIONS
|
|
-- Takes itemData and return a number, 0 for grey, 1 for manually marked trash, 2 for not-grey or marked not-trash
|
|
function S.Data.GetTrash(itemData)
|
|
local data = GetData()
|
|
if not data.trashItems then
|
|
data.trashItems = {}
|
|
end
|
|
if data.trashItems[itemData.itemID] then
|
|
return data.trashItems[itemData.itemID]
|
|
elseif itemData.quality == 0 then
|
|
return 0
|
|
else
|
|
return 2
|
|
end
|
|
end
|
|
function S.Data.ToggleTrash(itemData)
|
|
local data = GetData()
|
|
if not data.trashItems then
|
|
data.trashItems = {}
|
|
end
|
|
if data.trashItems[itemData.itemID] then
|
|
if data.trashItems[itemData.itemID] == 1 then
|
|
data.trashItems[itemData.itemID] = 2
|
|
else
|
|
data.trashItems[itemData.itemID] = 1
|
|
end
|
|
else
|
|
if itemData.quality == 0 then
|
|
data.trashItems[itemData.itemID] = 2
|
|
else
|
|
data.trashItems[itemData.itemID] = 1
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Takes itemData and returns a number 1-8 for the raid marker icon, or nil if none
|
|
function S.Data.GetFavorited(itemData)
|
|
if itemData.key then
|
|
local data = GetData()
|
|
return data.favoritedItems[itemData.key]
|
|
end
|
|
return nil
|
|
end
|
|
|
|
function S.Data.ToggleFavorited(itemData, value)
|
|
local key = itemData.key
|
|
local data = GetData()
|
|
if data.favoritedItems[key] then
|
|
if value then
|
|
data.favoritedItems[key] = value
|
|
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON)
|
|
else
|
|
if data.favoritedItems[key] and data.favoritedItems[key] > 0 then
|
|
data.favoritedItems[key] = nil
|
|
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF)
|
|
else
|
|
data.favoritedItems[key] = 1
|
|
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON)
|
|
end
|
|
end
|
|
else
|
|
if value then
|
|
data.favoritedItems[key] = value
|
|
else
|
|
data.favoritedItems[key] = 1
|
|
end
|
|
PlaySound(SOUNDKIT.IG_CHAT_SCROLL_UP)
|
|
end
|
|
end
|
|
|
|
function S.Data.Unfavorite(itemData)
|
|
local key = itemData.key
|
|
GetData().favoritedItems[key] = nil
|
|
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF)
|
|
end
|
|
|
|
-- CURRENCY FUNCTIONS
|
|
-- Takes currency data and returns true if it's tracked
|
|
function S.Data.GetCurrencyTracked(currency)
|
|
local data = GetData()
|
|
if data.trackedCurrencies then
|
|
for k,v in pairs(data.trackedCurrencies) do
|
|
if v == currency.id then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- Creates or removes an entry for the currency's id
|
|
-- Table is ordered in the order that the currencies were tracked in
|
|
function S.Data.ToggleCurrencyTracked(currency)
|
|
local data = GetData()
|
|
-- Remove it if it's already tracked
|
|
if data.trackedCurrencies then
|
|
for k,v in pairs(data.trackedCurrencies) do
|
|
if v == currency.id then
|
|
table.remove(data.trackedCurrencies, k)
|
|
return
|
|
end
|
|
end
|
|
end
|
|
-- Otherwise add it
|
|
if not data.trackedCurrencies then
|
|
data.trackedCurrencies = { currency.id }
|
|
else
|
|
table.insert(data.trackedCurrencies, currency.id)
|
|
end
|
|
end
|
|
function S.Data.GetTrackedCurrencies()
|
|
local data = GetData()
|
|
return data.trackedCurrencies
|
|
end
|
|
|
|
-- Takes currency and returns a number 1-8 for the raid marker icon, or nil if none
|
|
function S.Data.GetCurrencyFavorited(currency)
|
|
local data = GetData()
|
|
if data.favoritedCurrencies then
|
|
return data.favoritedCurrencies[currency.id]
|
|
end
|
|
end
|
|
|
|
function S.Data.ToggleCurrencyFavorited(currency, value)
|
|
local key = currency.id
|
|
local data = GetData()
|
|
-- If viewing another character which was last played before Sorted 2.0, create a table for them
|
|
if not data.favoritedCurrencies then
|
|
data.favoritedCurrencies = {}
|
|
end
|
|
if data.favoritedCurrencies[key] then
|
|
if value then
|
|
data.favoritedCurrencies[key] = value
|
|
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON)
|
|
else
|
|
if data.favoritedCurrencies[key] and data.favoritedCurrencies[key] > 0 then
|
|
data.favoritedCurrencies[key] = nil
|
|
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF)
|
|
else
|
|
data.favoritedCurrencies[key] = 1
|
|
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON)
|
|
end
|
|
end
|
|
else
|
|
if value then
|
|
data.favoritedCurrencies[key] = value
|
|
else
|
|
data.favoritedCurrencies[key] = 1
|
|
end
|
|
PlaySound(SOUNDKIT.IG_CHAT_SCROLL_UP)
|
|
end
|
|
end
|
|
|
|
function S.Data.UnfavoriteCurrency(currency)
|
|
local key = currency.id
|
|
GetData().favoritedCurrencies[key] = nil
|
|
PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF)
|
|
end
|
|
|
|
|
|
|
|
-- S.IsBankOpened() returns true when the player is currently using the bank and the bank contents are available
|
|
local bankOpen = false
|
|
function S.IsBankOpened()
|
|
return bankOpen
|
|
end
|
|
local guildOpen = false
|
|
function S.IsGuildBankOpened()
|
|
return guildOpen
|
|
end
|
|
local voidOpen = false
|
|
function S.IsVoidStorageOpened()
|
|
return voidOpen
|
|
end
|
|
|
|
|
|
-- EVENT HANDLING
|
|
-- Make BAG_UPDATE work like BAG_UPDATE_DELAYED
|
|
local bagUpdateHandlerFrame = CreateFrame("FRAME")
|
|
bagUpdateHandlerFrame:RegisterEvent("BAG_UPDATE")
|
|
bagUpdateHandlerFrame:SetScript("OnEvent", function(self)
|
|
self.doUpdate = true
|
|
end)
|
|
bagUpdateHandlerFrame:SetScript("OnUpdate", function(self)
|
|
if self.doUpdate and (not self.lastUpdateTime or self.lastUpdateTime < GetTime() - 0.2) then
|
|
self.lastUpdateTime = GetTime()
|
|
self.doUpdate = false
|
|
UpdateBagContents()
|
|
end
|
|
end)
|
|
|
|
local function BankFrameOpenedDelayed()
|
|
if bankOpen then
|
|
UpdateBagContents()
|
|
if S.WoWVersion() >= 11 then
|
|
S.Data.UpdateAccountBankTabs()
|
|
end
|
|
S.Utils.TriggerEvent("BankOpened")
|
|
end
|
|
end
|
|
|
|
-- Creates a frame to perform initialisation at appropriate points in WoW's loading process and handle other events
|
|
local eventHandlerFrame = CreateFrame("FRAME")
|
|
eventHandlerFrame:RegisterEvent("ADDON_LOADED")
|
|
eventHandlerFrame:RegisterEvent("PLAYER_LOGIN")
|
|
eventHandlerFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
--eventHandlerFrame:RegisterEvent("BAG_UPDATE_DELAYED") - Blizz broke this in WotLK. Good job Blizz.
|
|
eventHandlerFrame:RegisterEvent("BANKFRAME_OPENED")
|
|
eventHandlerFrame:RegisterEvent("BANKFRAME_CLOSED")
|
|
if S.WoWVersion() >= 11 then
|
|
eventHandlerFrame:RegisterEvent("BANK_TAB_SETTINGS_UPDATED")
|
|
end
|
|
eventHandlerFrame:RegisterEvent("GUILDBANK_UPDATE_TABS")
|
|
eventHandlerFrame:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED")
|
|
if S.WoWVersion() >= 3 then
|
|
eventHandlerFrame:RegisterEvent("EQUIPMENT_SETS_CHANGED")
|
|
end
|
|
if S.WoWVersion() >= 6 then
|
|
eventHandlerFrame:RegisterEvent("REAGENTBANK_PURCHASED")
|
|
end
|
|
eventHandlerFrame:RegisterEvent("PLAYER_GUILD_UPDATE")
|
|
eventHandlerFrame:RegisterEvent("CURRENCY_DISPLAY_UPDATE")
|
|
eventHandlerFrame:RegisterEvent("VOID_STORAGE_CONTENTS_UPDATE")
|
|
eventHandlerFrame:RegisterEvent("VOID_TRANSFER_DONE")
|
|
eventHandlerFrame:RegisterEvent("PLAYER_INTERACTION_MANAGER_FRAME_SHOW")
|
|
eventHandlerFrame:RegisterEvent("PLAYER_INTERACTION_MANAGER_FRAME_HIDE")
|
|
eventHandlerFrame:SetScript("OnEvent", function(self, event, param1, param2, param3)
|
|
if event == "ADDON_LOADED" then
|
|
if param1 == "Sorted" then
|
|
sortedData = Sorted_Data -- Update the local sortedData variable once Sorted_Data gets loaded from SavedVariables
|
|
InitialiseData()
|
|
end
|
|
elseif event == "PLAYER_LOGIN" then
|
|
UpdatePlayerData()
|
|
|
|
-- Clear characters after 1 month of inactivity, or if they have the same name as the current character. The alt is probably deleted
|
|
local toDelete = {}
|
|
for GUID, v in pairs(sortedData) do
|
|
if GUID ~= playerGUID then
|
|
if ((v.lastLogged and time() - v.lastLogged > 2678400) or (v.name == UnitName("player") and v.realm == GetRealmName())) then
|
|
table.insert(toDelete, GUID)
|
|
end
|
|
end
|
|
end
|
|
for k, GUID in pairs(toDelete) do
|
|
S.Data.DeleteCharacter(GUID)
|
|
end
|
|
|
|
-- Calculate total Alliance and Horde money on each realm, excluding the currently logged character since its money can change
|
|
totalMoney = {}
|
|
for GUID, v in pairs(sortedData) do
|
|
if v.realm then
|
|
if not totalMoney[v.realm] then
|
|
totalMoney[v.realm] = {}
|
|
totalMoney[v.realm].alliance = 0
|
|
totalMoney[v.realm].horde = 0
|
|
end
|
|
if GUID ~= playerGUID then
|
|
if v.money then
|
|
if v.faction == "Alliance" then
|
|
totalMoney[v.realm].alliance = totalMoney[v.realm].alliance + v.money
|
|
else
|
|
totalMoney[v.realm].horde = totalMoney[v.realm].horde + v.money
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
elseif event == "PLAYER_ENTERING_WORLD" then
|
|
S.SelectCharacter(UnitGUID("player"))
|
|
S.Settings.ReloadAll()
|
|
S.Data.UpdateGuildInfo()
|
|
UpdateCurrencies()
|
|
UpdateBagContents()
|
|
S.Utils.TriggerEvent("EnteredWorld")
|
|
S.Utils.TriggerEvent("Resized")
|
|
--[[elseif event == "BAG_UPDATE_DELAYED" then
|
|
UpdateBagContents()]]
|
|
elseif event == "BANKFRAME_OPENED" then
|
|
bankOpen = true
|
|
C_Timer.After(0.1, BankFrameOpenedDelayed)
|
|
elseif event == "BANKFRAME_CLOSED" then
|
|
bankOpen = false
|
|
S.Utils.TriggerEvent("BankClosed")
|
|
elseif event == "BANK_TAB_SETTINGS_UPDATED" then
|
|
S.Data.UpdateAccountBankTabs()
|
|
elseif event == "EQUIPMENT_SETS_CHANGED" then
|
|
UpdateEquipmentSets()
|
|
elseif event == "REAGENTBANK_PURCHASED" then
|
|
UpdateBagContents()
|
|
S.Utils.TriggerEvent("ReagentsPurchased")
|
|
elseif event == "CURRENCY_DISPLAY_UPDATE" then
|
|
UpdateCurrencies()
|
|
elseif event == "PLAYER_GUILD_UPDATE" then
|
|
S.Data.UpdateGuildInfo()
|
|
elseif event == "GUILDBANK_UPDATE_TABS" then
|
|
S.Data.UpdateGuildBankTabs()
|
|
elseif event == "VOID_STORAGE_CONTENTS_UPDATE" then
|
|
S.Data.UpdateVoidContents()
|
|
elseif event == "VOID_TRANSFER_DONE" then
|
|
S.Data.UpdateVoidContents()
|
|
elseif event == "PLAYER_INTERACTION_MANAGER_FRAME_SHOW" then
|
|
if param1 == Enum.PlayerInteractionType.VoidStorageBanker then
|
|
C_Timer.After(0.4, S.Data.UpdateVoidContents)
|
|
voidOpen = true
|
|
S.Utils.TriggerEvent("VoidStorageOpened")
|
|
S.OpenBag()
|
|
S.SelectCharacter(UnitGUID("player"))
|
|
elseif param1 == Enum.PlayerInteractionType.GuildBanker then
|
|
guildOpen = true
|
|
S.OpenBag()
|
|
S.SelectCharacter(UnitGUID("player"))
|
|
end
|
|
elseif event == "PLAYER_INTERACTION_MANAGER_FRAME_HIDE" then
|
|
if param1 == Enum.PlayerInteractionType.VoidStorageBanker then
|
|
voidOpen = false
|
|
S.Utils.TriggerEvent("VoidStorageClosed")
|
|
S.CloseBag()
|
|
elseif param1 == Enum.PlayerInteractionType.GuildBanker then
|
|
guildOpen = false
|
|
S.CloseBag()
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- Check for when the GuildBankFrame is loaded and estimate when the items will be available
|
|
local guildBankFrameLoadTime, guildBankLoaded = nil
|
|
eventHandlerFrame:SetScript("OnUpdate", function(self)
|
|
if GuildBankFrame then
|
|
if not guildBankFrameLoadTime then
|
|
guildBankFrameLoadTime = GetTime()
|
|
else
|
|
-- Give it 2 seconds after the GuildBankFrame is loaded
|
|
if GetTime() > guildBankFrameLoadTime + 2 then
|
|
guildBankLoaded = true
|
|
S.Utils.TriggerEvent("GuildBankAvailable")
|
|
eventHandlerFrame:SetScript("OnUpdate", nil)
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
function S.IsGuildBankAvailable()
|
|
return guildBankLoaded
|
|
end
|
|
|
|
function S.IsVoidStorageAvailable()
|
|
return CanUseVoidStorage and CanUseVoidStorage() and VoidStorageFrame
|
|
end
|