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.

492 lines
16 KiB

local _, addon = ...
local API = addon.API;
local MainFrame = addon.DialogueUI;
local IsInteractingWithDialogNPC = API.IsInteractingWithDialogNPC;
local CancelClosingGossipInteraction = API.CancelClosingGossipInteraction;
local QuestIsFromAreaTrigger = API.QuestIsFromAreaTrigger;
local GossipDataProvider = addon.GossipDataProvider;
local QuestGetAutoAccept = API.QuestGetAutoAccept;
local ShouldMuteQuestDetail = API.ShouldMuteQuestDetail;
local CloseQuest = CloseQuest;
local InCombatLockdown = InCombatLockdown;
local IsInInstance = IsInInstance;
local GetQuestID = GetQuestID;
local EVENT_PROCESS_DELAY = 0.017; --Affected by CameraMovement
local MAINTAIN_CAMERA_POSITION = false;
local USE_AUTO_QUEST_POPUP = true;
local DISABLE_DUI_IN_INSTANCE = false;
local HANDLE_EVENT_EXTERNALLY = false; --If true, Events will be handled by Skimmers
local EL = CreateFrame("Frame");
local Muter = {};
local function GetCustomGossipHandler()
end
local GossipEvents = {
"GOSSIP_SHOW", "GOSSIP_CLOSED",
"CONFIRM_TALENT_WIPE", --Classic
};
local QuestEvents = {
"QUEST_PROGRESS",
"QUEST_DETAIL",
"QUEST_FINISHED", --Close QuestFrame
"QUEST_GREETING", --Offer several quests
"QUEST_COMPLETE", --Talk to turn in quest
};
local MapEvents = {
PLAYER_ENTERING_WORLD = true,
ZONE_CHANGED_NEW_AREA = true,
};
local CloseDialogEvents = {};
if not addon.IsToCVersionEqualOrNewerThan(50000) then
local ClassicEvents = {
"CONFIRM_TALENT_WIPE", "CONFIRM_TALENT_WIPE",
};
for _, event in ipairs(ClassicEvents) do
table.insert(GossipEvents, event);
CloseDialogEvents[event] = true;
end
end
local function ShouldMuteQuest()
local questID = GetQuestID();
return ShouldMuteQuestDetail(questID)
end
function EL:OnManualEvent(event, ...)
self:SetScript("OnUpdate", nil);
if event == "QUEST_FINISHED" or event == "QUEST_FINISHED_FORCED" then
--For the issue where the quest window fails to close:
--Sometimes QUEST_FINISHED fires but IsInteractingWithNpcOfType still thinks we are interacting with QuestGiver
--/dump C_PlayerInteractionManager.IsInteractingWithNpcOfType(Enum.PlayerInteractionType.QuestGiver)
--print(event, "IS INTERACTING", IsInteractingWithDialogNPC(), GetTimePreciseSec()) --debug
if (event == "QUEST_FINISHED_FORCED") or (not IsInteractingWithDialogNPC()) then
self.timeSinceQuestFinish = nil;
MainFrame:HideUI();
end
elseif event == "GOSSIP_SHOW" then
MainFrame:ShowUI(event);
elseif event == "GOSSIP_CLOSED" then
self:OnGossipClosed(...);
end
end
function EL:OnGossipClosed(interactionIsContinuing)
if self.customFrame then
local f = self.customFrame;
self.customFrame = nil;
if not InCombatLockdown() then
HideUIPanel(f);
end
return
end
if not IsInteractingWithDialogNPC() then
if not MainFrame:IsGossipCloseConsumed() then
--MainFrame:SetInteractionIsContinuing(interactionIsContinuing);
self.timeSinceQuestFinish = nil;
MainFrame:HideUI();
end
GossipDataProvider:OnInteractStopped();
end
end
function EL:NegateLastEvent(event)
if event == self.lastEvent then
self.lastEvent = nil;
end
end
function EL:OnEvent(event, ...)
if HANDLE_EVENT_EXTERNALLY then
return
end
if event == "GOSSIP_SHOW" then
self.lastEvent = event;
local handler = GetCustomGossipHandler(...);
if handler then
self.customFrame = handler(...);
else
if self:ThrottleGossipEvent() then
GossipDataProvider:OnInteractWithNPC();
MainFrame:ShowUI(event); --Depends on the options, we may select the non-gossip one directly without openning the UI
CancelClosingGossipInteraction();
end
end
self:NegateLastEvent(event);
elseif event == "GOSSIP_CLOSED" then
self.lastEvent = event;
self:ProcessEventNextUpdate(0.1);
--self:OnGossipClosed(...);
elseif event == "QUEST_FINISHED" then
--When the quest giver has more than one quest
--sometimes there is a delay between QUEST_FINISHED and GOSSIP_SHOW (presumably depends on various of factors including latency)
--the game determinates interaction then re-engage, messing up ActionCam and gossip info
--our workaround is setting s delay to this event
--print(event, GetTimePreciseSec(), IsInteractingWithDialogNPC());
local delay = MainFrame:GetQuestFinishedDelay();
self.timeSinceQuestFinish = -delay;
if self.lastEvent ~= "QUEST_FINISHED_FORCED" then
self.lastEvent = event;
self:ProcessEventNextUpdate(delay);
end
elseif event == "QUEST_DETAIL" then
--Can fire multiple times in rare occasions, possibly due to cross-character progress
if ShouldMuteQuest() then
if API.IsQuestAutoAccepted() then
API.AcknowledgeAutoAcceptQuest();
end
CloseQuest();
return
end
self.lastEvent = event;
local questStartItemID = ...
if USE_AUTO_QUEST_POPUP and questStartItemID and questStartItemID ~= 0 then
addon.WidgetManager:AddAutoQuestPopUp(questStartItemID);
CloseQuest();
return
end
if USE_AUTO_QUEST_POPUP and QuestIsFromAreaTrigger() and (QuestGetAutoAccept() or InCombatLockdown()) then
--"QuestIsFromAreaTrigger" and "QuestGetAutoAccept" Doesn't work in Classic
--Some quests that triggered upon login aren't "QuestIsFromAreaTrigger"
addon.WidgetManager:AddAutoQuestPopUp();
CloseQuest();
else
MainFrame:ShowUI(event, questStartItemID);
end
elseif event == "QUEST_PROGRESS" or event == "QUEST_COMPLETE" or event == "QUEST_GREETING" then
--Sometimes QUEST_FINISHED fires before QUEST_COMPLETE
self.lastEvent = event;
MainFrame:ShowUI(event);
elseif CloseDialogEvents[event] then
self.lastEvent = event;
self.timeSinceQuestFinish = nil;
MainFrame:HideUI();
elseif MapEvents[event] then
if DISABLE_DUI_IN_INSTANCE then
Muter:UpdateForInstance();
end
end
--print(event, GetTimePreciseSec(), ...); --debug
end
function EL:ListenEvents(state)
local method;
if state then
method = "RegisterEvent";
self:SetScript("OnEvent", self.OnEvent);
else
method= "UnregisterEvent";
if DISABLE_DUI_IN_INSTANCE then
self:SetScript("OnEvent", self.OnEvent);
else
self:SetScript("OnEvent", nil);
end
end
for _, event in ipairs(GossipEvents) do
self[method](self, event);
end
for _, event in ipairs(QuestEvents) do
self[method](self, event);
end
--self[method](self, "PLAYER_INTERACTION_MANAGER_FRAME_SHOW"); --debug
--self[method](self, "PLAYER_INTERACTION_MANAGER_FRAME_HIDE");
end
function EL:OnUpdate(elapsed)
if self.timeSinceQuestFinish then
self.timeSinceQuestFinish = self.timeSinceQuestFinish + elapsed;
if self.timeSinceQuestFinish > EVENT_PROCESS_DELAY then
self.timeSinceQuestFinish = nil;
if self.lastEvent == "QUEST_FINISHED" or self.lastEvent == "QUEST_FINISHED_FORCED" then
if not IsInteractingWithDialogNPC() then
--print("COUNTER STOP", UnitExists("npc"))
self.processEvent = nil;
self.lastEvent = nil;
MainFrame:HideUI();
end
end
end
end
if self.processEvent then
self.t = self.t + elapsed;
if self.t > EVENT_PROCESS_DELAY then
self.t = 0;
self.processEvent = nil;
if self.lastEvent then
--print("LAST EVENT", self.lastEvent)
self:OnManualEvent(self.lastEvent);
self.lastEvent = nil;
end
end
end
if self.pauseGossip then
self.pauseGossip = self.pauseGossip + elapsed;
if self.pauseGossip >= 0 then
self.pauseGossip = nil;
end
end
if not (self.processEvent or self.pauseGossip) then
self:SetScript("OnUpdate", nil);
end
end
function EL:ThrottleGossipEvent()
if not self.pauseGossip then
self.pauseGossip = 0.016;
self:SetScript("OnUpdate", self.OnUpdate);
return true
end
return false
end
function EL:ProcessEventNextUpdate(customDelay)
customDelay = customDelay or 0;
self.t = -customDelay;
self.processEvent = true;
self:SetScript("OnUpdate", self.OnUpdate);
end
do
local DEFAULT_CAMERA_MODE = 1;
local function OnCameraModeChanged(_, mode)
if mode == 0 then --0: No Zoom
EVENT_PROCESS_DELAY = 0.017;
elseif mode == 1 then --1: Zoom to NPC
if MAINTAIN_CAMERA_POSITION then
EVENT_PROCESS_DELAY = 0.5;
else
EVENT_PROCESS_DELAY = 0.017;
end
elseif mode == 2 then --2: Shift camear horizontally
EVENT_PROCESS_DELAY = 0.5;
end
DEFAULT_CAMERA_MODE = mode;
end
addon.CallbackRegistry:Register("Camera.ModeChanged", OnCameraModeChanged, EL);
local function Settings_CameraMovement1MaintainPosition(dbValue)
MAINTAIN_CAMERA_POSITION = dbValue == true;
if DEFAULT_CAMERA_MODE then
OnCameraModeChanged(nil, DEFAULT_CAMERA_MODE);
end
end
addon.CallbackRegistry:Register("SettingChanged.CameraMovement1MaintainPosition", Settings_CameraMovement1MaintainPosition);
local function ManualTriggerQuestFinished(isAutoComplete)
--print("TRIGGER FINISH", GetTimePreciseSec()) --debug
if EL.lastEvent ~= "QUEST_FINISHED_FORCED" then
EL.lastEvent = "QUEST_FINISHED_FORCED";
EL:ProcessEventNextUpdate(1.5); --Force trigger QUEST_FINISHED event to close the UI. We use extended delay (1s) due to unavailable server latency
end
end
addon.CallbackRegistry:Register("TriggerQuestFinished", ManualTriggerQuestFinished);
local function Settings_AutoQuestPopup(dbValue)
USE_AUTO_QUEST_POPUP = dbValue ~= false;
end
addon.CallbackRegistry:Register("SettingChanged.AutoQuestPopup", Settings_AutoQuestPopup);
end
do --Unlisten events from default UI
--CustomGossipFrameManager:
--We need to mute this so HideUI doesn't trigger CloseGossip
--It handle NPE (Be A Guide) and Torghast Floor Selection
Muter.questEvents = {
QUEST_GREETING = true,
QUEST_DETAIL = true,
QUEST_PROGRESS = true,
QUEST_COMPLETE = true,
QUEST_FINISHED = true,
QUEST_ITEM_UPDATE = true,
QUEST_LOG_UPDATE = true,
UNIT_PORTRAIT_UPDATE = true,
PORTRAITS_UPDATED = true,
};
if addon.IsToCVersionEqualOrNewerThan(50000) then
Muter.questEvents.LEARNED_SPELL_IN_SKILL_LINE = true;
else
Muter.questEvents.LEARNED_SPELL_IN_TAB = true; --Classic
end
local function SetUseDialogueUI(state)
if state == nil then state = true end;
if state then
if Muter.muted then return end;
Muter.muted = true;
EL:ListenEvents(true);
if CustomGossipFrameManager then --CustomGossipFrameBase.lua (Retail)
CustomGossipFrameManager:UnregisterEvent("GOSSIP_SHOW");
CustomGossipFrameManager:UnregisterEvent("GOSSIP_CLOSED");
end
if GossipFrame then --Classic
GossipFrame:UnregisterEvent("GOSSIP_SHOW");
GossipFrame:UnregisterEvent("GOSSIP_CLOSED");
GossipFrame:UnregisterEvent("QUEST_LOG_UPDATE");
end
local hideQuestFrame = true; --false when we do debug
if hideQuestFrame then
QuestFrame:UnregisterAllEvents();
else
QuestFrame:SetParent(nil);
QuestFrame:SetScale(2/3);
end
elseif Muter.muted then
Muter.muted = false;
EL:ListenEvents(false);
if CustomGossipFrameManager then --CustomGossipFrameBase.lua (Retail)
CustomGossipFrameManager:RegisterEvent("GOSSIP_SHOW");
CustomGossipFrameManager:RegisterEvent("GOSSIP_CLOSED");
end
if GossipFrame then --Classic
GossipFrame:RegisterEvent("GOSSIP_SHOW");
GossipFrame:RegisterEvent("GOSSIP_CLOSED");
GossipFrame:RegisterEvent("QUEST_LOG_UPDATE");
end
local hideQuestFrame = true; --false when we do debug
if hideQuestFrame then
local qf = QuestFrame;
for event, valid in pairs(Muter.questEvents) do
if valid then
qf:RegisterEvent(event);
end
end
else
QuestFrame:SetParent(UIParent);
QuestFrame:SetScale(1);
end
end
addon.EnableBookUI(state);
end
addon.SetUseDialogueUI = SetUseDialogueUI;
SetUseDialogueUI(true);
function Muter:UpdateForInstance()
if IsInInstance() then
SetUseDialogueUI(false);
else
SetUseDialogueUI(true);
end
end
local function Settings_DisableDUIInInstance(dbValue, userInput)
DISABLE_DUI_IN_INSTANCE = dbValue == true;
if DISABLE_DUI_IN_INSTANCE then
for event in pairs(MapEvents) do
EL:RegisterEvent(event);
end
Muter:UpdateForInstance();
if userInput and IsInInstance() and MainFrame:IsShown() then
MainFrame:Hide();
end
else
for event in pairs(MapEvents) do
EL:UnregisterEvent(event);
end
SetUseDialogueUI(true);
end
end
addon.CallbackRegistry:Register("SettingChanged.DisableDUIInInstance", Settings_DisableDUIInInstance);
end
do --See Blizzard_UIPanels_Game/CustomGossipFrameBase.lua
local function HandleNPEGuideGossipShow(textureKit)
C_AddOns.LoadAddOn("Blizzard_NewPlayerExperienceGuide");
ShowUIPanel(GuideFrame);
return GuideFrame
end
local function HandleTorghastLevelPickerGossipShow(textureKit)
C_AddOns.LoadAddOn("Blizzard_TorghastLevelPicker");
TorghastLevelPickerFrame:TryShow(textureKit)
return TorghastLevelPickerFrame
end
local function HandleDelvesDifficultyPickerGossipShow(textureKit) --TWW
C_AddOns.LoadAddOn("Blizzard_DelvesDifficultyPicker");
DelvesDifficultyPickerFrame:TryShow(textureKit);
return DelvesDifficultyPickerFrame
end
local Handlers = {};
function EL:RegisterHandler(textureKit, func)
Handlers[textureKit] = func;
end
function EL:RegisterCustomGossipFrames()
self:RegisterHandler("npe-guide", HandleNPEGuideGossipShow);
self:RegisterHandler("skoldushall", HandleTorghastLevelPickerGossipShow);
self:RegisterHandler("mortregar", HandleTorghastLevelPickerGossipShow);
self:RegisterHandler("coldheartinterstitia", HandleTorghastLevelPickerGossipShow);
self:RegisterHandler("fracturechambers", HandleTorghastLevelPickerGossipShow);
self:RegisterHandler("soulforges", HandleTorghastLevelPickerGossipShow);
self:RegisterHandler("theupperreaches", HandleTorghastLevelPickerGossipShow);
self:RegisterHandler("twistingcorridors", HandleTorghastLevelPickerGossipShow);
self:RegisterHandler("delves-difficulty-picker", HandleDelvesDifficultyPickerGossipShow); --For some reason this textureKit is sometimes nil, causing issue
end
EL:RegisterCustomGossipFrames();
function GetCustomGossipHandler(textureKit)
return textureKit and Handlers[textureKit]
end
addon.GetCustomGossipHandler = GetCustomGossipHandler;
end
do --DEBUG Skimmer
local function SetHandleEventExternally(state)
HANDLE_EVENT_EXTERNALLY = state == true;
end
addon.SetHandleEventExternally = SetHandleEventExternally;
end