|
|
|
|
local _, addon = ...
|
|
|
|
|
|
|
|
|
|
local paused
|
|
|
|
|
|
|
|
|
|
local ignoredQuests = {}
|
|
|
|
|
local cashRewards = {
|
|
|
|
|
[45724] = 1e5, -- Champion's Purse, 10 gold
|
|
|
|
|
[64491] = 2e6, -- Royal Reward, 200 gold
|
|
|
|
|
|
|
|
|
|
-- items from the Sixtrigger brothers quest chain in Stormheim
|
|
|
|
|
[138127] = 15, -- Mysterious Coin, 15 copper
|
|
|
|
|
[138129] = 11, -- Swatch of Priceless Silk, 11 copper
|
|
|
|
|
[138131] = 24, -- Magical Sprouting Beans, 24 copper
|
|
|
|
|
[138123] = 15, -- Shiny Gold Nugget, 15 copper
|
|
|
|
|
[138125] = 16, -- Crystal Clear Gemstone, 16 copper
|
|
|
|
|
[138133] = 27, -- Elixir of Endless Wonder, 27 copper
|
|
|
|
|
}
|
|
|
|
|
local darkmoonFaireOptions = {
|
|
|
|
|
[40563] = true, -- whack
|
|
|
|
|
[28701] = true, -- cannon
|
|
|
|
|
[31202] = true, -- shoot
|
|
|
|
|
[39245] = true, -- tonk
|
|
|
|
|
[40224] = true, -- ring toss
|
|
|
|
|
[43060] = true, -- firebird
|
|
|
|
|
[52651] = true, -- dance
|
|
|
|
|
[41759] = true, -- pet battle 1
|
|
|
|
|
[42668] = true, -- pet battle 2
|
|
|
|
|
[40872] = true, -- cannon return (Teleportologist Fozlebub)
|
|
|
|
|
[40007] = true, -- Darkmoon Faire Mystic Mage (Horde)
|
|
|
|
|
[40457] = true, -- Darkmoon Faire Mystic Mage (Alliance)
|
|
|
|
|
}
|
|
|
|
|
local skipGossip = {
|
|
|
|
|
[109275] = true, -- Soridormi - begin time rift
|
|
|
|
|
[120619] = true, -- Big Dig task
|
|
|
|
|
[120620] = true, -- Big Dig task
|
|
|
|
|
}
|
|
|
|
|
local ignoreGossip = {
|
|
|
|
|
[122442] = true, -- leave the dungeon in remix
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
local function isQuestIgnored(questID)
|
|
|
|
|
if ignoredQuests[questID] then
|
|
|
|
|
return true
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local questTitle = tonumber(questID) and C_QuestLog.GetTitleForQuestID(questID) or ''
|
|
|
|
|
for key, value in next, addon.db.profile.blocklist.quests do
|
|
|
|
|
if key == questID or questTitle:lower():find(tostring(key):lower()) then
|
|
|
|
|
return value
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function isTrackingTrivialQuests()
|
|
|
|
|
for index = 1, C_Minimap.GetNumTrackingTypes() do
|
|
|
|
|
local name, _, isActive = C_Minimap.GetTrackingInfo(index)
|
|
|
|
|
if name == MINIMAP_TRACKING_TRIVIAL_QUESTS then
|
|
|
|
|
return isActive
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:GOSSIP_SHOW()
|
|
|
|
|
-- triggered when the player interacts with an NPC that presents dialogue
|
|
|
|
|
if paused then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if C_PlayerInteractionManager.IsInteractingWithNpcOfType(Enum.PlayerInteractionType.TaxiNode) then
|
|
|
|
|
-- don't annoy taxi addons
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local npcID = addon:GetNPCID('npc')
|
|
|
|
|
if addon.db.profile.blocklist.npcs[npcID] then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- we want to auto-accept the dialogues from Darkmoon Faire NPCs
|
|
|
|
|
for _, info in next, C_GossipInfo.GetOptions() do
|
|
|
|
|
if darkmoonFaireOptions[info.gossipOptionID] and addon.db.profile.general.paydarkmoonfaire then
|
|
|
|
|
C_GossipInfo.SelectOption(info.gossipOptionID, '', true)
|
|
|
|
|
return
|
|
|
|
|
elseif skipGossip[info.gossipOptionID] then
|
|
|
|
|
C_GossipInfo.SelectOption(info.gossipOptionID)
|
|
|
|
|
elseif FlagsUtil.IsSet(info.flags, Enum.GossipOptionRecFlags.QuestLabelPrepend) and addon.db.profile.general.autoquestgossip then
|
|
|
|
|
C_GossipInfo.SelectOption(info.gossipOptionID)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if C_GossipInfo.GetNumActiveQuests() > 0 or C_GossipInfo.GetNumAvailableQuests() > 0 then
|
|
|
|
|
-- bail if there is more than just dialogue
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local gossipOptions = C_GossipInfo.GetOptions()
|
|
|
|
|
if #gossipOptions == 1 and addon.db.profile.general.skipgossip and gossipOptions[1].gossipOptionID and not ignoreGossip[gossipOptions[1].gossipOptionID] then
|
|
|
|
|
-- automatically skip single dialogue under certain conditions
|
|
|
|
|
local _, instanceType = GetInstanceInfo()
|
|
|
|
|
if instanceType == 'raid' and addon.db.profile.general.skipgossipwhen > 0 then
|
|
|
|
|
if GetNumGroupMembers() <= 1 or addon.db.profile.general.skipgossipwhen == 2 then
|
|
|
|
|
-- select dialogue if alone or when configured to "Always" while in a raid
|
|
|
|
|
C_GossipInfo.SelectOption(gossipOptions[1].gossipOptionID)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
elseif instanceType ~= 'raid' then
|
|
|
|
|
-- always select single dialogue while outside a raid
|
|
|
|
|
C_GossipInfo.SelectOption(gossipOptions[1].gossipOptionID)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:GOSSIP_SHOW()
|
|
|
|
|
-- triggered when the player interacts with an NPC that presents dialogue
|
|
|
|
|
if paused then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if addon.db.profile.blocklist.npcs[addon:GetNPCID('npc')] then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- turn in all completed quests
|
|
|
|
|
if addon.db.profile.general.complete then
|
|
|
|
|
for _, info in next, C_GossipInfo.GetActiveQuests() do
|
|
|
|
|
if not isQuestIgnored(info.questID) then
|
|
|
|
|
if info.isComplete and not C_QuestLog.IsWorldQuest(info.questID) then
|
|
|
|
|
C_GossipInfo.SelectActiveQuest(info.questID)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- accept all available quests
|
|
|
|
|
if addon.db.profile.general.accept then
|
|
|
|
|
for _, info in next, C_GossipInfo.GetAvailableQuests() do
|
|
|
|
|
if not isQuestIgnored(info.questID) then
|
|
|
|
|
if (not info.isTrivial or isTrackingTrivialQuests()) and (not info.repeatable or addon.db.profile.general.acceptRepeatables) then
|
|
|
|
|
C_GossipInfo.SelectAvailableQuest(info.questID)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:QUEST_GREETING()
|
|
|
|
|
-- triggered when the player interacts with an NPC that hands in/out quests
|
|
|
|
|
if paused then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if addon.db.profile.blocklist.npcs[addon:GetNPCID('npc')] then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- turn in all completed quests
|
|
|
|
|
if addon.db.profile.general.complete then
|
|
|
|
|
for index = 1, GetNumActiveQuests() do
|
|
|
|
|
if not isQuestIgnored(GetActiveQuestID(index)) then
|
|
|
|
|
local _, isComplete = GetActiveTitle(index)
|
|
|
|
|
if isComplete and not C_QuestLog.IsWorldQuest(GetActiveQuestID(index)) then
|
|
|
|
|
SelectActiveQuest(index)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- accept all available quests
|
|
|
|
|
if addon.db.profile.general.accept then
|
|
|
|
|
for index = 1, GetNumAvailableQuests() do
|
|
|
|
|
local isTrivial, _, isRepeatable, _, questID = GetAvailableQuestInfo(index)
|
|
|
|
|
if not isQuestIgnored(questID) then
|
|
|
|
|
if (not isTrivial or isTrackingTrivialQuests()) and (not isRepeatable or addon.db.profile.general.acceptRepeatables) then
|
|
|
|
|
SelectAvailableQuest(index)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:QUEST_DETAIL()
|
|
|
|
|
-- triggered when the information about an available quest is available
|
|
|
|
|
if paused then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if addon.db.profile.general.accept then
|
|
|
|
|
if QuestIsFromAreaTrigger() then
|
|
|
|
|
-- this type of quest is automatically accepted, but the dialogue is presented in a way that
|
|
|
|
|
-- the player seems to have a choice to decline it, which they don't, so just accept it
|
|
|
|
|
AcceptQuest()
|
|
|
|
|
elseif QuestGetAutoAccept() then
|
|
|
|
|
-- this type of quest is automatically accepted, but the dialogue persists
|
|
|
|
|
AcknowledgeAutoAcceptQuest()
|
|
|
|
|
elseif not C_QuestLog.IsQuestTrivial(GetQuestID()) or isTrackingTrivialQuests() then
|
|
|
|
|
if isQuestIgnored(GetQuestID()) then
|
|
|
|
|
CloseQuest()
|
|
|
|
|
else
|
|
|
|
|
AcceptQuest()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local itemCacheQueue = {}
|
|
|
|
|
function addon:QUEST_ITEM_UPDATE()
|
|
|
|
|
local i, event = next(itemCacheQueue)
|
|
|
|
|
if i then
|
|
|
|
|
table.remove(itemCacheQueue, i)
|
|
|
|
|
addon[event]()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:QUEST_PROGRESS()
|
|
|
|
|
-- triggered when an active quest is selected during turn-in
|
|
|
|
|
if paused then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if addon.db.profile.blocklist.npcs[addon:GetNPCID('npc')] then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if not IsQuestCompletable() then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- iterate through the items part of the quest
|
|
|
|
|
for index = 1, GetNumQuestItems() do
|
|
|
|
|
local itemLink = GetQuestItemLink('required', index)
|
|
|
|
|
if itemLink then
|
|
|
|
|
-- check to see if the item is blocked
|
|
|
|
|
local questItemID = GetItemInfoFromHyperlink(itemLink)
|
|
|
|
|
if addon.db.profile.blocklist.items[questItemID] then
|
|
|
|
|
-- item is blocked, prevent this quest from opening again and close it
|
|
|
|
|
ignoredQuests[GetQuestID()] = true
|
|
|
|
|
CloseQuest()
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
-- item is not cached yet, trigger the item and wait for the cache to populate
|
|
|
|
|
table.insert(itemCacheQueue, 'QUEST_PROGRESS')
|
|
|
|
|
GetQuestItemInfo('required', index)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if addon.db.profile.general.complete then
|
|
|
|
|
CompleteQuest()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:QUEST_COMPLETE()
|
|
|
|
|
-- triggered when an active quest is ready to be completed
|
|
|
|
|
if paused then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if addon.db.profile.general.complete then
|
|
|
|
|
if GetNumQuestChoices() <= 1 then
|
|
|
|
|
-- complete the quest by accepting the first item
|
|
|
|
|
GetQuestReward(1)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:QUEST_COMPLETE()
|
|
|
|
|
if not addon.db.profile.general.selectreward then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- triggered when an active quest is ready to be completed
|
|
|
|
|
local numItemRewards = GetNumQuestChoices()
|
|
|
|
|
if numItemRewards <= 1 then
|
|
|
|
|
-- no point iterating over a single item or none at all
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local highestItemValue, highestItemValueIndex = 0
|
|
|
|
|
|
|
|
|
|
-- iterate through the item rewards and automatically select the one worth the most
|
|
|
|
|
for index = 1, numItemRewards do
|
|
|
|
|
local itemLink = GetQuestItemLink('choice', index)
|
|
|
|
|
if itemLink then
|
|
|
|
|
-- check the value on the item and compare it to the others
|
|
|
|
|
local _, _, _, _, _, _, _, _, _, _, itemValue = C_Item.GetItemInfo(itemLink)
|
|
|
|
|
local itemID = GetItemInfoFromHyperlink(itemLink)
|
|
|
|
|
|
|
|
|
|
-- some items are containers that contains currencies of worth
|
|
|
|
|
itemValue = cashRewards[itemID] or itemValue
|
|
|
|
|
|
|
|
|
|
-- compare the values
|
|
|
|
|
if itemValue > highestItemValue then
|
|
|
|
|
highestItemValue = itemValue
|
|
|
|
|
highestItemValueIndex = index
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
-- item is not cached yet, trigger the item and wait for the cache to populate
|
|
|
|
|
table.insert(itemCacheQueue, 'QUEST_COMPLETE')
|
|
|
|
|
GetQuestItemInfo('choice', index)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if highestItemValueIndex then
|
|
|
|
|
-- this is considered an intrusive action, as we're modifying the UI
|
|
|
|
|
QuestInfoItem_OnClick(QuestInfoRewardsFrame.RewardButtons[highestItemValueIndex])
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:QUEST_LOG_UPDATE()
|
|
|
|
|
-- triggered when the player's quest log has been altered
|
|
|
|
|
if paused or WorldMapFrame:IsShown() then -- see #45
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- check for quest popups whenever the quest log is updated, which also happens on login, and
|
|
|
|
|
-- when the player loots an item that starts a quest
|
|
|
|
|
if GetNumAutoQuestPopUps() > 0 then
|
|
|
|
|
if UnitIsDeadOrGhost('player') then
|
|
|
|
|
-- can't accept quests while we're dead
|
|
|
|
|
addon:Defer(addon, 'QUEST_LOG_UPDATE', addon)
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- this is considered an intrusive action, as we're modifying the UI
|
|
|
|
|
local questID, questType = GetAutoQuestPopUp(1)
|
|
|
|
|
if questType == 'OFFER' then
|
|
|
|
|
if addon.db.profile.general.accept then
|
|
|
|
|
ShowQuestOffer(questID)
|
|
|
|
|
end
|
|
|
|
|
elseif questType == 'COMPLETE' then
|
|
|
|
|
if addon.db.profile.general.complete then
|
|
|
|
|
ShowQuestComplete(questID)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- remove the popup once accepted/completed, the game logic doesn't handle this
|
|
|
|
|
RemoveAutoQuestPopUp(questID)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:QUEST_ACCEPT_CONFIRM()
|
|
|
|
|
-- triggered when a quest is shared in the party, but requires confirmation (like escorts)
|
|
|
|
|
if paused then
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if addon.db.profile.general.accept then
|
|
|
|
|
AcceptQuest()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:QUEST_ACCEPTED(questID)
|
|
|
|
|
-- triggered when a quest has been accepted by the player
|
|
|
|
|
if addon.db.profile.general.share then
|
|
|
|
|
local questLogIndex = C_QuestLog.GetLogIndexForQuestID(questID)
|
|
|
|
|
if questLogIndex then
|
|
|
|
|
QuestLogPushQuest(questLogIndex)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:MODIFIER_STATE_CHANGED(key, state)
|
|
|
|
|
-- triggered when the player clicks any modifier keys on the keyboard
|
|
|
|
|
if string.sub(key, 2) == addon.db.profile.general.pausekey then
|
|
|
|
|
-- change the paused state
|
|
|
|
|
if addon.db.profile.general.pausekeyreverse then
|
|
|
|
|
paused = state ~= 1
|
|
|
|
|
else
|
|
|
|
|
paused = state == 1
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function addon:PLAYER_LOGIN()
|
|
|
|
|
-- triggered when the game has completed the login process
|
|
|
|
|
if addon.db.profile.general.pausekeyreverse then
|
|
|
|
|
-- default to a paused state
|
|
|
|
|
paused = true
|
|
|
|
|
end
|
|
|
|
|
end
|