You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

307 lines
9.1 KiB

--@curseforge-project-slug: libspecialization@
if WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE then return end
local LS, oldminor = LibStub:NewLibrary("LibSpecialization", 4)
if not LS then return end -- No upgrade needed
-- Positions of roles
LS.positionTable = LS.positionTable or {
-- Death Knight
[250] = "MELEE", -- Blood (Tank)
[251] = "MELEE", -- Frost (DPS)
[252] = "MELEE", -- Unholy (DPS)
-- Demon Hunter
[577] = "MELEE", -- Havoc (DPS)
[581] = "MELEE", -- Vengeance (Tank)
-- Druid
[102] = "RANGED", -- Balance (DPS Owl)
[103] = "MELEE", -- Feral (DPS Cat)
[104] = "MELEE", -- Guardian (Tank Bear)
[105] = "RANGED", -- Restoration (Heal)
-- Evoker
[1467] = "RANGED", -- Devastation (DPS)
[1468] = "RANGED", -- Preservation (Heal)
-- Hunter
[253] = "RANGED", -- Beast Mastery
[254] = "RANGED", -- Marksmanship
[255] = "MELEE", -- Survival
-- Mage
[62] = "RANGED", -- Arcane
[63] = "RANGED", -- Fire
[64] = "RANGED", -- Frost
-- Monk
[268] = "MELEE", -- Brewmaster (Tank)
[269] = "MELEE", -- Windwalker (DPS)
[270] = "MELEE", -- Mistweaver (Heal)
-- Paladin
[65] = "MELEE", -- Holy (Heal)
[66] = "MELEE", -- Protection (Tank)
[70] = "MELEE", -- Retribution (DPS)
-- Priest
[256] = "RANGED", -- Discipline (Heal)
[257] = "RANGED", -- Holy (Heal)
[258] = "RANGED", -- Shadow (DPS)
-- Rogue
[259] = "MELEE", -- Assassination
[260] = "MELEE", -- Outlaw
[261] = "MELEE", -- Subtlety
-- Shaman
[262] = "RANGED", -- Elemental (DPS)
[263] = "MELEE", -- Enhancement (DPS)
[264] = "RANGED", -- Restoration (Heal)
-- Warlock
[265] = "RANGED", -- Affliction
[266] = "RANGED", -- Demonology
[267] = "RANGED", -- Destruction
-- Warrior
[71] = "MELEE", -- Arms (DPS)
[72] = "MELEE", -- Fury (DPS)
[73] = "MELEE", -- Protection (Tank)
}
-- Player roles
LS.roleTable = LS.roleTable or {
-- Death Knight
[250] = "TANK", -- Blood (Tank)
[251] = "DAMAGER", -- Frost (DPS)
[252] = "DAMAGER", -- Unholy (DPS)
-- Demon Hunter
[577] = "DAMAGER", -- Havoc (DPS)
[581] = "TANK", -- Vengeance (Tank)
-- Druid
[102] = "DAMAGER", -- Balance (DPS Owl)
[103] = "DAMAGER", -- Feral (DPS Cat)
[104] = "TANK", -- Guardian (Tank Bear)
[105] = "HEALER", -- Restoration (Heal)
-- Evoker
[1467] = "DAMAGER", -- Devastation (DPS)
[1468] = "HEALER", -- Preservation (Heal)
-- Hunter
[253] = "DAMAGER", -- Beast Mastery
[254] = "DAMAGER", -- Marksmanship
[255] = "DAMAGER", -- Survival
-- Mage
[62] = "DAMAGER", -- Arcane
[63] = "DAMAGER", -- Fire
[64] = "DAMAGER", -- Frost
-- Monk
[268] = "TANK", -- Brewmaster (Tank)
[269] = "DAMAGER", -- Windwalker (DPS)
[270] = "HEALER", -- Mistweaver (Heal)
-- Paladin
[65] = "HEALER", -- Holy (Heal)
[66] = "TANK", -- Protection (Tank)
[70] = "DAMAGER", -- Retribution (DPS)
-- Priest
[256] = "HEALER", -- Discipline (Heal)
[257] = "HEALER", -- Holy (Heal)
[258] = "DAMAGER", -- Shadow (DPS)
-- Rogue
[259] = "DAMAGER", -- Assassination
[260] = "DAMAGER", -- Outlaw
[261] = "DAMAGER", -- Subtlety
-- Shaman
[262] = "DAMAGER", -- Elemental (DPS)
[263] = "DAMAGER", -- Enhancement (DPS)
[264] = "HEALER", -- Restoration (Heal)
-- Warlock
[265] = "DAMAGER", -- Affliction
[266] = "DAMAGER", -- Demonology
[267] = "DAMAGER", -- Destruction
-- Warrior
[71] = "DAMAGER", -- Arms (DPS)
[72] = "DAMAGER", -- Fury (DPS)
[73] = "TANK", -- Protection (Tank)
}
LS.callbackMap = LS.callbackMap or {}
LS.frame = LS.frame or CreateFrame("Frame")
local callbackMap = LS.callbackMap
local positionTable = LS.positionTable
local roleTable = LS.roleTable
local frame = LS.frame
local starterSpecs = {
[1444] = true, -- Shaman
[1446] = true, -- Warrior
[1447] = true, -- Druid
[1448] = true, -- Hunter
[1449] = true, -- Mage
[1450] = true, -- Monk
[1451] = true, -- Paladin
[1452] = true, -- Priest
[1453] = true, -- Rogue
[1454] = true, -- Warlock
[1455] = true, -- Death Knight
[1456] = true, -- Demon Hunter
[1465] = true, -- Evoker
}
local next, type, error, tonumber, format = next, type, error, tonumber, string.format
local Ambiguate, geterrorhandler, GetTime, IsInGroup = Ambiguate, geterrorhandler, GetTime, IsInGroup
local GetSpecialization, GetSpecializationInfo = GetSpecialization, GetSpecializationInfo
local SendAddonMessage, CTimerAfter = C_ChatInfo.SendAddonMessage, C_Timer.After
local pName = UnitName("player")
if not C_ChatInfo.RegisterAddonMessagePrefix("LibSpec") then
error("LibSpecialization: Failed to register the addon prefix.")
end
do
local approved = {
["RAID"] = true,
["PARTY"] = true,
["INSTANCE_CHAT"] = true,
}
local talentChangeThrottle, currentSpecId = 0, 0
local timerInstance, timerGroup = false, false
local function SendToInstance()
timerInstance = false
if IsInGroup(2) then
SendAddonMessage("LibSpec", format("%d", currentSpecId), "INSTANCE_CHAT")
end
end
local function SendToGroup()
timerGroup = false
if IsInGroup(1) then
SendAddonMessage("LibSpec", format("%d", currentSpecId), "RAID") -- RAID auto downgrades to PARTY as needed
end
end
frame:SetScript("OnEvent", function(_, event, prefix, msg, channel, sender)
if event == "CHAT_MSG_ADDON" then
if prefix == "LibSpec" and approved[channel] then -- Only approved channels
if msg == "R" then
if channel == "INSTANCE_CHAT" then
local specId = LS:MySpecialization()
if specId then
currentSpecId = specId
if not timerInstance then
timerInstance = true
CTimerAfter(3, SendToInstance)
end
end
else -- RAID/PARTY
local specId = LS:MySpecialization()
if specId then
currentSpecId = specId
if not timerGroup then
timerGroup = true
CTimerAfter(3, SendToGroup)
end
end
end
return
end
local specId = tonumber(msg)
local role, position = roleTable[specId], positionTable[specId]
if role and position then
for _,func in next, callbackMap do
func(specId, role, position, Ambiguate(sender, "none"), channel)
end
end
end
elseif event == "GROUP_FORMED" then -- Join new group
LS:RequestSpecialization()
elseif event == "ACTIVE_TALENT_GROUP_CHANGED" then -- Talent change fires twice
local t = GetTime()
if t - talentChangeThrottle > 2 then
talentChangeThrottle = t
local specId, role, position = LS:MySpecialization()
if specId then
currentSpecId = specId -- Update this just in case a timer is queued
if IsInGroup() then
if IsInGroup(2) then -- Instance group
SendAddonMessage("LibSpec", format("%d", specId), "INSTANCE_CHAT")
end
if IsInGroup(1) then -- Normal group
SendAddonMessage("LibSpec", format("%d", specId), "RAID")
end
else
for _,func in next, callbackMap do
func(specId, role, position, pName, channel) -- This allows us to show our own spec info when not grouped
end
end
end
end
elseif event == "PLAYER_LOGIN" then
LS:RequestSpecialization()
end
end)
frame:RegisterEvent("CHAT_MSG_ADDON")
frame:RegisterEvent("GROUP_FORMED")
frame:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED")
frame:RegisterEvent("PLAYER_LOGIN")
end
-- Allow requesting only your specialization
function LS:MySpecialization()
local spec = GetSpecialization()
if type(spec) == "number" and spec > 0 then
local specId, _, _, _, role = GetSpecializationInfo(spec)
if specId and role then
local position = positionTable[specId]
if position then
return specId, role, position
elseif not starterSpecs[specId] then
geterrorhandler()(format("LibSpecialization: Unknown specId %q", specId))
end
end
end
end
do
local prev = 0
local timer = false
function LS:RequestSpecialization()
local specId, role, position = LS:MySpecialization()
if specId then
for _,func in next, callbackMap do
func(specId, role, position, pName) -- This allows us to show our own spec info when not grouped
end
end
if IsInGroup() then
local t = GetTime()
if t-prev > 3 then
timer = false
prev = t
if IsInGroup(2) then
SendAddonMessage("LibSpec", "R", "INSTANCE_CHAT")
end
if IsInGroup(1) then
SendAddonMessage("LibSpec", "R", "RAID")
end
elseif not timer then
timer = true
CTimerAfter(3.1-(t-prev), LS.RequestSpecialization)
end
end
end
end
if IsLoggedIn() and not oldminor then -- Player is logged in and library isn't upgrading
LS:RequestSpecialization()
end
function LS:Register(addon, func)
if not addon or addon == LS then
error("LibSpecialization: You must pass your own addon name or object to :Register.")
end
local t = type(func)
if t == "string" then
callbackMap[addon] = function(...) addon[func](addon, ...) end
elseif t == "function" then
callbackMap[addon] = func
else
error("LibSpecialization: Incorrect function type for :Register.")
end
end
function LS:Unregister(addon)
if not addon or addon == LS then
error("LibSpecialization: You must pass your own addon name or object to :Unregister.")
end
callbackMap[addon] = nil
end