local _ , addon = ...
local L = addon.L ;
local API = addon.API ;
local CallbackRegistry = addon.CallbackRegistry ;
local CameraUtil = addon.CameraUtil ;
local ThemeUtil = addon.ThemeUtil ;
local TooltipFrame = addon.SharedTooltip ;
local KeyboardControl = addon.KeyboardControl ;
local NameplateGossip = addon.NameplateGossip ;
local AlertFrame = addon.AlertFrame ; --top right of the screen
local ExperienceBar = addon.CreateStatusBar ( nil , " xp " ) ;
local ChatFrame = addon.ChatFrame ;
local FriendshipBar = addon.FriendshipBar ;
local PlaySound = addon.PlaySound ;
local IsAutoSelectOption = addon.IsAutoSelectOption ;
local GetDBBool = addon.GetDBBool ;
local IS_MODERN_WOW = not addon.IS_CLASSIC ;
local FadeFrame = API.UIFrameFade ;
local CloseGossipInteraction = API.CloseGossipInteraction ;
local IsPlayingCutscene = API.IsPlayingCutscene ;
-- User Settings
local FRAME_SIZE_MULTIPLIER = 1.1 ; --Default: 1.1
local SCROLLDOWN_THEN_ACCEPT_QUEST = false ;
local AUTO_SELECT_GOSSIP = false ;
local INPUT_DEVICE_GAME_PAD = false ;
--local ALWAYS_GOSSIP = false;
--local SHOW_NPC_NAME = false;
--local MARK_HIGHEST_SELL_PRICE = false;
------------------
local PADDING_H = 26.0 ;
local PADDING_TOP = 48.0 ;
local PADDING_BOTTOM = 36.0 ;
local BUTTON_HORIZONTAL_GAP = 8.0 ;
local FRAME_OFFSET_RATIO = 3 / 4 ; --Center align to 1/4 of the WorldFrame width (to the right)
local FONT_SIZE = 12 ;
local TEXT_SPACING = FONT_SIZE * 0.35 ; --Font Size /3
local PARAGRAPH_SPACING = 4 * TEXT_SPACING ; --4 * TEXT_SPACING
local PARAGRAPH_BUTTON_SPACING = 2 * FONT_SIZE ; --Font Size * 2
local CONTENT_BLEEDING = 16.0 ; --ContentFrame is sometimes ClipChildren and there may be an overlay frame that got clipped.
local CreateFrame = CreateFrame ;
local C_CampaignInfo = C_CampaignInfo ;
local C_GossipInfo = C_GossipInfo ;
local GetGossipText = API.GetGossipText ;
local CloseQuest = CloseQuest ;
local GetOptions = C_GossipInfo.GetOptions ;
local GetAvailableQuests = C_GossipInfo.GetAvailableQuests ;
local GetActiveQuests = C_GossipInfo.GetActiveQuests ;
local ForceGossip = C_GossipInfo.ForceGossip ;
local QuestIsFromAreaTrigger = API.QuestIsFromAreaTrigger ;
local GetQuestText = API.GetQuestText ; --usage GetQuestText("type") type: Detail, Progress, Complete, Greeting
local GetQuestTitle = GetTitleText ;
local GetObjectiveText = GetObjectiveText ;
local GetNumQuestItems = GetNumQuestItems ;
local GetNumQuestCurrencies = GetNumQuestCurrencies ;
local GetQuestID = GetQuestID ;
local IsQuestCompletable = IsQuestCompletable ;
local IsQuestItemHidden = IsQuestItemHidden ;
local GetQuestMoneyToGet = GetQuestMoneyToGet ;
local GetMoney = GetMoney ;
local GetNumAvailableQuests = GetNumAvailableQuests ;
local GetAvailableTitle = GetAvailableTitle ;
local GetNumActiveQuests = GetNumActiveQuests ;
local GetAvailableQuestInfo = API.GetAvailableQuestInfo ;
local GetActiveQuestID = API.GetActiveQuestID ;
local GetActiveTitle = GetActiveTitle ;
local GetSuggestedGroupSize = API.GetSuggestedGroupSize ;
local UnitExists = UnitExists ;
local UnitName = UnitName ;
local SetPortraitTexture = SetPortraitTexture ;
local AcceptQuest = AcceptQuest ;
local GetQuestPortraitGiver = GetQuestPortraitGiver ;
local GetNumQuestChoices = GetNumQuestChoices ;
local AcknowledgeAutoAcceptQuest = AcknowledgeAutoAcceptQuest ;
local After = C_Timer.After ;
local tinsert = table.insert ;
local tsort = table.sort ;
local find = string.find ;
local Esaing_OutSine = addon.EasingFunctions . outSine ;
local Round = API.Round ;
local DeltaLerp = API.DeltaLerp ;
local SCROLL_BLEND_SPEED = 0.15 ; --0.2
local MainFrame ;
local SETTINGS_UI_VISIBLE = false ;
local function ScrollFrame_Easing ( self , elapsed )
self.value = DeltaLerp ( self.value , self.scrollTarget , SCROLL_BLEND_SPEED , elapsed ) ;
if ( self.value - self.scrollTarget ) > - 0.4 and ( self.value - self.scrollTarget ) < 0.4 then
--complete
self.value = self.scrollTarget ;
self : SetScript ( " OnUpdate " , nil ) ;
if self.value == 0 then
--at top
--self.borderTop:Hide();
--FadeFrame(self.borderTop, 0.25, 0);
elseif self.value == self.range then
--at bottom
--self.borderBottom:Hide();
--FadeFrame(self.borderBottom, 0.25, 0);
end
end
self.topDividerAlpha = self.value / 24 ;
if self.topDividerAlpha > 1 then
self.topDividerAlpha = 1 ;
elseif self.topDividerAlpha < 0 then
self.topDividerAlpha = 0 ;
end
self.borderTop : SetAlpha ( self.topDividerAlpha ) ;
self.BottomDividerAlpha = ( self.range - self.value ) / 24 ;
if self.BottomDividerAlpha > 1 then
self.BottomDividerAlpha = 1 ;
elseif self.BottomDividerAlpha < 0 then
self.BottomDividerAlpha = 0 ;
end
self.borderBottom : SetAlpha ( self.BottomDividerAlpha ) ;
self : SetVerticalScroll ( self.value ) ;
end
DUIDialogBaseMixin = { } ;
function DUIDialogBaseMixin : CalculateBestFrameHeight ( )
local viewportWidth , viewportHeight = WorldFrame : GetSize ( ) ; --height unaffected by screen resolution
local heightRatio = 0.618 ;
local frameHeight = heightRatio * viewportHeight ;
local heightInPixel = API.GetSizeInPixel ( self : GetEffectiveScale ( ) , frameHeight ) ;
if heightInPixel < 640 then
--Switch to low resolution textures?
end
return frameHeight
end
local Schematic = {
[ " BackgroundFrame.ClipFrame.BackgroundDecor " ] = { width = 360 , height = 360 } ,
[ " FrontFrame.FooterDivider " ] = { width = 392 , height = 34 } ,
[ " FrontFrame.HeaderDivider " ] = { width = 392 , height = 34 } ,
[ " FrontFrame.Header " ] = { width = 358 , height = 51 , point = " TOP " , relativePoint = " TOP " , x = 0 , y = - 28 } ,
[ " FrontFrame.Header.Portrait " ] = { width = 34 , height = 34 , point = " CENTER " , relativePoint = " TOPLEFT " , x = 23 , y = - 23 } ,
[ " FrontFrame.Header.Divider " ] = { width = 358 , height = 51 } ,
[ " FrontFrame.Header.Title " ] = { point = " LEFT " , relativePoint = " LEFT " , x = 53 , y = 2 } ,
[ " FrontFrame.Header.TopLight " ] = { width = 358 , height = 34 } ,
[ " FrontFrame.Header.WarbandCompleteAlert " ] = { width = 44 , height = 44 , point = " CENTER " , relativePoint = " TOPRIGHT " , x = - 25 , y = - 20 } ,
[ " FrontFrame.QuestPortrait " ] = { maxSizeMultiplier = 1.1 , width = 170 , height = 170 , point = " TOP " , relativePoint = " TOPRIGHT " , x = 66 , y = - 64 } ,
[ " FrontFrame.QuestPortrait.Model " ] = { maxSizeMultiplier = 1.1 , width = 78 , height = 78 , point = " CENTER " , relativePoint = " TOP " , x = 0 , y = - 71 } ,
[ " FrontFrame.QuestPortrait.Name " ] = { maxSizeMultiplier = 1.1 , width = 70 , height = 48 , point = " CENTER " , relativePoint = " BOTTOM " , x = 0 , y = 42 } ,
} ;
local function SetupObjectSize ( root , key , data )
local obj = root ;
for k in string.gmatch ( key , " %w+ " ) do
obj = obj [ k ] ;
end
local a = FRAME_SIZE_MULTIPLIER ;
if data.maxSizeMultiplier and a > data.maxSizeMultiplier then
a = data.maxSizeMultiplier ;
end
if data.width then
obj : SetSize ( data.width * a , data.height * a ) ;
end
if data.point then
obj : SetPoint ( data.point , obj : GetParent ( ) , data.relativePoint , data.x * a , data.y * a ) ;
end
end
function DUIDialogBaseMixin : UpdateFrameBaseOffset ( viewportWidth )
if not viewportWidth then
viewportWidth = API.GetBestViewportSize ( ) ;
end
local offsetRatio = FRAME_OFFSET_RATIO ;
local frameOffsetX = Round ( viewportWidth * ( offsetRatio - 0.5 ) ) ;
ChatFrame : ClearAllPoints ( ) ;
if addon.IsDBValue ( " FrameOrientation " , 1 ) then
frameOffsetX = - frameOffsetX ;
ChatFrame : SetPoint ( " BOTTOMRIGHT " , ExperienceBar , " TOPRIGHT " , - 8 , 8 ) ;
else
ChatFrame : SetPoint ( " BOTTOMLEFT " , ExperienceBar , " TOPLEFT " , 8 , 8 ) ;
end
self.frameOffsetX = frameOffsetX ;
self : ClearAllPoints ( ) ;
self : SetPoint ( " CENTER " , nil , " CENTER " , frameOffsetX , 0 ) ;
end
function DUIDialogBaseMixin : UpdateFrameSize ( )
local viewportWidth , viewportHeight = API.GetBestViewportSize ( ) ;
AlertFrame : ClearAllPoints ( ) ;
local alertFrameOffset = 36 ;
AlertFrame : SetPoint ( " TOPRIGHT " , nil , " CENTER " , 0.5 * viewportWidth - alertFrameOffset , 0.5 * viewportHeight - alertFrameOffset ) ;
ExperienceBar : SetPoint ( " BOTTOM " , nil , " BOTTOM " , 0 , - 2 ) ;
ExperienceBar : SetBarWidth ( viewportWidth ) ;
ExperienceBar : SetHeight ( 8 ) ;
ExperienceBar : SetNumCompartment ( 20 ) ;
FriendshipBar : ClearAllPoints ( ) ;
FriendshipBar : SetPoint ( " CENTER " , self , " TOP " , 0 , 0 ) ;
local frameRatio = 0.85 ;
local frameHeight = self : CalculateBestFrameHeight ( ) * FRAME_SIZE_MULTIPLIER ;
local frameWidth = API.Round ( frameHeight * frameRatio ) ;
frameHeight = API.Round ( frameHeight ) ;
self : SetSize ( frameWidth , frameHeight ) ;
local paddingH = PADDING_H * FRAME_SIZE_MULTIPLIER ;
local paddingTop = PADDING_TOP * FRAME_SIZE_MULTIPLIER ;
local paddingBottom = PADDING_BOTTOM * FRAME_SIZE_MULTIPLIER ;
self.frameWidth = frameWidth ;
self.frameHeight = frameHeight ;
self.halfFrameWidth = Round ( 0.5 * ( frameWidth - 2 * paddingH - BUTTON_HORIZONTAL_GAP ) ) ;
self.quarterFrameWidth = Round ( 0.25 * ( frameWidth - 2 * paddingH - 3 * BUTTON_HORIZONTAL_GAP ) ) ;
self : UpdateFrameBaseOffset ( viewportWidth ) ;
self.FrontFrame : SetPoint ( " TOPLEFT " , self , " TOPLEFT " , paddingH , 0 ) ;
self.FrontFrame : SetPoint ( " BOTTOMRIGHT " , self , " BOTTOMRIGHT " , - paddingH , 0 ) ;
local parchmentWidth = 546.13 * FRAME_SIZE_MULTIPLIER ; --API.GetPixelForScale(1, 1024);
local parchmentheight = 136.53 * FRAME_SIZE_MULTIPLIER ; --API.GetPixelForScale(1, 256);
self.Parchments [ 1 ] : SetSize ( parchmentWidth , parchmentheight ) ;
self.Parchments [ 3 ] : SetSize ( parchmentWidth , parchmentheight ) ;
for key , data in pairs ( Schematic ) do
SetupObjectSize ( self , key , data ) ;
end
local AcceptButton = self : AcquireAcceptButton ( ) ;
AcceptButton : SetPoint ( " BOTTOMLEFT " , self , " BOTTOMLEFT " , paddingH , paddingBottom ) ;
AcceptButton : SetButtonWidth ( self.halfFrameWidth ) ;
local GoodbyeButton = self : AcquireExitButton ( ) ;
GoodbyeButton : SetPoint ( " BOTTOMRIGHT " , self , " BOTTOMRIGHT " , - paddingH , paddingBottom ) ;
GoodbyeButton : SetButtonWidth ( self.halfFrameWidth ) ;
--Resize Footer
local footerButtonHeight = GoodbyeButton : GetHeight ( ) ;
local footerOffset = Round ( footerButtonHeight + paddingBottom + BUTTON_HORIZONTAL_GAP * 2 ) ; --Default: 96 Affected by GoddbyeButton height
self.FrontFrame . FooterDivider : ClearAllPoints ( ) ;
self.FrontFrame . FooterDivider : SetPoint ( " CENTER " , self.FrontFrame , " BOTTOM " , 0 , footerOffset ) ;
self.ScrollFrame : SetPoint ( " TOPLEFT " , self , " TOPLEFT " , 0 , - 42 ) ;
self.ScrollFrame : SetPoint ( " BOTTOMRIGHT " , self , " BOTTOMRIGHT " , 0 , footerOffset ) ;
local scrollFrameBaseHeight = self.ScrollFrame : GetHeight ( ) ;
self.ScrollFrame . range = 0 ;
self.scrollFrameBaseHeight = scrollFrameBaseHeight ;
self.scrollViewHeight = scrollFrameBaseHeight ;
local contentWidth = frameWidth ; -- - 2*paddingH + 2*CONTENT_BLEEDING;
local contentHeight = Round ( scrollFrameBaseHeight ) ;
self.ContentFrame : SetWidth ( Round ( contentWidth ) ) ;
self.ContentFrame : SetHeight ( contentHeight ) ; --Irrelevant
self.ContentFrame : SetPoint ( " TOPLEFT " , self.ScrollFrame , " TOPLEFT " , 0 , 0 ) ;
self.ContentFrame : SetPoint ( " BOTTOMRIGHT " , self.ScrollFrame , " BOTTOMRIGHT " , 0 , 0 ) ;
self.contentWidth = contentWidth ;
self.InputBox : ClearAllPoints ( ) ;
self.InputBox : SetPoint ( " LEFT " , self , " LEFT " , PADDING_H , 0 ) ;
self.InputBox : SetPoint ( " RIGHT " , self , " RIGHT " , - PADDING_H , 0 ) ;
if self.optionButtonPool then
local buttonWidth = self.frameWidth - 2 * PADDING_H * FRAME_SIZE_MULTIPLIER ;
local function UpdateButtonWidth ( button )
button : SetButtonWidth ( buttonWidth ) ;
end
self.optionButtonPool : ProcessAllObjects ( UpdateButtonWidth ) ;
end
if self.itemButtonPool then
local buttonWidth = self.halfFrameWidth ;
local function UpdateButtonWidth ( button )
button : SetButtonWidth ( buttonWidth ) ;
end
self.itemButtonPool : ProcessAllObjects ( UpdateButtonWidth ) ;
end
if self.smallItemButtonPool then
local buttonWidth = self.quarterFrameWidth ;
local function UpdateButtonWidth ( button )
button : SetButtonWidth ( buttonWidth ) ;
end
self.smallItemButtonPool : ProcessAllObjects ( UpdateButtonWidth ) ;
end
end
function DUIDialogBaseMixin : OnLoad ( )
--table.insert(UISpecialFrames, self:GetName());
MainFrame = self ;
addon.DialogueUI = self ;
TooltipFrame : SetParent ( self ) ;
TooltipFrame : SetShowDelay ( 0.25 ) ;
AlertFrame : SetParent ( self ) ;
ChatFrame : SetParent ( self ) ;
FriendshipBar : SetParent ( self ) ;
ExperienceBar : SetParent ( self ) ;
ExperienceBar : OnLoad ( ) ;
ExperienceBar : Show ( ) ;
ExperienceBar : SetFrameStrata ( " BACKGROUND " ) ;
ExperienceBar : SetFixedFrameStrata ( true ) ;
addon.Banner : SetParent ( self ) ;
self.ButtonHighlight = self.ContentFrame . ButtonHighlight ;
self.RewardSelection = self.ContentFrame . RewardSelection ;
self.GamePadFocusIndicator = CreateFrame ( " Frame " , nil , self.FrontFrame , " DUIDialogHotkeyTemplate " ) ;
self.GamePadFocusIndicator : SetIgnoreParentAlpha ( true ) ;
API.DisableSharpening ( self.ButtonHighlight . BackTexture ) ;
--Warband Completed Alert
local wb = self.FrontFrame . Header.WarbandCompleteAlert ;
self.WarbandCompleteAlert = wb ;
wb.tooltipText = L [ " Quest Completed On Account " ] ;
wb : SetScript ( " OnEnter " , TooltipFrame.ShowWidgetTooltip ) ;
wb : SetScript ( " OnLeave " , TooltipFrame.HideTooltip ) ;
API.DisableSharpening ( wb.Icon ) ;
--Frame Background
self.Parchments = { } ;
for i = 1 , 3 do
local piece = self.BackgroundFrame : CreateTexture ( nil , " BACKGROUND " , nil , - 1 ) ;
self.Parchments [ i ] = piece ;
end
self.Parchments [ 1 ] : SetTexCoord ( 0 , 1 , 0 , 256 / 2048 ) ;
self.Parchments [ 1 ] : SetPoint ( " CENTER " , self , " TOP " , 0 , 0 ) ;
self.Parchments [ 3 ] : SetTexCoord ( 0 , 1 , 896 / 2048 , 1152 / 2048 ) ;
self.Parchments [ 3 ] : SetPoint ( " CENTER " , self , " BOTTOM " , 0 , 0 ) ;
self.Parchments [ 2 ] : SetTexCoord ( 0 , 1 , 256 / 2048 , 896 / 2048 ) ;
self.Parchments [ 2 ] : SetPoint ( " TOPLEFT " , self.Parchments [ 1 ] , " BOTTOMLEFT " , 0 , 0 ) ;
self.Parchments [ 2 ] : SetPoint ( " BOTTOMRIGHT " , self.Parchments [ 3 ] , " TOPRIGHT " , 0 , 0 ) ;
self.BackgroundDecor = self.BackgroundFrame . ClipFrame.BackgroundDecor ;
do
self.ScrollFrame . borderTop = self.FrontFrame . HeaderDivider ;
self.ScrollFrame . borderBottom = self.FrontFrame . FooterDivider ;
end
self : ResetScroll ( ) ;
local offsetPerScroll = 96 ;
local function ScrollFrame_OnMouseWheel ( f , delta )
if delta > 0 then
self : ScrollBy ( - offsetPerScroll ) ;
else
self : ScrollBy ( offsetPerScroll ) ;
end
end
self.ScrollFrame : SetScript ( " OnMouseWheel " , ScrollFrame_OnMouseWheel ) ;
self.ScrollFrame . OnMouseWheel = ScrollFrame_OnMouseWheel ;
local function CreateFontString ( )
local fontString = self.ContentFrame : CreateFontString ( nil , " ARTWORK " , " DUIFont_Quest_Paragraph " ) ;
fontString : SetSpacing ( TEXT_SPACING ) ;
return fontString
end
local function RemoveFontString ( fontString )
fontString : SetText ( nil ) ;
fontString : Hide ( ) ;
fontString : ClearAllPoints ( ) ;
end
self.fontStringPool = API.CreateObjectPool ( CreateFontString , RemoveFontString ) ;
local function CreateOptionButton ( )
local button = CreateFrame ( " Button " , nil , self.ContentFrame , " DUIDialogOptionButtonTemplate " ) ;
button : SetButtonWidth ( self.frameWidth - 2 * PADDING_H * FRAME_SIZE_MULTIPLIER ) ;
button : SetOwner ( self ) ;
return button
end
local function RemoveOptionButton ( button )
button : Hide ( ) ;
button : ClearAllPoints ( ) ;
button.HotkeyFrame = nil ;
end
local function OnAcquireOptionButton ( button )
button : ResetVisual ( ) ;
end
self.optionButtonPool = API.CreateObjectPool ( CreateOptionButton , RemoveOptionButton , OnAcquireOptionButton ) ;
local function CreateTextBackground ( )
local texture = self.ContentFrame : CreateTexture ( nil , " BORDER " ) ;
local corner = 8 ;
texture : SetTextureSliceMargins ( corner , corner , corner , corner ) ;
texture : SetTextureSliceMode ( 1 ) ;
texture : SetTexture ( ThemeUtil : GetTextureFile ( " SubHeaderBackground.png " ) ) ;
texture : SetSize ( 36 , 36 ) ;
return texture
end
local function RemoveTextBackground ( texture )
texture : ClearAllPoints ( ) ;
texture : Hide ( ) ;
end
self.textBackgroundPool = API.CreateObjectPool ( CreateTextBackground , RemoveTextBackground ) ;
local function CreateItemButton ( )
local button = CreateFrame ( " Button " , nil , self.ContentFrame , " DUIDialogItemButtonTemplate " ) ;
button : SetButtonWidth ( self.halfFrameWidth ) ;
return button
end
local function RemoveItemButton ( itemButton )
itemButton : OnRelease ( ) ;
end
local function OnAcquireItemButton ( itemButton )
itemButton : SetAlpha ( 1 ) ;
itemButton : SetBackgroundTexture ( 1 ) ;
end
self.itemButtonPool = API.CreateObjectPool ( CreateItemButton , RemoveItemButton , OnAcquireItemButton ) ;
local function CreateSmallItemButton ( )
local button = CreateFrame ( " Button " , nil , self.ContentFrame , " DUIDialogSmallItemButtonTemplate " ) ;
button : SetButtonWidth ( self.quarterFrameWidth ) ;
return button
end
local function RemoveSmallItemButton ( itemButton )
itemButton : OnRelease ( ) ;
end
self.smallItemButtonPool = API.CreateObjectPool ( CreateSmallItemButton , RemoveSmallItemButton ) ;
local function CreateQuestTypeFrame ( )
local f = CreateFrame ( " Frame " , nil , self , " DUIDialogQuestTypeFrameTemplate " ) ;
return f
end
local function RemoveFrame ( f )
f : Remove ( ) ;
f : SetParent ( self ) ;
end
self.questTypeFramePool = API.CreateObjectPool ( CreateQuestTypeFrame , RemoveFrame ) ;
local function CreateIconFrame ( )
local f = CreateFrame ( " Frame " , nil , self , " DUIDialogIconFrameTemplate " ) ;
return f
end
self.iconFramePool = API.CreateObjectPool ( CreateIconFrame , RemoveFrame ) ;
local function CreateHotkeyFrame ( )
local f = CreateFrame ( " Frame " , nil , self , " DUIDialogHotkeyTemplate " ) ;
return f
end
local function RemoveHotkeyFrame ( f )
f : Hide ( ) ;
f : ClearAllPoints ( ) ;
f : SetParent ( self ) ;
end
self.hotkeyFramePool = API.CreateObjectPool ( CreateHotkeyFrame , RemoveHotkeyFrame ) ;
if not self.Vignette then
self.Vignette = CreateFrame ( " Frame " , nil ) ;
self.Vignette : SetFrameStrata ( " BACKGROUND " ) ;
self.Vignette : SetPoint ( " TOPLEFT " , UIParent , " TOPLEFT " , 0 , 0 ) ;
self.Vignette : SetPoint ( " BOTTOMRIGHT " , UIParent , " BOTTOMRIGHT " , 0 , 0 ) ;
self.Vignette : SetAlpha ( 0 ) ;
self.Vignette : Hide ( ) ;
local texture = self.Vignette : CreateTexture ( nil , " BACKGROUND " ) ;
texture : SetAllPoints ( true ) ;
texture : SetTexture ( " Interface/AddOns/DialogueUI/Art/Theme_Shared/ScreenVignette.png " ) ;
end
self : UpdateFrameSize ( ) ;
API.SetPlayCutsceneCallback ( function ( )
self : HideUI ( ) ;
end ) ;
self.OnLoad = nil ;
self : SetScript ( " OnLoad " , nil ) ;
self.isGameLoading = true ;
self : RegisterEvent ( " LOADING_SCREEN_DISABLED " ) ;
end
function DUIDialogBaseMixin : LoadTheme ( )
local prefix = ThemeUtil : GetTexturePath ( ) ;
local parchmentFile = prefix .. " Parchment.png " ;
local themeID = ThemeUtil : GetThemeID ( ) ;
for _ , piece in ipairs ( self.Parchments ) do
piece : SetTexture ( parchmentFile ) ;
end
local ff = self.FrontFrame ;
ff.Header . Divider : SetTexture ( parchmentFile ) ;
ff.Header . Divider : SetTexCoord ( 0 , 0.65625 , 0.56640625 , 0.61328125 ) ;
ff.Header . TopLight : SetTexture ( parchmentFile ) ;
ff.Header . TopLight : SetTexCoord ( 0 , 0.65625 , 0.65234375 , 0.68359375 ) ;
ff.FooterDivider : SetTexture ( parchmentFile ) ;
ff.FooterDivider : SetTexCoord ( 0 , 0.71875 , 0.6875 , 0.71875 ) ; --0, 0.65625, 0.6171875, 0.6484375
ff.HeaderDivider : SetTexture ( parchmentFile ) ;
ff.HeaderDivider : SetTexCoord ( 0 , 0.71875 , 0.72265625 , 0.75390625 ) ; --0, 0.65625, 0.6484375, 0.6171875
ff.QuestPortrait . FrontTexture : SetTexture ( parchmentFile ) ;
ff.QuestPortrait . FrontTexture : SetTexCoord ( 0 , 0.3125 , 0.84375 , 1 ) ;
ff.QuestPortrait : SetTheme ( themeID ) ;
self.WarbandCompleteAlert . Icon : SetTexture ( parchmentFile ) ;
self.WarbandCompleteAlert . Icon : SetTexCoord ( 0.71875 , 0.8125 , 0.56640625 , 0.61328125 ) ;
self.RewardSelection . FrontTexture : SetTexture ( prefix .. " RewardChoice-Highlight.png " ) ;
self.RewardSelection . BackTexture : SetTexture ( prefix .. " RewardChoice-Highlight-Back.png " ) ;
self.RewardSelection . BackTexture : SetVertexColor ( 0.65 , 0 , 0 ) ;
if self.CopyTextButton then
self.CopyTextButton : SetTheme ( themeID ) ;
end
if self.TTSButton then
self.TTSButton : SetTheme ( themeID ) ;
end
if self.textBackgroundPool then
local bgFile = ThemeUtil : GetTextureFile ( " SubHeaderBackground.png " ) ;
local function SetBackGround ( texture )
texture : SetTexture ( bgFile ) ;
end
self.textBackgroundPool : ProcessAllObjects ( SetBackGround ) ;
end
if self.optionButtonPool then
local method = " LoadTheme " ;
self.optionButtonPool : CallAllObjects ( method ) ;
end
if self.itemButtonPool then
local method = " LoadTheme " ;
self.itemButtonPool : CallAllObjects ( method ) ;
end
if self.hotkeyFramePool then
local method = " LoadTheme " ;
self.hotkeyFramePool : CallAllObjects ( method ) ;
end
self.GamePadFocusIndicator : LoadTheme ( ) ;
if self.AcceptButton then
self.AcceptButton : LoadTheme ( ) ;
end
if self.ExitButton then
self.ExitButton : LoadTheme ( ) ;
end
FriendshipBar : LoadTheme ( ) ;
TooltipFrame : LoadTheme ( ) ;
self.ButtonHighlight . artID = nil ;
self : OnSettingsChanged ( ) ;
end
function DUIDialogBaseMixin : ReleaseAllObjects ( )
self.textHistory = { } ;
self.highlightedButton = nil ;
self.fontStringPool : Release ( ) ;
self.optionButtonPool : Release ( ) ;
self.textBackgroundPool : Release ( ) ;
self.itemButtonPool : Release ( ) ;
self.smallItemButtonPool : Release ( ) ;
self.questTypeFramePool : Release ( ) ;
self.iconFramePool : Release ( ) ;
self.hotkeyFramePool : Release ( ) ;
self : ResetScroll ( ) ;
self : HighlightButton ( nil ) ;
self : HighlightRewardChoice ( nil ) ;
self : ResetGamePadObjects ( ) ;
KeyboardControl : ResetKeyActions ( ) ;
end
function DUIDialogBaseMixin : AcquireFontString ( )
return self.fontStringPool : Acquire ( ) ;
end
function DUIDialogBaseMixin : AcquireAcceptButton ( enableHotkey )
if not self.AcceptButton then
self.AcceptButton = CreateFrame ( " Button " , nil , self , " DUIDialogOptionButtonTemplate " ) ; --self.FrontFrame
self.AcceptButton . HotkeyFrame = CreateFrame ( " Frame " , nil , self.AcceptButton , " DUIDialogHotkeyTemplate " ) ;
self.AcceptButton : SetOwner ( self ) ;
self.AcceptButton : SetButtonAcceptQuest ( ) ;
self.AcceptButtonLock = CreateFrame ( " Frame " , nil , self.AcceptButton , " DUIDialogOptionButtonLockTemplate " ) ;
self.AcceptButton . ButtonLock = self.AcceptButtonLock ;
self.AcceptButton : SetButtonWidth ( self.halfFrameWidth ) ;
end
if not self.AcceptButton : IsMouseOver ( ) then
self.AcceptButton : ResetVisual ( ) ;
end
self.AcceptButton : Hide ( ) ; --Trigger new OnEnter
self.AcceptButton : Show ( ) ;
if enableHotkey then
KeyboardControl : SetKeyButton ( " PRIMARY " , self.AcceptButton ) ;
end
return self.AcceptButton
end
function DUIDialogBaseMixin : AcquireExitButton ( )
if not self.ExitButton then
self.ExitButton = CreateFrame ( " Button " , nil , self , " DUIDialogOptionButtonTemplate " ) ; --self.FrontFrame
self.ExitButton . HotkeyFrame = CreateFrame ( " Frame " , nil , self.ExitButton , " DUIDialogHotkeyTemplate " ) ;
self.ExitButton : SetOwner ( self ) ;
self.ExitButton : SetButtonExitGossip ( ) ;
self.ExitButton : SetButtonWidth ( self.halfFrameWidth ) ;
end
self.ExitButton : ResetVisual ( ) ;
self.ExitButton : Hide ( ) ;
self.ExitButton : Show ( ) ;
KeyboardControl : SetKeyButton ( " ESCAPE " , self.ExitButton ) ;
return self.ExitButton
end
function DUIDialogBaseMixin : AcquireOptionButton ( )
return self.optionButtonPool : Acquire ( ) ;
end
function DUIDialogBaseMixin : SetSelectedGossipIndex ( gossipOrderIndex )
self.selectedGossipIndex = gossipOrderIndex ;
end
function DUIDialogBaseMixin : SetAcceptCurrentQuest ( )
self : SetConsumeGossipClose ( false ) ;
end
function DUIDialogBaseMixin : FlagPreviousGossipButtons ( )
self : HighlightButton ( nil ) ;
local index = self.selectedGossipIndex ;
self.optionButtonPool : ProcessActiveObjects (
function ( optionButton )
if optionButton.type == " gossip " then
optionButton : FlagAsPreviousGossip ( index ) ;
else
optionButton : Disable ( ) ;
end
end
) ;
end
function DUIDialogBaseMixin : AcquireLeftFontString ( )
local fs = self : AcquireFontString ( ) ;
fs : SetFontObject ( " DUIFont_Quest_Paragraph " ) ;
fs : SetJustifyV ( " TOP " ) ;
fs : SetJustifyH ( " LEFT " ) ;
return fs
end
function DUIDialogBaseMixin : AcquireAndSetSubHeader ( text )
local background = self.textBackgroundPool : Acquire ( ) ;
local fs = self : AcquireFontString ( ) ;
fs : SetFontObject ( " DUIFont_Quest_SubHeader " ) ;
fs : SetJustifyV ( " TOP " ) ;
fs : SetJustifyH ( " LEFT " ) ;
fs : SetText ( text ) ;
local width = fs : GetWrappedWidth ( ) ;
local paddingH = 8 ;
local paddingV = 4 ;
local backgroundWidth = Round ( width + 2 * paddingH ) ;
local backgroudHeight = 12 + 2 * paddingV ;
background : SetSize ( backgroundWidth , backgroudHeight ) ;
background.size = backgroudHeight + paddingV + TEXT_SPACING ;
fs : SetPoint ( " LEFT " , background , " LEFT " , paddingH , 0 ) ;
return background
end
function DUIDialogBaseMixin : UseQuestLayout ( state )
local forceUpdate = SETTINGS_UI_VISIBLE == true ;
if state then
local questID = GetQuestID ( ) ;
self.questID = questID ;
if ( not self.questLayout ) or forceUpdate then
self.questLayout = true ;
local topOffset = ( 28 + 40 ) * FRAME_SIZE_MULTIPLIER ;
self.scrollViewHeight = self.scrollFrameBaseHeight - 40 * FRAME_SIZE_MULTIPLIER ;
--self.ScrollFrame:SetPoint("TOPLEFT", self, "TOPLEFT", PADDING_H, -PADDING_TOP + topOffset);
self.ScrollFrame : SetPoint ( " TOPLEFT " , self , " TOPLEFT " , 0 , - topOffset ) ;
self.FrontFrame . Header : Show ( ) ;
self.FrontFrame . HeaderDivider : Hide ( ) ;
FriendshipBar : Hide ( ) ;
end
local unit = UnitExists ( " npc " ) and " npc " or " player " ;
SetPortraitTexture ( self.FrontFrame . Header.Portrait , unit ) ;
if ThemeUtil : IsDarkMode ( ) then
self.FrontFrame . Header.Portrait : SetVertexColor ( 1 , 1 , 1 ) ;
else
self.FrontFrame . Header.Portrait : SetVertexColor ( 1 , 0.9 , 0.78 ) ;
end
self.keepGossipHistory = false ;
self.hasActiveGossipQuests = false ;
self.activeQuestButtons = { } ;
if questID and API.IsQuestFlaggedCompletedOnAccount ( questID ) then
self.WarbandCompleteAlert : Show ( ) ;
self.FrontFrame . Header.Title : SetPoint ( " RIGHT " , self.FrontFrame . Header , " RIGHT " , - 56 , 2 ) ;
else
self.WarbandCompleteAlert : Hide ( ) ;
self.FrontFrame . Header.Title : SetPoint ( " RIGHT " , self.FrontFrame . Header , " RIGHT " , - 8 , 2 ) ;
end
elseif self.questLayout or forceUpdate then
self.questLayout = nil ;
self.questID = nil ;
self.scrollViewHeight = self.scrollFrameBaseHeight ;
--self.ScrollFrame:SetPoint("TOPLEFT", self, "TOPLEFT", PADDING_H, -PADDING_TOP);
self.ScrollFrame : SetPoint ( " TOPLEFT " , self , " TOPLEFT " , 0 , - 42 ) ;
self.FrontFrame . Header : Hide ( ) ;
self.BackgroundDecor : Hide ( ) ;
self.FrontFrame . QuestPortrait : FadeOut ( ) ;
self.WarbandCompleteAlert : Hide ( ) ;
end
end
function DUIDialogBaseMixin : UpdateQuestTitle ( )
local text = GetQuestTitle ( ) ;
local headerFrame = self.FrontFrame . Header ;
local title = headerFrame.Title ;
local subtitle = headerFrame.Subtitle ;
local subtitleFrame = headerFrame.SubtitleMouseOverFrame ;
subtitle : SetText ( nil ) ;
subtitleFrame : Hide ( ) ;
title : SetFontObject ( " DUIFont_Quest_Title_18 " ) ;
title : SetJustifyV ( " BOTTOM " ) ;
title : SetJustifyH ( " LEFT " ) ;
title : SetText ( text ) ;
local numLines = title : GetNumLines ( ) ;
if numLines > 1 then
title : SetFontObject ( " DUIFont_Quest_Title_16 " ) ;
numLines = title : GetNumLines ( ) ;
if numLines > 1 then
title : SetFontObject ( " DUIFont_Quest_Paragraph " ) ;
end
end
local questID = self.questID ;
local campaignID = C_CampaignInfo and C_CampaignInfo.GetCampaignID ( questID ) ;
if campaignID and campaignID ~= 0 then
local campaignInfo = C_CampaignInfo.GetCampaignInfo ( campaignID ) ;
if campaignInfo then
local questTypeFrame = self.questTypeFramePool : Acquire ( ) ;
questTypeFrame : SetPoint ( " BOTTOMLEFT " , title , " TOPLEFT " , 0 , 0 ) ;
questTypeFrame : SetParent ( headerFrame ) ;
questTypeFrame : SetCampaignNameID ( campaignInfo.name , campaignID ) ;
end
else
local questTagID = API.GetQuestTag ( questID ) ;
if questTagID then
--print("questTagID", questTagID) --debug
local tagName , tagIcon = API.GetQuestTagNameIcon ( questTagID ) ;
if tagName then
local questTypeFrame = self.questTypeFramePool : Acquire ( ) ;
questTypeFrame : SetPoint ( " BOTTOMLEFT " , title , " TOPLEFT " , 0 , 0 ) ;
questTypeFrame : SetParent ( headerFrame ) ;
questTypeFrame : SetQuestTagNameAndIcon ( tagName , tagIcon ) ;
end
end
end
local decor = API.GetQuestBackgroundDecor ( questID ) ;
self.BackgroundDecor : SetTexture ( decor ) ;
self.BackgroundDecor : Show ( ) ;
return 6 * ( FRAME_SIZE_MULTIPLIER ) --Accounted for Header Size
end
function DUIDialogBaseMixin : ScrollTo ( value )
local f = self.ScrollFrame ;
value = API.Clamp ( value , 0 , f.range ) ;
if value ~= f.scrollTarget then
f.scrollTarget = value ;
if not self.questLayout then
FadeFrame ( f.borderTop , 0.25 , 1 ) ;
end
if value < f.range then
FadeFrame ( f.borderBottom , 0.25 , 1 ) ;
end
f : SetScript ( " OnUpdate " , ScrollFrame_Easing ) ;
end
end
function DUIDialogBaseMixin : ScrollBy ( offset )
local f = self.ScrollFrame ;
local value = f.scrollTarget or f : GetVerticalScroll ( ) ;
self : ScrollTo ( value + offset ) ;
--[[
if offset > 0 and value < f.range then
anyChange = true ;
value = value + offset ;
if value > f.range then
value = f.range ;
end
elseif offset < 0 and value > 0 then
anyChange = true ;
value = value + offset ;
if value < 0 then
value = 0 ;
end
end
if anyChange then
f.scrollTarget = value ;
if not self.questLayout then
FadeFrame ( f.borderTop , 0.25 , 1 ) ;
end
if value < f.range then
FadeFrame ( f.borderBottom , 0.25 , 1 ) ;
end
f : SetScript ( " OnUpdate " , ScrollFrame_Easing ) ;
end
--]]
end
function DUIDialogBaseMixin : ScrollToBottom ( )
self : ScrollBy ( self.ScrollFrame . range ) ;
FadeFrame ( self.ScrollFrame . borderBottom , 0 , 0 ) ;
end
function DUIDialogBaseMixin : IsScrollAtBottom ( )
if not self : IsScrollable ( ) then
return true
end
local current = self.ScrollFrame . scrollTarget or self.ScrollFrame . value ;
local range = self.ScrollFrame . range ;
return current + 0.5 > range ;
end
function DUIDialogBaseMixin : ResetScroll ( )
self.ScrollFrame : SetScript ( " OnUpdate " , nil ) ;
self.ScrollFrame : SetHorizontalScroll ( 0 ) ;
self.ScrollFrame : SetVerticalScroll ( 0 ) ;
self.ScrollFrame . value = 0 ;
self.ScrollFrame . scrollTarget = 0 ;
FadeFrame ( self.ScrollFrame . borderTop , 0 , 0 ) ;
end
function DUIDialogBaseMixin : SetScrollable ( scrollable )
--Using ClipFrame (clipChildren or ScrollChild) breaks pixel-perfect
--Setting parent to ScrollChild dynamically, so we can still have good looking stroke
--Animation: ContentFrame has childChildren = true during unscroll animation
local forceUpdate = SETTINGS_UI_VISIBLE == true ;
if scrollable and ( ( not self.ContentFrame . scrollable ) or forceUpdate ) then
self.ContentFrame . scrollable = true ;
self.ContentFrame : ClearAllPoints ( ) ;
self.ContentFrame : SetParent ( self.ScrollFrame . ScrollChild ) ;
self.ContentFrame : SetPoint ( " TOPLEFT " , self.ScrollFrame . ScrollChild , " TOPLEFT " , 0 , 0 ) ;
self.ContentFrame : SetWidth ( self.contentWidth ) ;
self.FrontFrame . FooterDivider : Show ( ) ;
elseif ( not scrollable ) and ( self.ContentFrame . scrollable or forceUpdate ) then
self.ContentFrame . scrollable = false ;
self.ContentFrame : ClearAllPoints ( ) ;
self.ContentFrame : SetParent ( self ) ;
self.ContentFrame : SetPoint ( " TOPLEFT " , self.ScrollFrame , " TOPLEFT " , 0 , 0 ) ;
self.ContentFrame : SetPoint ( " BOTTOMRIGHT " , self.ScrollFrame , " BOTTOMRIGHT " , 0 , 0 ) ;
end
end
function DUIDialogBaseMixin : IsScrollable ( )
return self.ContentFrame . scrollable == true
end
function DUIDialogBaseMixin : SetScrollRange ( contentHeight )
self.contentHeight = contentHeight ;
local scrollViewHeight = self.scrollViewHeight ; --self.ScrollFrame:GetHeight(); --affected by intro animation!
local range = contentHeight - scrollViewHeight + PARAGRAPH_SPACING ;
local scrollable ;
if range > 0 then
scrollable = true ;
if range < 12 then
range = 12 ;
end
range = range + 36 ;
self.ScrollFrame . range = Round ( range ) ;
self.FrontFrame . FooterDivider : Show ( ) ;
self.FrontFrame . FooterDivider : SetAlpha ( 1 ) ;
else
scrollable = false ;
self.ScrollFrame . range = 0 ;
self.FrontFrame . FooterDivider : Hide ( ) ;
self.FrontFrame . HeaderDivider : Hide ( ) ;
end
self : SetScrollable ( scrollable ) ;
end
local function SortFunc_GossipOrder ( a , b )
return a.orderIndex < b.orderIndex ;
end
local GOSSIP_QUEST_LABEL = L [ " Gossip Quest Option Prepend " ] or " (Quest) " ;
local function SortFunc_GossipPrioritizeQuest ( a , b )
if a.flags and b.flags and ( a.flags ~= b.flags ) then
return a.flags > b.flags
end
local isQuestA = find ( a.name , GOSSIP_QUEST_LABEL ) ;
local isQuestB = find ( b.name , GOSSIP_QUEST_LABEL ) ;
if isQuestA ~= nil and isQuestB == nil then
return true
elseif isQuestA == nil and isQuestB ~= nil then
return false
end
return a.orderIndex < b.orderIndex ;
end
local function SortFunc_PrioritizeCompleteQuest ( a , b )
if a.isComplete ~= b.isComplete then
return a.isComplete
elseif a.isAvailableQuest ~= b.isAvailableQuest then
return a.isAvailableQuest
else
return a.originalOrder < b.originalOrder
end
end
function DUIDialogBaseMixin : FadeInContentFrame ( )
if self : IsShown ( ) and not SETTINGS_UI_VISIBLE then
FadeFrame ( self.ContentFrame , 0.35 , 1 , 0 ) ;
PlaySound ( " SOUNDKIT.IG_QUEST_LIST_OPEN " ) ;
else
self.ContentFrame : SetAlpha ( 1 ) ;
end
end
function DUIDialogBaseMixin : InsertText ( offsetY , text )
--Add no spacing
local fs = self : AcquireLeftFontString ( ) ;
fs : SetPoint ( " TOPLEFT " , self.ContentFrame , " TOPLEFT " , PADDING_H * FRAME_SIZE_MULTIPLIER , - offsetY ) ;
fs : SetPoint ( " RIGHT " , self.ContentFrame , " RIGHT " , - PADDING_H * FRAME_SIZE_MULTIPLIER , 0 ) ;
fs : SetText ( text ) ;
offsetY = Round ( offsetY + fs : GetHeight ( ) ) ;
return offsetY
end
function DUIDialogBaseMixin : InsertParagraph ( offsetY , paragraphText )
--Add paragrah spacing
return self : InsertText ( offsetY + PARAGRAPH_SPACING , paragraphText ) ;
end
function DUIDialogBaseMixin : FormatParagraph ( offsetY , text )
local paragraphs = API.SplitParagraph ( text ) ;
local firstObject , lastObject ;
if paragraphs and # paragraphs > 0 then
for i , paragraphText in ipairs ( paragraphs ) do
local fs = self : AcquireLeftFontString ( ) ;
if not firstObject then
firstObject = fs ;
end
fs : SetPoint ( " TOPLEFT " , self.ContentFrame , " TOPLEFT " , PADDING_H * FRAME_SIZE_MULTIPLIER , - offsetY ) ;
fs : SetPoint ( " RIGHT " , self.ContentFrame , " RIGHT " , - PADDING_H * FRAME_SIZE_MULTIPLIER , 0 ) ;
fs : SetText ( paragraphText ) ;
offsetY = Round ( offsetY + fs : GetHeight ( ) + PARAGRAPH_SPACING ) ;
lastObject = fs ;
end
offsetY = offsetY - PARAGRAPH_SPACING ;
else
--For QuestGreeting where the NPC says nothing
local fs = self : AcquireLeftFontString ( ) ;
firstObject = fs ;
fs : SetPoint ( " TOPLEFT " , self.ContentFrame , " TOPLEFT " , PADDING_H * FRAME_SIZE_MULTIPLIER , - offsetY ) ;
fs : SetPoint ( " RIGHT " , self.ContentFrame , " RIGHT " , - PADDING_H * FRAME_SIZE_MULTIPLIER , 0 ) ;
fs : SetText ( " " ) ;
lastObject = fs ;
end
return offsetY , firstObject , lastObject
end
local function ConcatenateNPCName ( text )
if GetDBBool ( " ShowNPCNameOnPage " ) and UnitExists ( " npc " ) then
local name = UnitName ( " npc " ) ;
if text and name and name ~= " " then
return name .. " : " .. text
end
end
return text
end
function DUIDialogBaseMixin : HandleInitialLoadingComplete ( )
if self.deferredEvent then
--We handle quests that are auto accepted upon logging in
--If the player talks to an NPC immediately after the initial loading screen, our UI won't turn visible
local questID = GetQuestID ( ) ;
if ( self.deferredEvent == " GOSSIP_SHOW " or self.deferredEvent == " QUEST_GREETING " ) or ( questID and questID ~= 0 ) then --Some quests are auto accepted and closed by the game
self : ShowUI ( self.deferredEvent ) ;
end
self.deferredEvent = nil ;
end
end
function DUIDialogBaseMixin : IsGossipHandledExternally ( )
--Some addons handle goosip options (Override in SupportedAddons)
--InteractiveWormholes
return false
end
function DUIDialogBaseMixin : HandleGossip ( )
if self : IsGossipHandledExternally ( ) then return false end ;
local availableQuests = GetAvailableQuests ( ) ;
local activeQuests = GetActiveQuests ( ) ;
local options = GetOptions ( ) ;
tsort ( options , SortFunc_GossipPrioritizeQuest ) ;
local anyActiveQuest = activeQuests and # activeQuests > 0 ;
local anyAvailableQuest = availableQuests and # availableQuests > 0 ;
local anyQuest = anyActiveQuest or anyAvailableQuest ;
local anyOption = options and # options > 0 ;
self.hasActiveGossipQuests = anyActiveQuest ;
self.numAvailableQuests = availableQuests and # availableQuests or 0 ;
if ( not ( anyQuest or anyOption ) ) and NameplateGossip : ShouldUseNameplate ( ) then
--debug
local success = addon.NameplateGossip : RequestDisplayGossip ( ) ;
if success then
self.keepGossipHistory = false ;
return false
end
end
local autoSelectGossip = GetDBBool ( " AutoSelectGossip " ) ;
if ( not GetDBBool ( " ForceGossip " ) ) and ( not anyQuest ) and ( # options == 1 ) and ( not ForceGossip ( ) ) then
if options [ 1 ] . selectOptionWhenOnlyOption then
C_GossipInfo.SelectOptionByIndex ( options [ 1 ] . orderIndex ) ;
return false
end
if autoSelectGossip and IsAutoSelectOption ( options [ 1 ] . gossipOptionID , true ) then
C_GossipInfo.SelectOption ( options [ 1 ] . gossipOptionID ) ;
API.PrintMessage ( L [ " Auto Select " ] , options [ 1 ] . name ) ;
return false
end
end
if autoSelectGossip then
for i , data in ipairs ( options ) do
if IsAutoSelectOption ( data.gossipOptionID ) then
C_GossipInfo.SelectOption ( data.gossipOptionID ) ;
API.PrintMessage ( L [ " Auto Select " ] , data.name ) ;
return false
end
end
end
local fromOffsetY = 0 ;
local hasPreviousGossip = false ;
if self.questLayout or ( not self.keepGossipHistory ) then
self : ReleaseAllObjects ( ) ;
else
self : ResetGamePadObjects ( ) ;
KeyboardControl : ResetKeyActions ( ) ;
fromOffsetY = self.contentHeight or fromOffsetY ;
if fromOffsetY > 0 then
--Has previous gossip history
hasPreviousGossip = true ;
fromOffsetY = fromOffsetY + PADDING_TOP ;
self : FlagPreviousGossipButtons ( ) ;
end
if fromOffsetY >= 5000 then
--Clear previous history
fromOffsetY = 0 ;
hasPreviousGossip = false ;
self : ReleaseAllObjects ( ) ;
end
end
local offsetY = fromOffsetY ;
self : UseQuestLayout ( false ) ;
local firstObject , lastObject ;
local button ;
--Welcome text
local gossipText = ConcatenateNPCName ( GetGossipText ( ) ) ;
offsetY , firstObject , lastObject = self : FormatParagraph ( offsetY , gossipText ) ;
local hotkeyIndex = 0 ;
local hotkey ;
local showGossipFirst = options [ 1 ] and options [ 1 ] . flags == 1 ;
if showGossipFirst then
--Show gossip first if there is a (Quest) Gossip
for i , data in ipairs ( options ) do
hotkeyIndex = hotkeyIndex + 1 ;
button = self : AcquireOptionButton ( ) ;
hotkey = KeyboardControl : SetKeyButton ( hotkeyIndex , button ) ;
button : SetGossip ( data , hotkey ) ;
if i == 1 then
local spacing = - PARAGRAPH_SPACING ;
button : SetPoint ( " TOPLEFT " , lastObject , " BOTTOMLEFT " , 0 , spacing ) ;
else
button : SetPoint ( " TOPLEFT " , lastObject , " BOTTOMLEFT " , 0 , 0 ) ;
end
lastObject = button ;
self : IndexGamePadObject ( button ) ;
end
end
--Quest
local questIndex = 0 ;
local quests = { } ;
self.activeQuestButtons = { } ;
for i , questInfo in ipairs ( availableQuests ) do
questIndex = questIndex + 1 ;
questInfo.isOnQuest = false ;
questInfo.isAvailableQuest = true ;
questInfo.originalOrder = questIndex ;
questInfo.index = i ;
quests [ questIndex ] = questInfo ;
end
for i , questInfo in ipairs ( activeQuests ) do
questIndex = questIndex + 1 ;
questInfo.isOnQuest = true ; --there is a delay between C_Gossip and C_QuestLog.IsOnQuest
questInfo.isAvailableQuest = false ;
questInfo.originalOrder = questIndex ;
questInfo.index = i ;
quests [ questIndex ] = questInfo ;
end
tsort ( quests , SortFunc_PrioritizeCompleteQuest ) ;
local lastQuestComplete , lastQuestAvailable ;
for i , questInfo in ipairs ( quests ) do
hotkeyIndex = hotkeyIndex + 1 ;
button = self : AcquireOptionButton ( ) ;
hotkey = KeyboardControl : SetKeyButton ( hotkeyIndex , button ) ;
if questInfo.isAvailableQuest then
button : SetAvailableQuest ( questInfo , questInfo.index , hotkey ) ;
else
button : SetActiveQuest ( questInfo , questInfo.index , hotkey ) ;
tinsert ( self.activeQuestButtons , button ) ;
end
if i == 1 or ( questInfo.isAvailableQuest ~= lastQuestAvailable ) or ( questInfo.isComplete ~= lastQuestComplete ) then
button : SetPoint ( " TOPLEFT " , lastObject , " BOTTOMLEFT " , 0 , - PARAGRAPH_BUTTON_SPACING ) ;
lastQuestAvailable = questInfo.isAvailableQuest ;
lastQuestComplete = questInfo.isComplete ;
else
button : SetPoint ( " TOPLEFT " , lastObject , " BOTTOMLEFT " , 0 , - 1 ) ;
end
lastObject = button ;
self : IndexGamePadObject ( button ) ;
end
--Options
if not showGossipFirst then
for i , data in ipairs ( options ) do
hotkeyIndex = hotkeyIndex + 1 ;
button = self : AcquireOptionButton ( ) ;
hotkey = KeyboardControl : SetKeyButton ( hotkeyIndex , button ) ;
button : SetGossip ( data , hotkey ) ;
if i == 1 then
local spacing = ( anyQuest and - PARAGRAPH_BUTTON_SPACING ) or - PARAGRAPH_SPACING ;
button : SetPoint ( " TOPLEFT " , lastObject , " BOTTOMLEFT " , 0 , spacing ) ;
else
button : SetPoint ( " TOPLEFT " , lastObject , " BOTTOMLEFT " , 0 , 0 ) ;
end
lastObject = button ;
self : IndexGamePadObject ( button ) ;
end
end
self.AcceptButton : Hide ( ) ;
local GoodbyeButton = self : AcquireExitButton ( ) ;
GoodbyeButton : SetButtonExitGossip ( ) ;
if not ( # options > 0 or anyQuest ) then
--If there is no options, allow pressing SPACE to goodbye
KeyboardControl : SetKeyButton ( " PRIMARY " , GoodbyeButton ) ;
end
local objectHeight = firstObject : GetTop ( ) - lastObject : GetBottom ( ) ;
local contentHeight = fromOffsetY + objectHeight ; --self.ContentFrame:GetTop()
contentHeight = contentHeight + ( hasPreviousGossip and PARAGRAPH_SPACING or 0 ) ; --Compensate for the top divider
self : SetScrollRange ( contentHeight ) ;
if hasPreviousGossip then
local scrollRangeDiff = objectHeight - self.scrollViewHeight + PARAGRAPH_SPACING ;
local extraScroll = 0 ;
if scrollRangeDiff > 0 then
extraScroll = scrollRangeDiff + 2 * PARAGRAPH_SPACING ;
end
local actualRange = Round ( fromOffsetY - PARAGRAPH_SPACING + extraScroll ) ;
self.ScrollFrame . range = actualRange ;
self : SetScrollable ( true ) ;
FadeFrame ( self.ContentFrame , 0.35 , 1 , 0 ) ;
if extraScroll == 0 then
self : ScrollToBottom ( ) ;
else
self : ScrollTo ( fromOffsetY - PARAGRAPH_SPACING ) ;
end
else
self : FadeInContentFrame ( ) ;
end
FriendshipBar : RequestUpdate ( ) ;
return true
end
function DUIDialogBaseMixin : HandleQuestDetail ( playFadeIn )
self : ReleaseAllObjects ( ) ;
self : UseQuestLayout ( true ) ;
local fs , text ;
--Title
local offsetY = self : UpdateQuestTitle ( ) ;
--Detail
text = ConcatenateNPCName ( GetQuestText ( " Detail " ) ) ;
if text then
offsetY = offsetY + PARAGRAPH_SPACING ;
offsetY = self : FormatParagraph ( offsetY , text ) ;
end
--Objectives
local objectiveText = GetObjectiveText ( ) ;
if objectiveText then
--Subtitle: Quest Objectives
offsetY = offsetY + PARAGRAPH_SPACING ;
local subheader = self : AcquireAndSetSubHeader ( L [ " Quest Objectives " ] ) ;
subheader : SetPoint ( " TOPLEFT " , self.ContentFrame , " TOPLEFT " , PADDING_H * FRAME_SIZE_MULTIPLIER , - offsetY ) ;
offsetY = Round ( offsetY + subheader.size ) ;
--Objective Texts
offsetY = self : FormatParagraph ( offsetY , objectiveText ) ;
local groupNum = GetSuggestedGroupSize ( ) ;
if groupNum and groupNum > 0 then
local groupText = L [ " Format Suggested Players " ] : format ( groupNum ) ;
offsetY = self : InsertParagraph ( offsetY , groupText ) ;
end
end
--Model
local portraitDisplayID , questPortraitText , questPortraitName , mountPortraitDisplayID , portraitModelSceneID = GetQuestPortraitGiver ( ) ;
--debug portrait
--portraitDisplayID = 115995;
--questPortraitName = "King Anduin Wrynn Pam Testing Long";
if portraitDisplayID then
if portraitDisplayID == - 1 then
--player
elseif portraitDisplayID > 0 then
self.FrontFrame . QuestPortrait : SetPortrait ( portraitDisplayID , questPortraitName ) ;
end
if questPortraitText and questPortraitText ~= " " and questPortraitText ~= objectiveText then
offsetY = self : InsertParagraph ( offsetY , questPortraitText ) ;
end
else
self.FrontFrame . QuestPortrait : FadeOut ( ) ;
end
--Rewards
local rewardList ;
rewardList , self.chooseItems = addon.BuildRewardList ( ) ;
if rewardList and # rewardList > 0 then
self : RegisterEvent ( " QUEST_ITEM_UPDATE " ) ;
offsetY = offsetY + PARAGRAPH_SPACING ;
local subheader = self : AcquireAndSetSubHeader ( ( # rewardList == 1 and L [ " Reward " ] ) or L [ " Rewards " ] ) ;
subheader : SetPoint ( " TOPLEFT " , self.ContentFrame , " TOPLEFT " , PADDING_H * FRAME_SIZE_MULTIPLIER , - offsetY ) ;
offsetY = Round ( offsetY + subheader.size ) ;
offsetY = self : FormatRewards ( offsetY , rewardList ) ;
end
self : SetScrollRange ( offsetY ) ;
local AcceptButton = self : AcquireAcceptButton ( true ) ;
local ExitButton = self : AcquireExitButton ( ) ;
if API.IsQuestAutoAccepted ( ) then
AcceptButton : SetButtonAlreadyOnQuest ( ) ;
ExitButton : SetButtonCloseAutoAcceptQuest ( ) ;
self.acknowledgeAutoAcceptQuest = true ;
else
AcceptButton : SetButtonAcceptQuest ( ) ;
ExitButton : SetButtonDeclineQuest ( self.questIsFromGossip ) ;
end
self.questIsFromGossip = nil ;
if playFadeIn then
self : FadeInContentFrame ( ) ;
end
return true
end
function DUIDialogBaseMixin : HandleQuestAccepted ( questID )
--QUEST_ACCEPTED
if self.handler == " HandleQuestDetail " then
local currentQuestID = GetQuestID ( ) ;
if currentQuestID and currentQuestID ~= 0 and currentQuestID == questID then
local AcceptButton = self : AcquireAcceptButton ( true ) ;
local ExitButton = self : AcquireExitButton ( ) ;
AcceptButton : SetButtonAlreadyOnQuest ( ) ;
ExitButton : SetButtonCloseAutoAcceptQuest ( ) ;
--local title = C_QuestLog.GetTitleForQuestID(questID);
--print(questID, title)
end
end
end
local function CalulateLockDuration ( rawCopper )
if ( not rawCopper ) or ( rawCopper <= 0 ) then
return 1
end
local playerMoney = GetMoney ( ) ;
if playerMoney <= 0 then
playerMoney = 1
end
if ( rawCopper > 5000000 ) or ( rawCopper / playerMoney ) > 0.05 then --500G or 5% of max money
return 4
else
return 1
end
end
function DUIDialogBaseMixin : HandleQuestProgress ( playFadeIn )
self : ReleaseAllObjects ( ) ;
self : UseQuestLayout ( true ) ;
--Title
local offsetY = self : UpdateQuestTitle ( ) ;
--Progress
local text = ConcatenateNPCName ( GetQuestText ( " Progress " ) ) ;
if text then
offsetY = offsetY + PARAGRAPH_SPACING ;
offsetY = self : FormatParagraph ( offsetY , text ) ;
end
--Required Items
local numRequiredItems = GetNumQuestItems ( ) ;
local numRequiredCurrencies = GetNumQuestCurrencies ( ) ;
local numRequiredMoney = GetQuestMoneyToGet ( ) ;
local lockDuration ; --Lock "Continue" if the quest costs gold
if numRequiredItems > 0 or numRequiredMoney > 0 or numRequiredCurrencies > 0 then
-- If there's money required then anchor and display it
if numRequiredMoney > 0 then
lockDuration = CalulateLockDuration ( numRequiredMoney ) ;
offsetY = offsetY + PARAGRAPH_SPACING ;
local subheader = self : AcquireAndSetSubHeader ( L [ " Costs " ] ) ;
subheader : SetPoint ( " TOPLEFT " , self.ContentFrame , " TOPLEFT " , PADDING_H * FRAME_SIZE_MULTIPLIER , - offsetY ) ;
offsetY = Round ( offsetY + subheader.size ) ;
local itemList = {
{ " SetRequiredMoney " , numRequiredMoney , small = true }
} ;
offsetY = self : FormatRewards ( offsetY , itemList ) ;
end
local itemList = { } ;
local actualNumRequiredItems = 0 ;
for index = 1 , numRequiredItems do
local hidden = IsQuestItemHidden ( index ) ;
if hidden == 0 then
table.insert ( itemList , { " SetRequiredItem " , index } ) ;
actualNumRequiredItems = actualNumRequiredItems + 1 ;
end
end
-- Show the "Required Items" text if needed.
local anyActualItems = ( actualNumRequiredItems + numRequiredCurrencies > 0 ) ;
if anyActualItems then
offsetY = offsetY + PARAGRAPH_SPACING ;
local subheader = self : AcquireAndSetSubHeader ( L [ " Requirements " ] ) ;
subheader : SetPoint ( " TOPLEFT " , self.ContentFrame , " TOPLEFT " , PADDING_H * FRAME_SIZE_MULTIPLIER , - offsetY ) ;
offsetY = Round ( offsetY + subheader.size ) ;
end
for index = 1 , numRequiredCurrencies do
table.insert ( itemList , { " SetRequiredCurrency " , index } ) ;
end
offsetY = self : FormatRewards ( offsetY , itemList ) ;
end
local canComplete = IsQuestCompletable ( ) ;
local ContinueButton = self : AcquireAcceptButton ( canComplete ) ;
ContinueButton : SetButtonContinueQuest ( canComplete , lockDuration ) ;
local CancelButton = self : AcquireExitButton ( ) ;
CancelButton : SetButtonCancelQuestProgress ( self.questIsFromGossip ) ;
self.questIsFromGossip = nil ;
if not canComplete then
KeyboardControl : SetKeyButton ( " PRIMARY " , CancelButton ) ;
end
self : SetScrollRange ( offsetY ) ;
if playFadeIn then
self : FadeInContentFrame ( ) ;
end
return true
end
function DUIDialogBaseMixin : IsRewardChosen ( )
local numRewardChoices = GetNumQuestChoices ( ) or 0 ;
local choiceID = self.rewardChoiceID ;
return numRewardChoices <= 1 or ( choiceID ~= nil ) ;
end
function DUIDialogBaseMixin : HandleQuestComplete ( playFadeIn )
self : ReleaseAllObjects ( ) ;
self : UseQuestLayout ( true ) ;
--Title
local offsetY = self : UpdateQuestTitle ( ) ;
--Progress
local text = ConcatenateNPCName ( GetQuestText ( " Complete " ) ) ;
if text then
offsetY = offsetY + PARAGRAPH_SPACING ;
offsetY = self : FormatParagraph ( offsetY , text ) ;
end
--Rewards
self.rewardChoiceID = nil ;
local questComplete = true ;
local rewardList ;
rewardList , self.chooseItems = addon.BuildRewardList ( questComplete ) ;
if rewardList and # rewardList > 0 then
self : RegisterEvent ( " QUEST_ITEM_UPDATE " ) ;
offsetY = offsetY + PARAGRAPH_SPACING ;
local subheader = self : AcquireAndSetSubHeader ( ( # rewardList == 1 and L [ " Reward " ] ) or L [ " Rewards " ] ) ;
subheader : SetPoint ( " TOPLEFT " , self.ContentFrame , " TOPLEFT " , PADDING_H * FRAME_SIZE_MULTIPLIER , - offsetY ) ;
offsetY = Round ( offsetY + subheader.size ) ;
offsetY = self : FormatRewards ( offsetY , rewardList ) ;
end
local CompleteButton = self : AcquireAcceptButton ( true ) ;
CompleteButton : SetButtonCompleteQuest ( ) ;
local CancelButton = self : AcquireExitButton ( ) ;
CancelButton : SetButtonCancelQuestProgress ( ) ;
self : SetScrollRange ( offsetY ) ;
if playFadeIn then
self : FadeInContentFrame ( ) ;
end
return true
end
local function SortFunc_QuestGreetingActiveQuests ( a , b )
if a.isComplete == b.isComplete then
return a.index < b.index
else
return a.isComplete
end
end
function DUIDialogBaseMixin : HandleQuestGreeting ( )
self : ReleaseAllObjects ( ) ;
self : UseQuestLayout ( false ) ;
local offsetY = 0 ;
local firstObject , lastObject ;
--local material = QuestFrame_GetMaterial();
local geetingText = ConcatenateNPCName ( GetQuestText ( " Greeting " ) ) ;
offsetY , firstObject , lastObject = self : FormatParagraph ( offsetY , geetingText ) ;
local questIndex = 0 ;
local quests = { } ;
self.activeQuestButtons = { } ;
local numAvailableQuests = GetNumAvailableQuests ( ) ;
for i = 1 , numAvailableQuests do
questIndex = questIndex + 1 ;
local title = GetAvailableTitle ( i ) ;
local isTrivial , frequency , isRepeatable , isLegendary , questID = GetAvailableQuestInfo ( i ) ;
local questInfo = {
index = i ,
title = title ,
questID = questID ,
isOnQuest = false ,
isTrivial = isTrivial ,
frequency = frequency ,
repeatable = isRepeatable ,
isLegendary = isLegendary ,
isAvailableQuest = true ,
originalOrder = questIndex ;
--isImportant
} ;
quests [ questIndex ] = questInfo ;
end
local numActiveQuests = GetNumActiveQuests ( ) ;
for i = 1 , numActiveQuests do
questIndex = questIndex + 1 ;
local title , isComplete = GetActiveTitle ( i ) ;
local questID = GetActiveQuestID ( i ) ;
local questInfo = {
index = i ,
title = title ,
isComplete = isComplete ,
questID = questID ,
isAvailableQuest = false ,
isOnQuest = true ,
originalOrder = questIndex ,
} ;
quests [ questIndex ] = questInfo ;
end
tsort ( quests , SortFunc_PrioritizeCompleteQuest ) ;
local lastQuestComplete , lastQuestAvailable ;
local hotkeyIndex = 0 ;
local hotkey ;
local button ;
for i , questInfo in ipairs ( quests ) do
hotkeyIndex = hotkeyIndex + 1 ;
button = self : AcquireOptionButton ( ) ;
hotkey = KeyboardControl : SetKeyButton ( hotkeyIndex , button ) ;
if questInfo.isAvailableQuest then
button : SetGreetingAvailableQuest ( questInfo , questInfo.index , hotkey ) ;
else
button : SetGreetingActiveQuest ( questInfo , questInfo.index , hotkey ) ;
tinsert ( self.activeQuestButtons , button ) ;
end
if i == 1 or ( questInfo.isAvailableQuest ~= lastQuestAvailable ) or ( questInfo.isComplete ~= lastQuestComplete ) then
button : SetPoint ( " TOPLEFT " , lastObject , " BOTTOMLEFT " , 0 , - PARAGRAPH_BUTTON_SPACING ) ;
lastQuestAvailable = questInfo.isAvailableQuest ;
lastQuestComplete = questInfo.isComplete ;
else
button : SetPoint ( " TOPLEFT " , lastObject , " BOTTOMLEFT " , 0 , - 1 ) ;
end
lastObject = button ;
self : IndexGamePadObject ( button ) ;
end
self.AcceptButton : Hide ( ) ;
local GoodbyeButton = self : AcquireExitButton ( ) ;
GoodbyeButton : SetButtonExitGossip ( ) ;
local contentHeight = firstObject : GetTop ( ) - lastObject : GetBottom ( ) ;
self : SetScrollRange ( contentHeight ) ;
self.numAvailableQuests = numAvailableQuests ;
return true
end
function DUIDialogBaseMixin : GetQuestFinishedDelay ( )
if ( self.numAvailableQuests and self.numAvailableQuests > 1 ) or QuestIsFromAreaTrigger ( ) then
return 0.5
else
return 0.03
end
end
function DUIDialogBaseMixin : UpdateGossipQuests ( )
if self.activeQuestButtons then
local activeQuests = GetActiveQuests ( ) ;
for i , questInfo in ipairs ( activeQuests ) do
questInfo.isOnQuest = true ;
questInfo.originalOrder = i ;
end
tsort ( activeQuests , SortFunc_PrioritizeCompleteQuest ) ;
for i , activeQuestButton in ipairs ( self.activeQuestButtons ) do
if activeQuests [ i ] and ( activeQuestButton.questID == activeQuests [ i ] . questID ) then
activeQuestButton : SetQuestVisual ( activeQuests [ i ] ) ;
end
end
end
end
function DUIDialogBaseMixin : HandleGossipConfirm ( gossipID , warningText , cost )
self.hasActiveGossipQuests = false ;
self.numAvailableQuests = 0 ;
self.keepGossipHistory = false ;
self.requireGossipConfirm = true ;
self : ReleaseAllObjects ( ) ;
self : UseQuestLayout ( false ) ;
local offsetY = 0 ;
warningText = ThemeUtil : AdjustTextColor ( warningText ) ;
offsetY = self : FormatParagraph ( offsetY , warningText ) ;
local lockDuration = CalulateLockDuration ( cost ) ;
if cost and cost > 0 then
offsetY = offsetY + PARAGRAPH_SPACING ;
local subheader = self : AcquireAndSetSubHeader ( L [ " Costs " ] ) ;
subheader : SetPoint ( " TOPLEFT " , self.ContentFrame , " TOPLEFT " , PADDING_H * FRAME_SIZE_MULTIPLIER , - offsetY ) ;
offsetY = Round ( offsetY + subheader.size ) ;
local itemList = {
{ " SetRequiredMoney " , cost , small = true }
} ;
offsetY = self : FormatRewards ( offsetY , itemList ) ;
end
local AcceptButton = self : AcquireAcceptButton ( true ) ;
AcceptButton : SetButtonConfirmGossip ( gossipID , lockDuration ) ;
local CancelButton = self : AcquireExitButton ( ) ;
CancelButton : SetButtonCancelConfirmGossip ( ) ;
self : SetScrollRange ( offsetY ) ;
FadeFrame ( self.ContentFrame , 0.35 , 1 , 0 ) ;
end
function DUIDialogBaseMixin : HideGossipConfirm ( )
if self : IsShown ( ) and self.requireGossipConfirm and self.handler == " HandleGossip " then
self.requireGossipConfirm = false ;
self.keepGossipHistory = false ;
if API.IsInteractingWithGossip ( ) then
self : HandleGossip ( ) ;
FadeFrame ( self.ContentFrame , 0.35 , 1 , 0 ) ;
end
end
end
function DUIDialogBaseMixin : HandleGossipEnterCode ( gossipID )
self.inputboxShown = true ;
self.InputBox : Show ( ) ;
self.InputBox : SetGossipID ( gossipID ) ;
self.InputBox : SetFocus ( ) ;
FadeFrame ( self.ContentFrame , 0.15 , 0.25 ) ;
FadeFrame ( self.FrontFrame , 0.15 , 0.25 ) ;
end
function DUIDialogBaseMixin : HideInputBox ( )
if self.inputboxShown then
self.InputBox : Hide ( ) ;
FadeFrame ( self.ContentFrame , 0.15 , 1 ) ;
FadeFrame ( self.FrontFrame , 0.15 , 1 ) ;
end
end
local function Predicate_ActiveChoiceButton ( itemButton )
return itemButton.type == " choice " and itemButton : IsShown ( )
end
function DUIDialogBaseMixin : IsChoosingReward ( )
return self.chooseItems == true
end
function DUIDialogBaseMixin : SelectRewardChoice ( choiceID )
if not self.chooseItems then return end ; --Handled in Formatter when building reward choices
local claimQuestReward ;
if INPUT_DEVICE_GAME_PAD then
self.GamePadFocusIndicator : Hide ( ) ;
--Briefly paused in case the button becomes too sensitive and claim the reward by accident
if not API.CheckActionThrottled ( " GamePadChooseQuestReward " ) then
if choiceID == self.rewardChoiceID then
claimQuestReward = true ;
end
end
end
self.rewardChoiceID = choiceID ;
local CompleteButton = self : AcquireAcceptButton ( true ) ;
CompleteButton : SetButtonCompleteQuest ( ) ;
if claimQuestReward and CompleteButton : IsEnabled ( ) then
CompleteButton : Click ( " LeftButton " ) ;
TooltipFrame : HideTooltip ( ) ;
end
local buttons = self.itemButtonPool : GetObjectsByPredicate ( Predicate_ActiveChoiceButton ) ;
for i , button in ipairs ( buttons ) do
if button.index == choiceID then
button : SetBackgroundTexture ( 1 ) ;
FadeFrame ( button , 0.15 , 1 ) ;
else
button : SetBackgroundTexture ( 1 ) ;
FadeFrame ( button , 0.15 , 0.25 ) ;
end
button : UpdateNameColor ( ) ;
end
self.RewardSelection . BackTexture : Hide ( ) ;
return true
end
function DUIDialogBaseMixin : HighlightRewardChoice ( rewardChoiceButton )
self.RewardSelection : Hide ( ) ;
self.RewardSelection : ClearAllPoints ( ) ;
self.GamePadFocusIndicator : Hide ( ) ;
if rewardChoiceButton and self.chooseItems then
self.RewardSelection : SetPoint ( " TOPLEFT " , rewardChoiceButton , " TOPLEFT " , 0 , 0 ) ;
self.RewardSelection : SetPoint ( " BOTTOMRIGHT " , rewardChoiceButton , " BOTTOMRIGHT " , 0 , 0 ) ;
self.RewardSelection : SetParent ( rewardChoiceButton ) ;
self.RewardSelection : SetFrameLevel ( rewardChoiceButton : GetFrameLevel ( ) ) ;
self.RewardSelection . BackTexture : SetShown ( self.rewardChoiceID == nil ) ;
self.RewardSelection : Show ( ) ;
self.GamePadFocusIndicator : ClearAllPoints ( ) ;
self.GamePadFocusIndicator : SetPoint ( " CENTER " , self.RewardSelection , " LEFT " , 0 , 0 ) ;
if INPUT_DEVICE_GAME_PAD then
self : UpdateCompleteButton ( rewardChoiceButton.index == self.rewardChoiceID ) ;
end
end
end
function DUIDialogBaseMixin : FlashRewardChoices ( )
local buttons = self.itemButtonPool : GetObjectsByPredicate ( Predicate_ActiveChoiceButton ) ;
if buttons then
for i , button in ipairs ( buttons ) do
button : PlaySheen ( ) ;
end
end
end
function DUIDialogBaseMixin : RequestSellPrice ( isRequery )
if not GetDBBool ( " MarkHighestSellPrice " ) then return end ;
local numRewardChoices = GetNumQuestChoices ( ) or 0 ;
if numRewardChoices <= 1 then return end ;
local maxPrice = 0 ;
local price , index ;
local anyZero ;
for i = 1 , numRewardChoices do
price = API.GetQuestChoiceSellPrice ( i ) ;
if price == 0 then
anyZero = true ;
end
if price > maxPrice then
maxPrice = price ;
index = i ;
end
end
if ( index and anyZero ) or ( not index ) then
if not isRequery then
After ( 0.8 , function ( )
self : RequestSellPrice ( true ) ;
end ) ;
end
else
local buttons = self.itemButtonPool : GetObjectsByPredicate ( Predicate_ActiveChoiceButton ) ;
if buttons then
for i , button in ipairs ( buttons ) do
if button.index == index then
local iconFrame = self.iconFramePool : Acquire ( ) ;
iconFrame : SetHighestSellPrice ( ) ;
iconFrame : SetParent ( button ) ;
iconFrame : SetPoint ( " CENTER " , button.Icon , " TOPLEFT " , 3 , - 3 ) ;
break
end
end
end
end
end
local ANIM_DURATION_SCROLL_EXPAND = 0.75 ;
local function AnimIntro_SimpleFadeIn_OnUpdate ( self , elapsed )
self.t = self.t + elapsed ;
local height = self.frameHeight ;
local alpha = 5 * self.t ;
if alpha >= 1 then
alpha = 1 ;
self : SetScript ( " OnUpdate " , nil ) ;
self.ContentFrame : SetClipsChildren ( false ) ;
end
self : SetHeight ( height ) ;
self : SetAlpha ( alpha ) ;
end
local function AnimIntro_Unfold_OnUpdate ( self , elapsed )
self.t = self.t + elapsed ;
local height = Esaing_OutSine ( self.t , self.fromHeight , self.frameHeight , ANIM_DURATION_SCROLL_EXPAND ) ;
local alpha = 4 * self.t ;
if alpha > 1 then
alpha = 1 ;
end
if self.t >= ANIM_DURATION_SCROLL_EXPAND then
height = self.frameHeight ;
self : SetScript ( " OnUpdate " , nil ) ;
self.ContentFrame : SetClipsChildren ( false ) ;
end
self : SetHeight ( height ) ;
self : SetAlpha ( alpha ) ;
end
local function AnimIntro_FlyIn_OnUpdate ( self , elapsed )
self.t = self.t + elapsed ;
local offsetX = Esaing_OutSine ( self.t , self.fromOffsetX , self.frameOffsetX , ANIM_DURATION_SCROLL_EXPAND ) ;
local alpha = 4 * self.t ;
local height = self.frameHeight ;
if alpha > 1 then
alpha = 1 ;
end
if self.t >= ANIM_DURATION_SCROLL_EXPAND then
offsetX = self.frameOffsetX ;
self : SetScript ( " OnUpdate " , nil ) ;
self.ContentFrame : SetClipsChildren ( false ) ;
end
self : SetPoint ( " CENTER " , nil , " CENTER " , offsetX , 0 ) ;
self : SetHeight ( height ) ;
self : SetAlpha ( alpha ) ;
end
local ActiveAnimIntro = AnimIntro_SimpleFadeIn_OnUpdate ;
function DUIDialogBaseMixin : PlayIntroAnimation ( )
self.fromHeight = 0.5 * self.frameHeight ;
self.fromOffsetX = self.frameOffsetX + ( ( self.frameOffsetX < 0 and - 72 ) or 72 ) ;
self.t = 0 ;
self.ContentFrame : SetClipsChildren ( true ) ;
self : SetScript ( " OnUpdate " , ActiveAnimIntro ) ;
end
local Handler = {
[ " GOSSIP_SHOW " ] = " HandleGossip " ,
[ " QUEST_DETAIL " ] = " HandleQuestDetail " , --See the details of an available quest
[ " QUEST_PROGRESS " ] = " HandleQuestProgress " , --Show status of a taken quest. "Continue" button
[ " QUEST_COMPLETE " ] = " HandleQuestComplete " , --Show "Complete Quest" button
[ " QUEST_GREETING " ] = " HandleQuestGreeting " , --Similar to GOSSIP_SHOW
} ;
function DUIDialogBaseMixin : ShowUI ( event )
if self.isGameLoading then
self.deferredEvent = event ;
return
end
if IsPlayingCutscene ( ) then
--For case: triggering cutscene when accepting quest and the quest is immediately flagged as complete
self : Hide ( ) ;
self : CloseDialogInteraction ( ) ;
return
end
local shouldShowUI ;
if Handler [ event ] then
self.handler = Handler [ event ] ;
local playFadeIn = true ;
shouldShowUI = self [ Handler [ event ] ] ( self , playFadeIn ) ;
end
if not shouldShowUI then return end ;
if not self : IsShown ( ) then
CameraUtil : InitiateInteraction ( ) ;
self : PlayIntroAnimation ( ) ;
self : OnEvent ( event ) ;
end
self : Show ( ) ;
self.hasInteraction = true ;
CallbackRegistry : Trigger ( " DialogueUI.HandleEvent " , event ) ;
end
function DUIDialogBaseMixin : HideUI ( cancelPopupFirst )
if not self : IsShown ( ) then return end ;
if cancelPopupFirst and self.requireGossipConfirm then
self : OnEvent ( " GOSSIP_CONFIRM_CANCEL " ) ;
return
end
self : Hide ( ) ;
end
function DUIDialogBaseMixin : OnShow ( )
KeyboardControl : SetParentFrame ( self ) ;
self : RegisterEvent ( " GOSSIP_SHOW " ) ;
self : RegisterEvent ( " GOSSIP_CLOSED " ) ;
self : RegisterEvent ( " GOSSIP_CONFIRM " ) ;
self : RegisterEvent ( " GOSSIP_ENTER_CODE " ) ;
self : RegisterEvent ( " QUEST_LOG_UPDATE " ) ;
self : RegisterEvent ( " QUEST_FINISHED " ) ;
self : RegisterEvent ( " QUEST_ACCEPTED " ) ;
self : RegisterEvent ( " PLAYER_REGEN_DISABLED " ) ;
self : RegisterEvent ( " LOADING_SCREEN_ENABLED " ) ;
self : RegisterEvent ( " ADVENTURE_MAP_OPEN " ) ;
if IS_MODERN_WOW then
self : RegisterEvent ( " PLAYER_CHOICE_UPDATE " ) ; --Watch TRAIT_SYSTEM_INTERACTION_STARTED
end
FadeFrame ( self.Vignette , 0.75 , 1 ) ;
CallbackRegistry : Trigger ( " DialogueUI.Show " ) ;
end
function DUIDialogBaseMixin : CloseDialogInteraction ( )
CloseQuest ( ) ;
CloseGossipInteraction ( ) ;
--Classic:
--HideUI will cause ClassTrainerFrame to not processing events (Blizzard_TrainerUI/Blizzard_TrainerUI.lua#72)
end
function DUIDialogBaseMixin : SetInteractionIsContinuing ( interactionIsContinuing )
--Not used
self.interactionIsContinuing = true ; --?
end
function DUIDialogBaseMixin : OnHide ( )
CameraUtil : Restore ( ) ;
self : CloseDialogInteraction ( ) ;
self.keepGossipHistory = false ;
self.requireGossipConfirm = false ;
self.selectedGossipIndex = nil ;
self.consumeGossipClose = nil ;
self.questIsFromGossip = nil ;
self.chooseItems = nil ;
self.handler = nil ;
self.contentHeight = 0 ;
self : UnregisterEvent ( " GOSSIP_SHOW " ) ;
self : UnregisterEvent ( " GOSSIP_CLOSED " ) ;
self : UnregisterEvent ( " GOSSIP_CONFIRM " ) ;
self : UnregisterEvent ( " GOSSIP_CONFIRM_CANCEL " ) ;
self : UnregisterEvent ( " GOSSIP_ENTER_CODE " ) ;
self : UnregisterEvent ( " QUEST_ITEM_UPDATE " ) ;
self : UnregisterEvent ( " QUEST_LOG_UPDATE " ) ;
self : UnregisterEvent ( " QUEST_FINISHED " ) ;
self : UnregisterEvent ( " QUEST_ACCEPTED " ) ;
self : UnregisterEvent ( " PLAYER_REGEN_DISABLED " ) ;
self : UnregisterEvent ( " LOADING_SCREEN_ENABLED " ) ;
self : UnregisterEvent ( " ADVENTURE_MAP_OPEN " ) ;
if IS_MODERN_WOW then
self : UnregisterEvent ( " PLAYER_CHOICE_UPDATE " ) ;
end
self : ReleaseAllObjects ( ) ;
self : HideInputBox ( ) ;
FadeFrame ( self.Vignette , 0.5 , 0 ) ;
TooltipFrame : Hide ( ) ;
CallbackRegistry : Trigger ( " DialogueUI.Hide " ) ;
if self.acknowledgeAutoAcceptQuest then
self.acknowledgeAutoAcceptQuest = nil ;
AcknowledgeAutoAcceptQuest ( ) ;
end
end
function DUIDialogBaseMixin : OnMouseUp ( button )
if button == " RightButton " and GetDBBool ( " RightClickToCloseUI " ) then
self : CloseDialogInteraction ( ) ;
end
end
function DUIDialogBaseMixin : OnMouseWheel ( delta )
self.ScrollFrame : OnMouseWheel ( delta ) ;
end
function DUIDialogBaseMixin : HighlightButton ( optionButton )
if optionButton and optionButton == self.highlightedButton then
return true
end
self.ButtonHighlight : ClearAllPoints ( ) ;
if optionButton and optionButton : IsEnabled ( ) and ( optionButton.artID ~= 3 ) then -- artID = 3 (Hollow, auto accepted quest)
optionButton : SetParentHighlightTexture ( self.ButtonHighlight ) ;
else
self.ButtonHighlight : Hide ( ) ;
end
self.highlightedButton = optionButton ;
if optionButton and optionButton.gamepadIndex then
self : SetGamePadFocusIndex ( optionButton.gamepadIndex ) ;
self.GamePadFocusIndicator : ClearAllPoints ( ) ;
self.GamePadFocusIndicator : SetPoint ( " CENTER " , optionButton , " LEFT " , 0 , 0 ) ;
self.GamePadFocusIndicator : Show ( ) ;
else
self.GamePadFocusIndicator : Hide ( ) ;
end
end
function DUIDialogBaseMixin : UpdateRewards ( )
if self.questLayout and self.handler then
--New items might appear after "QUEST_ITEM_UPDATE"
--self.itemButtonPool:CallActive("Refresh");
if not self.rewardUpdator then
self.rewardUpdator = CreateFrame ( " Frame " , self ) ;
self.rewardUpdator : SetScript ( " OnHide " , function ( f )
f : Hide ( ) ;
end ) ;
end
local function UpdateRewards_OnUpdate ( f , elapsed )
f.t = f.t + elapsed ;
if f.t > 0.5 then
f.t = nil ;
f : SetScript ( " OnUpdate " , nil ) ;
if self.questLayout and self.handler then
self [ self.handler ] ( self ) ;
end
end
end
self.rewardUpdator . t = 0 ;
self.rewardUpdator : SetScript ( " OnUpdate " , UpdateRewards_OnUpdate ) ;
self.rewardUpdator : Show ( ) ;
end
end
function DUIDialogBaseMixin : OnEvent ( event , ... )
if event == " QUEST_ITEM_UPDATE " then
self : UpdateRewards ( ) ;
elseif event == " GOSSIP_SHOW " then
self.keepGossipHistory = true ;
elseif event == " GOSSIP_CLOSED " then
self.keepGossipHistory = false ;
self.selectedGossipIndex = nil ;
elseif event == " QUEST_ACCEPTED " then
local questID = ...
self : HandleQuestAccepted ( questID ) ;
elseif event == " QUEST_LOG_UPDATE " then
if self.hasActiveGossipQuests then
self.keepGossipHistory = false ;
self : UpdateGossipQuests ( ) ;
elseif self.handler == " HandleQuestGreeting " then
self : HandleQuestGreeting ( ) ;
end
elseif event == " QUEST_FINISHED " then
self.keepGossipHistory = false ;
elseif event == " PLAYER_REGEN_DISABLED " then
if self : IsShown ( ) then
CameraUtil : OnEnterCombatDuringInteraction ( ) ;
end
elseif event == " GOSSIP_CONFIRM " then
local gossipID , text , cost = ...
self : RegisterEvent ( " GOSSIP_CONFIRM_CANCEL " ) ;
self : HandleGossipConfirm ( gossipID , text , cost ) ;
elseif event == " GOSSIP_CONFIRM_CANCEL " then
self : UnregisterEvent ( event ) ;
self : HideGossipConfirm ( ) ;
elseif event == " GOSSIP_ENTER_CODE " then
local gossipID = ...
self : HandleGossipEnterCode ( gossipID ) ;
elseif event == " LOADING_SCREEN_ENABLED " then
self : HideUI ( ) ;
elseif event == " ADVENTURE_MAP_OPEN " then
CallbackRegistry : Trigger ( " PlayerInteraction.ShowUI " , true ) ;
elseif event == " LOADING_SCREEN_DISABLED " then --not reliable on the intial login
self : UnregisterEvent ( event ) ;
C_Timer.After ( 4 , function ( )
self.isGameLoading = nil ;
self : HandleInitialLoadingComplete ( ) ;
end ) ;
elseif event == " PLAYER_CHOICE_UPDATE " then
--TWW: Show Weekly Quest Selection
self : UnregisterEvent ( event ) ;
self : CloseDialogInteraction ( ) ;
self : HideUI ( ) ;
end
end
function DUIDialogBaseMixin : SetConsumeGossipClose ( state )
--Event Sequence when selecting a quest from GossipFrame
--1.GOSSIP_CLOSE
--2.QUEST_DETAIL
if state then
if not self.consumeGossipClose then
self.consumeGossipClose = true ;
After ( 0.8 , function ( )
self.consumeGossipClose = nil ;
end ) ;
end
else
self.consumeGossipClose = nil ;
end
end
function DUIDialogBaseMixin : MarkQuestIsFromGossip ( )
--if the quest is from gossip, clicking Decline button will return user to previous dialog
self.questIsFromGossip = true ;
end
function DUIDialogBaseMixin : IsGossipCloseConsumed ( )
if self.consumeGossipClose then
self.consumeGossipClose = nil ;
return true
else
return false
end
end
function DUIDialogBaseMixin : ScrollDownOrAcceptQuest ( fromMouseClick )
if SCROLLDOWN_THEN_ACCEPT_QUEST and not fromMouseClick then
if not self : IsScrollAtBottom ( ) then
self : ScrollToBottom ( ) ;
local noFeedback = true ;
return noFeedback
end
end
self : SetAcceptCurrentQuest ( ) ; --For showing "Quest Accepted" banner
if self.acknowledgeAutoAcceptQuest then
self.acknowledgeAutoAcceptQuest = nil ;
AcknowledgeAutoAcceptQuest ( ) ;
else
AcceptQuest ( ) ;
end
end
do --Clipboard
local strjoin = strjoin ;
local function JoinText ( ... )
return strjoin ( " \n " , ... ) ;
end
local function ConcatenateQuestTable ( quests )
local title , questID , text ;
local str = " \n " ;
local idFormat = " [Quest: %d] %s " ;
for i , questInfo in ipairs ( quests ) do
text = idFormat : format ( questInfo.questID , questInfo.title ) ;
str = JoinText ( str , text ) ;
end
return str
end
local function ConcatenateOptionTable ( options )
local title , questID , text , name ;
local str = " \n " ;
local idFormat = " [OptionID: %d] %s " ;
for i , data in ipairs ( options ) do
name = data.name ;
if data.flags == 1 then
name = " (Quest) " .. name ;
end
text = idFormat : format ( data.gossipOptionID , name ) ;
str = JoinText ( str , text ) ;
end
return str
end
local function ConcatenateQuestIDTitle ( previousText )
local questID = GetQuestID ( ) ;
local title = GetQuestTitle ( ) ;
local idFormat = " [Quest: %d] %s " ;
if questID and questID ~= 0 then
local text = idFormat : format ( questID , title ) ;
if previousText then
previousText = JoinText ( previousText , text ) ;
else
previousText = text ;
end
end
return previousText
end
local function ConcatenateQuestItems ( sourceType , numItems )
local GetQuestItemInfo = GetQuestItemInfo ;
local str = " " ;
local idFormat = " [ItemID: %d] %s " ;
for index = 1 , numItems do
local hidden = IsQuestItemHidden ( index ) ;
if hidden == 0 then
local name , texture , count , quality , isUsable , itemID = GetQuestItemInfo ( sourceType , index ) ;
local text = idFormat : format ( itemID , name ) ;
if count and count > 1 then
text = text .. " x " .. count ;
end
str = JoinText ( str , text ) ;
end
end
return str
end
local function ConcatenateCurrencies ( sourceType , numCurrencies )
local GetQuestCurrency = API.GetQuestCurrency ;
local str = " " ;
local idFormat = " [CurrencyID: %d] %s " ;
for index = 1 , numCurrencies do
local currencyInfo = GetQuestCurrency ( sourceType , index ) ;
local name , amount , currencyID = currencyInfo.name , currencyInfo.duiDisplayedAmount , currencyInfo.currencyID ;
local text = idFormat : format ( currencyID , name ) ;
if amount and amount > 1 then
text = text .. " x " .. amount ;
end
str = JoinText ( str , text ) ;
end
return str
end
local function ConcatenateRewards ( previousText )
local anyRewards ;
local function AddItemText ( itemButton )
local text = itemButton : GetClipboardOutput ( ) ;
if text then
if not anyRewards then
anyRewards = true ;
previousText = JoinText ( previousText , " " , L [ " Rewards " ] , " " ) ;
end
previousText = JoinText ( previousText , text ) ;
end
end
MainFrame.itemButtonPool : ProcessActiveObjects ( AddItemText ) ;
MainFrame.smallItemButtonPool : ProcessActiveObjects ( AddItemText ) ;
return previousText
end
function DUIDialogBaseMixin : GetContentForTTS ( )
local content = { } ;
local GetGossipText = API.GetGossipText ;
local GetQuestText = API.GetQuestText ;
local npcName , npcID = API.GetCurrentNPCInfo ( ) ;
if npcName and npcID then
content.speaker = npcName ;
end
local questID = GetQuestID ( ) ;
if questID and questID ~= 0 then
content.title = GetQuestTitle ( ) ;
end
if self.handler == " HandleGossip " then
content.body = GetGossipText ( ) ;
elseif self.handler == " HandleQuestDetail " then
content.body = GetQuestText ( " Detail " ) ;
local objective = GetObjectiveText ( ) ;
if objective and objective ~= " " then
content.objective = JoinText ( L [ " Quest Objectives " ] , " " , objective ) ;
end
elseif self.handler == " HandleQuestProgress " then
content.body = GetQuestText ( " Progress " ) ;
elseif self.handler == " HandleQuestComplete " then
content.body = GetQuestText ( " Complete " ) ;
elseif self.handler == " HandleQuestGreeting " then
content.body = GetQuestText ( " Greeting " ) ;
end
return content
end
function DUIDialogBaseMixin : GetContentForClipboard ( )
local str ;
local GetGossipText = API.GetGossipText ;
local GetQuestText = API.GetQuestText ;
local npcName , npcID = API.GetCurrentNPCInfo ( ) ;
if npcName and npcID then
local idFormat = " [NPC: %d] %s " ;
str = idFormat : format ( npcID , npcName ) ;
end
if self.handler == " HandleGossip " then
local gossipText = GetGossipText ( ) ;
if str then
str = JoinText ( str , gossipText ) ;
else
str = gossipText ;
end
local availableQuests = GetAvailableQuests ( ) ;
local activeQuests = GetActiveQuests ( ) ;
local options = GetOptions ( ) ;
tsort ( options , SortFunc_GossipOrder ) ;
if # availableQuests > 0 then
str = str .. ConcatenateQuestTable ( availableQuests ) ;
end
if # activeQuests > 0 then
str = str .. ConcatenateQuestTable ( activeQuests ) ;
end
if # options > 0 then
str = str .. ConcatenateOptionTable ( options ) ;
end
elseif self.handler == " HandleQuestDetail " then
str = ConcatenateQuestIDTitle ( str ) ;
str = JoinText ( str , " " , GetQuestText ( " Detail " ) ) ;
local objective = GetObjectiveText ( ) ;
if objective and objective ~= " " then
str = JoinText ( str , " " , L [ " Quest Objectives " ] , " " , objective ) ;
end
str = ConcatenateRewards ( str ) ;
elseif self.handler == " HandleQuestProgress " then
str = ConcatenateQuestIDTitle ( str ) ;
str = JoinText ( str , " " , GetQuestText ( " Progress " ) ) ;
local numRequiredItems = GetNumQuestItems ( ) ;
local numRequiredCurrencies = GetNumQuestCurrencies ( ) ;
local numRequiredMoney = GetQuestMoneyToGet ( ) ;
if numRequiredItems > 0 or numRequiredMoney > 0 or numRequiredCurrencies > 0 then
str = JoinText ( str , " " , L [ " Requirements " ] ) ;
if numRequiredMoney > 0 then
local colorized = false ;
local noAbbreviation = true ;
local moneyText = API.GenerateMoneyText ( numRequiredMoney , colorized , noAbbreviation ) ;
str = JoinText ( str , moneyText ) ;
end
if numRequiredItems > 0 then
str = JoinText ( str , ConcatenateQuestItems ( " required " , numRequiredItems ) ) ;
end
if numRequiredCurrencies > 0 then
str = JoinText ( str , ConcatenateCurrencies ( " required " , numRequiredCurrencies ) ) ;
end
end
elseif self.handler == " HandleQuestComplete " then
str = ConcatenateQuestIDTitle ( str ) ;
str = JoinText ( str , " " , GetQuestText ( " Complete " ) ) ;
str = ConcatenateRewards ( str ) ;
elseif self.handler == " HandleQuestGreeting " then
str = ConcatenateQuestIDTitle ( str ) ;
str = JoinText ( str , " " , GetQuestText ( " Greeting " ) ) ;
local numAvailableQuests = GetNumAvailableQuests ( ) ;
local availableQuests = { } ;
for i = 1 , numAvailableQuests do
local title = GetAvailableTitle ( i ) ;
local isTrivial , frequency , isRepeatable , isLegendary , questID = GetAvailableQuestInfo ( i ) ;
local questInfo = {
title = title ,
questID = questID ,
} ;
tinsert ( availableQuests , questInfo ) ;
end
if numAvailableQuests > 0 then
str = str .. ConcatenateQuestTable ( availableQuests ) ;
end
local numActiveQuests = GetNumActiveQuests ( ) ;
local activeQuests = { } ;
for i = 1 , numActiveQuests do
local title , isComplete = GetActiveTitle ( i ) ;
local questID = GetActiveQuestID ( i ) ;
local questInfo = {
title = title ,
questID = questID ,
} ;
tinsert ( activeQuests , questInfo ) ;
end
if numActiveQuests > 0 then
str = str .. ConcatenateQuestTable ( activeQuests ) ;
end
end
return str
end
function DUIDialogBaseMixin : SendContentToClipboard ( )
local str = self : GetContentForClipboard ( ) ;
if str then
if StripHyperlinks then
--We remove the atlas/texture since it messes up spacing
local maintainColor = true ;
local maintainBrackets = true ;
str = StripHyperlinks ( str , true , true ) ;
end
addon.Clipboard : ShowContent ( str , self.CopyTextButton ) ;
end
end
end
do --Quest Rewards
local ITEM_BUTTON_SPACING = 8 ;
local GridLayout = API.CreateGridLayout ( ) ;
GridLayout : SetGrid ( 4 , 2 ) ;
GridLayout : SetSpacing ( 8 ) ;
local GetQuestItemInfoLootType = API.GetQuestItemInfoLootType ;
function DUIDialogBaseMixin : FormatRewards ( offsetY , rewardList )
-- 4 x 2 Grid Layout:
-- ItemButton: 2x2
-- SmallItemButton: 1x1
local baseOffsetX = PADDING_H * FRAME_SIZE_MULTIPLIER ;
local chooseItems = self.chooseItems ;
local itemButtonWidth = self.halfFrameWidth ;
local itemButtonHeight = 36 ;
local gridWidth = self.quarterFrameWidth ;
local smallItemButtonHeight = 15 ;
local sizeX , sizeY ;
GridLayout : ResetGrid ( ) ;
GridLayout : SetGridSize ( self.quarterFrameWidth , smallItemButtonHeight ) ;
for i , data in ipairs ( rewardList ) do
local object ;
local actualSizeX ;
if i == 1 and data.isRewardChoices then
--One choice reward has been processed
local sourceType = " choice " ;
local onlyChoice = false ;
local numChoices = data.numChoices ;
local offsetX = 0 ;
local backgroundID ;
sizeX = ( INPUT_DEVICE_GAME_PAD and 4 ) or 2 ;
local isChoosingReward = data.chooseItems ;
if isChoosingReward then
backgroundID = 2 ;
offsetY = self : InsertText ( offsetY , REWARD_CHOOSE ) ; --Choose
else
backgroundID = 1 ;
offsetY = self : InsertText ( offsetY , REWARD_CHOICES ) ; --Will be able to choose
end
offsetY = offsetY + ITEM_BUTTON_SPACING ;
local fromOffsetY = offsetY ;
for orderIndex = 1 , numChoices do
object = self.itemButtonPool : Acquire ( ) ;
object : SetBaseGridSize ( sizeX , gridWidth , ITEM_BUTTON_SPACING ) ;
object : SetBackgroundTexture ( backgroundID ) ;
local lootType = GetQuestItemInfoLootType ( sourceType , orderIndex ) ;
if ( lootType == 0 ) then -- LOOT_LIST_ITEM
object : SetRewardChoiceItem ( orderIndex , onlyChoice ) ;
elseif ( lootType == 1 ) then -- LOOT_LIST_CURRENCY
object : SetRewardChoiceCurrency ( orderIndex , onlyChoice ) ;
end
object : SetPoint ( " TOPLEFT " , self.ContentFrame , " TOPLEFT " , baseOffsetX + offsetX , - offsetY ) ;
offsetX = offsetX + 2 * gridWidth + 2 * ITEM_BUTTON_SPACING ;
if INPUT_DEVICE_GAME_PAD or orderIndex % 2 == 0 then
offsetY = offsetY + itemButtonHeight + ITEM_BUTTON_SPACING ;
offsetX = 0 ;
end
if chooseItems then
self : IndexGamePadObject ( object ) ;
end
end
local numRows = ( INPUT_DEVICE_GAME_PAD and numChoices ) or math.ceil ( numChoices / 2 ) ;
offsetY = fromOffsetY + ( itemButtonHeight + ITEM_BUTTON_SPACING ) * numRows - ITEM_BUTTON_SPACING ;
offsetY = offsetY + PARAGRAPH_SPACING ;
if # rewardList > 1 then
offsetY = self : InsertText ( offsetY , REWARD_ITEMS ) ; --You will also receive
offsetY = offsetY + ITEM_BUTTON_SPACING ;
end
if isChoosingReward then
self : RequestSellPrice ( ) ;
end
else
if data.header then
GridLayout : FlagPreviousRowFull ( ) ;
object = self : AcquireLeftFontString ( ) ;
object : SetText ( data.header ) ;
actualSizeX = 4 ;
sizeY = 1 ;
GridLayout : PlaceObject ( object , actualSizeX , sizeY , self.ContentFrame , baseOffsetX , - offsetY ) ;
end
local method = data [ 1 ] ;
if method then
if data.small then
sizeX = 1 ;
sizeY = 1 ;
object = self.smallItemButtonPool : Acquire ( ) ;
else
sizeX = 2 ;
sizeY = 2 ;
object = self.itemButtonPool : Acquire ( ) ;
end
object : SetBaseGridSize ( sizeX , gridWidth , ITEM_BUTTON_SPACING ) ;
object [ method ] ( object , data [ 2 ] , data [ 3 ] , data [ 4 ] , data [ 5 ] ) ;
actualSizeX = object : GetActualGridTaken ( ) or sizeX ;
GridLayout : PlaceObject ( object , actualSizeX , sizeY , self.ContentFrame , baseOffsetX , - offsetY ) ;
end
end
end
local width , height = GridLayout : GetWrappedSize ( ) ;
return offsetY + height
end
end
do
--Clipboard
local CopyTextButton ;
local function CopyTextButton_OnClick ( self )
if addon.Clipboard : CloseIfFromSameSender ( self ) then
return
end
MainFrame : SendContentToClipboard ( ) ;
end
local function Settings_ShowCopyTextButton ( dbValue )
if dbValue == true then
if not CopyTextButton then
local themeID = 1 ; --Brown
CopyTextButton = addon.CreateCopyTextButton ( MainFrame , CopyTextButton_OnClick , themeID ) ;
CopyTextButton : SetPoint ( " TOPRIGHT " , MainFrame , " TOPRIGHT " , - 8 , - 8 ) ;
MainFrame.CopyTextButton = CopyTextButton ;
--CopyTextButton.Icon:SetSize(18, 18);
end
CopyTextButton : Show ( ) ;
CopyTextButton : SetTheme ( ThemeUtil : GetThemeID ( ) ) ;
else
if CopyTextButton then
CopyTextButton : Hide ( ) ;
end
end
end
CallbackRegistry : Register ( " SettingChanged.ShowCopyTextButton " , Settings_ShowCopyTextButton ) ;
local function Settings_ScrollDownThenAcceptQuest ( dbValue )
SCROLLDOWN_THEN_ACCEPT_QUEST = dbValue == true ;
end
CallbackRegistry : Register ( " SettingChanged.ScrollDownThenAcceptQuest " , Settings_ScrollDownThenAcceptQuest ) ;
local function Settings_CameraMovement ( dbValue )
if dbValue == 0 then
ActiveAnimIntro = AnimIntro_SimpleFadeIn_OnUpdate ;
elseif dbValue == 1 then
ActiveAnimIntro = AnimIntro_Unfold_OnUpdate ;
elseif dbValue == 2 then
ActiveAnimIntro = AnimIntro_FlyIn_OnUpdate ;
end
end
CallbackRegistry : Register ( " SettingChanged.CameraMovement " , Settings_CameraMovement ) ;
end
do --GamePad/Controller
function DUIDialogBaseMixin : UpdateScrollFrameBound ( )
self.scrollFrameTop = self.ScrollFrame : GetTop ( ) ;
self.scrollFrameBottom = self.ScrollFrame : GetBottom ( ) ;
end
function DUIDialogBaseMixin : ResetGamePadObjects ( )
self.gamepadMaxIndex = 0 ;
self.gamepadFocusIndex = nil ;
self.gamepadFocus = nil ;
self.gamepadObjects = { } ;
end
function DUIDialogBaseMixin : IndexGamePadObject ( object )
self.gamepadMaxIndex = self.gamepadMaxIndex + 1 ;
self.gamepadObjects [ self.gamepadMaxIndex ] = object ;
object.gamepadIndex = self.gamepadMaxIndex ;
end
function DUIDialogBaseMixin : ClearGamePadFocus ( )
if self.gamepadFocus then
self.gamepadFocus : OnLeave ( ) ;
self.gamepadFocus = nil ;
end
end
function DUIDialogBaseMixin : SetGamePadFocusIndex ( index )
self.gamepadFocusIndex = index ;
end
function DUIDialogBaseMixin : FocusObjectByDelta ( delta )
local maxIndex = self.gamepadMaxIndex or 0 ;
local index = self.gamepadFocusIndex ;
if not index then
index = 0 ;
end
if delta < 0 and index < maxIndex then
index = index + 1 ;
elseif delta > 0 and index > 1 then
index = index - 1 ;
elseif index == 0 then
index = maxIndex ;
else
return
end
self : ClearGamePadFocus ( ) ;
self.gamepadFocusIndex = index ;
self.gamepadFocus = self.gamepadObjects [ index ] ;
if self.gamepadFocus then
self : UpdateScrollFrameBound ( ) ;
self.gamepadFocus : OnEnter ( ) ;
local buttonHeight = self.gamepadFocus : GetHeight ( ) ;
local threshold = 2 * buttonHeight - 4 ;
if delta > 0 then
local top = self.gamepadFocus : GetTop ( ) ;
if top + threshold >= self.scrollFrameTop then
self : ScrollBy ( - 3 * buttonHeight ) ;
end
else
local bottom = self.gamepadFocus : GetBottom ( ) ;
if bottom - threshold <= self.scrollFrameBottom then
self : ScrollBy ( 3 * buttonHeight ) ;
end
end
return true
end
end
function DUIDialogBaseMixin : FocusNextObject ( )
if self : FocusObjectByDelta ( - 1 ) then
return
end
if self : IsScrollable ( ) then
self : ScrollBy ( 192 ) ;
end
end
function DUIDialogBaseMixin : FocusPreviousObject ( )
if self : FocusObjectByDelta ( 1 ) then
return
end
if self : IsScrollable ( ) then
self : ScrollBy ( - 192 ) ;
end
end
function DUIDialogBaseMixin : ClickFocusedObject ( )
if self.gamepadFocus then
self.gamepadFocus : OnClick ( " GamePad " ) ;
return true
end
return false
end
function DUIDialogBaseMixin : UpdateCompleteButton ( highlightedButtonSelected )
local button = self.AcceptButton ;
local hotkey = button.HotkeyFrame ;
if not hotkey then return end ;
if highlightedButtonSelected then
hotkey : Show ( ) ;
button.hasHotkey = true ;
button : Layout ( true ) ;
else
hotkey : Hide ( ) ;
button.hasHotkey = false ;
button : Layout ( true ) ;
end
self.GamePadFocusIndicator : SetShown ( not highlightedButtonSelected ) ;
end
end
do --TTS
local TTSButton ;
local function Settings_TTSEnabled ( dbValue )
if dbValue == true then
if not TTSButton then
local themeID = 1 ;
TTSButton = addon.CreateTTSButton ( MainFrame , themeID ) ;
TTSButton : SetPoint ( " TOPLEFT " , MainFrame , " TOPLEFT " , 8 , - 8 ) ;
MainFrame.TTSButton = TTSButton ;
end
TTSButton : Show ( ) ;
TTSButton : SetTheme ( ThemeUtil : GetThemeID ( ) ) ;
else
if TTSButton then
TTSButton : Hide ( ) ;
end
end
end
CallbackRegistry : Register ( " SettingChanged.TTSEnabled " , Settings_TTSEnabled ) ;
end
do
function DUIDialogBaseMixin : OnSettingsChanged ( )
if self : IsVisible ( ) and self.handler then
if not self.settingsDirty then
self.settingsDirty = true ;
After ( 0 , function ( )
self.settingsDirty = nil ;
if self.handler then
self.keepGossipHistory = false ;
self [ self.handler ] ( self ) ;
end
end ) ;
end
end
end
local function OnFontSizeChanged ( baseFontSize , fontSizeID )
local f = MainFrame ;
if f.hotkeyFramePool then
local method = " UpdateBaseHeight " ;
f.hotkeyFramePool : CallAllObjects ( method ) ;
f.GamePadFocusIndicator : UpdateBaseHeight ( ) ;
end
if f.optionButtonPool then
local method = " OnFontSizeChanged " ;
f.optionButtonPool : CallAllObjects ( method ) ;
end
if f.AcceptButton . HotkeyFrame then
f.AcceptButton . HotkeyFrame : UpdateBaseHeight ( ) ;
end
if f.ExitButton . HotkeyFrame then
f.ExitButton . HotkeyFrame : UpdateBaseHeight ( ) ;
end
FONT_SIZE = baseFontSize ;
TEXT_SPACING = 0.35 * FONT_SIZE ; --Recommended Line Height: 1.2 - 1.5
PARAGRAPH_SPACING = 4 * TEXT_SPACING ; --4 * TEXT_SPACING
PARAGRAPH_BUTTON_SPACING = 2 * FONT_SIZE ; --Font Size * 2
f : OnSettingsChanged ( ) ;
end
CallbackRegistry : Register ( " FontSizeChanged " , OnFontSizeChanged ) ;
local function PostFontSizeChanged ( )
--There is delay before footer button height changed
After ( 0 , function ( )
MainFrame : UpdateFrameSize ( ) ;
MainFrame : OnSettingsChanged ( ) ;
end ) ;
end
CallbackRegistry : Register ( " PostFontSizeChanged " , PostFontSizeChanged ) ;
local FrameSizeIndexScale = {
[ 0 ] = 0.9 ,
[ 1 ] = 1.0 ,
[ 2 ] = 1.1 ,
[ 3 ] = 1.25 ,
} ;
local function Settings_FrameOrientation ( )
MainFrame : UpdateFrameBaseOffset ( ) ;
if addon.SettingsUI : IsShown ( ) then
addon.SettingsUI : MoveToBestPosition ( ) ;
end
end
CallbackRegistry : Register ( " SettingChanged.FrameOrientation " , Settings_FrameOrientation ) ;
local function Settings_FrameSize ( dbValue )
--1: 1.0, 2: 1.1, 3:1.25
local newScale = dbValue and FrameSizeIndexScale [ dbValue ]
if newScale and newScale ~= FRAME_SIZE_MULTIPLIER then
FRAME_SIZE_MULTIPLIER = newScale ;
if dbValue == 0 then
FRAME_OFFSET_RATIO = 4 / 5 ;
else
FRAME_OFFSET_RATIO = 3 / 4 ;
end
MainFrame : UpdateFrameSize ( ) ;
MainFrame : OnSettingsChanged ( ) ;
end
end
CallbackRegistry : Register ( " SettingChanged.FrameSize " , Settings_FrameSize ) ;
local function Settings_HideUI ( dbValue , useInput )
ExperienceBar : SetShown ( dbValue == true ) ;
end
CallbackRegistry : Register ( " SettingChanged.HideUI " , Settings_HideUI ) ;
local function Settings_UseRoleplayName ( dbValue )
if dbValue == true then
GetQuestText = API.GetModifiedQuestText ;
GetGossipText = API.GetModifiedGossipText ;
else
GetQuestText = API.GetQuestText ;
GetGossipText = API.GetGossipText ;
end
MainFrame : OnSettingsChanged ( ) ;
end
CallbackRegistry : Register ( " SettingChanged.UseRoleplayName " , Settings_UseRoleplayName ) ;
local function GenericOnSettingsChanged ( dbValue )
MainFrame : OnSettingsChanged ( ) ;
end
CallbackRegistry : Register ( " SettingChanged.MarkHighestSellPrice " , GenericOnSettingsChanged ) ;
CallbackRegistry : Register ( " SettingChanged.ShowNPCNameOnPage " , GenericOnSettingsChanged ) ;
CallbackRegistry : Register ( " SettingChanged.ForceGossip " , GenericOnSettingsChanged ) ;
CallbackRegistry : Register ( " SettingChanged.AutoSelectGossip " , GenericOnSettingsChanged ) ;
local function SettingsUI_Show ( )
SETTINGS_UI_VISIBLE = true ;
end
CallbackRegistry : Register ( " SettingsUI.Show " , SettingsUI_Show ) ;
local function SettingsUI_Hide ( )
SETTINGS_UI_VISIBLE = false ;
end
CallbackRegistry : Register ( " SettingsUI.Hide " , SettingsUI_Hide ) ;
local function UpdateMainOptionButtonHotkey ( b , key )
if b and b.HotkeyFrame then
b.HotkeyFrame . key = nil ;
local keyShown = b.HotkeyFrame : IsShown ( ) ;
b.HotkeyFrame : SetKey ( key ) ;
if keyShown then
b : Layout ( true ) ;
else
b.HotkeyFrame : Hide ( ) ;
end
end
end
local function PostInputDeviceChanged ( dbValue )
INPUT_DEVICE_GAME_PAD = dbValue ~= 1 ;
MainFrame : OnSettingsChanged ( ) ;
UpdateMainOptionButtonHotkey ( MainFrame.AcceptButton , " PRIMARY " ) ;
UpdateMainOptionButtonHotkey ( MainFrame.ExitButton , " Esc " ) ;
if INPUT_DEVICE_GAME_PAD then
MainFrame.GamePadFocusIndicator : SetKey ( " PRIMARY " ) ;
else
MainFrame.GamePadFocusIndicator : ClearKey ( ) ;
end
end
CallbackRegistry : Register ( " PostInputDeviceChanged " , PostInputDeviceChanged ) ;
end