local Details = _G.Details
local DF = _G.DetailsFramework
local openRaidLib = LibStub : GetLibrary ( " LibOpenRaid-1.0 " , true )
--namespace
Details.CooldownTracking = { }
--return if the cooldown tracker is enabled
function Details . CooldownTracking . IsEnabled ( )
return Details.ocd_tracker . enabled
end
--enable the cooldown tracker
function Details . CooldownTracking . EnableTracker ( )
Details.ocd_tracker . enabled = true
--register callbacks with the openRaidLib
openRaidLib.RegisterCallback ( Details.CooldownTracking , " CooldownListUpdate " , " OnReceiveUnitFullCooldownList " )
openRaidLib.RegisterCallback ( Details.CooldownTracking , " CooldownUpdate " , " OnReceiveSingleCooldownUpdate " )
openRaidLib.RegisterCallback ( Details.CooldownTracking , " CooldownListWipe " , " OnCooldownListWipe " )
openRaidLib.RegisterCallback ( Details.CooldownTracking , " CooldownAdded " , " OnCooldownAdded " )
openRaidLib.RegisterCallback ( Details.CooldownTracking , " CooldownRemoved " , " OnCooldownRemoved " )
Details.CooldownTracking . RefreshCooldownFrames ( )
end
--disable the cooldown tracker
function Details . CooldownTracking . DisableTracker ( )
Details.ocd_tracker . enabled = false
--hide the panel
if ( DetailsOnlineCDTrackerScreenPanel ) then
DetailsOnlineCDTrackerScreenPanel : Hide ( )
end
--unregister callbacks
openRaidLib.UnregisterCallback ( Details.CooldownTracking , " CooldownListUpdate " , " OnReceiveUnitFullCooldownList " )
openRaidLib.UnregisterCallback ( Details.CooldownTracking , " CooldownUpdate " , " OnReceiveSingleCooldownUpdate " )
openRaidLib.UnregisterCallback ( Details.CooldownTracking , " CooldownListWipe " , " OnCooldownListWipe " )
end
--> Library Open Raid Callbacks
--callback on the event 'CooldownListUpdate', this is triggered when a player in the group sent the list of cooldowns
--@unitId: which unit got updated
--@unitCooldows: a table with [spellId] = cooldownInfo
--@allUnitsCooldowns: a table containing all units [unitName] = {[spellId] = cooldownInfo}
function Details . CooldownTracking . OnReceiveUnitFullCooldownList ( unitId , unitCooldows , allUnitsCooldowns )
--print("|cFFFFFF00received full cooldown list|r from:", unitId)
Details.CooldownTracking . RefreshCooldownFrames ( )
end
--callback on the event 'CooldownUpdate', this is triggered when a player uses a cooldown or a cooldown got updated (time left reduced, etc)
--@unitId: which unit got updated
--@spellId: which cooldown spell got updated
--@cooldownInfo: cooldown information table to be passed with other functions
--@unitCooldows: a table with [spellId] = cooldownInfo
--@allUnitsCooldowns: a table containing all units [unitName] = {[spellId] = cooldownInfo}
function Details . CooldownTracking . OnReceiveSingleCooldownUpdate ( unitId , spellId , cooldownInfo , unitCooldows , allUnitsCooldowns )
local screenPanel = DetailsOnlineCDTrackerScreenPanel
local gotUpdated = false
local unitName = GetUnitName ( unitId , true )
if ( screenPanel ) then
local cooldownFrame = screenPanel.playerCache [ unitName ] and screenPanel.playerCache [ unitName ] [ spellId ]
if ( cooldownFrame ) then
--get the cooldown time from the lib, it return data ready to use on statusbar
local isReady , normalizedPercent , timeLeft , charges , minValue , maxValue , currentValue = openRaidLib.GetCooldownStatusFromCooldownInfo ( cooldownInfo )
if ( not isReady ) then
cooldownFrame : SetTimer ( currentValue , minValue , maxValue )
else
cooldownFrame : SetTimer ( )
end
gotUpdated = true
end
end
if ( not gotUpdated ) then
Details.CooldownTracking . RefreshCooldownFrames ( )
end
end
--when the list of cooldowns got wiped, usually happens when the player left a group
--@allUnitsCooldowns: a table containing all units [unitName] = {[spellId] = cooldownInfo}
function Details . CooldownTracking . OnCooldownListWipe ( allUnitsCooldowns )
Details.CooldownTracking . RefreshCooldownFrames ( )
end
--when a cooldown has been added to an unit
function Details . CooldownTracking . OnCooldownAdded ( unitId , spellId , cooldownInfo , unitCooldows , allUnitsCooldowns )
--here could update the cooldown of the unit, but I'm too lazy so it update all units
Details.CooldownTracking . RefreshCooldownFrames ( )
end
--when a cooldown has been removed from an unit
function Details . CooldownTracking . OnCooldownRemoved ( unitId , spellId , unitCooldows , allUnitsCooldowns )
Details.CooldownTracking . RefreshCooldownFrames ( )
end
--> Frames
--hide all bars created
function Details . CooldownTracking . HideAllBars ( )
for _ , bar in ipairs ( DetailsOnlineCDTrackerScreenPanel.bars ) do
bar : ClearAllPoints ( )
bar : Hide ( )
bar.cooldownInfo = nil
bar.spellId = nil
bar.class = nil
bar.unitName = nil
end
end
--get a cooldown frame
function Details . CooldownTracking . GetOrCreateNewCooldownFrame ( screenPanel , frameId )
local cooldownFrame = screenPanel.bars [ frameId ]
if ( cooldownFrame ) then
return cooldownFrame
end
local cooldownFrame = DF : CreateTimeBar ( screenPanel , [[Interface\AddOns\Details\images\bar_serenity]] , Details.ocd_tracker . width - 2 , Details.ocd_tracker . height - 2 , 100 , nil , screenPanel : GetName ( ) .. " CDFrame " .. frameId )
tinsert ( screenPanel.bars , cooldownFrame )
cooldownFrame : EnableMouse ( false )
return cooldownFrame
end
--create the screen panel, goes into the UIParent and show cooldowns
function Details . CooldownTracking . CreateScreenFrame ( )
DetailsOnlineCDTrackerScreenPanel = CreateFrame ( " frame " , " DetailsOnlineCDTrackerScreenPanel " , UIParent , " BackdropTemplate " )
local screenPanel = DetailsOnlineCDTrackerScreenPanel
screenPanel : Hide ( )
screenPanel : SetSize ( Details.ocd_tracker . width , Details.ocd_tracker . 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.ocd_tracker . pos )
libWindow.MakeDraggable ( screenPanel )
libWindow.RestorePosition ( screenPanel )
screenPanel : RegisterEvent ( " GROUP_ROSTER_UPDATE " )
screenPanel : SetScript ( " OnShow " , function ( )
screenPanel : RegisterEvent ( " GROUP_ROSTER_UPDATE " )
end )
screenPanel : SetScript ( " OnHide " , function ( )
screenPanel : UnregisterEvent ( " GROUP_ROSTER_UPDATE " )
end )
screenPanel : SetScript ( " OnEvent " , function ( self , event )
if ( event == " GROUP_ROSTER_UPDATE " ) then
if ( screenPanel.scheduleRosterUpdate ) then
return
end
screenPanel.scheduleRosterUpdate = C_Timer.NewTimer ( 1 , Details.CooldownTracking . RefreshCooldownFrames )
end
end )
screenPanel.bars = { }
screenPanel.cooldownCache = Details.ocd_tracker . current_cooldowns
screenPanel.playerCache = { }
screenPanel.statusBarFrameIndex = 1
return screenPanel
end
function Details . CooldownTracking . SetupCooldownFrame ( cooldownFrame )
local spellIcon = GetSpellTexture ( cooldownFrame.spellId )
if ( spellIcon ) then
cooldownFrame : SetIcon ( spellIcon , .1 , .9 , .1 , .9 )
local classColor = C_ClassColor.GetClassColor ( cooldownFrame.class )
cooldownFrame : SetStatusBarColor ( classColor.r , classColor.g , classColor.b )
cooldownFrame : SetLeftText ( DF : RemoveRealmName ( cooldownFrame.unitName ) )
cooldownFrame : SetSize ( Details.ocd_tracker . width , Details.ocd_tracker . height )
end
end
function Details . CooldownTracking . ProcessUnitCooldowns ( unitId , unitCooldowns , cooldownsOrganized )
if ( unitCooldowns ) then
local unitInfo = openRaidLib.GetUnitInfo ( unitId )
if ( unitInfo ) then
local screenPanel = DetailsOnlineCDTrackerScreenPanel
for spellId , cooldownInfo in pairs ( unitCooldowns ) do
--get a bar
local cooldownFrame = Details.CooldownTracking . GetOrCreateNewCooldownFrame ( screenPanel , screenPanel.statusBarFrameIndex )
cooldownFrame.cooldownInfo = cooldownInfo
local isReady , normalizedPercent , timeLeft , charges , minValue , maxValue , currentValue = openRaidLib.GetCooldownStatusFromCooldownInfo ( cooldownInfo )
cooldownFrame.spellId = spellId
cooldownFrame.class = unitInfo.class
cooldownFrame.unitName = unitInfo.nameFull
--setup the cooldown in the bar
Details.CooldownTracking . SetupCooldownFrame ( cooldownFrame )
--add the cooldown into the organized by class table
tinsert ( cooldownsOrganized [ unitInfo.classId ] , cooldownFrame )
--iterate to the next cooldown frame
screenPanel.statusBarFrameIndex = screenPanel.statusBarFrameIndex + 1
--store the cooldown frame into a cache to get the cooldown frame quicker when a cooldown receives updates
screenPanel.playerCache [ unitInfo.nameFull ] = screenPanel.playerCache [ unitInfo.nameFull ] or { }
screenPanel.playerCache [ unitInfo.nameFull ] [ spellId ] = cooldownFrame
end
end
end
end
--> update cooldown frames based on the amount of players in the group or raid
function Details . CooldownTracking . RefreshCooldownFrames ( )
local screenPanel = DetailsOnlineCDTrackerScreenPanel
if ( not screenPanel ) then
screenPanel = Details.CooldownTracking . CreateScreenFrame ( )
end
if ( Details.ocd_tracker . framme_locked ) then
screenPanel : EnableMouse ( false )
else
screenPanel : EnableMouse ( true )
end
Details.CooldownTracking . HideAllBars ( )
screenPanel.scheduleRosterUpdate = nil
wipe ( screenPanel.playerCache )
screenPanel.statusBarFrameIndex = 1
if ( Details.ocd_tracker . show_conditions.only_in_group ) then
if ( not IsInGroup ( ) ) then
screenPanel : Hide ( )
return
end
end
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 ( )
return
end
end
local cooldownsOrganized = { }
for classId = 1 , 12 do --12 classes
cooldownsOrganized [ classId ] = { }
end
local numGroupMembers = GetNumGroupMembers ( )
local filter = " "
for filterName , isEnabled in pairs ( Details.ocd_tracker . filters ) do
if ( isEnabled ) then
filter = filter .. filterName .. " , "
end
end
if ( IsInRaid ( ) ) then
for i = 1 , numGroupMembers do
local unitId = " raid " .. i
local unitCooldowns = openRaidLib.GetUnitCooldowns ( unitId , filter )
Details.CooldownTracking . ProcessUnitCooldowns ( unitId , unitCooldowns , cooldownsOrganized )
end
elseif ( IsInGroup ( ) ) then
for i = 1 , numGroupMembers - 1 do
local unitId = " party " .. i
local unitCooldowns = openRaidLib.GetUnitCooldowns ( unitId , filter )
Details.CooldownTracking . ProcessUnitCooldowns ( unitId , unitCooldowns , cooldownsOrganized )
end
--player
local unitCooldowns = openRaidLib.GetUnitCooldowns ( " player " , filter )
Details.CooldownTracking . ProcessUnitCooldowns ( " player " , unitCooldowns , cooldownsOrganized )
else
--player
local unitCooldowns = openRaidLib.GetUnitCooldowns ( " player " , filter )
Details.CooldownTracking . ProcessUnitCooldowns ( " player " , unitCooldowns , cooldownsOrganized )
end
for classId = 1 , 12 do --12 classes
table.sort ( cooldownsOrganized [ classId ] , function ( t1 , t2 ) return t1.spellId < t2.spellId end )
end
local xPos = 1
local yPos = 0
local maxHeight = 0
local maxWidth = Details.ocd_tracker . width + 2
local cooldownFrameIndex = 1
for classId = 1 , 12 do
local cooldownFrameList = cooldownsOrganized [ classId ]
for index , cooldownFrame in ipairs ( cooldownFrameList ) do
local cooldownInfo = cooldownFrame.cooldownInfo
local isReady , normalizedPercent , timeLeft , charges , minValue , maxValue , currentValue = openRaidLib.GetCooldownStatusFromCooldownInfo ( cooldownInfo )
--local isReady, normalizedPercent, timeLeft, charges, minValue, maxValue, currentValue = openRaidLib.GetCooldownStatusFromUnitSpellID(cooldownFrame.unitName, cooldownFrame.spellId)
if ( not isReady ) then
cooldownFrame : SetTimer ( currentValue , minValue , maxValue )
else
cooldownFrame : SetTimer ( )
end
--positioning
if ( cooldownFrameIndex % Details.ocd_tracker . lines_per_column == 0 ) then
xPos = xPos + Details.ocd_tracker . width + 2
maxWidth = xPos + Details.ocd_tracker . width + 2
yPos = 0
end
cooldownFrame : SetPoint ( " topleft " , screenPanel , " topleft " , xPos , yPos )
yPos = yPos - Details.ocd_tracker . height - 1
if ( yPos < maxHeight ) then
maxHeight = yPos
end
cooldownFrameIndex = cooldownFrameIndex + 1
end
end
maxHeight = abs ( maxHeight )
if ( maxHeight == 0 ) then
screenPanel : Hide ( )
return
end
screenPanel : SetSize ( maxWidth , maxHeight )
screenPanel : Show ( )
end
--> Options panel
--initialize the cooldown options window and embed it to Details! options panel
function Details : InitializeCDTrackerWindow ( )
local DetailsCDTrackerWindow = CreateFrame ( " frame " , " DetailsCDTrackerWindow " , UIParent , " BackdropTemplate " )
DetailsCDTrackerWindow : SetSize ( 700 , 480 )
DetailsCDTrackerWindow.Frame = DetailsCDTrackerWindow
DetailsCDTrackerWindow.__name = " Cooldown Tracker "
DetailsCDTrackerWindow.real_name = " DETAILS_CDTRACKERWINDOW "
DetailsCDTrackerWindow.__icon = [[Interface\TUTORIALFRAME\UI-TUTORIALFRAME-SPIRITREZ]]
DetailsCDTrackerWindow.__iconcoords = { 130 / 512 , 256 / 512 , 0 , 1 }
DetailsCDTrackerWindow.__iconcolor = " white "
_G.DetailsPluginContainerWindow . EmbedPlugin ( DetailsCDTrackerWindow , DetailsCDTrackerWindow , true )
function DetailsCDTrackerWindow . RefreshWindow ( )
Details.OpenCDTrackerWindow ( )
end
--check if is enabled at startup
if ( Details.CooldownTracking . IsEnabled ( ) ) then
Details.CooldownTracking . EnableTracker ( )
end
DetailsCDTrackerWindow : Hide ( )
end
function Details . OpenCDTrackerWindow ( )
--check if the window exists, if not create it
if ( not _G.DetailsCDTrackerWindow or not _G.DetailsCDTrackerWindow . Initialized ) then
_G.DetailsCDTrackerWindow . Initialized = true
local f = _G.DetailsCDTrackerWindow or DF : CreateSimplePanel ( UIParent , 700 , 480 , " Details! Online CD Tracker " , " DetailsCDTrackerWindow " )
DF : ApplyStandardBackdrop ( f )
--enabled with a toggle button
--execute to reset position
--misc configs
local options_text_template = DF : GetTemplate ( " font " , " OPTIONS_FONT_TEMPLATE " )
local options_dropdown_template = DF : GetTemplate ( " dropdown " , " OPTIONS_DROPDOWN_TEMPLATE " )
local options_switch_template = DF : GetTemplate ( " switch " , " OPTIONS_CHECKBOX_TEMPLATE " )
local options_slider_template = DF : GetTemplate ( " slider " , " OPTIONS_SLIDER_TEMPLATE " )
local options_button_template = DF : GetTemplate ( " button " , " OPTIONS_BUTTON_TEMPLATE " )
local generalOptions = {
{ --enable ocd
type = " toggle " ,
get = function ( ) return Details.ocd_tracker . enabled end ,
set = function ( self , fixedparam , value )
if ( value ) then
Details.CooldownTracking . EnableTracker ( )
else
Details.CooldownTracking . DisableTracker ( )
end
end ,
name = " Enable Experimental Cooldown Tracker " ,
desc = " Enable Experimental Cooldown Tracker " ,
} ,
{ --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 . RefreshCooldownFrames ( )
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 . RefreshCooldownFrames ( )
end ,
name = " Only Inside Instances " ,
desc = " Only Inside Instances " ,
} ,
{ --lock frame
type = " toggle " ,
get = function ( ) return Details.ocd_tracker . framme_locked end ,
set = function ( self , fixedparam , value )
Details.ocd_tracker . framme_locked = value
Details.CooldownTracking . RefreshCooldownFrames ( )
end ,
name = " Lock Frame " ,
desc = " Lock Frame " ,
} ,
{ type = " breakline " } ,
{ --filter: show raid wide defensive cooldowns
type = " toggle " ,
get = function ( ) return Details.ocd_tracker . filters [ " defensive-raid " ] end ,
set = function ( self , fixedparam , value )
Details.ocd_tracker . filters [ " defensive-raid " ] = value
Details.CooldownTracking . RefreshCooldownFrames ( )
end ,
name = " Defensive: Raid " ,
desc = " Exanple: druid tranquility. " ,
} ,
{ --filter: show target defensive cooldowns
type = " toggle " ,
get = function ( ) return Details.ocd_tracker . filters [ " defensive-target " ] end ,
set = function ( self , fixedparam , value )
Details.ocd_tracker . filters [ " defensive-target " ] = value
Details.CooldownTracking . RefreshCooldownFrames ( )
end ,
name = " Defensive: Target " ,
desc = " Exanple: priest pain suppression. " ,
} ,
{ --filter: show personal defensive cooldowns
type = " toggle " ,
get = function ( ) return Details.ocd_tracker . filters [ " defensive-personal " ] end ,
set = function ( self , fixedparam , value )
Details.ocd_tracker . filters [ " defensive-personal " ] = value
Details.CooldownTracking . RefreshCooldownFrames ( )
end ,
name = " Defensive: Personal " ,
desc = " Exanple: mage ice block. " ,
} ,
{ --filter: show ofensive cooldowns
type = " toggle " ,
get = function ( ) return Details.ocd_tracker . filters [ " ofensive " ] end ,
set = function ( self , fixedparam , value )
Details.ocd_tracker . filters [ " ofensive " ] = value
Details.CooldownTracking . RefreshCooldownFrames ( )
end ,
name = " Offensive Cooldowns " ,
desc = " Exanple: priest power infusion. " ,
} ,
{ --filter: show utility cooldowns
type = " toggle " ,
get = function ( ) return Details.ocd_tracker . filters [ " utility " ] end ,
set = function ( self , fixedparam , value )
Details.ocd_tracker . filters [ " utility " ] = value
Details.CooldownTracking . RefreshCooldownFrames ( )
end ,
name = " Utility Cooldowns " ,
desc = " Exanple: druid roar. " ,
} ,
{ --filter: show interrupt cooldowns
type = " toggle " ,
get = function ( ) return Details.ocd_tracker . filters [ " interrupt " ] end ,
set = function ( self , fixedparam , value )
Details.ocd_tracker . filters [ " interrupt " ] = value
Details.CooldownTracking . RefreshCooldownFrames ( )
end ,
name = " Interrupt Cooldowns " ,
desc = " Exanple: rogue kick. " ,
} ,
{ type = " breakline " } ,
{ --bar width
type = " range " ,
get = function ( ) return Details.ocd_tracker . width end ,
set = function ( self , fixedparam , value )
Details.ocd_tracker . width = value
Details.CooldownTracking . RefreshCooldownFrames ( )
end ,
min = 10 ,
max = 200 ,
step = 1 ,
name = " Width " ,
desc = " Width " ,
} ,
{ --bar height
type = " range " ,
get = function ( ) return Details.ocd_tracker . height end ,
set = function ( self , fixedparam , value )
Details.ocd_tracker . height = value
Details.CooldownTracking . RefreshCooldownFrames ( )
end ,
min = 10 ,
max = 200 ,
step = 1 ,
name = " Height " ,
desc = " Height " ,
} ,
{ --bar height
type = " range " ,
get = function ( ) return Details.ocd_tracker . lines_per_column end ,
set = function ( self , fixedparam , value )
Details.ocd_tracker . lines_per_column = floor ( value )
Details.CooldownTracking . RefreshCooldownFrames ( )
end ,
min = 1 ,
max = 30 ,
step = 1 ,
name = " Lines Per Column " ,
desc = " Lines Per Column " ,
} ,
}
DF : BuildMenu ( f , generalOptions , 5 , - 30 , 150 , true , options_text_template , options_dropdown_template , options_switch_template , true , options_slider_template , options_button_template )
--cooldown selection
local cooldownProfile = Details.ocd_tracker . cooldowns
local cooldownSelectionFrame = CreateFrame ( " frame " , " $parentCooldownSelectionFrame " , f , " BackdropTemplate " )
cooldownSelectionFrame : SetPoint ( " topleft " , f , " topleft " , 0 , - 150 )
cooldownSelectionFrame : SetPoint ( " bottomright " , f , " bottomright " , 0 , 10 )
DF : ApplyStandardBackdrop ( cooldownSelectionFrame )
--lib test test warning texts
local warning1 = cooldownSelectionFrame : CreateFontString ( nil , " overlay " , " GameFontNormal " , 5 )
warning1 : SetPoint ( " center " , f , " center " , 0 , 0 )
warning1 : SetText ( " A cooldown tracker on Details!? \n What's next, a Caw counter for Elwynn Forest? " )
DF : SetFontColor ( warning1 , " silver " )
DF : SetFontSize ( warning1 , 14 )
local animationHub = DF : CreateAnimationHub ( warning1 )
local anim1 = DF : CreateAnimation ( animationHub , " rotation " , 1 , 0 , 35 )
anim1 : SetEndDelay ( math.huge )
anim1 : SetSmoothProgress ( 1 )
animationHub : Play ( )
animationHub : Pause ( )
local warning2 = cooldownSelectionFrame : CreateFontString ( nil , " overlay " , " GameFontNormal " , 5 )
warning2 : SetJustifyH ( " left " )
warning2 : SetPoint ( " topleft " , f , " topleft " , 5 , - 160 )
DF : SetFontColor ( warning2 , " lime " )
warning2 : SetText ( " This is a concept of a cooldown tracker using the new library 'Open Raid' which uses comms to update cooldown timers. \n The code to implement is so small that can fit inside a weakaura \n If you're a coder, the implementation is on Details/frames/window_cdtracker.lua " )
end
_G.DetailsPluginContainerWindow . OpenPlugin ( _G.DetailsCDTrackerWindow )
_G.DetailsCDTrackerWindow : Show ( )
end