enUS Localization Update Announcement / localization-update-announcement (push) Canceled after 0s
141 lines
6.4 KiB
Lua
141 lines
6.4 KiB
Lua
-- Bagshui Active Quest Item Manager
|
|
-- Exposes: Bagshui.components.ActiveQuestItemManager
|
|
-- Raises: BAGSHUI_ACTIVE_QUEST_ITEM_UPDATE
|
|
--
|
|
-- Contains code based on QuestItem: https://github.com/wow-vanilla-addons/QuestItem/blob/master/QuestItem/QuestItem.lua
|
|
--
|
|
-- Keeps Bagshui.activeQuestItems updated with the NAMES of items which are objectives of current quests.
|
|
-- (We can't get item IDs due to Vanilla limitations).
|
|
--
|
|
-- Raises BAGSHUI_ACTIVE_QUEST_ITEM_UPDATE when changes to Bagshui.activeQuestItems occur.
|
|
--
|
|
-- This works by receiving QUEST_LOG_UPDATE events, which tend to come in fast and furious. To avoid constantly
|
|
-- rebuilding the list of active quest items, we're using an event queue:
|
|
-- 1. QUEST_LOG_UPDATE event comes in and BAGSHUI_QUEST_LOG_UPDATE event is queued to fire 1 second later.
|
|
-- If another QUEST_LOG_UPDATE event arrives before that 1 second is up, the timer is reset.
|
|
-- 2. BAGSHUI_QUEST_LOG_UPDATE event fires and triggers the actual parsing of the quest log.
|
|
-- After that is complete, BAGSHUI_ACTIVE_QUEST_ITEM_UPDATE event is fired immediately.
|
|
-- 3. Other components that have registered to received BAGSHUI_ACTIVE_QUEST_ITEM_UPDATE are now notified
|
|
-- and can trigger recategorization and resorting.
|
|
|
|
Bagshui:AddComponent(function()
|
|
-- Key in _G.BagshuiData where active quest items will be stored.
|
|
local ACTIVE_QUEST_ITEMS_DATA_STORAGE_KEY = "activeQuestItems"
|
|
|
|
-- Initialization (happens when this component is loaded during `ADDON_LOADED`)
|
|
if not Bagshui.currentCharacterData[ACTIVE_QUEST_ITEMS_DATA_STORAGE_KEY] then
|
|
Bagshui.currentCharacterData[ACTIVE_QUEST_ITEMS_DATA_STORAGE_KEY] = {}
|
|
end
|
|
|
|
local ActiveQuestItemManager = {
|
|
|
|
-- List of active quest items by item name.
|
|
--
|
|
-- Items must be stored in SavedVariables to to prevent inventory items from
|
|
-- jumping around during UI reload, because there is a delay before the quest
|
|
-- log can be read. The list is when QUEST_LOG_UPDATE fires for the first time.
|
|
-- ```
|
|
-- {
|
|
-- ["Item Name"] = {
|
|
-- questName = "Quest Name",
|
|
-- needed = #,
|
|
-- obtained = #,
|
|
-- }
|
|
-- }
|
|
--
|
|
-- ```
|
|
---@type table<string, { questName: string, needed: number, obtained: number }>
|
|
items = Bagshui.currentCharacterData[ACTIVE_QUEST_ITEMS_DATA_STORAGE_KEY],
|
|
}
|
|
|
|
--- Event handling.
|
|
---@param event string Event name.
|
|
---@param arg1 any Event argument.
|
|
function ActiveQuestItemManager:OnEvent(event, arg1)
|
|
-- WoW says "Something has happened with the quest log!" (it says this a lot).
|
|
-- Queue an event so that we only do our update after all the events have finished firing
|
|
-- This will be the most common event received, by far, so it goes first.
|
|
if event == "QUEST_LOG_UPDATE" then
|
|
Bagshui:QueueEvent("BAGSHUI_QUEST_LOG_UPDATE", 1)
|
|
return
|
|
end
|
|
|
|
-- Enough time has elapsed since the last QUEST_LOG_UPDATE event to actually do our update.
|
|
if event == "BAGSHUI_QUEST_LOG_UPDATE" then
|
|
self:Update()
|
|
Bagshui:RaiseEvent("BAGSHUI_ACTIVE_QUEST_ITEM_UPDATE")
|
|
return
|
|
end
|
|
end
|
|
|
|
--- Parse the quest log to find the names of items that are quest objectives.
|
|
function ActiveQuestItemManager:Update()
|
|
-- The quest log is one of those annoying things where you can't directly ask
|
|
-- about a quest; you have the tell the client to *select* the quest, and then
|
|
-- all the quest info functions work on that. This becomes a problem if the
|
|
-- Quest Log is open and we want to update, since we need to loop through
|
|
-- all quests, we're going to have to change the selected quest. What ends up
|
|
-- happening is that once we're done, the very last quest in the log remains
|
|
-- selected and is out of sync with the Quest Log UI. This matters when someone
|
|
-- abandons multiple quests in a row, because the first abandonment will be
|
|
-- accurate, but then the next Abandon Quest click will target the last quest
|
|
-- in the list instead of the one that looks like it's selected.
|
|
-- All that to say -- we need to store the currently selected quest number
|
|
-- before we start so it can be restored once we're done.
|
|
local previouslySelectedQuestNum = _G.GetQuestLogSelection()
|
|
|
|
-- In theory we could keep a list of the items we've actually seen and remove the ones
|
|
-- we don't see, but erasing it is easier. (Can always change if it's not performant enough).
|
|
BsUtil.TableClear(self.items)
|
|
|
|
local questName, isHeader, objectiveText, itemType, itemName, numNeeded, numObtained
|
|
|
|
for questNum = 1, _G.GetNumQuestLogEntries(), 1 do
|
|
-- Only need a couple pieces of information from GetQuestLogTitle.
|
|
questName, _, _, isHeader, _, _ = _G.GetQuestLogTitle(questNum)
|
|
|
|
if not isHeader then
|
|
itemName = nil
|
|
numNeeded = 1
|
|
numObtained = 0
|
|
|
|
-- All subsequent function calls depend on selecting the quest log entry.
|
|
_G.SelectQuestLogEntry(questNum)
|
|
|
|
-- If description and quest objective text is ever needed, here's how to get it:
|
|
-- local questionDescription, questObjectiveText = _G.GetQuestLogQuestText()
|
|
|
|
-- Quest objectives are in the "Leader Boards".
|
|
for i = 1, _G.GetNumQuestLeaderBoards() do
|
|
objectiveText, itemType = _G.GetQuestLogLeaderBoard(i)
|
|
|
|
-- We only care if type is item/object (not monster, event, etc.).
|
|
if itemType ~= nil and (itemType == "item" or itemType == "object") then
|
|
-- Parse and store the item information from the objective text, which is formatted as:
|
|
-- `<Item Name>: <Number Obtained>/<Total Needed>`
|
|
_, _, itemName, numObtained, numNeeded = string.find(objectiveText, "(.+): (%d+)/(%d+)")
|
|
if itemName then
|
|
self.items[itemName] = {
|
|
questName = questName,
|
|
needed = numNeeded,
|
|
obtained = numObtained,
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Restore Quest Log selection, if any (see the dissertation at the beginning of this function).
|
|
if previouslySelectedQuestNum then
|
|
_G.SelectQuestLogEntry(previouslySelectedQuestNum)
|
|
end
|
|
end
|
|
|
|
-- Exports and registration.
|
|
Bagshui.components.ActiveQuestItemManager = ActiveQuestItemManager
|
|
Bagshui.activeQuestItems = ActiveQuestItemManager.items
|
|
Bagshui:RegisterEvent("QUEST_LOG_UPDATE", ActiveQuestItemManager) -- Quest log changes.
|
|
Bagshui:RegisterEvent("BAGSHUI_QUEST_LOG_UPDATE", ActiveQuestItemManager) -- Our custom trigger to parse the quest log.
|
|
end)
|