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.

465 lines
15 KiB

3 years ago
--[[
State provider for quests
]]
local ADDON_NAME, Internal = ...
local External = _G[ADDON_NAME]
local L = Internal.L
local QuestFrequencyHalfWeekly = 3
local questMapNameToID = {}
local specialEventQuests = {
-- [63854] = "", -- Tormentors
-- Relic Cache
[64316] = "LOOT_READY",
[64317] = "LOOT_READY",
[64318] = "LOOT_READY",
[64564] = "LOOT_READY",
[64565] = "LOOT_READY",
-- Nest of Unusual Materials
[64358] = "LOOT_READY",
[64359] = "LOOT_READY",
[64360] = "LOOT_READY",
[64361] = "LOOT_READY",
[64362] = "LOOT_READY",
-- Invasive Mawshroom
[64351] = "LOOT_READY",
[64354] = "LOOT_READY",
[64355] = "LOOT_READY",
[64356] = "LOOT_READY",
[64357] = "LOOT_READY",
-- Mawsworn Cache
[64021] = "LOOT_READY",
[64363] = "LOOT_READY",
[64364] = "LOOT_READY",
-- Spectral Bound Chest
[64247] = "LOOT_READY",
[64248] = "CRITERIA_UPDATE",
[64249] = "CRITERIA_UPDATE",
[64250] = "CRITERIA_UPDATE",
-- Riftbound Chest
[64470] = "LOOT_READY",
[64471] = "LOOT_READY",
[64472] = "LOOT_READY",
[64456] = "LOOT_READY",
-- Death-Bound Shard
[64347] = "CHAT_MSG_LOOT",
}
local QuestMixin = CreateFromMixins(External.StateMixin)
function QuestMixin:Init(questID)
External.StateMixin.Init(self, questID)
if Internal.data and Internal.data.quests and Internal.data.quests[questID] then
Mixin(self, Internal.data.quests[questID]);
end
if BtWTodoCache.quests[questID] then
Mixin(self, BtWTodoCache.quests[questID]);
end
local questLogIndex = C_QuestLog.GetLogIndexForQuestID(questID); -- may not exist, if it doesn't then you get minimal info
if questLogIndex then
Mixin(self, C_QuestLog.GetInfo(questLogIndex));
-- Remove all dynamic data that could become stale
self.questLogIndex = nil;
self.isOnMap = nil;
self.isCollapsed = nil;
self.hasLocalPOI = nil;
-- Used for data that is only available while the quest is in the log
if self.frequency ~= Enum.QuestFrequency.Default and (not Internal.data.quests[questID] or not Internal.data.quests[questID].authority) then
Internal.data.quests[questID] = {
frequency = self.frequency
}
end
end
self.title = "";
self.isRepeatable = false;
self.isLegendary = false;
self.objectives = nil;
QuestEventListener:AddCallback(questID, function()
self.title = QuestUtils_GetQuestName(questID);
self.isRepeatable = C_QuestLog.IsRepeatableQuest(questID);
self.isLegendary = C_QuestLog.IsLegendaryQuest(questID);
self.objectives = C_QuestLog.GetQuestObjectives(questID);
for _,objective in ipairs(self.objectives) do
objective.numFulfilled = nil
objective.finished = nil
end
end);
end
function QuestMixin:GetDisplayName(supportCallback)
local title = self:GetTitle()
if title == "" and supportCallback then
local callback, result = nil, nil
QuestEventListener:AddCallback(self:GetID(), function()
title = self:GetTitle()
result = string.format(L["Quest: %s"], title ~= "" and title or self:GetID())
if callback then
callback(result)
end
end);
return function (func)
callback = func
if result then
callback(result)
else
callback(string.format(L["Quest: %s"], self:GetID()))
end
end
else
return string.format(L["Quest: %s"], title ~= "" and title or self:GetID())
end
end
function QuestMixin:GetUniqueKey()
return "quest:" .. self:GetID()
end
function QuestMixin:GetTitle()
return self.title
end
function QuestMixin:IsActive()
if self:GetCharacter():IsPlayer() then
return C_QuestLog.GetLogIndexForQuestID(self:GetID()) ~= nil;
else
return self:GetCharacter():GetData("questLog", self:GetID()) ~= nil
end
end
function QuestMixin:IsComplete()
if self:GetCharacter():IsPlayer() then
return C_QuestLog.IsComplete(self:GetID());
else
return self:GetCharacter():GetData("questLog", self:GetID()) == true
end
end
function QuestMixin:IsCompleted()
if self:GetCharacter():IsPlayer() then
return C_QuestLog.IsQuestFlaggedCompleted(self:GetID());
else
return self:GetCharacter():GetData("questCompleted", self:GetID())
end
end
function QuestMixin:IsCampaign()
return self:GetCampaignID() ~= 0;
end
function QuestMixin:GetCampaignID()
if self.campaignID == nil then
self.campaignID = C_CampaignInfo.GetCampaignID(self:GetID());
end
return self.campaignID;
end
function QuestMixin:IsCalling()
if self.isCalling == nil then
self.isCalling = C_QuestLog.IsQuestCalling(self:GetID());
end
return self.isCalling;
end
function QuestMixin:IsRepeatableQuest()
return self.isRepeatable;
end
function QuestMixin:IsLegendary()
return self.isLegendary;
end
function QuestMixin:GetNumObjectives()
return #self.objectives;
end
function QuestMixin:GetObjectives()
return self.objectives;
end
function QuestMixin:GetObjective(index)
return self:GetObjectives()[index];
end
function QuestMixin:GetObjectiveFulfilled(index)
if self:GetCharacter():IsPlayer() then
return (select(4, GetQuestObjectiveInfo(self:GetID(), index, false)))
else
return 0
end
end
function QuestMixin:RegisterEventsFor(driver)
if self:GetCharacter():IsRemote() then
self:GetCharacter():RegisterRemoteEvents(driver, "questLog", "questCompleted")
else
driver:RegisterEvents("PLAYER_ENTERING_WORLD", "QUEST_TURNED_IN", "QUEST_REMOVED", "QUEST_ACCEPTED", "DAILY_RESET", "HALF_WEEKLY_RESET")
if specialEventQuests[self:GetID()] then
driver:RegisterEvents(specialEventQuests[self:GetID()])
end
end
end
local QuestProviderMixin = CreateFromMixins(External.StateProviderMixin)
function QuestProviderMixin:GetID()
return "quest"
end
function QuestProviderMixin:GetName()
return L["Quest"]
end
function QuestProviderMixin:GetAddTitle()
return string.format(BTWTODO_ADD_ITEM, self:GetName()), L["Enter the quest name or id below"]
end
function QuestProviderMixin:Acquire(...)
return CreateAndInitFromMixin(QuestMixin, ...)
end
function QuestProviderMixin:GetFunctions()
return {
{
name = "GetTitle",
returnValue = "string",
description = L["Quest title"]
},
{
name = "IsComplete",
returnValue = "bool",
description = L["Quest is ready to hand in"]
},
{
name = "IsCompleted",
returnValue = "bool",
description = L["Is the quest flagged as completed"]
},
}
end
function QuestProviderMixin:GetDefaults()
return { -- Completed Default
{"IsCompleted"}
}, nil -- Text Default
end
function QuestProviderMixin:ParseInput(value)
local num = tonumber(value)
if num ~= nil then
return true, num
end
if questMapNameToID[value] then
return true, questMapNameToID[value]
end
return false, L["Unknown quest"]
end
function QuestProviderMixin:FillAutoComplete(tbl, text, offset, length)
local text = strsub(text, offset, length):lower()
for value in pairs(questMapNameToID) do
local name = value:lower()
if #name >= #text and strsub(name, offset, length) == text then
tbl[#tbl+1] = value
end
end
table.sort(tbl)
end
Internal.RegisterStateProvider(CreateFromMixins(QuestProviderMixin))
-- Set up quest cache
local questData = {
-- 9.1 Covenant assaults
[63543] = {frequency = QuestFrequencyHalfWeekly, authority = true},
[63822] = {frequency = QuestFrequencyHalfWeekly, authority = true},
[63823] = {frequency = QuestFrequencyHalfWeekly, authority = true},
[63824] = {frequency = QuestFrequencyHalfWeekly, authority = true},
-- World Boss
[64547] = {frequency = Enum.QuestFrequency.Weekly, authority = true},
-- Tormentors of Torghast
[63854] = {frequency = Enum.QuestFrequency.Weekly, authority = true},
-- Korthia Dailies
[64271] = {frequency = Enum.QuestFrequency.Daily},
[63783] = {frequency = Enum.QuestFrequency.Daily},
[63779] = {frequency = Enum.QuestFrequency.Daily},
[63934] = {frequency = Enum.QuestFrequency.Daily},
[63793] = {frequency = Enum.QuestFrequency.Daily},
[63964] = {frequency = Enum.QuestFrequency.Daily},
[63794] = {frequency = Enum.QuestFrequency.Daily},
[63790] = {frequency = Enum.QuestFrequency.Daily},
[63792] = {frequency = Enum.QuestFrequency.Daily},
[63963] = {frequency = Enum.QuestFrequency.Daily},
[63791] = {frequency = Enum.QuestFrequency.Daily},
[64129] = {frequency = Enum.QuestFrequency.Daily},
[63787] = {frequency = Enum.QuestFrequency.Daily},
[63788] = {frequency = Enum.QuestFrequency.Daily},
[63789] = {frequency = Enum.QuestFrequency.Daily},
[63785] = {frequency = Enum.QuestFrequency.Daily},
[63775] = {frequency = Enum.QuestFrequency.Daily},
[63936] = {frequency = Enum.QuestFrequency.Daily},
[64080] = {frequency = Enum.QuestFrequency.Daily},
[64240] = {frequency = Enum.QuestFrequency.Daily},
[63784] = {frequency = Enum.QuestFrequency.Daily},
[64015] = {frequency = Enum.QuestFrequency.Daily},
[64065] = {frequency = Enum.QuestFrequency.Daily},
[63781] = {frequency = Enum.QuestFrequency.Daily},
[63782] = {frequency = Enum.QuestFrequency.Daily},
[63937] = {frequency = Enum.QuestFrequency.Daily},
[63962] = {frequency = Enum.QuestFrequency.Daily},
[63959] = {frequency = Enum.QuestFrequency.Daily},
[63776] = {frequency = Enum.QuestFrequency.Daily},
[63957] = {frequency = Enum.QuestFrequency.Daily},
[63958] = {frequency = Enum.QuestFrequency.Daily},
[63960] = {frequency = Enum.QuestFrequency.Daily},
[64103] = {frequency = Enum.QuestFrequency.Daily},
[64040] = {frequency = Enum.QuestFrequency.Daily},
[64017] = {frequency = Enum.QuestFrequency.Daily},
[64016] = {frequency = Enum.QuestFrequency.Daily},
[63989] = {frequency = Enum.QuestFrequency.Daily},
[63935] = {frequency = Enum.QuestFrequency.Daily},
[64166] = {frequency = Enum.QuestFrequency.Daily},
[63950] = {frequency = Enum.QuestFrequency.Daily},
[63961] = {frequency = Enum.QuestFrequency.Daily},
[63777] = {frequency = Enum.QuestFrequency.Daily},
[63954] = {frequency = Enum.QuestFrequency.Daily},
[63955] = {frequency = Enum.QuestFrequency.Daily},
[63956] = {frequency = Enum.QuestFrequency.Daily},
[63780] = {frequency = Enum.QuestFrequency.Daily},
[64430] = {frequency = Enum.QuestFrequency.Daily},
[64070] = {frequency = Enum.QuestFrequency.Daily},
[64432] = {frequency = Enum.QuestFrequency.Daily},
[63786] = {frequency = Enum.QuestFrequency.Daily},
[64089] = {frequency = Enum.QuestFrequency.Daily},
[64101] = {frequency = Enum.QuestFrequency.Daily},
[64018] = {frequency = Enum.QuestFrequency.Daily},
[64104] = {frequency = Enum.QuestFrequency.Daily},
[64194] = {frequency = Enum.QuestFrequency.Daily},
[63778] = {frequency = Enum.QuestFrequency.Daily},
[64043] = {frequency = Enum.QuestFrequency.Daily},
[63965] = {frequency = Enum.QuestFrequency.Daily},
}
function Internal.IterateQuestData()
return pairs(questData)
end
Internal.RegisterEvent("ADDON_LOADED", function (event, addon)
if addon == ADDON_NAME then
BtWTodoCache.quests = BtWTodoCache.quests or {}
Internal.data.quests = setmetatable({}, {
__index = Mixin(questData, BtWTodoCache.quests),
__newindex = function (self, key, data)
if self[key] == nil or not tCompare(self[key], data, 1) then
questData[key] = data
BtWTodoCache.quests[key] = data
end
end,
})
end
end, -5)
local mawAssaults = {
63543, 63822, 63823, 63824
}
-- Save Quest Data for Player
local function SavedQuests()
local player = Internal.GetPlayer()
local questLog = player:GetDataTable("questLog")
local questCompleted = player:GetDataTable("questCompleted")
wipe(questLog)
wipe(questCompleted)
for questLogIndex = 1, C_QuestLog.GetNumQuestLogEntries() do
local info = C_QuestLog.GetInfo(questLogIndex);
if info and not info.isHeader then
local objectives = C_QuestLog.GetQuestObjectives(info.questID)
local isComplete = C_QuestLog.IsComplete(info.questID)
if isComplete then
questLog[info.questID] = true
else
for _,objective in ipairs(objectives) do
objective.text = nil
objective.type = nil
objective.numRequired = nil
end
questLog[info.questID] = objectives
end
end
end
local quests = C_QuestLog.GetAllCompletedQuestIDs()
for _,questID in ipairs(quests) do
questCompleted[questID] = true
end
-- Record if the first maw assault happened before the half weekly reset
if Internal.IsBeforeHalfWeeklyReset() then
for _,questID in ipairs(mawAssaults) do
if C_QuestLog.IsQuestFlaggedCompleted(questID) then
player.data.firstMawAssaultCompleted = questID
break
end
end
end
end
Internal.RegisterEvent("PLAYER_ENTERING_WORLD", SavedQuests)
Internal.RegisterEvent("QUEST_REMOVED", SavedQuests)
-- Reset our records for daily/weekly quests
Internal.RegisterEvent("DAILY_RESET", function (event, isWeekly)
for _,character in Internal.IterateCharacters() do
-- print("[" .. ADDON_NAME .. "]: Clearing daily quests for " .. character:GetDisplayName())
local data = character:GetDataTable("questCompleted")
for questID,quest in Internal.IterateQuestData() do
if quest.frequency == Enum.QuestFrequency.Daily then
-- print("Clear daily quest " .. questID)
data[questID] = nil
elseif quest.frequency == Enum.QuestFrequency.Weekly and isWeekly then
-- print("Clear weekly quest " .. questID)
data[questID] = nil
end
end
end
end, -1)
Internal.RegisterEvent("HALF_WEEKLY_RESET", function (event, isWeekly)
for _,character in Internal.IterateCharacters() do
-- print("[" .. ADDON_NAME .. "]: Clearing half weekly quests for " .. character:GetDisplayName())
local data = character:GetDataTable("questCompleted")
for questID,quest in Internal.IterateQuestData() do
if quest.frequency == QuestFrequencyHalfWeekly then
-- print("Clear half weekly quest " .. questID)
data[questID] = nil
end
end
end
end, -1)
-- Clear the flag for the first maw assault being complete
Internal.RegisterEvent("WEEKLY_RESET", function (event)
for _,character in Internal.IterateCharacters() do
character.data.firstMawAssaultCompleted = nil
end
end, -1)
-- Store quest data for use with the add quest auto complete/name scan
Internal.RegisterEvent("QUEST_DATA_LOAD_RESULT", function (event, questID, success)
if success then
local title = QuestUtils_GetQuestName(questID);
if title ~= "" then
questMapNameToID[format("%s (%s)", title, questID)] = questID
end
end
end)
Internal.RegisterCustomStateFunction("AddQuestToTooltip", function (state, tooltip)
local name = state:GetTitle()
if name == "" then
name = state:GetUniqueKey()
end
if IsShiftKeyDown() then
name = format("%s [%d]", name, state:GetID())
end
if state:IsCompleted() then
tooltip:AddLine(Internal.Images.COMPLETE .. name, 0, 1, 0)
elseif state:IsComplete() then
tooltip:AddLine(Internal.Images.QUEST_TURN_IN .. name, 1, 1, 0)
elseif state:IsActive() then
tooltip:AddLine(Internal.Images.PADDING .. name, 1, 1, 0)
else
tooltip:AddLine(Internal.Images.QUEST_PICKUP .. name, 1, 1, 1)
end
end)