diff --git a/Details.toc b/Details.toc
index 481ad8ab..d6088c30 100644
--- a/Details.toc
+++ b/Details.toc
@@ -67,7 +67,7 @@ frames\window_copy.lua
frames\window_options2.lua
frames\window_options2_sections.lua
frames\window_api.lua
-#frames\window_cdtracker.lua
+frames\window_cdtracker.lua
frames\window_playerbreakdown.lua
frames\window_playerbreakdown_list.lua
frames\window_report.lua
diff --git a/Libs/DF/fw.lua b/Libs/DF/fw.lua
index acc4593a..7bd6f4b5 100644
--- a/Libs/DF/fw.lua
+++ b/Libs/DF/fw.lua
@@ -1,6 +1,6 @@
-local dversion = 220
+local dversion = 221
local major, minor = "DetailsFramework-1.0", dversion
local DF, oldminor = LibStub:NewLibrary (major, minor)
@@ -3509,6 +3509,30 @@ DF.AlliedRaceList = {
[41] = "MagharOrc",
}
+local slotIdToIcon = {
+ [1] = "Interface\\ICONS\\" .. "INV_Helmet_29", --head
+ [2] = "Interface\\ICONS\\" .. "INV_Jewelry_Necklace_07", --neck
+ [3] = "Interface\\ICONS\\" .. "INV_Shoulder_25", --shoulder
+ [5] = "Interface\\ICONS\\" .. "INV_Chest_Cloth_08", --chest
+ [6] = "Interface\\ICONS\\" .. "INV_Belt_15", --waist
+ [7] = "Interface\\ICONS\\" .. "INV_Pants_08", --legs
+ [8] = "Interface\\ICONS\\" .. "INV_Boots_Cloth_03", --feet
+ [9] = "Interface\\ICONS\\" .. "INV_Bracer_07", --wrist
+ [10] = "Interface\\ICONS\\" .. "INV_Gauntlets_17", --hands
+ [11] = "Interface\\ICONS\\" .. "INV_Jewelry_Ring_22", --finger 1
+ [12] = "Interface\\ICONS\\" .. "INV_Jewelry_Ring_22", --finger 2
+ [13] = "Interface\\ICONS\\" .. "INV_Jewelry_Talisman_07", --trinket 1
+ [14] = "Interface\\ICONS\\" .. "INV_Jewelry_Talisman_07", --trinket 2
+ [15] = "Interface\\ICONS\\" .. "INV_Misc_Cape_19", --back
+ [16] = "Interface\\ICONS\\" .. "INV_Sword_39", --main hand
+ [17] = "Interface\\ICONS\\" .. "INV_Sword_39", --off hand
+}
+
+function DF:GetArmorIconByArmorSlot(equipSlotId)
+ return slotIdToIcon[equipSlotId] or ""
+end
+
+
--> store and return a list of character races, always return the non-localized value
DF.RaceCache = {}
function DF:GetCharacterRaceList (fullList)
diff --git a/Libs/DF/spells.lua b/Libs/DF/spells.lua
index ca86db2d..54663ffe 100644
--- a/Libs/DF/spells.lua
+++ b/Libs/DF/spells.lua
@@ -879,9 +879,7 @@ for specId, cooldownTable in pairs (DF.CooldownsBySpec) do
end
DF.CooldownToClass [spellId] = DF.SpecIds [spellId]
-
end
-
end
function DF:FindClassForCooldown (spellId)
@@ -900,6 +898,15 @@ end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--consumables
+DF.WeaponEnchantIds = {
+ [6188] = true, --shadowcore oil
+ [6190] = true, --embalmer's oil
+ [6201] = true, --weighted
+ [6200] = true, --sharpened
+ [5400] = true, --flametongue
+ [5401] = true, --windfury
+}
+
DF.FlaskIDs = {
--Shadowlands
[307185] = true, --Spectral Flask of Power
diff --git a/Libs/LibRaidStatus/LibRaidStatus.lua b/Libs/LibRaidStatus/LibRaidStatus.lua
new file mode 100644
index 00000000..28cecb3c
--- /dev/null
+++ b/Libs/LibRaidStatus/LibRaidStatus.lua
@@ -0,0 +1,1292 @@
+--terminei de fazer o onDead e onAlive events
+--repair precisa registrar isso e mandar na comm e a comm precisa receber e atualizar na lista
+--terminei de fazer o ondeath e oalive; comm nao aceita comm do proprio jogador; tem que ver se o cooldown passa a data certin pro player quando ele casta pq a comm nao vai passar
+--terminei de fazer a restruturação da comm dos cooldowns, agora não existe mais o comando _FULL, cooldowns sempre são mandados separadamente
+
+local major = "LibRaidStatus-1.0"
+local CONST_LIB_VERSION = 4
+LIB_RAID_STATUS_CAN_LOAD = false
+
+--declae the library within the LibStub
+ local libStub = _G.LibStub
+ local raidStatusLib = libStub:NewLibrary(major, CONST_LIB_VERSION)
+ if (not raidStatusLib) then
+ return
+ end
+
+ LIB_RAID_STATUS_CAN_LOAD = true
+
+--default values
+ raidStatusLib.inGroup = false
+ raidStatusLib.CanReceiveComms = false
+
+ --print failures (when the function return an error) results to chat
+ local CONST_DIAGNOSTIC_ERRORS = true
+ --print the data to be sent and data received from comm
+ local CONST_DIAGNOSTIC_COMM = true
+
+ local CONST_COMM_PREFIX = "LRS"
+ local CONST_COMM_COOLDOWNUPDATE_PREFIX = "U"
+ local CONST_COMM_COOLDOWNFULLLIST_PREFIX = "C"
+ local CONST_COMM_GEARINFO_FULL_PREFIX = "G"
+ local CONST_COMM_GEARINFO_DURABILITY_PREFIX = "R"
+ local CONST_COMM_PLAYER_DEAD_PREFIX = "D"
+ local CONST_COMM_PLAYER_ALIVE_PREFIX = "A"
+
+ local CONST_ONE_SECOND = 1.0
+ local CONST_TWO_SECONDS = 2.0
+ local CONST_THREE_SECONDS = 3.0
+ local CONST_FRACTION_OF_A_SECOND = 0.01
+
+ local CONST_COOLDOWN_CHECK_INTERVAL = CONST_THREE_SECONDS
+ local CONST_COOLDOWN_TIMELEFT_HAS_CHANGED = CONST_THREE_SECONDS
+
+ local diagnosticError = function(msg, ...)
+ if (CONST_DIAGNOSTIC_ERRORS) then
+ print("|cFFFF9922raidStatusLib|r:", msg, ...)
+ end
+ end
+
+ local diagnosticComm = function(msg, ...)
+ if (CONST_DIAGNOSTIC_COMM) then
+ print("|cFFFF9922raidStatusLib|r:", msg, ...)
+ end
+ end
+
+ --return the current specId of the player
+ function raidStatusLib.GetPlayerSpecId()
+ local spec = GetSpecialization()
+ if (spec) then
+ local specId = GetSpecializationInfo(spec)
+ if (specId and specId > 0) then
+ return specId
+ end
+ end
+ end
+
+ function raidStatusLib.UpdatePlayerAliveStatus(onLogin)
+ if (UnitIsDeadOrGhost("player")) then
+ if (raidStatusLib.playerAlive) then
+ raidStatusLib.playerAlive = false
+
+ --trigger event if this isn't from login
+ if (not onLogin) then
+ raidStatusLib.internalCallback.TriggerEvent("onPlayerDeath")
+ end
+ end
+ else
+ if (not raidStatusLib.playerAlive) then
+ raidStatusLib.playerAlive = true
+
+ --trigger event if this isn't from login
+ if (not onLogin) then
+ raidStatusLib.internalCallback.TriggerEvent("onPlayerRess")
+ end
+ end
+ end
+ end
+
+ --creates two tables, one with indexed talents and another with pairs values ([talentId] = true)
+ function raidStatusLib.GetPlayerTalents()
+ local talentsPairs = {}
+ local talentsIndex = {}
+ for i = 1, 7 do
+ for o = 1, 3 do
+ local talentId, _, _, selected = GetTalentInfo(i, o, 1)
+ if (selected) then
+ talentsPairs[talentId] = true
+ talentsIndex[#talentsIndex+1] = talentId
+ break
+ end
+ end
+ end
+ return talentsPairs, talentsIndex
+ end
+
+ --simple non recursive table copy
+ function raidStatusLib.TCopy(tableToReceive, tableToCopy)
+ for key, value in pairs(tableToCopy) do
+ tableToReceive[key] = value
+ end
+ end
+
+ --transform a table index a string dividing values with a comma
+ --@table: an indexed table with unknown size
+ function raidStatusLib.PackTable(table)
+ local tableSize = #table
+ local newString = "" .. tableSize .. ","
+ for i = 1, tableSize do
+ newString = newString .. table[i] .. ","
+ end
+
+ newString = newString:gsub(",$", "")
+ return newString
+ end
+
+ --stract some indexes of a table
+ local selectIndexes = function(table, startIndex, amountIndexes)
+ local values = {}
+ for i = startIndex, startIndex+amountIndexes do
+ values[#values+1] = tonumber(table[i]) or 0
+ end
+ return values
+ end
+
+ --return is a number is almost equal to another within a tolerance range
+ function raidStatusLib.isNearlyEqual(value1, value2, tolerance)
+ tolerance = tolerance or CONST_FRACTION_OF_A_SECOND
+ return abs(value1 - value2) <= tolerance
+ end
+
+ --return true if the lib is allowed to receive comms from other players
+ function raidStatusLib.IsCommAllowed()
+ return raidStatusLib.CanReceiveComms
+ end
+
+ --transform a string table into a regular table
+ --@table: a table with unknown values
+ --@index: where in the table is the information we want
+ --@isPair: if true treat the table as pairs(), ipairs() otherwise
+ --@valueAsTable: return {value1, value2, value3}
+ --@amountOfValues: for the parameter above
+ function raidStatusLib.UnpackTable(table, index, isPair, valueIsTable, amountOfValues)
+ local result = {}
+ local reservedIndexes = table[index]
+ local indexStart = index+1
+ local indexEnd = reservedIndexes+index
+
+ if (isPair) then
+ amountOfValues = amountOfValues or 2
+ for i = indexStart, indexEnd, amountOfValues do
+ if (valueIsTable) then
+ local key = tonumber(table[i])
+ local values = selectIndexes(table, i+1, 1)
+ result[key] = values
+ else
+ local key = tonumber(table[i])
+ local value = tonumber(table[i+1])
+ result[key] = value
+ end
+ end
+ else
+ for i = indexStart, indexEnd do
+ local value = tonumber(table[i])
+ result[#result+1] = value
+ end
+ end
+
+ return result
+ end
+
+ --returns if the player is in group
+ function raidStatusLib.IsInGroup()
+ local inParty = IsInGroup()
+ local inRaid = IsInRaid()
+ return inParty or inRaid
+ end
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+--> ~comms
+ raidStatusLib.commHandler = {}
+
+ function raidStatusLib.commHandler.OnReceiveComm(self, event, prefix, text, channel, sender, target, zoneChannelID, localID, name, instanceID)
+ --check if the data belong to us
+ if (prefix == CONST_COMM_PREFIX) then
+ --check if the lib can receive comms
+ if (not raidStatusLib.IsCommAllowed()) then
+ return
+ end
+
+ sender = Ambiguate(sender, "none")
+
+ --don't receive comms from the player it self
+ local playerName = UnitName("player")
+ if (playerName == sender) then
+ --return --commented for debug
+ end
+
+ local data = text
+ local LibDeflate = LibStub:GetLibrary("LibDeflate")
+ local dataCompressed = LibDeflate:DecodeForWoWAddonChannel(data)
+ data = LibDeflate:DecompressDeflate(dataCompressed)
+
+ --get the first byte of the data, it indicates what type of data was transmited
+ local dataTypePrefix = data:match("^.")
+ --get the table with functions regitered for this type of data
+ local callbackTable = raidStatusLib.commHandler.commCallback[dataTypePrefix]
+ --convert to table
+ local dataAsTable = {strsplit(",", data)}
+ --remove the first index (prefix)
+ tremove(dataAsTable, 1)
+ --trigger callbacks
+ for i = 1, #callbackTable do
+ callbackTable[i](dataAsTable, sender)
+ end
+ end
+ end
+
+ C_ChatInfo.RegisterAddonMessagePrefix(CONST_COMM_PREFIX)
+ raidStatusLib.commHandler.eventFrame = CreateFrame("frame")
+ raidStatusLib.commHandler.eventFrame:RegisterEvent("CHAT_MSG_ADDON")
+ raidStatusLib.commHandler.eventFrame:SetScript("OnEvent", raidStatusLib.commHandler.OnReceiveComm)
+
+ raidStatusLib.commHandler.commCallback = {
+ --when transmiting
+ [CONST_COMM_COOLDOWNFULLLIST_PREFIX] = {}, --all cooldowns of a player
+ [CONST_COMM_COOLDOWNUPDATE_PREFIX] = {}, --an update of a single cooldown
+ [CONST_COMM_GEARINFO_FULL_PREFIX] = {}, --an update of gear information
+ [CONST_COMM_GEARINFO_DURABILITY_PREFIX] = {}, --an update of the player gear durability
+ [CONST_COMM_PLAYER_DEAD_PREFIX] = {}, --player is dead
+ [CONST_COMM_PLAYER_ALIVE_PREFIX] = {}, --player is alive
+ }
+
+ function raidStatusLib.commHandler.RegisterComm(prefix, func)
+ --the table for the prefix need to be declared at the 'raidStatusLib.commHandler.commCallback' table
+ tinsert(raidStatusLib.commHandler.commCallback[prefix], func)
+ end
+
+ function raidStatusLib.commHandler.SendCommData(data)
+ local LibDeflate = LibStub:GetLibrary("LibDeflate")
+ local dataCompressed = LibDeflate:CompressDeflate(data, {level = 9})
+ local dataEncoded = LibDeflate:EncodeForWoWAddonChannel(dataCompressed)
+
+ if (IsInGroup() and not IsInRaid()) then --in party only
+ C_ChatInfo.SendAddonMessage(CONST_COMM_PREFIX, dataEncoded, IsInGroup(LE_PARTY_CATEGORY_INSTANCE) and "INSTANCE_CHAT" or "PARTY")
+
+ elseif (IsInRaid()) then
+ C_ChatInfo.SendAddonMessage(CONST_COMM_PREFIX, dataEncoded, IsInRaid(LE_PARTY_CATEGORY_INSTANCE) and "INSTANCE_CHAT" or "RAID")
+ end
+ end
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+--> ~schedule ~timers
+
+ raidStatusLib.Schedules = {
+ registeredUniqueTimers = {}
+ }
+
+ --run a scheduled function with its payload
+ local triggerScheduledTick = function(tickerObject)
+ local payload = tickerObject.payload
+ local callback = tickerObject.callback
+
+ local result, errortext = pcall(callback, _G.unpack(payload))
+ if (not result) then
+ print("raidStatusLib: error on scheduler:", tickerObject.scheduleName, tickerObject.stack, errortext)
+ end
+
+ if (tickerObject.isUnique) then
+ local namespace = tickerObject.namespace
+ local scheduleName = tickerObject.scheduleName
+ raidStatusLib.Schedules.CancelUniqueTimer(namespace, scheduleName)
+ end
+
+ return result
+ end
+
+ --create a new schedule
+ function raidStatusLib.Schedules.NewTimer(time, callback, ...)
+ local payload = {...}
+ local newTimer = C_Timer.NewTimer(time, triggerScheduledTick)
+ newTimer.payload = payload
+ newTimer.callback = callback
+ newTimer.stack = debugstack()
+ return newTimer
+ end
+
+ --create an unique schedule
+ --if a schedule already exists, cancels it and make a new
+ function raidStatusLib.Schedules.NewUniqueTimer(time, callback, namespace, scheduleName, ...)
+ raidStatusLib.Schedules.CancelUniqueTimer(namespace, scheduleName)
+
+ local newTimer = raidStatusLib.Schedules.NewTimer(time, callback, ...)
+ newTimer.namespace = namespace
+ newTimer.scheduleName = scheduleName
+ newTimer.stack = debugstack()
+ newTimer.isUnique = true
+
+ local registeredUniqueTimers = raidStatusLib.Schedules.registeredUniqueTimers
+ registeredUniqueTimers[namespace] = registeredUniqueTimers[namespace] or {}
+ registeredUniqueTimers[namespace][scheduleName] = newTimer
+ end
+
+ --cancel an unique schedule
+ function raidStatusLib.Schedules.CancelUniqueTimer(namespace, scheduleName)
+ local registeredUniqueTimers = raidStatusLib.Schedules.registeredUniqueTimers
+ local currentSchedule = registeredUniqueTimers[namespace] and registeredUniqueTimers[namespace][scheduleName]
+
+ if (currentSchedule) then
+ if (not currentSchedule._cancelled) then
+ currentSchedule:Cancel()
+ end
+ registeredUniqueTimers[namespace][scheduleName] = nil
+ end
+ end
+
+ --cancel all unique timers
+ function raidStatusLib.Schedules.CancelAllUniqueTimers()
+ local registeredUniqueTimers = raidStatusLib.Schedules.registeredUniqueTimers
+ for namespace, schedulesTable in pairs(registeredUniqueTimers) do
+ for scheduleName, timerObject in pairs (schedulesTable) do
+ if (timerObject and not timerObject._cancelled) then
+ timerObject:Cancel()
+ end
+ end
+ end
+ table.wipe(registeredUniqueTimers)
+ end
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+--> ~public ~callbacks
+--these are the events where other addons can register and receive calls
+ local allPublicCallbacks = {
+ "CooldownListUpdate",
+ "CooldownListWiped",
+ "CooldownUpdate",
+ "OnPlayerDeath",
+ "OnPlayerRess",
+ "GearListWiped",
+ "GearUpdate",
+ "GearDurabilityUpdate",
+ }
+
+ --save build the table to avoid lose registered events on older versions
+ raidStatusLib.publicCallback = raidStatusLib.publicCallback or {}
+ raidStatusLib.publicCallback.events = raidStatusLib.publicCallback.events or {}
+ for _, callbackName in ipairs(allPublicCallbacks) do
+ raidStatusLib.publicCallback.events[callbackName] = raidStatusLib.publicCallback.events[callbackName] or {}
+ end
+
+ local checkRegisterDataIntegrity = function(addonObject, event, callbackMemberName)
+ --check of integrity
+ if (type(addonObject) == "string") then
+ addonObject = _G[addonObject]
+ end
+
+ if (type(addonObject) ~= "table") then
+ return 1
+ end
+
+ if (not raidStatusLib.publicCallback.events[event]) then
+ return 2
+
+ elseif (not addonObject[callbackMemberName]) then
+ return 3
+ end
+
+ return true
+ end
+
+ --call the registered function within the addon namespace
+ --payload is sent together within the call
+ function raidStatusLib.publicCallback.TriggerCallback(event, ...)
+ local callbacks = raidStatusLib.publicCallback.events[event]
+
+ for i = 1, #callbacks do
+ local addonObject = callbacks[i][1]
+ local functionName = callbacks[i][2]
+ local func = addonObject[functionName]
+
+ if (func) then
+ --using pcall at the moment, should get a better caller in the future
+ local okay, errorMessage = pcall(func, ...)
+ if (not okay) then
+ print("error:", errorMessage)
+ end
+ end
+ end
+ end
+
+ function raidStatusLib.RegisterCallback(addonObject, event, callbackMemberName)
+ --check of integrity
+ local integrity = checkRegisterDataIntegrity(addonObject, event, callbackMemberName)
+ if (integrity and type(integrity) ~= "boolean") then
+ return integrity
+ end
+
+ --register
+ tinsert(raidStatusLib.publicCallback.events[event], {addonObject, callbackMemberName})
+ return true
+ end
+
+ function raidStatusLib.UnregisterCallback(addonObject, event, callbackMemberName)
+ --check of integrity
+ local integrity = checkRegisterDataIntegrity(addonObject, event, callbackMemberName)
+ if (integrity and type(integrity) ~= "boolean") then
+ return integrity
+ end
+
+ for i = 1, #raidStatusLib.publicCallback.events[event] do
+ local registeredCallback = raidStatusLib.publicCallback.events[event][i]
+ if (registeredCallback[1] == addonObject and registeredCallback[2] == callbackMemberName) then
+ tremove(raidStatusLib.publicCallback.events[event], i)
+ break
+ end
+ end
+ end
+
+--------------------------------------------------------------------------------------------------------------------------------
+--> ~internal ~callbacks
+--internally, each module can register events through the internal callback to be notified when something happens in the game
+
+ raidStatusLib.internalCallback = {}
+ raidStatusLib.internalCallback.events = {
+ ["onEnterGroup"] = {},
+ ["onLeaveGroup"] = {},
+ ["playerCast"] = {},
+ ["onEnterWorld"] = {},
+ ["talentUpdate"] = {},
+ ["onPlayerDeath"] = {},
+ ["onPlayerRess"] = {},
+ }
+
+ raidStatusLib.internalCallback.RegisterCallback = function(event, func)
+ tinsert(raidStatusLib.internalCallback.events[event], func)
+ end
+
+ raidStatusLib.internalCallback.UnRegisterCallback = function(event, func)
+ local container = raidStatusLib.internalCallback.events[event]
+ for i = 1, #container do
+ if (container[i] == func) then
+ tremove(container, i)
+ break
+ end
+ end
+ end
+
+ function raidStatusLib.internalCallback.TriggerEvent(event, ...)
+ local container = raidStatusLib.internalCallback.events[event]
+ for i = 1, #container do
+ container[i](event, ...)
+ end
+ end
+
+ --create the frame for receiving game events
+ local eventFrame = _G.RaidStatusLibFrame
+ if (not eventFrame) then
+ eventFrame = CreateFrame("frame", "RaidStatusLibFrame", UIParent)
+ end
+
+ local eventFunctions = {
+ --check if the player joined a group
+ ["GROUP_ROSTER_UPDATE"] = function()
+ local eventTriggered = false
+ if (raidStatusLib.IsInGroup()) then
+ if (not raidStatusLib.inGroup) then
+ raidStatusLib.inGroup = true
+ raidStatusLib.internalCallback.TriggerEvent("onEnterGroup")
+ eventTriggered = true
+ end
+ else
+ if (raidStatusLib.inGroup) then
+ raidStatusLib.inGroup = false
+ raidStatusLib.internalCallback.TriggerEvent("onLeaveGroup")
+ eventTriggered = true
+ end
+ end
+
+ if (not eventTriggered and raidStatusLib.IsInGroup()) then --the player didn't left or enter a group
+ --the group has changed, trigger a long timer to send full data
+ --as the timer is unique, a new change to the group will replace and refresh the time
+ --using random time, players won't trigger all at the same time
+ local randomTime = 4.0 + math.random(1.0, 4.5)
+ raidStatusLib.Schedules.NewUniqueTimer(randomTime, raidStatusLib.mainControl.SendFullData, "mainControl", "sendFullData_Schedule")
+ end
+ end,
+
+ ["UNIT_SPELLCAST_SUCCEEDED"] = function(...)
+ local unitId, castGUID, spellId = ...
+ C_Timer.After(0.1, function()
+ raidStatusLib.internalCallback.TriggerEvent("playerCast", spellId)
+ end)
+ end,
+
+ ["PLAYER_ENTERING_WORLD"] = function(...)
+ raidStatusLib.internalCallback.TriggerEvent("onEnterWorld")
+ end,
+
+ --["PLAYER_SPECIALIZATION_CHANGED"] = function(...) end, --on changing spec, the talent_update event is also triggered
+ ["PLAYER_TALENT_UPDATE"] = function(...)
+ raidStatusLib.internalCallback.TriggerEvent("talentUpdate")
+ end,
+
+ ["PLAYER_DEAD"] = function(...)
+ raidStatusLib.UpdatePlayerAliveStatus()
+ end,
+ ["PLAYER_ALIVE"] = function(...)
+ raidStatusLib.UpdatePlayerAliveStatus()
+ end,
+ ["PLAYER_UNGHOST"] = function(...)
+ raidStatusLib.UpdatePlayerAliveStatus()
+ end,
+
+ ["PLAYER_REGEN_DISABLED"] = function(...)
+
+ end,
+
+ ["PLAYER_REGEN_ENABLED"] = function(...)
+
+ end,
+ }
+
+ eventFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
+ eventFrame:RegisterUnitEvent("UNIT_SPELLCAST_SUCCEEDED", "player")
+ eventFrame:RegisterEvent("PLAYER_ENTERING_WORLD")
+ eventFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
+ eventFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
+ --eventFrame:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
+ eventFrame:RegisterEvent("PLAYER_TALENT_UPDATE")
+ eventFrame:RegisterEvent("PLAYER_DEAD")
+ eventFrame:RegisterEvent("PLAYER_ALIVE")
+ eventFrame:RegisterEvent("PLAYER_UNGHOST")
+
+ eventFrame:SetScript("OnEvent", function(self, event, ...)
+ eventFunctions[event](...)
+ end)
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+--> ~main ~control
+
+ raidStatusLib.mainControl = {
+ playerAliveStatus = {},
+ }
+
+ --send full data (all data available)
+ function raidStatusLib.mainControl.SendFullData()
+
+ --send cooldown data
+ raidStatusLib.cooldownManager.SendAllCooldowns()
+
+ --send gear data
+ raidStatusLib.gearManager.SendAllGearInfo()
+ end
+
+ raidStatusLib.mainControl.onEnterWorld = function()
+ --update the alive status of the player
+ raidStatusLib.UpdatePlayerAliveStatus(true)
+
+ --the game client is fully loadded and all information is available
+ if (raidStatusLib.IsInGroup()) then
+ raidStatusLib.Schedules.NewUniqueTimer(1.0, raidStatusLib.mainControl.SendFullData, "mainControl", "sendFullData_Schedule")
+ raidStatusLib.CanReceiveComms = true
+ end
+ end
+
+ raidStatusLib.mainControl.OnEnterGroup = function()
+ --the player entered in a group
+ --schedule to send data
+ raidStatusLib.Schedules.NewUniqueTimer(1.0, raidStatusLib.mainControl.SendFullData, "mainControl", "sendFullData_Schedule")
+ raidStatusLib.CanReceiveComms = true
+ end
+
+ raidStatusLib.mainControl.OnLeftGroup = function()
+ --the player left a group
+ --wipe group data (each module registers the OnLeftGroup)
+
+ --cancel all schedules
+ raidStatusLib.Schedules.CancelAllUniqueTimers()
+
+ --wipe alive status
+ table.wipe(raidStatusLib.mainControl.playerAliveStatus)
+
+ --toggle off comms
+ raidStatusLib.CanReceiveComms = false
+ end
+
+ raidStatusLib.mainControl.OnPlayerDeath = function()
+ local playerName = UnitName("player")
+ raidStatusLib.mainControl.playerAliveStatus[playerName] = false
+
+ local dataToSend = CONST_COMM_PLAYER_DEAD_PREFIX
+ raidStatusLib.commHandler.SendCommData(dataToSend)
+ diagnosticComm("OnPlayerDeath| " .. dataToSend) --debug
+
+ raidStatusLib.publicCallback.TriggerCallback("OnPlayerDeath", playerName)
+ end
+
+ raidStatusLib.mainControl.OnPlayerRess = function()
+ local playerName = UnitName("player")
+ raidStatusLib.mainControl.playerAliveStatus[playerName] = true
+
+ local dataToSend = CONST_COMM_PLAYER_ALIVE_PREFIX
+ raidStatusLib.commHandler.SendCommData(dataToSend)
+ diagnosticComm("OnPlayerRess| " .. dataToSend) --debug
+
+ raidStatusLib.publicCallback.TriggerCallback("OnPlayerRess", playerName)
+ end
+
+ raidStatusLib.internalCallback.RegisterCallback("onEnterWorld", raidStatusLib.mainControl.onEnterWorld)
+ raidStatusLib.internalCallback.RegisterCallback("onEnterGroup", raidStatusLib.mainControl.OnEnterGroup)
+ raidStatusLib.internalCallback.RegisterCallback("onLeaveGroup", raidStatusLib.mainControl.OnLeftGroup)
+ raidStatusLib.internalCallback.RegisterCallback("onPlayerDeath", raidStatusLib.mainControl.OnPlayerDeath)
+ raidStatusLib.internalCallback.RegisterCallback("onPlayerRess", raidStatusLib.mainControl.OnPlayerRess)
+
+ --a player in the group died
+ raidStatusLib.commHandler.RegisterComm(CONST_COMM_PLAYER_DEAD_PREFIX, function(data, sourceName)
+ raidStatusLib.mainControl.playerAliveStatus[sourceName] = false
+ raidStatusLib.publicCallback.TriggerCallback("OnPlayerDeath", sourceName)
+ end)
+
+ --a player in the group is now alive
+ raidStatusLib.commHandler.RegisterComm(CONST_COMM_PLAYER_ALIVE_PREFIX, function(data, sourceName)
+ raidStatusLib.mainControl.playerAliveStatus[sourceName] = true
+ raidStatusLib.publicCallback.TriggerCallback("OnPlayerRess", sourceName)
+ end)
+
+--------------------------------------------------------------------------------------------------------------------------------
+--> ~cooldowns
+ raidStatusLib.cooldownManager = {
+ playerData = {}, --stores the list of cooldowns each player has sent
+ playerCurrentCooldowns = {},
+ cooldownTickers = {}, --store C_Timer.NewTicker
+ }
+
+ --check if a cooldown has changed or done
+ local cooldownTimeLeftCheck = function(tickerObject)
+ local spellId = tickerObject.spellId
+ tickerObject.cooldownTimeLeft = tickerObject.cooldownTimeLeft - CONST_COOLDOWN_CHECK_INTERVAL
+ local timeLeft, charges = raidStatusLib.cooldownManager.GetCooldownStatus(spellId)
+
+ --is the spell ready to use?
+ if (timeLeft == 0) then
+ --it's ready
+ raidStatusLib.cooldownManager.SendCooldownUpdate(spellId, 0, charges)
+ raidStatusLib.cooldownManager.cooldownTickers[spellId] = nil
+ tickerObject:Cancel()
+ else
+ --check if the time left has changed
+ if (not raidStatusLib.isNearlyEqual(tickerObject.cooldownTimeLeft, timeLeft, CONST_COOLDOWN_TIMELEFT_HAS_CHANGED)) then
+ --there's a deviation, send a comm to communicate the change in the time left
+ raidStatusLib.cooldownManager.SendCooldownUpdate(spellId, timeLeft, charges)
+ tickerObject.cooldownTimeLeft = timeLeft
+ end
+ end
+ end
+
+ --after a spell is casted by the player, start a ticker to check its cooldown
+ local cooldownStartTicker = function(spellId, cooldownTimeLeft)
+ local existingTicker = raidStatusLib.cooldownManager.cooldownTickers[spellId]
+ if (existingTicker) then
+ --is a ticker already exists, might be the cooldown of a charge
+ --if the ticker isn't about to expire, just keep the timer
+ --when the ticker finishes it'll check again for charges
+ if (existingTicker.startTime + existingTicker.cooldownTime - GetTime() > 2) then
+ return
+ end
+
+ --cancel the existing ticker
+ if (not existingTicker._cancelled) then
+ existingTicker:Cancel()
+ end
+ end
+
+ --create a new ticker
+ local maxTicks = ceil(cooldownTimeLeft / CONST_COOLDOWN_CHECK_INTERVAL)
+ local newTicker = C_Timer.NewTicker(CONST_COOLDOWN_CHECK_INTERVAL, cooldownTimeLeftCheck, maxTicks)
+
+ --store the ticker
+ raidStatusLib.cooldownManager.cooldownTickers[spellId] = newTicker
+ newTicker.spellId = spellId
+ newTicker.cooldownTimeLeft = cooldownTimeLeft
+ newTicker.startTime = GetTime()
+ newTicker.endTime = GetTime() + cooldownTimeLeft
+ end
+
+ local cooldownGetUnitTable = function(unitName, shouldWipe)
+ local unitCooldownTable = raidStatusLib.cooldownManager.playerData[unitName]
+ --check if the unit has a cooldownTable
+ if (not unitCooldownTable) then
+ unitCooldownTable = {}
+ raidStatusLib.cooldownManager.playerData[unitName] = unitCooldownTable
+ else
+ --as the unit could have changed a talent or spec, wipe the table before using it
+ if (shouldWipe) then
+ table.wipe(unitCooldownTable)
+ end
+ end
+
+ return unitCooldownTable
+ end
+
+ --update a single spell time and charges
+ --called when the player casted a cooldown and when received a cooldown update from another player
+ local singleCooldownUpdate = function(unitName, spellId, newTimeLeft, newCharges)
+ local unitCooldownTable = cooldownGetUnitTable(unitName)
+ local spellIdTable = unitCooldownTable[spellId] or {}
+ spellIdTable[1] = newTimeLeft
+ spellIdTable[2] = newCharges
+ unitCooldownTable[spellId] = spellIdTable
+ end
+
+ function raidStatusLib.cooldownManager.GetCooldownTable()
+ return raidStatusLib.cooldownManager.playerData
+ end
+
+ function raidStatusLib.cooldownManager.GetPlayerCooldownTable(playerName)
+ return raidStatusLib.cooldownManager.playerData[playerName]
+ end
+
+ function raidStatusLib.cooldownManager.OnPlayerCast(event, spellId)
+ --player casted a spell, check if the spell is registered as cooldown
+ local playerSpec = raidStatusLib.GetPlayerSpecId()
+ if (playerSpec) then
+ if (LIB_RAID_STATUS_COOLDOWNS_BY_SPEC[playerSpec] and LIB_RAID_STATUS_COOLDOWNS_BY_SPEC[playerSpec][spellId]) then
+ --get the cooldown time for this spell
+ local timeLeft, charges = raidStatusLib.cooldownManager.GetCooldownStatus(spellId)
+
+ local playerName = UnitName("player")
+
+ --update the time left
+ singleCooldownUpdate(playerName, spellId, timeLeft, charges)
+
+ --trigger a public callback
+ raidStatusLib.publicCallback.TriggerCallback("CooldownUpdate", playerName, spellId, timeLeft, charges, raidStatusLib.cooldownManager.playerData)
+
+ --send to comm
+ raidStatusLib.cooldownManager.SendCooldownUpdate(spellId, timeLeft, charges)
+
+ --create a timer to monitor the time of this cooldown
+ --as there's just a few of them to monitor, there's no issue on creating one timer per spell
+ cooldownStartTicker(spellId, timeLeft)
+ end
+ end
+ end
+ raidStatusLib.internalCallback.RegisterCallback("playerCast", raidStatusLib.cooldownManager.OnPlayerCast)
+
+ --received a cooldown update from another unit (sent by the function above)
+ raidStatusLib.commHandler.RegisterComm(CONST_COMM_COOLDOWNUPDATE_PREFIX, function(data, sourceName)
+ --get data
+ local dataAsArray = data
+ local spellId = tonumber(dataAsArray[2])
+ local cooldownTimer = tonumber(dataAsArray[3])
+ local charges = tonumber(dataAsArray[4])
+
+ --check integraty
+ if (not spellId or spellId == 0) then
+ return diagnosticError("cooldownManager|comm received|spellId is invalid")
+
+ elseif (not cooldownTimer) then
+ return diagnosticError("cooldownManager|comm received|cooldownTimer is invalid")
+
+ elseif (not charges) then
+ return diagnosticError("cooldownManager|comm received|charges is invalid")
+ end
+
+ --update
+ singleCooldownUpdate(sourceName, spellId, cooldownTimer, charges)
+
+ --trigger a public callback
+ raidStatusLib.publicCallback.TriggerCallback("CooldownUpdate", sourceName, spellId, cooldownTimer, charges, raidStatusLib.cooldownManager.playerData)
+ end)
+
+ --when the player is ressed while in a group, send the cooldown list
+ function raidStatusLib.cooldownManager.OnPlayerRess()
+ --check if is in group
+ if (raidStatusLib.IsInGroup()) then
+ raidStatusLib.Schedules.NewUniqueTimer(1.0 + math.random(0.0, 6.0), raidStatusLib.cooldownManager.SendAllCooldowns, "cooldownManager", "sendAllCooldowns_Schedule")
+ end
+ end
+ raidStatusLib.internalCallback.RegisterCallback("onPlayerRess", raidStatusLib.cooldownManager.OnPlayerRess)
+
+ --clear data stored
+ function raidStatusLib.cooldownManager.EraseData()
+ table.wipe(raidStatusLib.cooldownManager.playerData)
+ end
+
+ function raidStatusLib.cooldownManager.OnLeaveGroup()
+ --clear the data
+ raidStatusLib.cooldownManager.EraseData()
+
+ --trigger a public callback
+ raidStatusLib.publicCallback.TriggerCallback("CooldownListWiped", raidStatusLib.cooldownManager.playerData)
+ end
+ raidStatusLib.internalCallback.RegisterCallback("onLeaveGroup", raidStatusLib.cooldownManager.OnLeaveGroup)
+
+ --adds a list of cooldowns for another player in the group
+ --this is called from the received cooldown list from comm
+ function raidStatusLib.cooldownManager.AddUnitCooldownsList(unitName, cooldownsTable)
+ local unitCooldownTable = cooldownGetUnitTable(unitName, true)
+ raidStatusLib.TCopy(unitCooldownTable, cooldownsTable)
+
+ --trigger a public callback
+ raidStatusLib.publicCallback.TriggerCallback("CooldownListUpdate", unitName, raidStatusLib.cooldownManager.playerData)
+ end
+
+ --check if a player cooldown is ready or if is in cooldown
+ --@spellId: the spellId to check for cooldown
+ function raidStatusLib.cooldownManager.GetCooldownStatus(spellId)
+ --check if is a charge spell
+ local cooldownInfo = LIB_RAID_STATUS_COOLDOWNS_INFO[spellId]
+ if (cooldownInfo.charges and cooldownInfo.charges > 1) then
+ local chargesAvailable, chargesTotal, start, duration = GetSpellCharges(spellId)
+
+ if (chargesAvailable == chargesTotal) then
+ return 0, chargesTotal --all charges are ready to use
+ else
+ --return the time to the next charge
+ local timeLeft = start + duration - GetTime()
+ return ceil(timeLeft), chargesAvailable
+ end
+
+ else
+ local start, duration = GetSpellCooldown(spellId)
+ if (start == 0) then --cooldown is ready
+ return 0, 1
+ else
+ local timeLeft = start + duration - GetTime()
+ return ceil(timeLeft), 0
+ end
+ end
+ end
+
+ --send to comm all cooldowns available for the player
+ function raidStatusLib.cooldownManager.SendAllCooldowns()
+ --get the full cooldown list
+ local playerCooldownList = raidStatusLib.cooldownManager.GetPlayerCooldownList()
+ local dataToSend = CONST_COMM_COOLDOWNFULLLIST_PREFIX .. ","
+ --pack
+
+ local playerCooldownString = raidStatusLib.PackTable(playerCooldownList)
+ dataToSend = dataToSend .. playerCooldownString
+
+ --send the data
+ raidStatusLib.commHandler.SendCommData(dataToSend)
+ diagnosticComm("SendAllCooldowns| " .. dataToSend) --debug
+ end
+
+ --send to comm a specific cooldown that was just used, a charge got available or its cooldown is over (ready to use)
+ function raidStatusLib.cooldownManager.SendCooldownUpdate(spellId, cooldownTimeLeft, charges)
+ local dataToSend = CONST_COMM_COOLDOWNUPDATE_PREFIX .. "," .. spellId .. "," .. cooldownTimeLeft .. "," .. charges
+ raidStatusLib.commHandler.SendCommData(dataToSend)
+ diagnosticComm("SendCooldownUpdate| " .. dataToSend) --debug
+ end
+
+ --triggered when the lib receives a full list of cooldowns from another player in the raid
+ --@data: table received from comm
+ --@source: player name
+ function raidStatusLib.cooldownManager.OnReceiveCooldowns(data, source)
+ --unpack the table as a pairs table
+ local unpackedTable = raidStatusLib.UnpackTable(data, 1, true, true, 3)
+ --add the list of cooldowns
+ raidStatusLib.cooldownManager.AddUnitCooldownsList(source, unpackedTable)
+ end
+ raidStatusLib.commHandler.RegisterComm(CONST_COMM_COOLDOWNFULLLIST_PREFIX, raidStatusLib.cooldownManager.OnReceiveCooldowns)
+
+
+
+ --build a list with the local player cooldowns
+ function raidStatusLib.cooldownManager.GetPlayerCooldownList()
+ --get the player specId
+ local specId = raidStatusLib.GetPlayerSpecId()
+ if (specId) then
+ --get the cooldowns for the specialization
+ local playerCooldowns = LIB_RAID_STATUS_COOLDOWNS_BY_SPEC[specId]
+ if (not playerCooldowns) then
+ diagnosticError("cooldownManager|GetPlayerCooldownList|can't find player cooldowns for specId:", specId)
+ return {}
+ end
+
+ local cooldowns = {}
+ local talentsHash, talentsIndex = raidStatusLib.GetPlayerTalents()
+
+ for cooldownSpellId, cooldownType in pairs(playerCooldowns) do
+ --get all the information about this cooldow
+ local cooldownInfo = LIB_RAID_STATUS_COOLDOWNS_INFO[cooldownSpellId]
+ if (cooldownInfo) then
+ --does this cooldown is based on a talent?
+ local talentId = cooldownInfo.talent
+ if (talentId) then
+ --check if the player has the talent selected
+ if (talentsHash[talentId]) then
+ cooldowns[#cooldowns+1] = cooldownSpellId
+ local timeLeft, charges = raidStatusLib.cooldownManager.GetCooldownStatus(cooldownSpellId)
+ cooldowns[#cooldowns+1] = timeLeft
+ cooldowns[#cooldowns+1] = charges
+ end
+ else
+ cooldowns[#cooldowns+1] = cooldownSpellId
+ local timeLeft, charges = raidStatusLib.cooldownManager.GetCooldownStatus(cooldownSpellId)
+ cooldowns[#cooldowns+1] = timeLeft
+ cooldowns[#cooldowns+1] = charges
+ end
+ end
+ end
+ return cooldowns
+ else
+ return {}
+ end
+ end
+
+--------------------------------------------------------------------------------------------------------------------------------
+--> ~equipment
+
+ raidStatusLib.gearManager = {
+ --structure:
+ --[playerName] = {ilevel = 100, durability = 100, weaponEnchant = 0, noGems = {}, noEnchants = {}}
+ playerData = {},
+ }
+
+ function raidStatusLib.gearManager.GetGearTable()
+ return raidStatusLib.gearManager.playerData
+ end
+
+ function raidStatusLib.gearManager.GetPlayerGearTable(playerName, createNew)
+ local playerGearInfo = raidStatusLib.gearManager.playerData[playerName]
+ if (not playerGearInfo and createNew) then
+ playerGearInfo = {
+ ilevel = 0,
+ durability = 0,
+ weaponEnchant = 0,
+ noGems = {},
+ noEnchants = {},
+ }
+ raidStatusLib.gearManager.playerData[playerName] = playerGearInfo
+ end
+ return playerGearInfo
+ end
+
+ --return an integer between zero and one hundret indicating the player gear durability
+ function raidStatusLib.gearManager.GetGearDurability()
+ local durabilityTotalPercent, totalItems = 0, 0
+ for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
+ local durability, maxDurability = GetInventoryItemDurability(i)
+ if (durability and maxDurability) then
+ local itemDurability = durability / maxDurability * 100
+ durabilityTotalPercent = durabilityTotalPercent + itemDurability
+ totalItems = totalItems + 1
+ end
+ end
+
+ if (totalItems == 0) then
+ return 100
+ end
+
+ return floor(durabilityTotalPercent / totalItems)
+ end
+
+ --clear data stored
+ function raidStatusLib.gearManager.EraseData()
+ table.wipe(raidStatusLib.gearManager.playerData)
+ end
+
+ function raidStatusLib.gearManager.OnLeaveGroup()
+ --clear the data
+ raidStatusLib.gearManager.EraseData()
+
+ --trigger a public callback
+ raidStatusLib.publicCallback.TriggerCallback("GearListWiped", raidStatusLib.gearManager.playerData)
+ end
+ raidStatusLib.internalCallback.RegisterCallback("onLeaveGroup", raidStatusLib.gearManager.OnLeaveGroup)
+
+ --when the player is ressed while in a group, send the cooldown list
+ function raidStatusLib.gearManager.OnPlayerRess()
+ --check if is in group
+ if (raidStatusLib.IsInGroup()) then
+ raidStatusLib.Schedules.NewUniqueTimer(1.0 + math.random(0.0, 6.0), raidStatusLib.gearManager.SendDurability, "gearManager", "sendDurability_Schedule")
+ end
+ end
+ raidStatusLib.internalCallback.RegisterCallback("onPlayerRess", raidStatusLib.gearManager.OnPlayerRess)
+
+ --send only the gear durability
+ function raidStatusLib.gearManager.SendDurability()
+ local dataToSend = CONST_COMM_GEARINFO_DURABILITY_PREFIX .. ","
+ local playerGearDurability = raidStatusLib.gearManager.GetGearDurability()
+
+ dataToSend = dataToSend .. playerGearDurability
+
+ --send the data
+ raidStatusLib.commHandler.SendCommData(dataToSend)
+ diagnosticComm("SendGearDurabilityData| " .. dataToSend) --debug
+ end
+
+ function raidStatusLib.gearManager.OnReceiveGearDurability(data, source)
+ local durability = tonumber(data[1])
+ raidStatusLib.gearManager.UpdateUnitGearDurability(source, durability)
+ end
+ raidStatusLib.commHandler.RegisterComm(CONST_COMM_GEARINFO_DURABILITY_PREFIX, raidStatusLib.gearManager.OnReceiveGearDurability)
+
+ --on receive the durability (sent when the player get a ress)
+ function raidStatusLib.gearManager.UpdateUnitGearDurability(playerName, durability)
+ local playerGearInfo = raidStatusLib.gearManager.GetPlayerGearTable(playerName)
+ if (playerGearInfo) then
+ playerGearInfo.durability = durability
+ raidStatusLib.publicCallback.TriggerCallback("GearDurabilityUpdate", playerName, durability, raidStatusLib.gearManager.GetGearTable())
+ end
+ end
+
+ --get gear information from what the player has equipped at the moment
+ function raidStatusLib.gearManager.GetPlayerGearInfo()
+
+ --get the player class and specId
+ local _, playerClass = UnitClass("player")
+ local specId = raidStatusLib.GetPlayerSpecId()
+ --get which attribute the spec uses
+ local specMainAttribute = raidStatusLib.specAttribute[playerClass][specId] --1 int, 2 dex, 3 str
+
+ if (not specId or not specMainAttribute) then
+ return {0, 0, 0, {}, {}}
+ end
+
+ --item level
+ local _, itemLevel = GetAverageItemLevel()
+ itemLevel = floor(itemLevel)
+
+ --repair status
+ local gearDurability = raidStatusLib.gearManager.GetGearDurability()
+
+ --get weapon enchant
+ local weaponEnchant = 0
+ local _, _, _, mainHandEnchantId, _, _, _, offHandEnchantId = GetWeaponEnchantInfo()
+ if (LIB_RAID_STATUS_WEAPON_ENCHANT_IDS[mainHandEnchantId]) then
+ weaponEnchant = 1
+
+ elseif(LIB_RAID_STATUS_WEAPON_ENCHANT_IDS[offHandEnchantId]) then
+ weaponEnchant = 1
+ end
+
+ --enchants and gems
+ --hold equipmentSlotId of equipment with a gem socket but it's empty
+ local slotsWithoutGems = {}
+ --hold equipmentSlotId of equipments without an enchant
+ local slotsWithoutEnchant = {}
+
+ for equipmentSlotId = 1, 17 do
+
+ local itemLink = GetInventoryItemLink("player", equipmentSlotId)
+
+ if (itemLink) then
+ --get the information from the item
+ local _, itemId, enchantId, gemId1, gemId2, gemId3, gemId4, suffixId, uniqueId, levelOfTheItem, specId, upgradeInfo, instanceDifficultyId, numBonusIds, restLink = strsplit(":", itemLink)
+ local gemsIds = {gemId1, gemId2, gemId3, gemId4}
+
+ --enchant
+ --check if the slot can receive enchat and if the equipment has an enchant
+ local enchantAttribute = LIB_RAID_STATUS_ENCHANT_SLOTS[equipmentSlotId]
+ if (enchantAttribute) then --this slot can receive an enchat
+
+ --check if this slot is relevant for the class, some slots can have enchants only for Agility which won't matter for Priests as an example
+ --if the value is an integer it points to an attribute (int, dex, str), otherwise it's true (boolean)
+ local slotIsRelevant = true
+ if (type (enchantAttribute) == "number") then
+ if (specMainAttribute ~= enchantAttribute) then
+ slotIsRelevant = false
+ end
+ end
+
+ if (slotIsRelevant) then
+ --does the slot has any enchant?
+ if (not enchantId or enchantId == "0" or enchantId == "") then
+ slotsWithoutEnchant[#slotsWithoutEnchant+1] = equipmentSlotId
+
+ else
+ --convert to integer
+ local enchantIdInt = tonumber(enchantId)
+ if (enchantIdInt) then
+ --does the enchant is relevent for the character?
+ if (not LIB_RAID_STATUS_ENCHANT_IDS[enchantIdInt]) then
+ slotsWithoutEnchant[#slotsWithoutEnchant+1] = equipmentSlotId
+ end
+
+ else
+ --the enchat has an invalid id
+ slotsWithoutEnchant[#slotsWithoutEnchant+1] = equipmentSlotId
+ end
+ end
+ end
+ end
+
+ --gems
+ local itemStatsTable = {}
+ --fill the table above with information about the item
+ GetItemStats(itemLink, itemStatsTable)
+
+ --check if the item has a socket
+ if (itemStatsTable.EMPTY_SOCKET_PRISMATIC) then
+ --check if the socket is empty
+ for i = 1, itemStatsTable.EMPTY_SOCKET_PRISMATIC do
+ local gemId = tonumber(gemsIds[i])
+ if (not gemId or gemId == 0) then
+ slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
+
+ --check if the gem is not a valid gem (deprecated gem)
+ elseif (not LIB_RAID_STATUS_GEM_IDS[gemId]) then
+ slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
+
+ end
+ end
+ end
+ end
+ end --end of enchants and gems
+
+ --build the table with the gear information
+ local playerGearInfo = {}
+ playerGearInfo[#playerGearInfo+1] = itemLevel --[1]
+ playerGearInfo[#playerGearInfo+1] = gearDurability --[2]
+ playerGearInfo[#playerGearInfo+1] = weaponEnchant --[3]
+ playerGearInfo[#playerGearInfo+1] = slotsWithoutEnchant --[4]
+ playerGearInfo[#playerGearInfo+1] = slotsWithoutGems --[5]
+
+ --update the player table
+ raidStatusLib.gearManager.AddUnitGearInfoList(UnitName("player"), itemLevel, gearDurability, weaponEnchant, slotsWithoutEnchant, slotsWithoutGems)
+
+ return playerGearInfo
+ end
+
+ --when received the gear update from another player, store it and trigger a callback
+ function raidStatusLib.gearManager.AddUnitGearInfoList(playerName, itemLevel, durability, weaponEnchant, noEnchantTable, noGemsTable)
+ local playerGearInfo = raidStatusLib.gearManager.GetPlayerGearTable(playerName, true)
+
+ playerGearInfo.ilevel = itemLevel
+ playerGearInfo.durability = durability
+ playerGearInfo.weaponEnchant = weaponEnchant
+ playerGearInfo.noGems = noGemsTable
+ playerGearInfo.noEnchants = noEnchantTable
+
+ raidStatusLib.publicCallback.TriggerCallback("GearUpdate", playerName, playerGearInfo, raidStatusLib.gearManager.GetGearTable())
+ end
+
+ --triggered when the lib receives a gear information from another player in the raid
+ --@data: table received from comm
+ --@source: player name
+ function raidStatusLib.gearManager.OnReceiveGearFullInfo(data, source)
+ local itemLevel = tonumber(data[1])
+ local durability = tonumber(data[2])
+ local weaponEnchant = tonumber(data[3])
+
+ local noEnchantTableSize = tonumber(data[4])
+ local noGemsTableIndex = tonumber(noEnchantTableSize + 5)
+ local noGemsTableSize = data[noGemsTableIndex]
+
+ --raidStatusLib.UnpackTable(table, index, isPair, valueIsTable, amountOfValues)
+
+ --unpack the enchant data as a ipairs table
+ local noEnchantTableUnpacked = raidStatusLib.UnpackTable(data, 4, false, false, noEnchantTableSize)
+ --unpack the enchant data as a ipairs table
+ local noGemsTableUnpacked = raidStatusLib.UnpackTable(data, noGemsTableIndex, false, false, noGemsTableSize)
+
+ --add to the list of gear information
+ raidStatusLib.gearManager.AddUnitGearInfoList(source, itemLevel, durability, weaponEnchant, noEnchantTableUnpacked, noGemsTableUnpacked)
+ end
+ raidStatusLib.commHandler.RegisterComm(CONST_COMM_GEARINFO_FULL_PREFIX, raidStatusLib.gearManager.OnReceiveGearFullInfo)
+
+ function raidStatusLib.gearManager.SendAllGearInfo()
+ --get gear information, gear info has 4 indexes:
+ --[1] int item level
+ --[2] int durability
+ --[3] int weapon enchant
+ --[3] table with integers of equipSlot without enchant
+ --[4] table with integers of equipSlot which has a gem slot but the slot is empty
+
+ local dataToSend = CONST_COMM_GEARINFO_FULL_PREFIX .. ","
+ local playerGearInfo = raidStatusLib.gearManager.GetPlayerGearInfo()
+
+ dataToSend = dataToSend .. playerGearInfo[1] .. "," --item level
+ dataToSend = dataToSend .. playerGearInfo[2] .. "," --durability
+ dataToSend = dataToSend .. playerGearInfo[3] .. "," --weapon enchant
+ dataToSend = dataToSend .. raidStatusLib.PackTable(playerGearInfo[4]) .. "," --slots without enchant
+ dataToSend = dataToSend .. raidStatusLib.PackTable(playerGearInfo[5]) -- slots with empty gem sockets
+
+ --send the data
+ raidStatusLib.commHandler.SendCommData(dataToSend)
+ diagnosticComm("SendGearFullData| " .. dataToSend) --debug
+ end
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+--> ~player general info
+
+raidStatusLib.playerInfoManager = {}
+
+function raidStatusLib.playerInfoManager.GetPlayerInfo()
+ local playerInfo = {}
+ --name
+ playerInfo[1] = UnitName("player")
+
+ --spec
+
+ --talents
+
+ --renown
+
+ --conduits
+
+end
+
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+--> data
+
+--which is the main attribute of each spec
+--1 Intellect
+--2 Agility
+--3 Strenth
+raidStatusLib.specAttribute = {
+ ["DEMONHUNTER"] = {
+ [577] = 2,
+ [581] = 2,
+ },
+ ["DEATHKNIGHT"] = {
+ [250] = 3,
+ [251] = 3,
+ [252] = 3,
+ },
+ ["WARRIOR"] = {
+ [71] = 3,
+ [72] = 3,
+ [73] = 3,
+ },
+ ["MAGE"] = {
+ [62] = 1,
+ [63] = 1,
+ [64] = 1,
+ },
+ ["ROGUE"] = {
+ [259] = 2,
+ [260] = 2,
+ [261] = 2,
+ },
+ ["DRUID"] = {
+ [102] = 1,
+ [103] = 2,
+ [104] = 2,
+ [105] = 1,
+ },
+ ["HUNTER"] = {
+ [253] = 2,
+ [254] = 2,
+ [255] = 2,
+ },
+ ["SHAMAN"] = {
+ [262] = 1,
+ [263] = 2,
+ [264] = 1,
+ },
+ ["PRIEST"] = {
+ [256] = 1,
+ [257] = 1,
+ [258] = 1,
+ },
+ ["WARLOCK"] = {
+ [265] = 1,
+ [266] = 1,
+ [267] =1 ,
+ },
+ ["PALADIN"] = {
+ [65] = 1,
+ [66] = 3,
+ [70] = 3,
+ },
+ ["MONK"] = {
+ [268] = 2,
+ [269] = 2,
+ [270] = 1,
+ }
+}
\ No newline at end of file
diff --git a/Libs/LibRaidStatus/LibRaidStatus.toc b/Libs/LibRaidStatus/LibRaidStatus.toc
new file mode 100644
index 00000000..063bfa59
--- /dev/null
+++ b/Libs/LibRaidStatus/LibRaidStatus.toc
@@ -0,0 +1,5 @@
+## Interface: 90002
+## Title: Library Raid Status
+## Notes: This is a library used by addons.
+
+lib.xml
diff --git a/Libs/LibRaidStatus/ThingsToMantain.lua b/Libs/LibRaidStatus/ThingsToMantain.lua
new file mode 100644
index 00000000..a1b9b70e
--- /dev/null
+++ b/Libs/LibRaidStatus/ThingsToMantain.lua
@@ -0,0 +1,789 @@
+
+--data which main need maintenance over time
+
+if (not LIB_RAID_STATUS_CAN_LOAD) then
+ return
+end
+
+--which gear slots can be enchanted on the latest retail version of the game
+--when the value is a number, the slot only receives enchants for a specific attribute
+LIB_RAID_STATUS_ENCHANT_SLOTS = {
+ --[INVSLOT_NECK] = true,
+
+ [INVSLOT_BACK] = true, --for all
+ [INVSLOT_CHEST] = true, --for all
+ [INVSLOT_FINGER1] = true, --for all
+ [INVSLOT_FINGER2] = true, --for all
+ [INVSLOT_MAINHAND] = true, --for all
+
+ [INVSLOT_FEET] = 2, --agility only
+ [INVSLOT_WRIST] = 1, --intellect only
+ [INVSLOT_HAND] = 3, --strenth only
+}
+
+-- how to get the enchantId:
+-- local itemLink = GetInventoryItemLink("player", slotId)
+-- local enchandId = select (3, strsplit(":", itemLink))
+-- print("enchantId:", enchandId)
+LIB_RAID_STATUS_ENCHANT_IDS = {
+ --FEET
+ --[6207] = INVSLOT_FEET, --[Enchant Boots - Speed of Soul]
+ [6211] = INVSLOT_FEET, --[Enchant Boots - Eternal Agility] + 15 agi
+ [6212] = INVSLOT_FEET, --[Enchant Boots - Agile Soulwalker] + 10 agi
+
+ --WRIST
+ --[6222] = INVSLOT_WRIST, [Enchant Bracers - Shaded Hearthing]
+ [6219] = INVSLOT_WRIST, --[Enchant Bracers - Illuminated Soul] + 10 int
+ [6220] = INVSLOT_WRIST, --[Enchant Bracers - Eternal Intellect] + 15 int
+
+ --HAND
+ --[6205] = INVSLOT_HAND, --[Enchant Gloves - Shadowlands Gathering]
+ [6209] = INVSLOT_HAND, --[Enchant Gloves - Strength of Soul] +10 str
+ [6210] = INVSLOT_HAND, --[Enchant Gloves - Eternal Strength] +15 str
+
+ --FINGER
+ [6164] = INVSLOT_FINGER1, --[Enchant Ring - Tenet of Critical Strike] +16
+ [6166] = INVSLOT_FINGER1, --[Enchant Ring - Tenet of Haste] +16
+ [6168] = INVSLOT_FINGER1, --[Enchant Ring - Tenet of Mastery] +16
+ [6170] = INVSLOT_FINGER1, --[Enchant Ring - Tenet of Versatility] +16
+
+ --BACK
+ [6202] = INVSLOT_BACK, --[Enchant Cloak - Fortified Speed] +20 stam +30 speed
+ [6203] = INVSLOT_BACK, --[Enchant Cloak - Fortified Avoidance] +20 stam +30 avoidance
+ [6204] = INVSLOT_BACK, --[Enchant Cloak - Fortified Leech]
+ [6208] = INVSLOT_BACK, --[Enchant Cloak - Soul Vitality]
+
+ --CHEST
+ [6213] = INVSLOT_CHEST, --[Enchant Chest - Eternal Bulwark] +25 armor +20 agi or str
+ [6214] = INVSLOT_CHEST, --[Enchant Chest - Eternal Skirmish] +20 agi or str +more white damage
+ [6217] = INVSLOT_CHEST, --[Enchant Chest - Eternal Bounds] +20 int + 6% mana
+ [6216] = INVSLOT_CHEST, --[Enchant Chest - Sacred Stats] +20 all stats
+ [6230] = INVSLOT_CHEST, --[Enchant Chest - Eternal Stats] +30 all stats
+
+ --MAINHAND
+ [6223] = INVSLOT_MAINHAND, --[Enchant Weapon - Lightless Force] + shadow wave damage
+ [6226] = INVSLOT_MAINHAND, --[Enchant Weapon - Eternal Grace] + burst of healing done
+ [6227] = INVSLOT_MAINHAND, --[Enchant Weapon - Ascended Vigor] + healing received increased
+ [6228] = INVSLOT_MAINHAND, --[Enchant Weapon - Sinful Revelation] + 6% bleed damage
+ [6229] = INVSLOT_MAINHAND, --[Enchant Weapon - Celestial Guidance] + 5% agility
+}
+
+-- how to get the gemId:
+-- local itemLink = GetInventoryItemLink("player", slotId)
+-- local gemId = select (4, strsplit(":", itemLink))
+-- print("gemId:", gemId)
+LIB_RAID_STATUS_GEM_IDS = {
+ [173126] = true, --Straddling Jewel Doublet (green, +12 speed)
+ [173125] = true, --Revitalizing Jewel Doublet (green, +100 health)
+ [173130] = true, --Masterful Jewel Cluster (blue, master)
+ [173129] = true, --Versatile Jewel Cluster (blue, versatility)
+ [173127] = true, --Deadly Jewel Cluster (blue, crit)
+ [173128] = true, --Quick Jewel Cluster (blue, haste)
+}
+
+LIB_RAID_STATUS_WEAPON_ENCHANT_IDS = {
+ [6188] = true, --shadowcore oil
+ [6190] = true, --embalmer's oil
+ [6201] = true, --weighted
+ [6200] = true, --sharpened
+ [5400] = true, --flametongue
+ [5401] = true, --windfury
+}
+
+LIB_RAID_STATUS_COOLDOWNS_BY_SPEC = {
+ -- 1 attack cooldown
+ -- 2 personal defensive cooldown
+ -- 3 targetted defensive cooldown
+ -- 4 raid defensive cooldown
+ -- 5 personal utility cooldown
+
+ --Shadowlands 9.0.2 revision by Juliana Maison
+
+ --MAGE
+ --arcane
+ [62] = {
+ [12042] = 1, --Arcane Power
+ [55342] = 1, --Mirror Image
+ [45438] = 2, --Ice Block
+ [12051] = 5, --Evocation
+ [110960] = 5, --Greater Invisibility
+ [235450] = 5, --Prismatic Barrier
+ },
+ --fire
+ [63] = {
+ [190319] = 1, --Combustion
+ [55342] = 1, --Mirror Image
+ [45438] = 2, --Ice Block
+ [66] = 5, --Invisibility
+ [235313] = 5, --Blazing Barrier
+ },
+ --frost
+ [64] = {
+ [12472] = 1, --Icy Veins
+ [205021] = 1, --Ray of Frost (talent)
+ [55342] = 1, --Mirror Image
+ [45438] = 2, --Ice Block
+ [66] = 5, --Invisibility
+ [235219] = 5, --Cold Snap
+ [11426] = 5, --Ice Barrier
+ [113724] = 5, --Ring of Frost (talent)
+ },
+
+ --PRIEST
+ --discipline
+ [256] = {
+ [10060] = 1, --Power Infusion
+ [34433] = 1, --Shadowfiend
+ [123040] = 1, --Mindbender
+ [33206] = 3, --Pain Suppression
+ [62618] = 4, --Power Word: Barrier
+ [271466] = 4, --Luminous Barrier (talent)
+ [109964] = 4, --Spirit Shell (talent)
+ [47536] = 5, --Rapture
+ [19236] = 5, --Desperate Prayer
+ [8122] = 5, --Psychic Scream
+ },
+ --holy
+ [257] = {
+ [10060] = 1, --Power Infusion
+ [200183] = 2, --Apotheosis
+ [47788] = 3, --Guardian Spirit
+ [64844] = 4, --Divine Hymn
+ [64901] = 4, --Symbol of Hope
+ [265202] = 4, --Holy Word: Salvation (talent)
+ [88625] = 5, --Holy Word: Chastise
+ [34861] = 5, --Holy Word: Sanctify
+ [2050] = 5, --Holy Word: Serenity
+ [19236] = 5, --Desperate Prayer
+ [8122] = 5, --Psychic Scream
+ },
+ --shadow priest
+ [258] = {
+ [10060] = 1, --Power Infusion
+ [34433] = 1, --Shadowfiend
+ [200174] = 1, --Mindbender
+ [205385] = 1, --Shadow Clash
+ [193223] = 1, --Surrender to Madness
+ [47585] = 2, --Dispersion
+ [15286] = 4, --Vampiric Embrace
+ [19236] = 5, --Desperate Prayer
+ [64044] = 5, --Psychic Horror
+ [8122] = 5, --Psychic Scream
+ [205369] = 5, --Mind Bomb
+ },
+
+ --ROGUE
+ --assassination
+ [259] = {
+ [79140] = 1, --Vendetta
+ [1856] = 2, --Vanish
+ [5277] = 2, --Evasion
+ [31224] = 2, --Cloak of Shadows
+ [2094] = 5, --Blind
+ [185311] = 5, --Crimson Vial
+ [114018] = 5, --Shroud of Concealment
+ },
+ --outlaw
+ [260] = {
+ [13750] = 1, --Adrenaline Rush
+ [51690] = 1, --Killing Spree (talent)
+ [199754] = 2, --Riposte
+ [31224] = 2, --Cloak of Shadows
+ [5277] = 2, --Evasion
+ [1856] = 2, --Vanish
+ [2094] = 5, --Blind
+ [185311] = 5, --Crimson Vial
+ [114018] = 5, --Shroud of Concealment
+ [343142] = 5, --Dreadblades
+ },
+ --subtlety
+ [261] = {
+ [121471] = 1, --Shadow Blades
+ [31224] = 2, --Cloak of Shadows
+ [1856] = 2, --Vanish
+ [5277] = 2, --Evasion
+ [2094] = 5, --Blind
+ [185311] = 5, --Crimson Vial
+ [114018] = 5, --Shroud of Concealment
+ },
+
+ --WARLOCK
+ --affliction
+ [265] = {
+ [205180] = 1, --Summon Darkglare
+ [342601] = 1, --Ritual of Doom
+ [113860] = 1, --Dark Soul: Misery (talent)
+ [104773] = 2, --Unending Resolve
+ [108416] = 2, --Dark Pact (talent)
+ [30283] = 5, --Shadowfury
+ [6789] = 5, --Mortal Coil (talent)
+ [333889] = 5, --Fel Domination
+ },
+ --demonology
+ [266] = {
+ [265187] = 1, --Summon Demonic Tyrant
+ [342601] = 1, --Ritual of Doom
+ [267171] = 1, --Demonic Strength (talent)
+ [111898] = 1, --Grimoire: Felguard (talent)
+ [267217] = 1, --Nether Portal (talent)
+
+ [104773] = 2, --Unending Resolve
+ [108416] = 2, --Dark Pact (talent)
+
+ [30283] = 5, --Shadowfury
+ [6789] = 5, --Mortal Coil (talent)
+ [5484] = 5, --Howl of Terror (talent)
+ [333889] = 5, --Fel Domination
+ },
+ --destruction
+ [267] = {
+ [1122] = 1, --Summon Infernal
+ [342601] = 1, --Ritual of Doom
+ [113858] = 1, --Dark Soul: Instability (talent)
+ [104773] = 2, --Unending Resolve
+ [108416] = 2, --Dark Pact (talent)
+ [6789] = 5, --Mortal Coil (talent)
+ [30283] = 5, --Shadowfury
+ [333889] = 5, --Fel Domination
+ },
+
+ --WARRIOR
+ --Arms
+ [71] = {
+ [107574] = 1, --Avatar (talent)
+ [227847] = 1, --Bladestorm
+ [152277] = 1, --Ravager (talent)
+ [118038] = 2, --Die by the Sword
+ [97462] = 4, --Rallying Cry
+ [64382] = 5, --Shattering Throw
+ [18499] = 5, --Berserker Rage
+ [5246] = 5, --Intimidating Shout
+ },
+ --Fury
+ [72] = {
+ [1719] = 1, --Recklessness
+ [46924] = 1, --Bladestorm (talent)
+ [184364] = 2, --Enraged Regeneration
+ [97462] = 4, --Rallying Cry
+ [64382] = 5, --Shattering Throw
+ [18499] = 5, --Berserker Rage
+ [5246] = 5, --Intimidating Shout
+ },
+ --Protection
+ [73] = {
+ [228920] = 1, --Ravager (talent)
+ [107574] = 1, --Avatar
+ [12975] = 2, --Last Stand
+ [871] = 2, --Shield Wall
+ [97462] = 4, --Rallying Cry
+ [64382] = 5, --Shattering Throw
+ [18499] = 5, --Berserker Rage
+ [5246] = 5, --Intimidating Shout
+ },
+
+ --PALADIN
+ --holy
+ [65] = {
+ [31884] = 1, --Avenging Wrath
+ [216331] = 1, --Avenging Crusader (talent)
+ [498] = 2, --Divine Protection
+ [642] = 2, --Divine Shield
+ [105809] = 2, --Holy Avenger (talent)
+ [152262] = 2, --Seraphim
+ [633] = 3, --Lay on Hands
+ [1022] = 3, --Blessing of Protection
+ [6940] = 3, --Blessing of Sacrifice
+ [31821] = 4, --Aura Mastery
+ [1044] = 5, --Blessing of Freedom
+ [853] = 5, --Hammer of Justice
+ [115750] = 5, --Blinding Light (talent)
+ },
+
+ --protection
+ [66] = {
+ [31884] = 1, --Avenging Wrath
+ [327193] = 1, --Moment of Glory (talent)
+ [31850] = 2, --Ardent Defender
+ [86659] = 2, --Guardian of Ancient Kings
+ [105809] = 2, --Holy Avenger (talent)
+ [152262] = 2, --Seraphim
+ [1022] = 3, --Blessing of Protection
+ [204018] = 3, --Blessing of Spellwarding (talent)
+ [6940] = 3, --Blessing of Sacrifice
+ [1044] = 5, --Blessing of Freedom
+ [853] = 5, --Hammer of Justice
+ [115750] = 5, --Blinding Light (talent)
+ },
+
+ --retribution
+ [70] = {
+ [31884] = 1, --Avenging Wrath
+ [231895] = 1, --Crusade (talent)
+ [205191] = 2, --Eye for an Eye (talent)
+ [184662] = 2, --Shield of Vengeance
+ [642] = 2, --Divine Shield
+ [1022] = 3, --Blessing of Protection
+ [6940] = 3, --Blessing of Sacrifice
+ [633] = 3, --Lay on Hands
+ [1044] = 5, --Blessing of Freedom
+ [853] = 5, --Hammer of Justice
+ [115750] = 5, --Blinding Light (talent)
+ },
+
+ --DEMON HUNTER
+ --havoc
+ [577] = {
+ [200166] = 1, --Metamorphosis
+ [198589] = 2, --Blur
+ [196555] = 2, --Netherwalk (talent)
+ [196718] = 4, --Darkness
+ [188501] = 5, --Spectral Sight
+ [179057] = 5, --Chaos Nova
+ [211881] = 5, --Fel Eruption (talent)
+ },
+ --vengeance
+ [581] = {
+ [320341] = 1, --Bulk Extraction (talent)
+ [187827] = 2, --Metamorphosis
+ [204021] = 2, --Fiery Brand
+ [263648] = 2, --Soul Barrier (talent)
+ [207684] = 5, --Sigil of Misery
+ [202137] = 5, --Sigil of Silence
+ [202138] = 5, --Sigil of Chains (talent)
+ [188501] = 5, --Spectral Sight
+ },
+
+ --DEATH KNIGHT
+ --unholy
+ [252] = {
+ [275699] = 1, --Apocalypse
+ [42650] = 1, --Army of the Dead
+ [49206] = 1, --Summon Gargoyle (talent)
+ [207289] = 1, --Unholy Assault (talent)
+ [48707] = 2, --Anti-magic Shell
+ [48792] = 2, --Icebound Fortitude
+ [48743] = 2, --Death Pact (talent)
+ [51052] = 4, --Anti-magic Zone
+ [108194] = 5, --Asphyxiate (talent)
+ [287081] = 5, --Lichborne
+ [212552] = 5, --Wraith walk (talent)
+
+ },
+ --frost
+ [251] = {
+ [152279] = 1, --Breath of Sindragosa (talent)
+ [47568] = 1, --Empower Rune Weapon
+ [279302] = 1, --Frostwyrm's Fury
+ [48707] = 2, --Anti-magic Shell
+ [48792] = 2, --Icebound Fortitude
+ [48743] = 2, --Death Pact (talent)
+ [51052] = 4, --Anti-magic Zone
+ [207167] = 5, --Blinding Sleet (talent)
+ [108194] = 5, --Asphyxiate (talent)
+ [287081] = 5, --Lichborne
+ [212552] = 5, --Wraith walk (talent)
+ },
+ --blood
+ [250] = {
+ [49028] = 1, --Dancing Rune Weapon
+ [48707] = 2, --Anti-magic Shell
+ [48743] = 2, --Death Pact (talent)
+ [219809] = 2, --Tombstone (talent)
+ [55233] = 2, --Vampiric Blood
+ [48792] = 2, --Icebound Fortitude
+ [51052] = 4, --Anti-magic Zone
+ [108199] = 5, --Gorefiend's Grasp
+ [221562] = 5, --Asphyxiate
+ [212552] = 5, --Wraith walk (talent)
+ },
+
+ --DRUID
+ --Balance
+ [102] = {
+ [194223] = 1, --Celestial Alignment
+ [102560] = 1, --Incarnation: Chosen of Elune (talent)
+ [22812] = 2, --Barkskin
+ [108238] = 2, --Renewal (talent)
+ [29166] = 3, --Innervate
+ [77761] = 4, --Stampeding Roar
+ [99] = 5, --Incapacitating Roar
+ [319454] = 5, --Heart of the Wild (talent)
+ [132469] = 5, --Typhoon
+ [78675] = 5, --Solar Beam
+ },
+ --Feral
+ [103] = {
+ [106951] = 1, --Berserk
+ [102543] = 1, --Incarnation: King of the Jungle (talent)
+ [22812] = 2, --Barkskin
+ [61336] = 2, --Survival Instincts
+ [108238] = 2, --Renewal (talent)
+ [77764] = 4, --Stampeding Roar
+ [132469] = 5, --Typhoon
+ [319454] = 5, --Heart of the Wild (talent)
+ },
+ --Guardian
+ [104] = {
+ [106951] = 1, --Berserk
+ [204066] = 1, --Lunar Beam
+ [22812] = 2, --Barkskin
+ [61336] = 2, --Survival Instincts
+ [102558] = 2, --Incarnation: Guardian of Ursoc (talent)
+ [108238] = 2, --Renewal (talent)
+ [77761] = 4, --Stampeding Roar
+ [132469] = 5, --Typhoon
+ [99] = 5, --Incapacitating Roar
+ [319454] = 5, --Heart of the Wild (talent)
+ },
+ --Restoration
+ [105] = {
+
+ [22812] = 2, --Barkskin
+ [108238] = 2, --Renewal (talent)
+ [33891] = 2, --Incarnation: Tree of Life (talent)
+ [102342] = 3, --Ironbark
+ [29166] = 3, --Innervate
+ [203651] = 3, --Overgrowth (talent)
+ [740] = 4, --Tranquility
+ [197721] = 4, --Flourish (talent)
+ [77761] = 4, --Stampeding Roar
+ [319454] = 5, --Heart of the Wild (talent)
+ [102793] = 5, --Ursol's Vortex
+ },
+
+ --HUNTER
+ --beast mastery
+ [253] = {
+ [193530] = 1, --Aspect of the Wild
+ [19574] = 1, --Bestial Wrath
+ [201430] = 1, --Stampede (talent)
+ [186265] = 2, --Aspect of the Turtle
+ [109304] = 2, --Exhilaration
+ [199483] = 2, --Camouflage (talent)
+ [186257] = 5, --Aspect of the cheetah
+ [19577] = 5, --Intimidation
+ [109248] = 5, --Binding Shot (talent)
+ [187650] = 5, --Freezing Trap
+ },
+ --marksmanship
+ [254] = {
+ [193526] = 1, --Trueshot
+ [260402] = 1, --Double tap
+ [186265] = 2, --Aspect of the Turtle
+ [199483] = 2, --Camouflage (talent)
+ [109304] = 2, --Exhilaration
+ [281195] = 2, --Survival of the Fittest
+ [186257] = 5, --Aspect of the cheetah
+ [187650] = 5, --Freezing Trap
+ },
+ --survival
+ [255] = {
+ [266779] = 1, --Coordinated Assault
+ [186265] = 2, --Aspect of the Turtle
+ [199483] = 2, --Camouflage (talent)
+ [109304] = 2, --Exhilaration
+ [186289] = 5, --Aspect of the eagle
+ [19577] = 5, --Intimidation
+ [187650] = 5, --Freezing Trap
+ },
+
+ --MONK
+ --brewmaster
+ [268] = {
+ [132578] = 1, --Invoke Niuzao, the Black Ox
+ [115080] = 1, --Touch of Death
+ [115203] = 2, --Fortifying Brew
+ [115399] = 2, --Black Ox brew (talent)
+ [115176] = 2, --Zen Meditation
+ [122278] = 2, --Dampen Harm (talent)
+ [116844] = 5, --Ring of peace (talent)
+ [119381] = 5, --Leg Sweep
+ },
+ --windwalker
+ [269] = {
+ [137639] = 1, --Storm, Earth, and Fire
+ [123904] = 1, --Invoke Xuen, the White Tiger
+ [152173] = 1, --Serenity (talent)
+ [115080] = 1, --Touch of Death
+ [115203] = 2, --Fortifying Brew
+ [122470] = 2, --Touch of Karma
+ [122278] = 2, --Dampen Harm (talent)
+ [122783] = 2, --Diffuse Magic (talent)
+ [116844] = 5, --Ring of peace (talent)
+ [119381] = 5, --Leg Sweep
+ },
+ --mistweaver
+ [270] = {
+ [115080] = 1, --Touch of Death
+ [122278] = 2, --Dampen Harm (talent)
+ [243435] = 2, --Fortifying Brew
+ [122783] = 2, --Diffuse Magic (talent)
+ [116849] = 3, --Life Cocoon
+ [322118] = 4, --Invoke Yulon, the Jade serpent
+-- [198664] = 4, --Invoke Chi-Ji, the Red Crane (talent)
+ [115310] = 4, --Revival
+ [116844] = 5, --Ring of peace (talent)
+ [197908] = 5, --Mana tea (talent)
+ [119381] = 5, --Leg Sweep
+ },
+
+ --SHAMAN
+ --elemental
+ [262] = {
+ [198067] = 1, --Fire Elemental
+ [192249] = 1, --Storm Elemental (talent)
+ [114050] = 1, --Ascendance (talent)
+ [108271] = 2, --Astral Shift
+ [108281] = 4, --Ancestral Guidance (talent)
+ [198103] = 2, --Earth Elemental
+ [79206] = 5, --Spiritwalkers grace
+ [65992] = 5, --Tremor Totem
+ [192058] = 5, --Capacitor Totem
+ [192077] = 5, --Wind Rush Totem (talent)
+ },
+ --enhancement
+ [263] = {
+ [51533] = 1, --Feral Spirit
+ [114051] = 1, --Ascendance (talent)
+ [108271] = 2, --Astral Shift
+ [198103] = 2, --Earth Elemental
+ [65992] = 5, --Tremor Totem
+ [192058] = 5, --Capacitor Totem
+
+ },
+ --restoration
+ [264] = {
+ [108271] = 2, --Astral Shift
+ [114052] = 2, --Ascendance (talent)
+ [98008] = 4, --Spirit Link Totem
+ [108280] = 4, --Healing Tide Totem
+ [16191] = 4, --Mana Tide Totem
+ [207399] = 4, --Ancestral Protection Totem (talent)
+ [198103] = 2, --Earth Elemental
+ [65992] = 5, --Tremor Totem
+ },
+}
+
+--tells the duration, requirements and cooldown
+--information about a cooldown is mainly get from tooltips
+--if talent is required, use the command:
+--/dump GetTalentInfo (talentTier, talentColumn, 1)
+--example: to get the second talent of the last talent line, use: /dump GetTalentInfo (7, 2, 1)
+LIB_RAID_STATUS_COOLDOWNS_INFO = {
+ --> paladin
+ [31884] = {cooldown = 120, duration = 20, talent = false, charges = 1, class = "PALADIN", type = 1}, --Avenging Wrath
+ [216331] = {cooldown = 120, duration = 20, talent = 22190, charges = 1, class = "PALADIN", type = 1}, --Avenging Crusader (talent)
+ [498] = {cooldown = 60, duration = 8, talent = false, charges = 1, class = "PALADIN", type = 2}, --Divine Protection
+ [642] = {cooldown = 300, duration = 8, talent = false, charges = 1, class = "PALADIN", type = 2}, --Divine Shield
+ [105809] = {cooldown = 90, duration = 20, talent = 22164, charges = 1, class = "PALADIN", type = 2}, --Holy Avenger (talent)
+ [152262] = { cooldown = 45, duration = 15, talent = 17601, charges = 1, class = "PALADIN", type = 2}, --Seraphim
+ [633] = {cooldown = 600, duration = false, talent = false, charges = 1, class = "PALADIN", type = 3}, --Lay on Hands
+ [1022] = {cooldown = 300, duration = 10, talent = false, charges = 1, class = "PALADIN", type = 3}, --Blessing of Protection
+ [6940] = {cooldown = 120, duration = 12, talent = false, charges = 1, class = "PALADIN", type = 3}, --Blessing of Sacrifice
+ [31821] = {cooldown = 180, duration = 8, talent = false, charges = 1, class = "PALADIN", type = 4}, --Aura Mastery
+ [1044] = {cooldown = 25, duration = 8, talent = false, charges = 1, class = "PALADIN", type = 5}, --Blessing of Freedom
+ [853] = {cooldown = 60, duration = 6, talent = false, charges = 1, class = "PALADIN", type = 5}, --Hammer of Justice
+ [115750] = {cooldown = 90, duration = 6, talent = 21811, charges = 1, class = "PALADIN", type = 5}, --Blinding Light(talent)
+ [327193] = {cooldown = 90, duration = 15, talent = 23468, charges = 1, class = "PALADIN", type = 1}, --Moment of Glory (talent)
+ [31850] = {cooldown = 120, duration = 8, talent = false, charges = 1, class = "PALADIN", type = 2}, --Ardent Defender
+ [86659] = {cooldown = 300, duration = 8, talent = false, charges = 1, class = "PALADIN", type = 2}, --Guardian of Ancient Kings
+ [204018] = {cooldown = 180, duration = 10, talent = 22435, charges = 1, class = "PALADIN", type = 3}, --Blessing of Spellwarding (talent)
+ [231895] = {cooldown = 120, duration = 25, talent = 22215, charges = 1, class = "PALADIN", type = 1}, --Crusade (talent)
+ [205191] = {cooldown = 60, duration = 10, talent = 22183, charges = 1, class = "PALADIN", type = 2}, --Eye for an Eye (talent)
+ [184662] = {cooldown = 120, duration = 15, talent = false, charges = 1, class = "PALADIN", type = 2}, --Shield of Vengeance
+
+ --> warrior
+ [107574] = {cooldown = 90, duration = 20, talent = 22397, charges = 1, class = "WARRIOR", type = 1}, --Avatar
+ [227847] = {cooldown = 90, duration = 5, talent = false, charges = 1, class = "WARRIOR", type = 1}, --Bladestorm
+ [152277] = {cooldown = 60, duration = 6, talent = 21667, charges = 1, class = "WARRIOR", type = 1}, --Ravager (talent)
+ [118038] = {cooldown = 180, duration = 8, talent = false, charges = 1, class = "WARRIOR", type = 2}, --Die by the Sword
+ [97462] = {cooldown = 180, duration = 10, talent = false, charges = 1, class = "WARRIOR", type = 4}, --Rallying Cry
+ [1719] = {cooldown = 90, duration = 10, talent = false, charges = 1, class = "WARRIOR", type = 1}, --Recklessness
+ [46924] = {cooldown = 60, duration = 4, talent = 22400, charges = 1, class = "WARRIOR", type = 1}, --Bladestorm (talent)
+ [184364] = {cooldown = 120, duration = 8, talent = false, charges = 1, class = "WARRIOR", type = 2}, --Enraged Regeneration
+ [228920] = {cooldown = 60, duration = 6, talent = 23099, charges = 1, class = "WARRIOR", type = 1}, --Ravager (talent)
+ [12975] = {cooldown = 180, duration = 15, talent = false, charges = 1, class = "WARRIOR", type = 2}, --Last Stand
+ [871] = {cooldown = 8, duration = 240, talent = false, charges = 1, class = "WARRIOR", type = 2}, --Shield Wall
+ [64382] = {cooldown = 180, duration = false, talent = false, charges = 1, class = "WARRIOR", type = 5}, --Shattering Throw
+ [5246] = {cooldown = 90, duration = 8, talent = false, charges = 1, class = "WARRIOR", type = 5}, --Intimidating Shout
+
+
+ --> warlock
+ [205180] = {cooldown = 180, duration = 20, talent = false, charges = 1, class = "WARLOCK", type = 1}, --Summon Darkglare
+ [342601] = {cooldown = 3600, duration = false, talent = false, charges = 1, class = "WARLOCK", type = 1}, --Ritual of Doom
+ [113860] = {cooldown = 120, duration = 20, talent = 19293, charges = 1, class = "WARLOCK", type = 1}, --Dark Soul: Misery (talent)
+ [104773] = {cooldown = 180, duration = 8, talent = false, charges = 1, class = "WARLOCK", type = 2}, --Unending Resolve
+ [108416] = {cooldown = 60, duration = 20, talent = 19286, charges = 1, class = "WARLOCK", type = 2}, --Dark Pact (talent)
+ [265187] = {cooldown = 90, duration = 15, talent = false, charges = 1, class = "WARLOCK", type = 1}, --Summon Demonic Tyrant
+ [111898] = {cooldown = 120, duration = 15, talent = 21717, charges = 1, class = "WARLOCK", type = 1}, --Grimoire: Felguard (talent)
+ [267171] = {cooldown = 60, duration = false, talent = 23138, charges = 1, class = "WARLOCK", type = 1}, --Demonic Strength (talent)
+ [267217] = {cooldown = 180, duration = 20, talent = 23091, charges = 1, class = "WARLOCK", type = 1}, --Nether Portal
+ [1122] = {cooldown = 180, duration = 30, talent = false, charges = 1, class = "WARLOCK", type = 1}, --Summon Infernal
+ [113858] = {cooldown = 120, duration = 20, talent = 23092, charges = 1, class = "WARLOCK", type = 1}, --Dark Soul: Instability (talent)
+ [30283] = {cooldown = 60, duration = 3, talent = false, charges = 1, class = "WARLOCK", type = 5}, --Shadowfury
+ [333889] = {cooldown = 180, duration = 15, talent = false, charges = 1, class = "WARLOCK", type = 5}, --Fel Domination
+
+ --> shaman
+ [198067] = {cooldown = 150, duration = 30, talent = false, charges = 1, class = "SHAMAN", type = 1}, --Fire Elemental
+ [192249] = {cooldown = 150, duration = 30, talent = 19272, charges = 1, class = "SHAMAN", type = 1}, --Storm Elemental (talent)
+ [108271] = {cooldown = 90, duration = 8, talent = false, charges = 1, class = "SHAMAN", type = 2}, --Astral Shift
+ [108281] = {cooldown = 120, duration = 10, talent = 22172, charges = 1, class = "SHAMAN", type = 4}, --Ancestral Guidance (talent)
+ [51533] = {cooldown = 120, duration = 15, talent = false, charges = 1, class = "SHAMAN", type = 1}, --Feral Spirit
+ [114050] = {cooldown = 180, duration = 15, talent = 21675, charges = 1, class = "SHAMAN", type = 1}, --Ascendance (talent)
+ [114051] = {cooldown = 180, duration = 15, talent = 21972, charges = 1, class = "SHAMAN", type = 1}, --Ascendance (talent)
+ [114052] = {cooldown = 180, duration = 15, talent = 22359, charges = 1, class = "SHAMAN", type = 2}, --Ascendance (talent)
+ [98008] = {cooldown = 180, duration = 6, talent = false, charges = 1, class = "SHAMAN", type = 4}, --Spirit Link Totem
+ [108280] = {cooldown = 180, duration = 10, talent = false, charges = 1, class = "SHAMAN", type = 4}, --Healing Tide Totem
+ [207399] = {cooldown = 240, duration = 30, talent = 22323, charges = 1, class = "SHAMAN", type = 4}, --Ancestral Protection Totem (talent)
+ [16191] = {cooldown = 180, duration = 8, talent = false, charges = 1, class = "SHAMAN", type = 4}, --Mana Tide Totem
+ [198103] = {cooldown = 300, duration = 60, talent = false, charges = 1, class = "SHAMAN", type = 2}, --Earth Elemental
+ [192058] = {cooldown = 60, duration = false, talent = false, charges = 1, class = "SHAMAN", type = 5}, --Capacitor Totem
+ [65992] = {cooldown = 60, duration = 10, talent = false, charges = 1, class = "SHAMAN", type = 5}, --Tremor Totem
+ [192077] = {cooldown = 120, duration = 15, talent = 21966, charges = 1, class = "SHAMAN", type = 5}, --Wind Rush Totem (talent)
+
+ --> monk
+ [132578] = {cooldown = 180, duration = 25, talent = false, charges = 1, class = "MONK", type = 1}, --Invoke Niuzao, the Black Ox
+ [115080] = {cooldown = 180, duration = false, talent = false, charges = 1, class = "MONK", type = 1}, --Touch of Death
+ [115203] = {cooldown = 420, duration = 15, talent = false, charges = 1, class = "MONK", type = 2}, --Fortifying Brew
+ [115176] = {cooldown = 300, duration = 8, talent = false, charges = 1, class = "MONK", type = 2}, --Zen Meditation
+ [115399] = {cooldown = 120, duration = false, talent = 19992, charges = 1, class = "MONK", type = 2}, --Black Ox brew (talent)
+ [122278] = {cooldown = 120, duration = 10, talent = 20175, charges = 1, class = "MONK", type = 2}, --Dampen Harm (talent)
+ [137639] = {cooldown = 90, duration = 15, talent = false, charges = 1, class = "MONK", type = 1}, --Storm, Earth, and Fire
+ [123904] = {cooldown = 120, duration = 24, talent = false, charges = 1, class = "MONK", type = 1}, --Invoke Xuen, the White Tiger
+ [152173] = {cooldown = 90, duration = 12, talent = 21191, charges = 1, class = "MONK", type = 1}, --Serenity (talent)
+ [122470] = {cooldown = 90, duration = 6, talent = false, charges = 1, class = "MONK", type = 2}, --Touch of Karma
+ [322118] = {cooldown = 180, duration = 25, talent = false, charges = 1, class = "MONK", type = 4}, --Invoke Yulon, the Jade serpent
+-- [198664] = {cooldown = 180, duration = 25, talent = 22214, charges = 1, class = "MONK", type = 4}, --Invoke Chi-Ji, the Red Crane (talent)
+ [243435] = {cooldown = 90, duration = 15, talent = false, charges = 1, class = "MONK", type = 2}, --Fortifying Brew
+ [122783] = {cooldown = 90, duration = 6, talent = 20173, charges = 1, class = "MONK", type = 2}, --Diffuse Magic (talent)
+ [116849] = {cooldown = 120, duration = 12, talent = false, charges = 1, class = "MONK", type = 3}, --Life Cocoon
+ [115310] = {cooldown = 180, duration = false, talent = false, charges = 1, class = "MONK", type = 4}, --Revival
+ [197908] = {cooldown = 90, duration = 10, talent = 22166, charges = 1, class = "MONK", type = 5}, --Mana tea (talent)
+ [116844] = {cooldown = 45, duration = 5, talent = 19995, charges = 1, class = "MONK", type = 5}, --Ring of peace (talent)
+ [119381] = {cooldown = 50, duration = 3, talent = false, charges = 1, class = "MONK", type = 5}, --Leg Sweep
+
+ --> hunter
+ [193530] = {cooldown = 120, duration = 20, talent = false, charges = 1, class = "HUNTER", type = 1}, --Aspect of the Wild
+ [19574] = {cooldown = 90, duration = 12, talent = false, charges = 1, class = "HUNTER", type = 1}, --Bestial Wrath
+ [201430] = {cooldown = 180, duration = 12, talent = 23044, charges = 1, class = "HUNTER", type = 1}, --Stampede (talent)
+ [193526] = {cooldown = 180, duration = 15, talent = false, charges = 1, class = "HUNTER", type = 1}, --Trueshot
+ [199483] = {cooldown = 60, duration = 60, talent = 23100, charges = 1, class = "HUNTER", type = 2}, --Camouflage (talent)
+ [281195] = {cooldown = 180, duration = 6, talent = false, charges = 1, class = "HUNTER", type = 2}, --Survival of the Fittest
+ [266779] = {cooldown = 120, duration = 20, talent = false, charges = 1, class = "HUNTER", type = 1}, --Coordinated Assault
+ [186265] = {cooldown = 180, duration = 8, talent = false, charges = 1, class = "HUNTER", type = 2}, --Aspect of the Turtle
+ [109304] = {cooldown = 120, duration = false, talent = false, charges = 1, class = "HUNTER", type = 2}, --Exhilaration
+ [186257] = {cooldown = 144, duration = 14, talent = false, charges = 1, class = "HUNTER", type = 5}, --Aspect of the cheetah
+ [19577] = {cooldown = 60, duration = 5, talent = false, charges = 1, class = "HUNTER", type = 5}, --Intimidation
+ [109248] = {cooldown = 45, duration = 10, talent = 22499, charges = 1, class = "HUNTER", type = 5}, --Binding Shot (talent)
+ [187650] = {cooldown = 25, duration = 60, talent = false, charges = 1, class = "HUNTER", type = 5}, --Freezing Trap
+ [186289] = {cooldown = 72, duration = 15, talent = false, charges = 1, class = "HUNTER", type = 5}, --Aspect of the eagle
+
+ --> druid
+ [194223] = {cooldown = 180, duration = 20, talent = false, charges = 1, class = "DRUID", type = 1}, --Celestial Alignment
+ [102560] = {cooldown = 180, duration = 30, talent = 21702, charges = 1, class = "DRUID", type = 1}, --Incarnation: Chosen of Elune (talent)
+ [22812] = {cooldown = 60, duration = 12, talent = false, charges = 1, class = "DRUID", type = 2}, --Barkskin
+ [108238] = {cooldown = 90, duration = false, talent = 18570, charges = 1, class = "DRUID", type = 2}, --Renewal (talent)
+ [29166] = {cooldown = 180, duration = 12, talent = false, charges = 1, class = "DRUID", type = 3}, --Innervate
+ [78675] = {cooldown = 60, duration = 8, talent = false, charges = 1, class = "DRUID", type = 5}, --Solar Beam
+ [106951] = {cooldown = 180, duration = 15, talent = false, charges = 1, class = "DRUID", type = 1}, --Berserk
+ [102543] = {cooldown = 30, duration = 180, talent = 21704, charges = 1, class = "DRUID", type = 1}, --Incarnation: King of the Jungle (talent)
+ [61336] = {cooldown = 120, duration = 6, talent = false, charges = 2, class = "DRUID", type = 2}, --Survival Instincts (2min feral 4min guardian, same spellid)
+ [77764] = {cooldown = 120, duration = 8, talent = false, charges = 1, class = "DRUID", type = 4}, --Stampeding Roar (utility)
+ [102558] = {cooldown = 180, duration = 30, talent = 22388, charges = 1, class = "DRUID", type = 2}, --Incarnation: Guardian of Ursoc (talent)
+ [33891] = {cooldown = 180, duration = 30, talent = 22421, charges = 1, class = "DRUID", type = 2}, --Incarnation: Tree of Life (talent)
+ [102342] = {cooldown = 60, duration = 12, talent = false, charges = 1, class = "DRUID", type = 3}, --Ironbark
+ [203651] = {cooldown = 60, duration = false, talent = 22422, charges = 1, class = "DRUID", type = 3}, --Overgrowth (talent)
+ [740] = {cooldown = 180, duration = 8, talent = false, charges = 1, class = "DRUID", type = 4}, --Tranquility
+ [197721] = {cooldown = 90, duration = 8, talent = 22404, charges = 1, class = "DRUID", type = 4}, --Flourish (talent)
+ [132469] = {cooldown = 30, duration = false, talent = false, charges = 1, class = "DRUID", type = 5}, --Typhoon
+ [319454] = {cooldown = 300, duration = 45, talent = 18577, charges = 1, class = "DRUID", type = 5}, --Heart of the Wild (talent)
+
+ --> death knight
+ [275699] = {cooldown = 90, duration = 15, talent = false, charges = 1, class = "DEATHKNIGHT", type = 1}, --Apocalypse
+ [42650] = {cooldown = 480, duration = 30, talent = false, charges = 1, class = "DEATHKNIGHT", type = 1}, --Army of the Dead
+ [49206] = {cooldown = 180, duration = 30, talent = 22110, charges = 1, class = "DEATHKNIGHT", type = 1}, --Summon Gargoyle (talent)
+ [207289] = {cooldown = 78, duration = 12, talent = 22538, charges = 1, class = "DEATHKNIGHT", type = 1}, --Unholy Assault (talent)
+ [48743] = {cooldown = 120, duration = 15, talent = 23373, charges = 1, class = "DEATHKNIGHT", type = 2}, --Death Pact (talent)
+ [48707] = {cooldown = 60, duration = 10, talent = 23373, charges = 1, class = "DEATHKNIGHT", type = 2}, --Anti-magic Shell
+ [152279] = {cooldown = 120, duration = 5, talent = 22537, charges = 1, class = "DEATHKNIGHT", type = 1}, --Breath of Sindragosa (talent)
+ [47568] = {cooldown = 120, duration = 20, talent = false, charges = 1, class = "DEATHKNIGHT", type = 1}, --Empower Rune Weapon
+ [279302] = {cooldown = 120, duration = 10, talent = 22535, charges = 1, class = "DEATHKNIGHT", type = 1}, --Frostwyrm's Fury (talent)
+ [49028] = {cooldown = 120, duration = 8, talent = false, charges = 1, class = "DEATHKNIGHT", type = 1}, --Dancing Rune Weapon
+ [55233] = {cooldown = 90, duration = 10, talent = false, charges = 1, class = "DEATHKNIGHT", type = 2}, --Vampiric Blood
+ [48792] = {cooldown = 120, duration = 8, talent = false, charges = 1, class = "DEATHKNIGHT", type = 2}, --Icebound Fortitude
+ [51052] = {cooldown = 120, duration = 10, talent = false, charges = 1, class = "DEATHKNIGHT", type = 4}, --Anti-magic Zone
+ [219809] = {cooldown = 60, duration = 8, talent = 23454, charges = 1, class = "DEATHKNIGHT", type = 2}, --Tombstone (talent)
+ [108199] = {cooldown = 120, duration = false, talent = false, charges = 1, class = "DEATHKNIGHT", type = 5}, --Gorefiend's Grasp
+ [207167] = {cooldown = 60, duration = 5, talent = 22519, charges = 1, class = "DEATHKNIGHT", type = 5}, --Blinding Sleet (talent)
+ [108194] = {cooldown = 45, duration = 4, talent = 22520, charges = 1, class = "DEATHKNIGHT", type = 5}, --Asphyxiate (talent)
+ [221562] = {cooldown = 45, duration = 5, talent = false, charges = 1, class = "DEATHKNIGHT", type = 5}, --Asphyxiate
+
+ --> demon hunter
+ [200166] = {cooldown = 240, duration = 30, talent = false, charges = 1, class = "DEMONHUNTER", type = 1}, --Metamorphosis
+ [198589] = {cooldown = 60, duration = 10, talent = false, charges = 1, class = "DEMONHUNTER", type = 2}, --Blur
+ [196555] = {cooldown = 120, duration = 5, talent = 21865, charges = 1, class = "DEMONHUNTER", type = 2}, --Netherwalk (talent)
+ [196718] = {cooldown = 180, duration = 8, talent = false, charges = 1, class = "DEMONHUNTER", type = 4}, --Darkness
+ [187827] = {cooldown = 180, duration = 15, talent = false, charges = 1, class = "DEMONHUNTER", type = 2}, --Metamorphosis
+ [196718] = {cooldown = 180, duration = 8, talent = false, charges = 1, class = "DEMONHUNTER", type = 4}, --Darkness
+ [188501] = {cooldown = 30, duration = 10, talent = false, charges = 1, class = "DEMONHUNTER", type = 5}, --Spectral Sight
+ [179057] = {cooldown = 60, duration = 2, talent = false, charges = 1, class = "DEMONHUNTER", type = 5}, --Chaos Nova
+ [211881] = {cooldown = 30, duration = 4, talent = 22767, charges = 1, class = "DEMONHUNTER", type = 5}, --Fel Eruption (talent)
+ [320341] = {cooldown = 90, duration = false, talent = 21902, charges = 1, class = "DEMONHUNTER", type = 1}, --Bulk Extraction (talent)
+ [204021] = {cooldown = 60, duration = 10, talent = false, charges = 1, class = "DEMONHUNTER", type = 2}, --Fiery Brand
+ [263648] = {cooldown = 30, duration = 12, talent = 22768, charges = 1, class = "DEMONHUNTER", type = 2}, --Soul Barrier (talent)
+ [207684] = {cooldown = 90, duration = 12, talent = false, charges = 1, class = "DEMONHUNTER", type = 5}, --Sigil of Misery
+ [202137] = {cooldown = 60, duration = 8, talent = false, charges = 1, class = "DEMONHUNTER", type = 5}, --Sigil of Silence
+ [202138] = {cooldown = 90, duration = 6, talent = 22511, charges = 1, class = "DEMONHUNTER", type = 5}, --Sigil of Chains (talent)
+
+ --> mage
+ [12042] = {cooldown = 90, duration = 10, talent = false, charges = 1, class = "MAGE", type = 1}, --Arcane Power
+ [12051] = {cooldown = 90, duration = 6, talent = false, charges = 1, class = "MAGE", type = 1}, --Evocation
+ [110960] = {cooldown = 120, duration = 20, talent = false, charges = 1, class = "MAGE", type = 2}, --Greater Invisibility
+ [235450] = {cooldown = 25, duration = 60, talent = false, charges = 1, class = "MAGE", type = 5}, --Prismatic Barrier
+ [235313] = {cooldown = 25, duration = 60, talent = false, charges = 1, class = "MAGE", type = 5}, --Blazing Barrier
+ [11426] = {cooldown = 25, duration = 60, talent = false, charges = 1, class = "MAGE", type = 5}, --Ice Barrier
+ [190319] = {cooldown = 120, duration = 10, talent = false, charges = 1, class = "MAGE", type = 1}, --Combustion
+ [55342] = {cooldown = 120, duration = 40, talent = 22445, charges = 1, class = "MAGE", type = 1}, --Mirror Image
+ [66] = {cooldown = 300, duration = 20, talent = false, charges = 1, class = "MAGE", type = 2}, --Invisibility
+ [12472] = {cooldown = 180, duration = 20, talent = false, charges = 1, class = "MAGE", type = 1}, --Icy Veins
+ [205021] = {cooldown = 78, duration = 5, talent = 22309, charges = 1, class = "MAGE", type = 1}, --Ray of Frost (talent)
+ [45438] = {cooldown = 240, duration = 10, talent = false, charges = 1, class = "MAGE", type = 2}, --Ice Block
+ [235219] = {cooldown = 300, duration = false, talent = false, charges = 1, class = "MAGE", type = 5}, --Cold Snap
+ [113724] = {cooldown = 45, duration = 10, talent = 22471, charges = 1, class = "MAGE", type = 5}, --Ring of Frost (talent)
+
+ --> priest
+ [10060] = {cooldown = 120, duration = 20, talent = false, charges = 1, class = "PRIEST", type = 1}, --Power Infusion
+ [34433] = {cooldown = 180, duration = 15, talent = false, charges = 1, class = "PRIEST", type = 1}, --Shadowfiend
+ [123040] = {cooldown = 60, duration = 12, talent = 22094, charges = 1, class = "PRIEST", type = 1}, --Mindbender (talent)
+ [33206] = {cooldown = 180, duration = 8, talent = false, charges = 1, class = "PRIEST", type = 3}, --Pain Suppression
+ [62618] = {cooldown = 180, duration = 10, talent = false, charges = 1, class = "PRIEST", type = 4}, --Power Word: Barrier
+ [271466] = {cooldown = 180, duration = 10, talent = 21184, charges = 1, class = "PRIEST", type = 4}, --Luminous Barrier (talent)
+ [47536] = {cooldown = 90, duration = 10, talent = false, charges = 1, class = "PRIEST", type = 5}, --Rapture
+ [19236] = {cooldown = 90, duration = 10, talent = false, charges = 1, class = "PRIEST", type = 5}, --Desperate Prayer
+ [200183] = {cooldown = 120, duration = 20, talent = 21644, charges = 1, class = "PRIEST", type = 2}, --Apotheosis (talent)
+ [47788] = {cooldown = 180, duration = 10, talent = false, charges = 1, class = "PRIEST", type = 3}, --Guardian Spirit
+ [64844] = {cooldown = 180, duration = 8, talent = false, charges = 1, class = "PRIEST", type = 4}, --Divine Hymn
+ [64901] = {cooldown = 300, duration = 6, talent = false, charges = 1, class = "PRIEST", type = 4}, --Symbol of Hope
+ [265202] = {cooldown = 720, duration = false, talent = 23145, charges = 1, class = "PRIEST", type = 4}, --Holy Word: Salvation (talent)
+ [109964] = {cooldown = 60, duration = 12, talent = 21184, charges = 1, class = "PRIEST", type = 4}, --Spirit Shell (talent)
+ [8122] = {cooldown = 60, duration = 8, talent = false, charges = 1, class = "PRIEST", type = 5}, --Psychic Scream
+ [200174] = {cooldown = 60, duration = 15, talent = 21719, charges = 1, class = "PRIEST", type = 1}, --Mindbender (talent)
+ [193223] = {cooldown = 240, duration = 60, talent = 21979, charges = 1, class = "PRIEST", type = 1}, --Surrender to Madness (talent)
+ [47585] = {cooldown = 120, duration = 6, talent = false, charges = 1, class = "PRIEST", type = 2}, --Dispersion
+ [15286] = {cooldown = 120, duration = 15, talent = false, charges = 1, class = "PRIEST", type = 4}, --Vampiric Embrace
+
+ --> rogue
+ [79140] = {cooldown = 120, duration = 20, talent = false, charges = 1, class = "ROGUE", type = 1}, --Vendetta
+ [1856] = {cooldown = 120, duration = 3, talent = false, charges = 1, class = "ROGUE", type = 2}, --Vanish
+ [5277] = {cooldown = 120, duration = 10, talent = false, charges = 1, class = "ROGUE", type = 2}, --Evasion
+ [31224] = {cooldown = 120, duration = 5, talent = false, charges = 1, class = "ROGUE", type = 2}, --Cloak of Shadows
+ [2094] = {cooldown = 120, duration = 60, talent = false, charges = 1, class = "ROGUE", type = 5}, --Blind
+ [114018] = {cooldown = 360, duration = 15, talent = false, charges = 1, class = "ROGUE", type = 5}, --Shroud of Concealment
+ [185311] = {cooldown = 30, duration = 15, talent = false, charges = 1, class = "ROGUE", type = 5}, --Crimson Vial
+ [13750] = {cooldown = 180, duration = 20, talent = false, charges = 1, class = "ROGUE", type = 1}, --Adrenaline Rush
+ [51690] = {cooldown = 120, duration = 2, talent = 23175, charges = 1, class = "ROGUE", type = 1}, --Killing Spree (talent)
+ [199754] = {cooldown = 120, duration = 10, talent = false, charges = 1, class = "ROGUE", type = 2}, --Riposte
+ [121471] = {cooldown = 180, duration = 20, talent = false, charges = 1, class = "ROGUE", type = 1}, --Shadow Blades
+ [343142] = {cooldown = 90, duration = 10, talent = 19250, charges = 1, class = "ROGUE", type = 5}, --Dreadblades
+ [121471] = {cooldown = 180, duration = 20, talent = false, charges = 1, class = "ROGUE", type = 1}, --Shadow Blades
+}
\ No newline at end of file
diff --git a/Libs/LibRaidStatus/docs.txt b/Libs/LibRaidStatus/docs.txt
new file mode 100644
index 00000000..123748f5
--- /dev/null
+++ b/Libs/LibRaidStatus/docs.txt
@@ -0,0 +1,99 @@
+
+Functions:
+
+local playerGearInfo = raidStatusLib.gearManager.GetPlayerGearTable(playerName)
+playerGearInfo = {
+ .durability = number
+ .ilevel = number
+ .noGems = {socketId}
+ .noEnchants = {socketId}
+}
+
+
+
+Callbacks available
+
+"CooldownListUpdate": triggers when the lib received a list of cooldowns from another player in the group.
+
+function MyAddonObject.OnReceiveCooldownListUpdate(unitName, cooldownTable)
+ --foreach player in the cooldown table
+ for unitName, playerCooldownTable in pairs(cooldownTable) do
+ for spellId, cooldownInfoTable in pairs(playerCooldownTable) do
+ --if timeLeft is zero, the spell is ready
+ local timeLeft = cooldownInfoTable[1]
+ --in some cases the spell is on cooldown but there's a charge to use
+ local charges = cooldownInfoTable[2]
+ end
+ end
+
+ --get the cooldowns for the unit which got the cooldown update
+ local unitCooldownTable = cooldownTable[unitName]
+ for spellId, cooldownInfoTable in pairs(unitCooldownTable) do
+ --if timeLeft is zero, the spell is ready
+ local timeLeft = cooldownInfoTable[1]
+ --in some cases the spell is on cooldown but there's a charge to use
+ local charges = cooldownInfoTable[2]
+ end
+end
+raidStatusLib.RegisterCallback(MyAddonObject, "CooldownListUpdate", "OnReceiveCooldownListUpdate")
+
+
+"CooldownUpdate": triggered when any unit in the group used a cooldown or the timeleft got an update
+
+function MyAddonObject.OnReceiveCooldownUpdate(unitName, spellId, cooldownTimeLeft, charges, playerCooldownTable)
+ local unitCooldowns = cooldownTable[unitName]
+ local cooldownTimeLeft2 = unitCooldowns[spellId]
+ print("is iqual:", cooldownTimeLeft == cooldownTimeLeft2)
+
+ --get the cooldowns for the unit which got the cooldown update
+ for spellId, cooldownInfoTable in pairs(playerCooldownTable) do
+ --if timeLeft is zero, the spell is ready
+ local timeLeft = cooldownInfoTable[1]
+ --in some cases the spell is on cooldown but there's a charge to use
+ local charges = cooldownInfoTable[2]
+ end
+end
+raidStatusLib.RegisterCallback(MyAddonObject, "CooldownUpdate", "OnReceiveCooldownUpdate")
+
+
+"CooldownListWiped": when the list of cooldowns get a wipe, usually when the player leave the group
+
+function MyAddonObject.OnCooldownListWipe(cooldownTable)
+ print ("is nil:", next(cooldownTable))
+end
+raidStatusLib.RegisterCallback(MyAddonObject, "CooldownListWiped", "OnCooldownListWipe")
+
+
+"GearDurabilityUpdate": when a player in the group revives, the gear durability is sent
+
+function MyAddonObject.OnGearDurabilityUpdate(playerName, durability, gearTable)
+ print(playerName .. " durability is now " .. durability)
+end
+raidStatusLib.RegisterCallback(MyAddonObject, "GearDurabilityUpdate", "OnGearDurabilityUpdate")
+
+
+"GearUpdate": when received an update from a player with all information about the gear
+
+function MyAddonObject.OnGearUpdate(playerName, playerGearInfo, gearTable)
+ local itemLevelNumber = playerGearInfo.ilevel
+ local durabilityNumber = playerGearInfo.durability
+ --hasWeaponEnchant is 1 have enchant or 0 is don't
+ local hasWeaponEnchantNumber = playerGearInfo.weaponEnchant
+ local noEnchantTable = playerGearInfo.noEnchants
+ local noGemsTable = playerGearInfo.noGems
+
+ for index, slotIdWithoutEnchant in ipairs (noEnchantTable) do
+ end
+
+ for index, slotIdWithEmptyGemSocket in ipairs (noGemsTable) do
+ end
+end
+raidStatusLib.RegisterCallback(MyAddonObject, "GearUpdate", "OnGearUpdate")
+
+
+"GearListWiped": when the list of gear get a wipe, usually when the player leave the group
+
+function MyAddonObject.OnGearListWiped(gearTable)
+ print ("is nil:", next(gearTable))
+end
+raidStatusLib.RegisterCallback(MyAddonObject, "GearListWiped", "OnGearListWiped")
diff --git a/Libs/LibRaidStatus/lib.xml b/Libs/LibRaidStatus/lib.xml
new file mode 100644
index 00000000..a5d0a4ee
--- /dev/null
+++ b/Libs/LibRaidStatus/lib.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/Libs/libs.xml b/Libs/libs.xml
index 4bc83fe1..65471664 100644
--- a/Libs/libs.xml
+++ b/Libs/libs.xml
@@ -17,6 +17,7 @@
+
diff --git a/frames/window_cdtracker.lua b/frames/window_cdtracker.lua
index 6c417312..712aa635 100644
--- a/frames/window_cdtracker.lua
+++ b/frames/window_cdtracker.lua
@@ -2,6 +2,11 @@
local Details = _G.Details
local DF = _G.DetailsFramework
+local raidStatusLib = LibStub:GetLibrary("LibRaidStatus-1.0")
+
+local width = 170
+local height = 300
+local bar_height = 20
--namespace
Details.CooldownTracking = {}
@@ -22,71 +27,90 @@ function Details:InitializeCDTrackerWindow()
--check if is enabled at startup
if (Details.CooldownTracking.IsEnabled()) then
- Details.CooldownTracking.RefreshScreenPanel()
+ Details.CooldownTracking.EnableTracker()
end
DetailsCDTrackerWindow:Hide()
end
function Details.CooldownTracking.IsEnabled()
- return Details.cd_tracker.enabled
+ return Details.ocd_tracker.enabled
end
function Details.CooldownTracking.EnableTracker()
+ Details.ocd_tracker.enabled = true
+
+ --register callbacks
+ raidStatusLib.RegisterCallback(Details.CooldownTracking, "CooldownListUpdate", "CooldownListUpdateFunc")
+ raidStatusLib.RegisterCallback(Details.CooldownTracking, "CooldownListWiped", "CooldownListWipedFunc")
+ raidStatusLib.RegisterCallback(Details.CooldownTracking, "CooldownUpdate", "CooldownUpdateFunc")
+
Details.CooldownTracking.RefreshScreenPanel()
end
function Details.CooldownTracking.DisableTracker()
+ Details.ocd_tracker.enabled = false
+
--hide the panel
if (DetailsOnlineCDTrackerScreenPanel) then
DetailsOnlineCDTrackerScreenPanel:Hide()
end
--unregister callbacks
- local libRaidStatus = LibStub("LibRaidStatus-1.0")
- libRaidStatus.UnregisterCallback(Details.CooldownTracking, "CooldownListUpdate", "CooldownListUpdateFunc")
- libRaidStatus.UnregisterCallback(Details.CooldownTracking, "CooldownListWiped", "CooldownListWipedFunc")
- libRaidStatus.UnregisterCallback(Details.CooldownTracking, "CooldownUpdate", "CooldownUpdateFunc")
-
- --unregister events
-
+ raidStatusLib.UnregisterCallback(Details.CooldownTracking, "CooldownListUpdate", "CooldownListUpdateFunc")
+ raidStatusLib.UnregisterCallback(Details.CooldownTracking, "CooldownListWiped", "CooldownListWipedFunc")
+ raidStatusLib.UnregisterCallback(Details.CooldownTracking, "CooldownUpdate", "CooldownUpdateFunc")
end
function Details.CooldownTracking.CooldownListUpdateFunc()
-
+ Details.CooldownTracking.RefreshScreenPanel()
end
function Details.CooldownTracking.CooldownListWipedFunc()
-
+ Details.CooldownTracking.RefreshScreenPanel()
end
function Details.CooldownTracking.CooldownUpdateFunc()
-
+ print("cooldown update...")
+ Details.CooldownTracking.RefreshScreenPanel()
end
function Details.CooldownTracking.RefreshScreenPanel()
if (not DetailsOnlineCDTrackerScreenPanel) then
--screen panel (goes into the UIParent and show cooldowns there)
- local screenPanel = CreateFrame("frame", "DetailsOnlineCDTrackerScreenPanel", UIParent)
+ local screenPanel = CreateFrame("frame", "DetailsOnlineCDTrackerScreenPanel", UIParent, "BackdropTemplate")
screenPanel:Hide()
+ screenPanel:SetSize(width, height)
+ screenPanel:SetPoint("center", 0, 0)
+ screenPanel:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
+ screenPanel:SetBackdropColor(0, 0, 0, .55)
+ screenPanel:SetBackdropBorderColor(0, 0, 0, .3)
+ screenPanel:EnableMouse(true)
--register on libwindow
local libWindow = LibStub("LibWindow-1.1")
- libWindow.RegisterConfig(screenPanel, _detalhes.cd_tracker.pos)
+ libWindow.RegisterConfig(screenPanel, _detalhes.ocd_tracker.pos)
libWindow.MakeDraggable(screenPanel)
libWindow.RestorePosition(screenPanel)
end
local screenPanel = _G.DetailsOnlineCDTrackerScreenPanel
+ screenPanel.bars = {}
- if (Details.cd_tracker.show_conditions.only_in_group) then
+ function screenPanel.HideAllBars()
+ for _, bar in ipairs (screenPanel.bars) do
+ bar:Hide()
+ end
+ end
+
+ if (Details.ocd_tracker.show_conditions.only_in_group) then
if (not IsInGroup()) then
screenPanel:Hide()
return
end
end
- if (Details.cd_tracker.show_conditions.only_inside_instance) then
+ if (Details.ocd_tracker.show_conditions.only_inside_instance) then
local isInInstanceType = select(2, GetInstanceInfo())
if (isInInstanceType ~= "party" and isInInstanceType ~= "raid" and isInInstanceType ~= "scenario" and isInInstanceType ~= "arena") then
screenPanel:Hide()
@@ -94,15 +118,76 @@ function Details.CooldownTracking.RefreshScreenPanel()
end
end
- --register callbacks from LibRaidStatus
- local libRaidStatus = LibStub("LibRaidStatus-1.0")
- if (libRaidStatus) then
- libRaidStatus.RegisterCallback(Details.CooldownTracking, "CooldownListUpdate", "CooldownListUpdateFunc")
- libRaidStatus.RegisterCallback(Details.CooldownTracking, "CooldownListWiped", "CooldownListWipedFunc")
- libRaidStatus.RegisterCallback(Details.CooldownTracking, "CooldownUpdate", "CooldownUpdateFunc")
+ local cooldownsAvailable = raidStatusLib.cooldownManager.GetCooldownTable()
+ local cooldownsEnabled = Details.ocd_tracker.cooldowns
+ local cooldownsOrganized = {}
+
+ for classId = 1, 12 do --12 classes
+ cooldownsOrganized[classId] = {}
end
- --parei aqui, precisa pegar a tabela de cooldowns da library e atualizar as statusbars
+ for playerName, allPlayerCooldowns in pairs(cooldownsAvailable) do
+ local _, _, classId = UnitClass(playerName)
+ if (classId) then
+ for spellId, cooldownInfo in pairs(allPlayerCooldowns) do
+ if (cooldownsEnabled[spellId]) then
+ cooldownsOrganized[classId][#cooldownsOrganized[classId]+1] = {playerName, cooldownInfo[1], cooldownInfo[2], classId, spellId} --playerName, spellId, timeLeft, chargesLeft
+ --local spellName = GetSpellInfo(spellId) --debug
+ --print("Cooldown Added", playerName, spellName) --debug
+ end
+ end
+ end
+ end
+
+ for classId = 1, 12 do --12 classes
+ local t = cooldownsOrganized[classId]
+ table.sort(t, function(t1, t2) return t1[5] < t2[5] end) --sort by spellId
+ end
+
+ screenPanel.HideAllBars()
+
+ local cooldownIndex = 1
+ for classId = 1, 12 do --12 classes
+ local t = cooldownsOrganized[classId]
+ for i = 1, #t do
+ local bar = screenPanel.bars[cooldownIndex]
+ if (not bar) then
+ bar = DF:CreateBar(screenPanel, [[Interface\AddOns\Details\images\bar_serenity]], width-2, bar_height-1, 100)
+ bar:SetPoint("topleft", screenPanel, "topleft", 1, (cooldownIndex-1)*bar_height)
+ tinsert(screenPanel.bars, bar)
+
+ bar:SetHook("OnTimerEnd", function()
+ bar:Show()
+ bar:SetValue(100)
+ bar.timer_texture:Hide()
+ bar.timer_textureR:Hide()
+ bar.div_timer:Hide()
+ bar.timer = false
+ return true
+ end)
+ end
+
+ local cooldownTable = t[i]
+ local spellName, _, spellIcon = GetSpellInfo(cooldownTable[5])
+ bar:SetLeftText(cooldownTable[1])
+ bar:SetIcon(spellIcon, {.1, .9, .1, .9})
+
+ bar:CancelTimerBar(true)
+
+ local timeLeft = cooldownTable[2]
+ if (timeLeft > 0) then
+ bar:SetTimer(timeLeft)
+ else
+ bar:SetValue(100)
+ end
+
+ bar:Show()
+ --print("Shown Bar", cooldownIndex) --debug
+ cooldownIndex = cooldownIndex + 1
+ end
+ end
+
+ DetailsOnlineCDTrackerScreenPanel:Show()
end
function Details.OpenCDTrackerWindow()
@@ -122,9 +207,9 @@ function Details.OpenCDTrackerWindow()
local options_button_template = DF:GetTemplate ("button", "OPTIONS_BUTTON_TEMPLATE")
local generalOptions = {
- {--enable tracking
+ {--enable ocd
type = "toggle",
- get = function() return Details.cd_tracker.enabled end,
+ get = function() return Details.ocd_tracker.enabled end,
set = function (self, fixedparam, value)
if (value) then
Details.CooldownTracking.EnableTracker()
@@ -135,12 +220,34 @@ function Details.OpenCDTrackerWindow()
name = "Enable Online Cooldown Tracker",
desc = "Enable Online Cooldown Tracker",
},
- }
- DF:BuildMenu(generalOptions, f, 5, -5, 150, true, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template)
+ {--show only in group
+ type = "toggle",
+ get = function() return Details.ocd_tracker.show_conditions.only_in_group end,
+ set = function (self, fixedparam, value)
+ Details.ocd_tracker.show_conditions.only_in_group = value
+ Details.CooldownTracking.RefreshScreenPanel()
+ end,
+ name = "Only in Group",
+ desc = "Only in Group",
+ },
+
+ {--show only inside instances
+ type = "toggle",
+ get = function() return Details.ocd_tracker.show_conditions.only_inside_instance end,
+ set = function (self, fixedparam, value)
+ Details.ocd_tracker.show_conditions.only_inside_instance = value
+ Details.CooldownTracking.RefreshScreenPanel()
+ end,
+ name = "Only Inside Instances",
+ desc = "Only Inside Instances",
+ },
+ }
+
+ DF:BuildMenu(f, generalOptions, 5, -35, 150, true, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template)
--cooldown selection
- local cooldownProfile = Details.cd_tracker.cds_enabled
+ local cooldownProfile = Details.ocd_tracker.cooldowns
local cooldownSelectionFrame = CreateFrame("frame", "$parentCooldownSelectionFrame", f, "BackdropTemplate")
cooldownSelectionFrame:SetPoint("topleft", f, "topleft", 0, -150)
@@ -149,43 +256,60 @@ function Details.OpenCDTrackerWindow()
--list of cooldowns to show, each one with a toggle button
local cooldownList = {}
+ local alreadyAdded = {}
if (LIB_RAID_STATUS_COOLDOWNS_BY_SPEC) then
for specId, cooldownTable in pairs(LIB_RAID_STATUS_COOLDOWNS_BY_SPEC) do
- cooldownList[#cooldownList+1] = {type = "label", get = function() return "" .. specId end}
+
+ local currentIndex = #cooldownList+1
+ local cooldownAdded = false
for spellId, cooldownType in pairs(cooldownTable) do
- local spellName, _, spellicon = GetSpellInfo(spellId)
-
- if (spellName) then
+ if (not alreadyAdded[spellId]) then
if (cooldownType == 3 or cooldownType == 4) then
- cooldownList[#cooldownList+1] = {
- type = "toggle",
- get = function()
- if (cooldownProfile[spellId] == nil) then
- if (cooldownType == 3 or cooldownType == 4) then
- cooldownProfile[spellId] = true
- else
- cooldownProfile[spellId] = false
+ local spellName, _, spellIcon = GetSpellInfo(spellId)
+ if (spellName) then
+ cooldownList[#cooldownList+1] = {
+ type = "toggle",
+ get = function()
+ if (cooldownProfile[spellId] == nil) then
+ if (cooldownType == 3 or cooldownType == 4) then
+ cooldownProfile[spellId] = true
+ end
end
+ return cooldownProfile[spellId]
+ end,
+ set = function (self, fixedparam, value)
+ if (value) then
+ cooldownProfile[spellId] = value
+ else
+ cooldownProfile[spellId] = nil
end
- return cooldownProfile[spellId]
- end,
- set = function (self, fixedparam, value)
- cooldownProfile[spellId] = value
- end,
- name = spellName,
- desc = spellName,
- boxfirst = true,
- }
+ end,
+ name = "|T" .. spellIcon .. ":" .. (16) .. ":" .. (16) .. ":0:0:64:64:" .. 0.1*64 .. ":" .. 0.9*64 .. ":" .. 0.1*64 .. ":" .. 0.9*64 .. "|t" .. spellName,
+ desc = spellName,
+ boxfirst = true,
+ }
+
+ alreadyAdded[spellId] = true
+ cooldownAdded = true
+ end
end
end
end
- cooldownList[#cooldownList+1] = {type = "blank"}
+ if (cooldownAdded) then
+ local _, spenName, _, specIcon = GetSpecializationInfoByID(specId)
+ local iconString = "|T" .. specIcon .. ":" .. (16) .. ":" .. (16) .. ":0:0:64:64:" .. 0.1*64 .. ":" .. 0.9*64 .. ":" .. 0.1*64 .. ":" .. 0.9*64 .. "|t"
+
+ tinsert(cooldownList, currentIndex, {type = "label", get = function() return iconString .. " " .. spenName end})
+ if (currentIndex > 1) then
+ tinsert(cooldownList, currentIndex, {type = "blank"})
+ end
+ end
end
end
- DF:BuildMenu(cooldownSelectionFrame, cooldownList, 5, -5, cooldownSelectionFrame:GetHeight(), false, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template)
+ DF:BuildMenu(cooldownSelectionFrame, cooldownList, 5, -5, cooldownSelectionFrame:GetHeight() - 40, false, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template)
@@ -193,5 +317,4 @@ function Details.OpenCDTrackerWindow()
_G.DetailsPluginContainerWindow.OpenPlugin(_G.DetailsCDTrackerWindow)
_G.DetailsCDTrackerWindow:Show()
-
end
\ No newline at end of file
diff --git a/functions/pack.lua b/functions/pack.lua
index 4699ad83..daaf90ea 100644
--- a/functions/pack.lua
+++ b/functions/pack.lua
@@ -153,6 +153,10 @@ function Details.packFunctions.PackCombatData(combatObject, flags)
--if true then return exportedString end
+ if (isDebugging) then
+ print(exportedString)
+ end
+
--compress
local LibDeflate = _G.LibStub:GetLibrary("LibDeflate")
local dataCompressed = LibDeflate:CompressDeflate(exportedString, {level = 9})
@@ -1010,7 +1014,8 @@ function Details.packFunctions.UnpackTable(table, index, isPair, valueAsTable, a
return result
end
---what this function receives?
+--DEPRECATED
+--what this function receives:
--@packedCombatData: packed combat, ready to be unpacked
function Details.packFunctions.UnPackCombatData(packedCombatData)
diff --git a/functions/profiles.lua b/functions/profiles.lua
index 5ee2ffc8..1b9b97db 100644
--- a/functions/profiles.lua
+++ b/functions/profiles.lua
@@ -835,6 +835,17 @@ local default_profile = {
},
},
+ --> ocd tracker test
+ ocd_tracker = {
+ enabled = false,
+ cooldowns = {},
+ pos = {},
+ show_conditions = {
+ only_in_group = true,
+ only_inside_instance = true,
+ }
+ },
+
--> minimap
minimap = {hide = false, radius = 160, minimapPos = 220, onclick_what_todo = 1, text_type = 1, text_format = 3},
data_broker_text = "",
@@ -1104,17 +1115,6 @@ local default_player_data = {
enabled = false,
},
- --> cd tracker
- cd_tracker = {
- pos = {},
- enabled = false,
- cds_enabled = {},
- show_conditions = {
- only_in_group = true,
- only_inside_instance = true,
- }
- },
-
--> force all fonts to have this outline
force_font_outline = "",
diff --git a/startup.lua b/startup.lua
index b568af1e..b43d28b8 100644
--- a/startup.lua
+++ b/startup.lua
@@ -54,7 +54,7 @@ function Details:StartMeUp() --I'll never stop!
self:InitializePlaterIntegrationWindow()
self:InitializeMacrosWindow()
- --self:InitializeCDTrackerWindow()
+ self:InitializeCDTrackerWindow()
--custom window
self.custom = self.custom or {}