Files
andrew6180 1e9fa2aaca init
2023-04-16 00:31:14 -07:00

530 lines
22 KiB
Lua

setfenv(1, VoiceOver)
Options = { }
local AceGUI = LibStub("AceGUI-3.0")
local AceConfigDialog = LibStub("AceConfigDialog-3.0")
local AceDBOptions = LibStub("AceDBOptions-3.0")
------------------------------------------------------------
-- Construction of the options table for AceConfigDialog --
-- Needed to preserve order (modern AceGUI has support for custom sorting of dropdown items, but old versions don't)
local FRAME_STRATAS =
{
"BACKGROUND",
"LOW",
"MEDIUM",
"HIGH",
"DIALOG",
}
local slashCommandsHandler = {}
function slashCommandsHandler:values(info)
if not self.indexToName then
self.indexToName = { "Nothing" }
self.indexToCommand = { "" }
self.commandToIndex = { [""] = 1 }
for command, handler in Utils:Ordered(Options.table.args.SlashCommands.args, function(a, b) return (a.order or 100) < (b.order or 100) end) do
if not handler.dropdownHidden then
table.insert(self.indexToName, handler.name)
table.insert(self.indexToCommand, command)
self.commandToIndex[command] = #self.indexToCommand
end
end
end
return self.indexToName
end
function slashCommandsHandler:get(info)
local config, key = info.arg()
return self.commandToIndex[config[key]]
end
function slashCommandsHandler:set(info, value)
local config, key = info.arg()
config[key] = self.indexToCommand[value]
end
-- General Tab
local GeneralTab =
{
name = "General",
type = "group",
order = 10,
args = {
MinimapButton = {
type = "group",
order = 2,
inline = true,
name = "Minimap Button",
args = {
MinimapButtonShow = {
type = "toggle",
order = 1,
name = "Show Minimap Button",
get = function(info) return not Addon.db.profile.MinimapButton.LibDBIcon.hide end,
set = function(info, value)
Addon.db.profile.MinimapButton.LibDBIcon.hide = not value
if value then
LibStub("LibDBIcon-1.0"):Show("VoiceOver")
else
LibStub("LibDBIcon-1.0"):Hide("VoiceOver")
end
end,
},
MinimapButtonLock = {
type = "toggle",
order = 2,
name = "Lock Position",
get = function(info) return Addon.db.profile.MinimapButton.LibDBIcon.lock end,
set = function(info, value)
if value then
LibStub("LibDBIcon-1.0"):Lock("VoiceOver")
else
LibStub("LibDBIcon-1.0"):Unlock("VoiceOver")
end
end,
},
LineBreak1 = { type = "description", name = "", order = 3 },
MinimapButtons = {
type = "group",
inline = true,
name = "",
handler = slashCommandsHandler,
args = {
MinimapButtonLeftClick = {
type = "select",
order = 4,
name = "Left Click",
desc = "Action performed by left-clicking the minimap button.",
values = "values", get = "get", set = "set",
arg = function(value) return Addon.db.profile.MinimapButton.Commands, "LeftButton" end,
},
MinimapButtonMiddleClick = {
type = "select",
order = 4,
name = "Middle Click",
desc = "Action performed by middle-clicking the minimap button.",
values = "values", get = "get", set = "set",
arg = function(value) return Addon.db.profile.MinimapButton.Commands, "MiddleButton" end,
},
MinimapButtonRightClick = {
type = "select",
order = 4,
name = "Right Click",
desc = "Action performed by right-clicking the minimap button.",
values = "values", get = "get", set = "set",
arg = function(value) return Addon.db.profile.MinimapButton.Commands, "RightButton" end,
}
}
}
}
},
Frame = {
type = "group",
order = 3,
inline = true,
name = "Frame",
disabled = function(info) return Addon.db.profile.SoundQueueUI.HideFrame end,
args = {
LockFrame = {
type = "toggle",
order = 1,
name = "Lock Frame",
desc = "Prevent the frame from being moved or resized.",
get = function(info) return Addon.db.profile.SoundQueueUI.LockFrame end,
set = function(info, value)
Addon.db.profile.SoundQueueUI.LockFrame = value
Addon.soundQueue.ui:RefreshConfig()
end,
},
ResetFrame = {
type = "execute",
order = 2,
name = "Reset Frame",
desc = "Resets frame position and size back to default.",
func = function(info)
Addon.soundQueue.ui.frame:Reset()
end,
},
LineBreak1 = { type = "description", name = "", order = 3 },
FrameStrata = {
type = "select",
order = 5,
name = "Frame Strata",
desc = "Changes the \"depth\" of the frame, determining which other frames will it overlap or fall behind.",
values = FRAME_STRATAS,
get = function(info)
for k, v in ipairs(FRAME_STRATAS) do
if v == Addon.db.profile.SoundQueueUI.FrameStrata then
return k;
end
end
end,
set = function(info, value)
Addon.db.profile.SoundQueueUI.FrameStrata = FRAME_STRATAS[value]
Addon.soundQueue.ui.frame:SetFrameStrata(Addon.db.profile.SoundQueueUI.FrameStrata)
end,
},
FrameScale = {
type = "range",
order = 4,
name = "Frame Scale",
desc = "Automatically hides the takling frame when no voice over is playing.",
softMin = 0.5,
softMax = 2,
bigStep = 0.05,
isPercent = true,
get = function(info) return Addon.db.profile.SoundQueueUI.FrameScale end,
set = function(info, value)
Addon.db.profile.SoundQueueUI.FrameScale = value
Addon.soundQueue.ui:RefreshConfig()
end,
},
LineBreak2 = { type = "description", name = "", order = 6 },
HidePortrait = {
type = "toggle",
order = 7,
name = "Hide NPC Portrait",
desc = "Talking NPC portrait will not appear when voice over audio is played.\n\n" ..
Utils:ColorizeText("This might be useful when using other addons that replace the dialog experience, such as " ..
Utils:ColorizeText("Immersion", NORMAL_FONT_COLOR_CODE) .. ".",
GRAY_FONT_COLOR_CODE),
get = function(info) return Addon.db.profile.SoundQueueUI.HidePortrait end,
set = function(info, value)
Addon.db.profile.SoundQueueUI.HidePortrait = value
Addon.soundQueue.ui:RefreshConfig()
end,
},
HideFrame = {
type = "toggle",
order = 8,
name = "Hide Entirely",
desc = "Play voiceovers without ever displaying the frame.",
disabled = false,
get = function(info) return Addon.db.profile.SoundQueueUI.HideFrame end,
set = function(info, value)
Addon.db.profile.SoundQueueUI.HideFrame = value
Addon.soundQueue.ui:RefreshConfig()
end,
},
},
},
Audio = {
type = "group",
order = 4,
inline = true,
name = "Audio",
args = {
SoundChannel = Version:IsRetailOrAboveLegacyVersion(40000) and {
type = "select",
width = 0.75,
order = 1,
name = "Sound Channel",
desc = "Controls which sound channel VoiceOver will play in.",
values = Enums.SoundChannel:GetValueToNameMap(),
get = function(info) return Addon.db.profile.Audio.SoundChannel end,
set = function(info, value)
Addon.db.profile.Audio.SoundChannel = value
Addon.soundQueue.ui:RefreshConfig()
end,
},
LineBreak = { type = "description", name = "", order = 2 },
GossipFrequency = {
type = "select",
width = 1.1,
order = 3,
name = "NPC Greeting Playback Frequency",
desc = "Controls how often VoiceOver will play NPC greeting dialog.",
values = {
[Enums.GossipFrequency.Always] = "Always",
[Enums.GossipFrequency.OncePerQuestNPC] = "Play Once for Quest NPCs",
[Enums.GossipFrequency.OncePerNPC] = "Play Once for All NPCs",
[Enums.GossipFrequency.Never] = "Never",
},
get = function(info) return Addon.db.profile.Audio.GossipFrequency end,
set = function(info, value)
Addon.db.profile.Audio.GossipFrequency = value
Addon.soundQueue.ui:RefreshConfig()
end,
},
AutoToggleDialog = Version:IsRetailOrAboveLegacyVersion(60100) and {
type = "toggle",
width = 2.25,
order = 4,
name = "Mute Vocal NPCs Greetings While VoiceOver is Playing",
desc = "While VoiceOver is playing, the Dialog channel will be muted.",
get = function(info) return Addon.db.profile.Audio.AutoToggleDialog end,
set = function(info, value)
Addon.db.profile.Audio.AutoToggleDialog = value
Addon.soundQueue.ui:RefreshConfig()
if Addon.db.profile.Audio.AutoToggleDialog then
SetCVar("Sound_EnableDialog", 1)
end
end,
},
}
},
Debug = {
type = "group",
order = 5,
inline = true,
name = "Debugging Tools",
args = {
DebugEnabled = {
type = "toggle",
order = 1,
width = 1.25,
name = "Enable Debug Messages",
desc = "Enables printing of some \"useful\" debug messages to the chat window.",
get = function(info) return Addon.db.profile.DebugEnabled end,
set = function(info, value) Addon.db.profile.DebugEnabled = value end,
},
}
}
}
}
local LegacyWrathTab = Version.IsLegacyWrath and {
type = "group",
name = "3.3.5 Backport",
order = 19,
args = {
PlayOnMusicChannel = {
type = "group",
order = 100,
name = "Play Voiceovers on Music Channel",
inline = true,
args = {
Description = {
type = "description",
order = 100,
name = "3.3.5 client lacks the ability to stop addon sounds at will. As a workaround, you can play the voiceovers on the music channel instead, which, unlike sounds, can be stopped. Regular background music will not be playing throughout the duration of voiceovers.|n|nIf you normally play with music disabled - it will be temporarily enabled during voiceovers, but no actual background music will be played.",
},
Enabled = {
type = "toggle",
order = 200,
name = "Enable",
disabled = false,
get = function(info) return Addon.db.profile.LegacyWrath.PlayOnMusicChannel.Enabled end,
set = function(info, value) Addon.db.profile.LegacyWrath.PlayOnMusicChannel.Enabled = value end,
},
Disabled = {
type = "description",
order = 300,
name = format("With this option disabled you %swill not be able to pause|r voiceovers after they start playing. Attempting to pause will instead %1$spause the voiceover queue|r once the current sound has finished playing.", RED_FONT_COLOR_CODE),
hidden = function(info) return Addon.db.profile.LegacyWrath.PlayOnMusicChannel.Enabled end,
},
Settings = {
type = "group",
order = 400,
name = "",
inline = true,
hidden = function(info) return not Addon.db.profile.LegacyWrath.PlayOnMusicChannel.Enabled end,
args = {
FadeOutMusic = {
type = "range",
order = 100,
name = "Music Fade Out (secs)",
desc = "Background music will fade out over this number of seconds before playing voiceovers. Has no effect if in-game music is disabled or muted.",
min = 0,
softMax = 2,
bigStep = 0.05,
get = function(info) return Addon.db.profile.LegacyWrath.PlayOnMusicChannel.FadeOutMusic end,
set = function(info, value) Addon.db.profile.LegacyWrath.PlayOnMusicChannel.FadeOutMusic = value end,
},
Volume = {
type = "range",
order = 200,
name = "Voiceover Volume",
desc = "Music channel volume will be temporarily adjusted to this value while the voiceovers are playing.",
min = 0,
max = 1,
bigStep = 0.01,
isPercent = true,
get = function(info) return Addon.db.profile.LegacyWrath.PlayOnMusicChannel.Volume end,
set = function(info, value) Addon.db.profile.LegacyWrath.PlayOnMusicChannel.Volume = value end,
},
}
},
}
},
}
}
local DataModulesTab =
{
name = "Data Modules",
type = "group",
childGroups = "tree",
order = 20,
args = {}
}
local SlashCommands = {
type = "group",
name = "Commands",
order = 110,
inline = true,
dialogHidden = true,
args = {
PlayPause = {
type = "execute",
order = 1,
name = "Play/Pause Audio",
desc = "Play/Pause voiceovers",
hidden = true,
func = function(info)
Addon.soundQueue:TogglePauseQueue()
end
},
Play = {
type = "execute",
order = 2,
name = "Play Audio",
desc = "Resume the playback of voiceovers",
func = function(info)
Addon.soundQueue:ResumeQueue()
end
},
Pause = {
type = "execute",
order = 3,
name = "Pause Audio",
desc = "Pause the playback of voiceovers",
func = function(info)
Addon.soundQueue:PauseQueue()
end
},
Skip = {
type = "execute",
order = 4,
name = "Skip Line",
desc = "Skip the currently played voiceover",
func = function(info)
local soundData = Addon.soundQueue.sounds[1]
if soundData then
Addon.soundQueue:RemoveSoundFromQueue(soundData)
end
end
},
Clear = {
type = "execute",
order = 5,
name = "Clear Queue",
desc = "Stop the playback and clears the voiceovers queue",
func = function(info)
Addon.soundQueue:RemoveAllSoundsFromQueue()
end
},
Options = {
type = "execute",
order = 100,
name = "Open Options",
desc = "Open the options panel",
func = function(info)
Options:OpenConfigWindow()
end
},
}
}
Options.table = {
name = "Voice Over",
type = "group",
childGroups = "tab",
args = {
General = GeneralTab,
LegacyWrath = LegacyWrathTab,
DataModules = DataModulesTab,
Profiles = nil, -- Filled in Options:OnInitialize, order is implicity 100
SlashCommands = SlashCommands,
}
}
------------------------------------------------------------
function Options:AddDataModule(module, order)
local descriptionOrder = 0
local function GetNextOrder()
descriptionOrder = descriptionOrder + 1
return descriptionOrder
end
local function MakeDescription(header, text)
return { type = "description", order = GetNextOrder(), name = function() return format("%s%s: |r%s", NORMAL_FONT_COLOR_CODE, header, type(text) == "function" and text() or text) end }
end
local name, title, notes, loadable, reason = GetAddOnInfo(module.AddonName)
if reason == "DEMAND_LOADED" or reason == "INTERFACE_VERSION" then
reason = nil
end
DataModulesTab.args[module.AddonName] = {
name = function()
local isLoaded = DataModules:GetModule(module.AddonName)
return format("%d. %s%s%s|r",
order,
reason and RED_FONT_COLOR_CODE or isLoaded and HIGHLIGHT_FONT_COLOR_CODE or GRAY_FONT_COLOR_CODE,
module.Title:gsub("VoiceOver Data %- ", ""),
isLoaded and "" or " (not loaded)")
end,
type = "group",
order = order,
args = {
AddonName = MakeDescription("Addon Name", module.AddonName),
Title = MakeDescription("Title", module.Title),
ModuleVersion = MakeDescription("Module Data Format Version", module.ModuleVersion),
ModulePriority = MakeDescription("Module Priority", module.ModulePriority),
ContentVersion = MakeDescription("Content Version", module.ContentVersion),
LoadOnDemand = MakeDescription("Load on Demand", module.LoadOnDemand and "Yes" or "No"),
Loaded = MakeDescription("Is Loaded", function() return DataModules:GetModule(module.AddonName) and "Yes" or "No" end),
NotLoadableReason = {
type = "description",
order = GetNextOrder(),
name = format("%sReason: |r%s%s|r", NORMAL_FONT_COLOR_CODE, RED_FONT_COLOR_CODE, reason and _G["ADDON_"..reason] or ""),
hidden = not reason,
},
Load = {
type = "execute",
order = GetNextOrder(),
name = "Load",
hidden = function() return reason or not module.LoadOnDemand or DataModules:GetModule(module.AddonName) end,
func = function()
DataModules:LoadModule(module)
end,
},
}
}
end
---Initialization of opens panel
function Options:Initialize()
self.table.args.Profiles = AceDBOptions:GetOptionsTable(Addon.db)
-- Create options table
Debug:Print("Registering options table...", "Options")
LibStub("AceConfig-3.0"):RegisterOptionsTable("VoiceOver", self.table, "vo")
AceConfigDialog:AddToBlizOptions("VoiceOver", "VoiceOver")
Debug:Print("Done!", "Options")
-- Create the option frame
---@type AceGUIFrame
self.frame = AceGUI:Create("Frame")
--AceConfigDialog:SetDefaultSize("VoiceOver", 640, 780) -- Let it be auto-sized
AceConfigDialog:Open("VoiceOver", self.frame)
self.frame:SetLayout("Fill")
self.frame:Hide()
-- Enable the frame to be closed with Escape key
_G["VoiceOverOptions"] = self.frame.frame
tinsert(UISpecialFrames, "VoiceOverOptions")
end
function Options:OpenConfigWindow()
if self.frame:IsShown() then
PlaySound(SOUNDKIT.ESCAPE_SCREEN_CLOSE)
self.frame:Hide()
else
PlaySound(SOUNDKIT.ESCAPE_SCREEN_OPEN)
self.frame:Show()
AceConfigDialog:Open("VoiceOver", self.frame)
end
end