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