313 lines
12 KiB
Lua
313 lines
12 KiB
Lua
--[[
|
|
LibDualSpec-1.0 - Adds dual spec support to individual AceDB-3.0 databases
|
|
Copyright (C) 2009 Adirelle
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
|
|
* Redistributions of source code must retain the above copyright notice,
|
|
this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
* Redistribution of a stand alone version is strictly prohibited without
|
|
prior written authorization from the LibDualSpec project manager.
|
|
* Neither the name of the LibDualSpec authors nor the names of its contributors
|
|
may be used to endorse or promote products derived from this software without
|
|
specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
--]]
|
|
|
|
local MAJOR, MINOR = "LibDualSpec-1.0", 4
|
|
assert(LibStub, MAJOR.." requires LibStub")
|
|
local lib = LibStub:NewLibrary(MAJOR, MINOR)
|
|
if not lib then return end
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
-- Library data
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
lib.talentGroup = lib.talentGroup or GetActiveTalentGroup()
|
|
lib.eventFrame = lib.eventFrame or CreateFrame("Frame")
|
|
|
|
lib.registry = lib.registry or {}
|
|
lib.options = lib.options or {}
|
|
lib.mixin = lib.mixin or {}
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
-- Locals
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
local registry = lib.registry
|
|
local options = lib.options
|
|
local mixin = lib.mixin
|
|
|
|
-- "Externals"
|
|
local AceDB3 = LibStub('AceDB-3.0', true)
|
|
local AceDBOptions3 = LibStub('AceDBOptions-3.0', true)
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
-- Localization
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
local L_DUALSPEC_DESC, L_ENABLED, L_ENABLED_DESC, L_DUAL_PROFILE, L_DUAL_PROFILE_DESC
|
|
|
|
do
|
|
L_DUALSPEC_DESC = "When enabled, this feature allow you to select a different "..
|
|
"profile for each talent spec. The dual profile will be swapped with the "..
|
|
"current profile each time you switch from a talent spec to the other."
|
|
L_ENABLED = 'Enable dual profile'
|
|
L_ENABLED_DESC = 'Check this box to automatically swap profiles on talent switch.'
|
|
L_DUAL_PROFILE = 'Dual profile'
|
|
L_DUAL_PROFILE_DESC = 'Select the profile to swap with on talent switch.'
|
|
|
|
local locale = GetLocale()
|
|
if locale == "frFR" then
|
|
L_DUALSPEC_DESC = "Lorsqu'elle est activée, cette fonctionnalité vous permet "..
|
|
"de choisir un profil différent pour chaque spécialisation de talents. "..
|
|
"Le second profil sera échangé avec le profil courant chaque fois que vous "..
|
|
"passerez d'une spécialisation à l'autre."
|
|
L_ENABLED = 'Activez le second profil'
|
|
L_ENABLED_DESC = "Cochez cette case pour échanger automatiquement les profils "..
|
|
"lors d'un changement de spécialisation."
|
|
L_DUAL_PROFILE = 'Second profil'
|
|
L_DUAL_PROFILE_DESC = "Sélectionnez le profil à échanger avec le profil courant "..
|
|
"lors du changement de spécialisation."
|
|
elseif locale == "deDE" then
|
|
L_DUAL_PROFILE = "Duales Profil"
|
|
L_DUAL_PROFILE_DESC = "W\195\164hle das Profil, das beim Wechsel der Talente aktiviert wird."
|
|
L_DUALSPEC_DESC = "Wenn aktiv, wechselt dieses Feature bei jedem Wechsel "..
|
|
"der dualen Talentspezialisierung das Profil. Das duale Profil wird beim "..
|
|
"Wechsel automatisch mit dem derzeit aktiven Profil getauscht."
|
|
L_ENABLED = "Aktiviere Duale Profile"
|
|
L_ENABLED_DESC = "Aktiviere diese Option, um beim Talentwechsel automatisch "..
|
|
"zwischen den Profilen zu wechseln."
|
|
elseif locale == "zhCN" then
|
|
L_DUAL_PROFILE = "双重配置文件"
|
|
L_DUAL_PROFILE_DESC = "选择转换天赋时所要使用的配置文件"
|
|
L_DUALSPEC_DESC = "启时,你可以为你的双天赋设定另一组配置文件,你的双重配置文件将在你转换天赋时自动与目前使用配置文件交换。"
|
|
L_ENABLED = "开启双重配置文件"
|
|
L_ENABLED_DESC = "勾选以便转换天赋时自动交换配置文件。"
|
|
elseif locale == "zhTW" then
|
|
L_DUALSPEC_DESC = "啟用時,你可以為你的雙天賦設定另一組設定檔。你的雙設定檔將在你轉換天賦時自動與目前使用設定檔交換。"
|
|
L_ENABLED = "啟用雙設定檔"
|
|
L_ENABLED_DESC = "勾選以在轉換天賦時自動交換設定檔"
|
|
L_DUAL_PROFILE = "雙設定檔"
|
|
L_DUAL_PROFILE_DESC = "選擇轉換天賦後所要使用的設定檔"
|
|
end
|
|
end
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
-- Mixin
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
--- Get dual spec feature status.
|
|
-- @return (boolean) true is dual spec feature enabled.
|
|
-- @name enhancedDB:IsDualSpecEnabled
|
|
function mixin:IsDualSpecEnabled()
|
|
return registry[self].db.char.enabled
|
|
end
|
|
|
|
--- Enable/disabled dual spec feature.
|
|
-- @param enabled (boolean) true to enable dual spec feature, false to disable it.
|
|
-- @name enhancedDB:SetDualSpecEnabled
|
|
function mixin:SetDualSpecEnabled(enabled)
|
|
local db = registry[self].db
|
|
if enabled and not db.char.talentGroup then
|
|
db.char.talentGroup = lib.talentGroup
|
|
db.char.profile = self:GetCurrentProfile()
|
|
db.char.enabled = true
|
|
else
|
|
db.char.enabled = enabled
|
|
self:CheckDualSpecState()
|
|
end
|
|
end
|
|
|
|
--- Get the alternate profile name.
|
|
-- Defaults to the current profile.
|
|
-- @return (string) Alternate profile name.
|
|
-- @name enhancedDB:GetDualSpecProfile
|
|
function mixin:GetDualSpecProfile()
|
|
return registry[self].db.char.profile or self:GetCurrentProfile()
|
|
end
|
|
|
|
--- Set the alternate profile name.
|
|
-- No validation are done to ensure the profile is valid.
|
|
-- @param profileName (string) the profile name to use.
|
|
-- @name enhancedDB:SetDualSpecProfile
|
|
function mixin:SetDualSpecProfile(profileName)
|
|
registry[self].db.char.profile = profileName
|
|
end
|
|
|
|
--- Check if a profile swap should occur.
|
|
-- Do nothing if the dual spec feature is disabled. In the other
|
|
-- case, if the internally stored talent spec is different from the
|
|
-- actual active talent spec, the database swaps to the alternate profile.
|
|
-- There is normally no reason to call this method directly as LibDualSpec
|
|
-- takes care of calling it at appropriate times.
|
|
-- @name enhancedDB:CheckDualSpecState
|
|
function mixin:CheckDualSpecState()
|
|
local db = registry[self].db
|
|
if db.char.enabled and db.char.talentGroup ~= lib.talentGroup then
|
|
local currentProfile = self:GetCurrentProfile()
|
|
local newProfile = db.char.profile
|
|
db.char.talentGroup = lib.talentGroup
|
|
if newProfile ~= currentProfile then
|
|
self:SetProfile(newProfile)
|
|
db.char.profile = currentProfile
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
-- AceDB-3.0 support
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
local function EmbedMixin(target)
|
|
for k,v in pairs(mixin) do
|
|
rawset(target, k, v)
|
|
end
|
|
end
|
|
|
|
-- Upgrade existing mixins
|
|
for target in pairs(registry) do
|
|
EmbedMixin(target)
|
|
end
|
|
|
|
--- Embed dual spec feature into an existing AceDB-3.0 database.
|
|
-- LibDualSpec specific methods are added to the instance.
|
|
-- @name LibDualSpec:EnhanceDatabase
|
|
-- @param target (table) the AceDB-3.0 instance.
|
|
-- @param name (string) a user-friendly name of the database (best bet is the addon name).
|
|
function lib:EnhanceDatabase(target, name)
|
|
AceDB3 = AceDB3 or LibStub('AceDB-3.0', true)
|
|
if type(target) ~= "table" then
|
|
error("Usage: LibDualSpec:EnhanceDatabase(target, name): target should be a table.", 2)
|
|
elseif type(name) ~= "string" then
|
|
error("Usage: LibDualSpec:EnhanceDatabase(target, name): name should be a string.", 2)
|
|
elseif not AceDB3 or not AceDB3.db_registry[target] then
|
|
error("Usage: LibDualSpec:EnhanceDatabase(target, name): target should be an AceDB-3.0 database.", 2)
|
|
elseif target.parent then
|
|
error("Usage: LibDualSpec:EnhanceDatabase(target, name): cannot enhance a namespace.", 2)
|
|
elseif registry[target] then
|
|
return
|
|
end
|
|
local db = target:GetNamespace(MAJOR, true) or target:RegisterNamespace(MAJOR)
|
|
registry[target] = { name = name, db = db }
|
|
EmbedMixin(target)
|
|
target:CheckDualSpecState()
|
|
end
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
-- AceDBOptions-3.0 support
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
local function NoDualSpec()
|
|
return GetNumTalentGroups() == 1
|
|
end
|
|
|
|
options.dualSpecDesc = {
|
|
name = L_DUALSPEC_DESC,
|
|
type = 'description',
|
|
order = 40.1,
|
|
hidden = NoDualSpec,
|
|
}
|
|
|
|
options.enabled = {
|
|
name = L_ENABLED,
|
|
desc = L_ENABLED_DESC,
|
|
type = 'toggle',
|
|
order = 40.2,
|
|
get = function(info) return info.handler.db:IsDualSpecEnabled() end,
|
|
set = function(info, value) info.handler.db:SetDualSpecEnabled(value) end,
|
|
hidden = NoDualSpec,
|
|
}
|
|
|
|
options.dualProfile = {
|
|
name = L_DUAL_PROFILE,
|
|
desc = L_DUAL_PROFILE_DESC,
|
|
type = 'select',
|
|
order = 40.3,
|
|
get = function(info) return info.handler.db:GetDualSpecProfile() end,
|
|
set = function(info, value) info.handler.db:SetDualSpecProfile(value) end,
|
|
values = "ListProfiles",
|
|
arg = "common",
|
|
hidden = NoDualSpec,
|
|
disabled = function(info) return not info.handler.db:IsDualSpecEnabled() end,
|
|
}
|
|
|
|
--- Embed dual spec options into an existing AceDBOptions-3.0 option table.
|
|
-- @name LibDualSpec:EnhanceOptions
|
|
-- @param optionTable (table) The option table returned by AceDBOptions-3.0.
|
|
-- @param target (table) The AceDB-3.0 the options operate on.
|
|
function lib:EnhanceOptions(optionTable, target)
|
|
AceDBOptions3 = AceDBOptions3 or LibStub('AceDBOptions-3.0', true)
|
|
if type(optionTable) ~= "table" then
|
|
error("Usage: LibDualSpec:EnhanceOptions(optionTable, target): optionTable should be a table.", 2)
|
|
elseif type(target) ~= "table" then
|
|
error("Usage: LibDualSpec:EnhanceOptions(optionTable, target): target should be a table.", 2)
|
|
elseif not (AceDBOptions3 and AceDBOptions3.optionTables[target]) then
|
|
error("Usage: LibDualSpec:EnhanceOptions(optionTable, target): optionTable is not an AceDBOptions-3.0 table.", 2)
|
|
elseif optionTable.handler.db ~= target then
|
|
error("Usage: LibDualSpec:EnhanceOptions(optionTable, target): optionTable must be the option table of target.", 2)
|
|
elseif not registry[target] then
|
|
error("Usage: LibDualSpec:EnhanceOptions(optionTable, target): EnhanceDatabase should be called before EnhanceOptions(optionTable, target).", 2)
|
|
elseif optionTable.plugins and optionTable.plugins[MAJOR] then
|
|
return
|
|
end
|
|
if not optionTable.plugins then
|
|
optionTable.plugins = {}
|
|
end
|
|
optionTable.plugins[MAJOR] = options
|
|
end
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
-- Inspection
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
local function iterator(registry, key)
|
|
local data
|
|
key, data = next(registry, key)
|
|
if key then
|
|
return key, data.name
|
|
end
|
|
end
|
|
|
|
--- Iterate through enhanced AceDB3.0 instances.
|
|
-- The iterator returns (instance, name) pairs where instance and name are the
|
|
-- arguments that were provided to lib:EnhanceDatabase.
|
|
-- @name LibDualSpec:IterateDatabases
|
|
-- @return Values to be used in a for .. in .. do statement.
|
|
function lib:IterateDatabases()
|
|
return iterator, lib.registry
|
|
end
|
|
|
|
-- ----------------------------------------------------------------------------
|
|
-- Switching logic
|
|
-- ----------------------------------------------------------------------------
|
|
|
|
lib.eventFrame:RegisterEvent('PLAYER_TALENT_UPDATE')
|
|
lib.eventFrame:SetScript('OnEvent', function()
|
|
local newTalentGroup = GetActiveTalentGroup()
|
|
if lib.talentGroup ~= newTalentGroup then
|
|
lib.talentGroup = newTalentGroup
|
|
for target in pairs(registry) do
|
|
target:CheckDualSpecState()
|
|
end
|
|
end
|
|
end)
|
|
|