You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3540 lines
130 KiB
3540 lines
130 KiB
|
3 years ago
|
|
||
|
|
--note: do maintenance on spelltable.ChartData
|
||
|
|
|
||
|
|
local addonName, Details222 = ...
|
||
|
|
local breakdownWindow = Details.BreakdownWindow
|
||
|
|
local Loc = LibStub("AceLocale-3.0"):GetLocale ( "Details" )
|
||
|
|
local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0")
|
||
|
|
local unpack = unpack
|
||
|
|
local GetTime = GetTime
|
||
|
|
local wipe = wipe
|
||
|
|
local CreateFrame = CreateFrame
|
||
|
|
local GetSpellLink = GetSpellLink
|
||
|
|
local GetSpellInfo = GetSpellInfo
|
||
|
|
local _GetSpellInfo = Details.GetSpellInfo
|
||
|
|
local GameTooltip = GameTooltip
|
||
|
|
local IsShiftKeyDown = IsShiftKeyDown
|
||
|
|
local DF = DetailsFramework
|
||
|
|
local tinsert = tinsert
|
||
|
|
|
||
|
|
---@type breakdownspelltab
|
||
|
|
local spellsTab = {}
|
||
|
|
|
||
|
|
--expose the object to the global namespace
|
||
|
|
DetailsSpellBreakdownTab = spellsTab
|
||
|
|
|
||
|
|
local iconTableSummary = {
|
||
|
|
texture = [[Interface\AddOns\Details\images\icons]],
|
||
|
|
coords = {238/512, 255/512, 0, 18/512},
|
||
|
|
width = 16,
|
||
|
|
height = 16,
|
||
|
|
}
|
||
|
|
|
||
|
|
local spellBlockContainerSettings = {
|
||
|
|
amount = 6, --amount of block the container have
|
||
|
|
lineAmount = 3, --amount of line each block have
|
||
|
|
}
|
||
|
|
|
||
|
|
local CONST_BAR_HEIGHT = 20
|
||
|
|
local CONST_SPELLSCROLL_LINEHEIGHT = 20
|
||
|
|
local CONST_TARGET_TEXTURE = [[Interface\MINIMAP\TRACKING\Target]]
|
||
|
|
local CONST_SPELLBLOCK_DEFAULT_COLOR = {.4, .4, .4, 1}
|
||
|
|
local CONST_SPELLBLOCK_HEADERTEXT_COLOR = {.9, .8, 0, 1}
|
||
|
|
local CONST_SPELLBLOCK_HEADERTEXT_SIZE = 11
|
||
|
|
|
||
|
|
Details.SpellGroups = {
|
||
|
|
[193473] = 15407, --mind flay
|
||
|
|
}
|
||
|
|
|
||
|
|
---return the actor currently in use by the breakdown window
|
||
|
|
---@return actor
|
||
|
|
function spellsTab.GetActor() --this cache must be cleared when the actor changes or the breakdown window is closed
|
||
|
|
return spellsTab.currentActor
|
||
|
|
end
|
||
|
|
|
||
|
|
---return the combat currently in use by the breakdown window
|
||
|
|
---@return combat
|
||
|
|
function spellsTab.GetCombat() --must be cleared
|
||
|
|
return spellsTab.combatObject
|
||
|
|
end
|
||
|
|
|
||
|
|
---@return instance
|
||
|
|
function spellsTab.GetInstance()
|
||
|
|
return spellsTab.instance or Details:GetActiveWindowFromBreakdownWindow()
|
||
|
|
end
|
||
|
|
|
||
|
|
---set the backdrop of scrollframe and container following the settings of the breakdown window
|
||
|
|
---@param containerFrame frame
|
||
|
|
---@param scrollFrame frame|nil
|
||
|
|
function spellsTab.ApplyStandardBackdrop(containerFrame, scrollFrame)
|
||
|
|
C_Timer.After(0, function()
|
||
|
|
containerFrame:SetBackdrop(Details222.BreakdownWindow.BackdropSettings.backdrop)
|
||
|
|
containerFrame:SetBackdropColor(unpack(Details222.BreakdownWindow.BackdropSettings.backdropcolor))
|
||
|
|
containerFrame:SetBackdropBorderColor(unpack(Details222.BreakdownWindow.BackdropSettings.backdropbordercolor))
|
||
|
|
|
||
|
|
if (scrollFrame) then
|
||
|
|
scrollFrame:SetBackdrop({})
|
||
|
|
if (scrollFrame["__background"]) then
|
||
|
|
scrollFrame["__background"]:Hide()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
---return the breakdownspellscrollframe object, there's only one of this in the breakdown window
|
||
|
|
---@return breakdownspellscrollframe
|
||
|
|
function spellsTab.GetSpellScrollFrame()
|
||
|
|
return spellsTab.TabFrame.SpellScrollFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---return the breakdownspellblockframe object, there's only one of this in the breakdown window
|
||
|
|
---@return breakdownspellblockframe
|
||
|
|
function spellsTab.GetSpellBlockFrame()
|
||
|
|
return spellsTab.TabFrame.SpellBlockFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---@return breakdowntargetscrollframe
|
||
|
|
function spellsTab.GetTargetScrollFrame()
|
||
|
|
return spellsTab.TargetScrollFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---@return breakdowntargetscrollframe
|
||
|
|
function spellsTab.GetPhaseScrollFrame()
|
||
|
|
return spellsTab.PhaseScrollFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---@return breakdowntargetscrollframe
|
||
|
|
function spellsTab.GetGenericScrollFrame()
|
||
|
|
return spellsTab.GenericScrollFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---@return df_framecontainer
|
||
|
|
function spellsTab.GetSpellScrollContainer()
|
||
|
|
return spellsTab.SpellContainerFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---@return df_framecontainer
|
||
|
|
function spellsTab.GetSpellBlockContainer()
|
||
|
|
return spellsTab.BlocksContainerFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---@return df_framecontainer
|
||
|
|
function spellsTab.GetTargetScrollContainer()
|
||
|
|
return spellsTab.TargetsContainerFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---@return df_framecontainer
|
||
|
|
function spellsTab.GetPhaseScrollContainer()
|
||
|
|
return spellsTab.PhaseContainerFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---@return df_framecontainer
|
||
|
|
function spellsTab.GetGenericScrollContainer()
|
||
|
|
return spellsTab.GenericContainerFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
function spellsTab.GetScrollFrameByContainerType(containerType)
|
||
|
|
if (containerType == "spells") then
|
||
|
|
return spellsTab.GetSpellScrollFrame()
|
||
|
|
|
||
|
|
elseif (containerType == "targets") then
|
||
|
|
return spellsTab.GetTargetScrollFrame()
|
||
|
|
|
||
|
|
elseif (containerType == "phases") then
|
||
|
|
return spellsTab.GetPhaseScrollFrame()
|
||
|
|
|
||
|
|
elseif (containerType == "generic") then
|
||
|
|
return spellsTab.GetGenericScrollFrame()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function spellsTab.OnProfileChange()
|
||
|
|
--no need to cache, just call the db from there
|
||
|
|
spellsTab.UpdateHeadersSettings("spells")
|
||
|
|
spellsTab.UpdateHeadersSettings("targets")
|
||
|
|
spellsTab.UpdateHeadersSettings("phases")
|
||
|
|
spellsTab.UpdateHeadersSettings("generic")
|
||
|
|
end
|
||
|
|
|
||
|
|
------------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
|
--Header
|
||
|
|
|
||
|
|
---store the header object has key and its type as value, the header type can be 'spell' or 'target'
|
||
|
|
---@type table<uiobject, string>
|
||
|
|
local headerContainerType = {}
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local columnOffset = 0
|
||
|
|
|
||
|
|
---column header information saved into details database: if is enabaled, its with and align
|
||
|
|
local settingsPrototype = {
|
||
|
|
enabled = true,
|
||
|
|
width = 100,
|
||
|
|
align = "left",
|
||
|
|
}
|
||
|
|
|
||
|
|
---contains the column settings for each header column, the table key is columnName and the value is headercolumndatasaved
|
||
|
|
---@class headercolumndatabase : table<string, headercolumndatasaved>
|
||
|
|
|
||
|
|
---headercolumndata goes inside the header table which is passed to the header constructor or header:SetHeaderTable()
|
||
|
|
---@class headercolumndata : {name:string, width:number, text:string, align:string, key:string, selected:boolean, canSort:boolean, dataType:string, order:string, offset:number, key:string}
|
||
|
|
|
||
|
|
---columndata is the raw table with all options which can be used to create a headertable, some may not be used due to settings or filtering
|
||
|
|
---@class columndata : {name:string, width:number, key:string, selected:boolean, label:string, align:string, enabled:boolean, attribute:number, canSort:boolean, dataType:string, order:string, offset:number}
|
||
|
|
|
||
|
|
---default settings for the header of the spells container, label is a localized string, name is a string used to save the column settings, key is the key used to get the value from the spell table, width is the width of the column, align is the alignment of the text, enabled is if the column is enabled, canSort is if the column can be sorted, sortKey is the key used to sort the column, dataType is the type of data the column is sorting, order is the order of the sorting, offset is the offset of the column
|
||
|
|
---@type columndata[]
|
||
|
|
local spellContainerColumnData = {
|
||
|
|
--the align seems to be bugged as the left is aligning in the center and center is on the left side
|
||
|
|
{name = "icon", width = 22, label = "", align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "target", width = 22, label = "", align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "rank", label = "#", width = 16, align = "center", enabled = true, offset = 6, dataType = "number"},
|
||
|
|
{name = "expand", label = "^", width = 16, align = "left", enabled = true, offset = -4}, --maybe -3
|
||
|
|
{name = "name", label = "spell name", width = 231, align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "amount", label = "total", key = "total", selected = true, width = 50, align = "left", enabled = true, canSort = true, sortKey = "total", dataType = "number", order = "DESC", offset = columnOffset},
|
||
|
|
{name = "persecond", label = "ps", key = "total", width = 50, align = "left", enabled = false, canSort = true, sortKey = "ps", offset = columnOffset, order = "DESC", dataType = "number"},
|
||
|
|
{name = "percent", label = "%", key = "total", width = 50, align = "left", enabled = true, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
|
||
|
|
{name = "casts", label = "casts", key = "casts", width = 40, align = "left", enabled = false, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
|
||
|
|
{name = "critpercent", label = "crit %", key = "critpercent", width = 40, align = "left", enabled = false, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
|
||
|
|
{name = "hits", label = "hits", key = "counter", width = 40, align = "left", enabled = false, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
|
||
|
|
{name = "castavg", label = "cast avg", key = "castavg", width = 50, align = "left", enabled = false, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
|
||
|
|
{name = "uptime", label = "uptime", key = "uptime", width = 45, align = "left", enabled = false, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
|
||
|
|
{name = "overheal", label = "overheal", key = "overheal", width = 70, align = "left", enabled = true, canSort = true, order = "DESC", dataType = "number", attribute = DETAILS_ATTRIBUTE_HEAL, offset = columnOffset},
|
||
|
|
{name = "absorbed", label = "absorbed", key = "healabsorbed", width = 55, align = "left", enabled = false, canSort = true, order = "DESC", dataType = "number", attribute = DETAILS_ATTRIBUTE_HEAL, offset = columnOffset},
|
||
|
|
}
|
||
|
|
|
||
|
|
local targetContainerColumnData = {
|
||
|
|
{name = "icon", width = 22, label = "", align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "rank", label = "#", width = 20, align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "name", label = "name", width = 185, align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "amount", label = "total", key = "total", selected = true, width = 50, align = "left", enabled = true, canSort = true, sortKey = "total", dataType = "number", order = "DESC", offset = columnOffset},
|
||
|
|
{name = "overheal", label = "overheal", key = "overheal", width = 70, align = "left", enabled = true, canSort = true, sortKey = "total", dataType = "number", order = "DESC", offset = columnOffset, attribute = DETAILS_ATTRIBUTE_HEAL},
|
||
|
|
{name = "percent", label = "%", key = "total", width = 50, align = "left", enabled = true, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
|
||
|
|
}
|
||
|
|
|
||
|
|
local phaseContainerColumnData = {
|
||
|
|
{name = "icon", width = 22, label = "", align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "name", label = "name", width = 90, align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "rank", label = "#", width = 30, align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "amount", label = "total", key = "total", width = 50, align = "left", enabled = true, canSort = true, sortKey = "total", dataType = "number", order = "DESC", offset = columnOffset, selected = true},
|
||
|
|
{name = "persecond", label = "ps", key = "total", width = 44, align = "left", enabled = true, canSort = true, sortKey = "ps", dataType = "number", order = "DESC", offset = columnOffset},
|
||
|
|
{name = "percent", label = "%", key = "total", width = 44, align = "left", enabled = true, canSort = true, sortKey = "total", dataType = "number", order = "DESC", offset = columnOffset},
|
||
|
|
}
|
||
|
|
|
||
|
|
--generic container can show data from any attribute
|
||
|
|
local genericContainerColumnData = {
|
||
|
|
{name = "icon", width = 22, label = "", align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "name", label = "name", width = 200, align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "rank", label = "#", width = 30, align = "left", enabled = true, offset = columnOffset},
|
||
|
|
{name = "amount", label = "total", key = "total", width = 50, align = "left", enabled = true, canSort = true, sortKey = "total", dataType = "number", order = "DESC", offset = columnOffset, selected = true},
|
||
|
|
{name = "persecond", label = "ps", key = "total", width = 50, align = "left", enabled = true, canSort = true, sortKey = "ps", dataType = "number", order = "DESC", offset = columnOffset},
|
||
|
|
{name = "percent", label = "%", key = "total", width = 50, align = "left", enabled = true, canSort = true, sortKey = "total", dataType = "number", order = "DESC", offset = columnOffset},
|
||
|
|
}
|
||
|
|
|
||
|
|
---get the header settings from details saved variables and the container column data
|
||
|
|
---@param containerType "spells"|"targets"|"phases"|"generic"
|
||
|
|
---@return headercolumndatabase
|
||
|
|
---@return columndata
|
||
|
|
function spellsTab.GetHeaderSettings(containerType)
|
||
|
|
local settings
|
||
|
|
---@type headercolumndata
|
||
|
|
local containerColumnData
|
||
|
|
|
||
|
|
if (containerType == "spells") then
|
||
|
|
settings = Details.breakdown_spell_tab.spellcontainer_headers
|
||
|
|
containerColumnData = spellContainerColumnData
|
||
|
|
|
||
|
|
elseif (containerType == "targets") then
|
||
|
|
settings = Details.breakdown_spell_tab.targetcontainer_headers
|
||
|
|
containerColumnData = targetContainerColumnData
|
||
|
|
|
||
|
|
elseif (containerType == "phases") then
|
||
|
|
settings = Details.breakdown_spell_tab.phasecontainer_headers
|
||
|
|
containerColumnData = phaseContainerColumnData
|
||
|
|
|
||
|
|
elseif (containerType == "generic") then
|
||
|
|
settings = Details.breakdown_spell_tab.genericcontainer_headers
|
||
|
|
containerColumnData = genericContainerColumnData
|
||
|
|
|
||
|
|
--as the generic data is received, it may have which columns can be shown
|
||
|
|
if (spellsTab.headersAllowed) then
|
||
|
|
for index, columnData in ipairs(containerColumnData) do
|
||
|
|
local newEnabledState = spellsTab.headersAllowed[columnData.name] or false
|
||
|
|
columnData.enabled = newEnabledState
|
||
|
|
--check if the settings already has the data, and then set the header enabled value to follow the headersAllowed table
|
||
|
|
if (settings[columnData.name]) then
|
||
|
|
settings[columnData.name].enabled = newEnabledState
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
---@cast settings headercolumndatabase
|
||
|
|
return settings, containerColumnData
|
||
|
|
end
|
||
|
|
|
||
|
|
---callback for when the user resizes a column on the header
|
||
|
|
---@param headerFrame df_headerframe
|
||
|
|
---@param optionName string
|
||
|
|
---@param columnName string
|
||
|
|
---@param value any
|
||
|
|
local onHeaderColumnOptionChanged = function(headerFrame, optionName, columnName, value)
|
||
|
|
---@type "spells"|"targets"|"phases"|"generic"
|
||
|
|
local containerType = headerContainerType[headerFrame]
|
||
|
|
---@type headercolumndatabase
|
||
|
|
local settings = spellsTab.GetHeaderSettings(containerType)
|
||
|
|
|
||
|
|
settings[columnName][optionName] = value
|
||
|
|
spellsTab.UpdateHeadersSettings(containerType)
|
||
|
|
end
|
||
|
|
|
||
|
|
---run when the user clicks the columnHeader
|
||
|
|
---@param headerFrame df_headerframe
|
||
|
|
---@param columnHeader df_headercolumnframe
|
||
|
|
local onColumnHeaderClickCallback = function(headerFrame, columnHeader)
|
||
|
|
---@type string
|
||
|
|
local containerType = headerContainerType[headerFrame]
|
||
|
|
|
||
|
|
local scrollFrame = spellsTab.GetScrollFrameByContainerType(containerType)
|
||
|
|
scrollFrame:Refresh()
|
||
|
|
|
||
|
|
local instance = spellsTab.GetInstance()
|
||
|
|
instance:RefreshWindow(true)
|
||
|
|
end
|
||
|
|
|
||
|
|
local onAnyColumnHeaderClickCallback = function()
|
||
|
|
local instance = spellsTab.GetInstance()
|
||
|
|
instance:RefreshWindow(true)
|
||
|
|
end
|
||
|
|
|
||
|
|
---copy settings from the ColumnInfo table which doesn't exists in the details profile
|
||
|
|
---this is called when the profile changes or when the tab is opened with a different actor than before
|
||
|
|
---@param containerType "spells"|"targets"|"phases"|"generic"
|
||
|
|
function spellsTab.UpdateHeadersSettings(containerType)
|
||
|
|
---details table which hold the settings for a container header
|
||
|
|
local settings, containerColumnData = spellsTab.GetHeaderSettings(containerType)
|
||
|
|
|
||
|
|
--do a loop and check if the column data from columnInfo exists in the details profile settings, if not, add it
|
||
|
|
for i = 1, #containerColumnData do
|
||
|
|
--default column settings
|
||
|
|
local columnData = containerColumnData[i]
|
||
|
|
---@type string
|
||
|
|
local columnName = columnData.name
|
||
|
|
|
||
|
|
--column settings for the column on details profile
|
||
|
|
---@type headercolumndatasaved
|
||
|
|
local columnSettings = settings[columnName]
|
||
|
|
|
||
|
|
--check if this column does not have a mirror table in details profile
|
||
|
|
if (not columnSettings) then
|
||
|
|
--create a table in Details! saved variables to save the column settings
|
||
|
|
---@type headercolumndatasaved
|
||
|
|
local newColumnSettings = DetailsFramework.table.copy({}, settingsPrototype)
|
||
|
|
settings[columnName] = newColumnSettings
|
||
|
|
|
||
|
|
newColumnSettings.enabled = columnData.enabled
|
||
|
|
newColumnSettings.width = columnData.width
|
||
|
|
newColumnSettings.align = columnData.align
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (containerType == "spells") then
|
||
|
|
spellsTab.spellsHeaderData = spellsTab.BuildHeaderTable(containerType)
|
||
|
|
|
||
|
|
local spellContainer = spellsTab.GetSpellScrollContainer()
|
||
|
|
local spellScrollFrame = spellsTab.GetSpellScrollFrame()
|
||
|
|
|
||
|
|
local headerFrame = spellScrollFrame.Header
|
||
|
|
headerFrame:SetHeaderTable(spellsTab.spellsHeaderData)
|
||
|
|
|
||
|
|
local width = headerFrame:GetWidth()
|
||
|
|
|
||
|
|
--SetHeaderTable() calls Header:Refresh() which reset its width
|
||
|
|
--if the spell container get a resize to be as big as the sum of all columns width, the option to resize the container's width is useless
|
||
|
|
spellContainer:SetWidth(width)
|
||
|
|
--save the width of the spell container in Details settings
|
||
|
|
Details.breakdown_spell_tab.spellcontainer_width = width
|
||
|
|
|
||
|
|
elseif (containerType == "targets") then
|
||
|
|
spellsTab.targetsHeaderData = spellsTab.BuildHeaderTable(containerType)
|
||
|
|
spellsTab.GetTargetScrollFrame().Header:SetHeaderTable(spellsTab.targetsHeaderData)
|
||
|
|
|
||
|
|
local width = spellsTab.GetTargetScrollFrame().Header:GetWidth()
|
||
|
|
spellsTab.GetTargetScrollContainer():SetWidth(width)
|
||
|
|
|
||
|
|
--save the width of the target container in Details settings
|
||
|
|
Details.breakdown_spell_tab.targetcontainer_width = width
|
||
|
|
|
||
|
|
elseif (containerType == "phases") then
|
||
|
|
spellsTab.phasesHeaderData = spellsTab.BuildHeaderTable(containerType)
|
||
|
|
spellsTab.GetPhaseScrollFrame().Header:SetHeaderTable(spellsTab.phasesHeaderData)
|
||
|
|
|
||
|
|
elseif (containerType == "generic") then
|
||
|
|
spellsTab.genericHeaderData = spellsTab.BuildHeaderTable(containerType)
|
||
|
|
spellsTab.GetGenericScrollFrame().Header:SetHeaderTable(spellsTab.genericHeaderData)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
---get the header settings from details profile and build a header table using the table which store all headers columns information
|
||
|
|
---the data for each header is stored on 'spellContainerColumnInfo' and 'targetContainerColumnInfo' variables
|
||
|
|
---@param containerType "spells"|"targets"|"phases"|"generic"
|
||
|
|
---@return {name: string, width: number, text: string, align: string}[]
|
||
|
|
function spellsTab.BuildHeaderTable(containerType)
|
||
|
|
---@type headercolumndata[]
|
||
|
|
local headerTable = {}
|
||
|
|
|
||
|
|
---@type instance
|
||
|
|
local instance = spellsTab.GetInstance()
|
||
|
|
|
||
|
|
---@type number, number
|
||
|
|
local mainAttribute, subAttribute = instance:GetDisplay()
|
||
|
|
|
||
|
|
--settings from profile | updated at UpdateHeadersSettings() > called on OnProfileChange() and when the tab is opened
|
||
|
|
local settings, containerColumnData = spellsTab.GetHeaderSettings(containerType)
|
||
|
|
|
||
|
|
---result of the sum of all columns width
|
||
|
|
---@type number
|
||
|
|
local totalWidth = 0
|
||
|
|
|
||
|
|
for i = 1, #containerColumnData do
|
||
|
|
local columnData = containerColumnData[i]
|
||
|
|
---@type headercolumndatasaved
|
||
|
|
local columnSettings = settings[columnData.name]
|
||
|
|
|
||
|
|
if (columnSettings.enabled) then
|
||
|
|
local bCanAdd = true
|
||
|
|
if (columnData.attribute) then
|
||
|
|
if (columnData.attribute ~= mainAttribute) then
|
||
|
|
bCanAdd = false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (bCanAdd) then
|
||
|
|
---@type headercolumndata
|
||
|
|
local headerColumnData = {
|
||
|
|
width = columnSettings.width,
|
||
|
|
text = columnData.label,
|
||
|
|
name = columnData.name,
|
||
|
|
|
||
|
|
--these values may be nil
|
||
|
|
selected = columnData.selected,
|
||
|
|
align = columnData.align,
|
||
|
|
canSort = columnData.canSort,
|
||
|
|
dataType = columnData.dataType,
|
||
|
|
order = columnData.order,
|
||
|
|
offset = columnData.offset,
|
||
|
|
key = columnData.key,
|
||
|
|
}
|
||
|
|
|
||
|
|
totalWidth = totalWidth + headerColumnData.width
|
||
|
|
headerTable[#headerTable+1] = headerColumnData
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
return headerTable
|
||
|
|
end
|
||
|
|
|
||
|
|
---some values required by the header sort key is not available in the spellTable, so they need to be calculated
|
||
|
|
---@param combatObject combat
|
||
|
|
---@param spellData spelltable|spelltableadv
|
||
|
|
---@param key string
|
||
|
|
---@return any
|
||
|
|
local getValueForHeaderSortKey = function(combatObject, spellData, key)
|
||
|
|
if (key == "critpercent") then
|
||
|
|
return Details.SpellTableMixin.GetCritPercent(spellData)
|
||
|
|
|
||
|
|
elseif (key == "casts") then
|
||
|
|
local spellName = GetSpellInfo(spellData.id)
|
||
|
|
local amountOfCasts = combatObject:GetSpellCastAmount(spellsTab.GetActor():Name(), spellName)
|
||
|
|
return amountOfCasts
|
||
|
|
|
||
|
|
elseif (key == "castavg") then
|
||
|
|
local spellName = GetSpellInfo(spellData.id)
|
||
|
|
local amountOfCasts = combatObject:GetSpellCastAmount(spellsTab.GetActor():Name(), spellName)
|
||
|
|
return Details.SpellTableMixin.GetCastAverage(spellData, amountOfCasts)
|
||
|
|
|
||
|
|
elseif (key == "uptime") then
|
||
|
|
return combatObject:GetSpellUptime(spellsTab.GetActor():Name(), spellData.id)
|
||
|
|
|
||
|
|
elseif (key == "healabsorbed") then
|
||
|
|
return spellData.absorbed
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
------------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
|
--Bar Selection
|
||
|
|
|
||
|
|
--store the current spellbar selected, this is used to lock the spellblock container to the spellbar selected
|
||
|
|
spellsTab.selectedSpellBar = nil
|
||
|
|
|
||
|
|
---selected a breakdownspellbar, locking into the bar
|
||
|
|
---when a breakdownspellbar is selected, all the other breakdownspellbar has it's hover over disabled
|
||
|
|
---@param spellBar breakdownspellbar
|
||
|
|
function spellsTab.SelectSpellBar(spellBar)
|
||
|
|
--if already has a spellbar selected, unselect it
|
||
|
|
if (spellsTab.HasSelectedSpellBar()) then --unselect and stop the function if the bar selected is the same as the one being selected
|
||
|
|
if (spellsTab.GetSelectedSpellBar() == spellBar) then
|
||
|
|
spellsTab.UnSelectSpellBar()
|
||
|
|
return
|
||
|
|
else
|
||
|
|
spellsTab.UnSelectSpellBar()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--as the spell block container get an update when hovering over
|
||
|
|
--update the spell block container for the breakdownspellbar just selected
|
||
|
|
--this is necessary since a previous breakdownspellbar could have been selected and prevented this breakdownspellbar to update on hover over
|
||
|
|
---@type function
|
||
|
|
local onEnterScript = spellBar:GetScript("OnEnter")
|
||
|
|
if (onEnterScript) then
|
||
|
|
onEnterScript(spellBar)
|
||
|
|
end
|
||
|
|
|
||
|
|
--set the new breakdownspellbar as selected
|
||
|
|
spellsTab.selectedSpellBar = spellBar
|
||
|
|
spellsTab.selectedSpellBar.overlayTexture:Show()
|
||
|
|
end
|
||
|
|
|
||
|
|
---deselect the breakdownspellbar
|
||
|
|
function spellsTab.UnSelectSpellBar()
|
||
|
|
if (spellsTab.selectedSpellBar) then
|
||
|
|
spellsTab.selectedSpellBar.overlayTexture:Hide()
|
||
|
|
end
|
||
|
|
spellsTab.selectedSpellBar = nil
|
||
|
|
end
|
||
|
|
|
||
|
|
---get the spellbar currently selected
|
||
|
|
---@return breakdownspellbar
|
||
|
|
function spellsTab.GetSelectedSpellBar()
|
||
|
|
return spellsTab.selectedSpellBar
|
||
|
|
end
|
||
|
|
|
||
|
|
---return true if there's a spell bar selected
|
||
|
|
---@return boolean
|
||
|
|
function spellsTab.HasSelectedSpellBar()
|
||
|
|
return spellsTab.selectedSpellBar ~= nil
|
||
|
|
end
|
||
|
|
|
||
|
|
function spellsTab.OnShownTab()
|
||
|
|
--unselect any selected breakdownspellbar
|
||
|
|
spellsTab.UnSelectSpellBar()
|
||
|
|
--reset the spell blocks
|
||
|
|
spellsTab.GetSpellBlockFrame():ClearBlocks()
|
||
|
|
--update spells and target header frame (spellscroll and targetscroll)
|
||
|
|
spellsTab.UpdateHeadersSettings("spells")
|
||
|
|
spellsTab.UpdateHeadersSettings("targets")
|
||
|
|
spellsTab.UpdateHeadersSettings("phases")
|
||
|
|
spellsTab.UpdateHeadersSettings("generic")
|
||
|
|
end
|
||
|
|
|
||
|
|
---called when the tab is getting created, run only once
|
||
|
|
---@param tabButton button
|
||
|
|
---@param tabFrame breakdownspellstab
|
||
|
|
function spellsTab.OnCreateTabCallback(tabButton, tabFrame) --~init
|
||
|
|
spellsTab.TabFrame = tabFrame
|
||
|
|
|
||
|
|
--initialize the allowed headers for generic data container
|
||
|
|
spellsTab.headersAllowed = {icon = true, name = true, rank = true, amount = true, persecond = true, percent = true}
|
||
|
|
|
||
|
|
--create the scrollbar to show the spells in the breakdown window
|
||
|
|
spellsTab.CreateSpellScrollContainer(tabFrame) --finished
|
||
|
|
--create the 6 spell blocks in the right side of the breakdown window, these blocks show the spell info like normal hits, critical hits, average, etc
|
||
|
|
spellsTab.CreateSpellBlockContainer(tabFrame)
|
||
|
|
--create the targets container
|
||
|
|
spellsTab.CreateTargetContainer(tabFrame)
|
||
|
|
--create phases container
|
||
|
|
spellsTab.CreatePhasesContainer(tabFrame)
|
||
|
|
--create generic container
|
||
|
|
spellsTab.CreateGenericContainer(tabFrame)
|
||
|
|
|
||
|
|
--create the report buttons for each container
|
||
|
|
--spellsTab.CreateReportButtons(tabFrame)
|
||
|
|
|
||
|
|
--create a button in the breakdown window to open the options for this tab
|
||
|
|
local optionsButton = DF:CreateButton(tabFrame, Details.OpenSpellBreakdownOptions, 130, 20, "options", 14, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"))
|
||
|
|
optionsButton:SetPoint("bottomright", tabFrame, "bottomright", -5, 5)
|
||
|
|
optionsButton.textsize = 16
|
||
|
|
optionsButton.textcolor = "yellow"
|
||
|
|
|
||
|
|
--open the breakdown window at startup for testing
|
||
|
|
--[=[ debug
|
||
|
|
C_Timer.After(1, function()
|
||
|
|
Details:OpenPlayerDetails(1)
|
||
|
|
C_Timer.After(1, function()
|
||
|
|
Details:OpenPlayerDetails(1)
|
||
|
|
Details:OpenPlayerDetails(1)
|
||
|
|
end)
|
||
|
|
end)
|
||
|
|
--]=]
|
||
|
|
end
|
||
|
|
|
||
|
|
---------------------------------------------------------------------------------------------------
|
||
|
|
--Scripts
|
||
|
|
|
||
|
|
--create a details bar on the right side of the window
|
||
|
|
local onEnterSpellBlock = function(spellBlock) --info background is the 6 bars in the right side of the window?
|
||
|
|
spellBlock.overlay:Show()
|
||
|
|
spellBlock.reportButton:Show()
|
||
|
|
end
|
||
|
|
|
||
|
|
local onLeaveSpellBlock = function(spellBlock)
|
||
|
|
spellBlock.overlay:Hide()
|
||
|
|
spellBlock.reportButton:Hide()
|
||
|
|
end
|
||
|
|
|
||
|
|
local onEnterInfoReport = function(self)
|
||
|
|
Details.FadeHandler.Fader(self:GetParent().overlay, 0)
|
||
|
|
Details.FadeHandler.Fader(self, 0)
|
||
|
|
end
|
||
|
|
|
||
|
|
local onLeaveInfoReport = function(self)
|
||
|
|
Details.FadeHandler.Fader(self:GetParent().overlay, 1)
|
||
|
|
Details.FadeHandler.Fader(self, 1)
|
||
|
|
end
|
||
|
|
|
||
|
|
---run this function when the mouse hover over a breakdownspellbar
|
||
|
|
---@param spellBar breakdownspellbar
|
||
|
|
---@param motion boolean|nil
|
||
|
|
local onEnterSpellBar = function(spellBar, motion) --parei aqui: precisa por nomes nas funções e formatar as linhas das funcções
|
||
|
|
--all values from spellBar are cached values
|
||
|
|
--check if there's a spellbar selected, if there's one, ignore the mouseover
|
||
|
|
if (spellsTab.HasSelectedSpellBar() and motion) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
spellsTab.currentSpellBar = spellBar
|
||
|
|
|
||
|
|
---@type instance
|
||
|
|
local instance = spellsTab.GetInstance()
|
||
|
|
|
||
|
|
---@type combat
|
||
|
|
local combatObject = spellsTab.GetCombat()
|
||
|
|
|
||
|
|
---@type number, number
|
||
|
|
local mainAttribute, subAttribute = instance:GetDisplay()
|
||
|
|
|
||
|
|
---@type breakdownspellblockframe
|
||
|
|
local spellBlockContainer = spellsTab.GetSpellBlockFrame()
|
||
|
|
spellBlockContainer:ClearBlocks()
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local spellId = spellBar.spellId
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local elapsedTime = spellBar.combatTime --this should be actorObject:Tempo()
|
||
|
|
|
||
|
|
---@type string
|
||
|
|
local actorName = spellsTab.GetActor():Name()
|
||
|
|
|
||
|
|
---@type spelltable
|
||
|
|
local spellTable = spellBar.spellTable
|
||
|
|
|
||
|
|
if (IsShiftKeyDown()) then
|
||
|
|
if (type(spellId) == "number") then
|
||
|
|
GameCooltip:Preset(2)
|
||
|
|
GameCooltip:SetOwner(spellBar)
|
||
|
|
GameCooltip:AddLine(Loc ["ABILITY_ID"] .. ": " .. spellBar.spellId)
|
||
|
|
GameCooltip:Show()
|
||
|
|
|
||
|
|
---@type spelltable
|
||
|
|
local thisSpellTable = combatObject:GetActor(mainAttribute, actorName).spells._ActorTable[spellId]
|
||
|
|
|
||
|
|
local textToEditor = ""
|
||
|
|
for key, value in pairs(thisSpellTable) do
|
||
|
|
if (type(value) ~= "function" and type(value) ~= "table") then
|
||
|
|
textToEditor = textToEditor .. key .. " = " .. tostring(value) .. "\n"
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
breakdownWindow.dumpDataFrame:Show()
|
||
|
|
breakdownWindow.dumpDataFrame.luaEditor:SetText(textToEditor)
|
||
|
|
--hide the scroll bar
|
||
|
|
_G["DetailsBreakdownWindowPlayerScrollBoxDumpTableFrameCodeEditorWindowScrollBar"]:Hide()
|
||
|
|
end
|
||
|
|
|
||
|
|
elseif (breakdownWindow.dumpDataFrame:IsShown()) then
|
||
|
|
breakdownWindow.dumpDataFrame:Hide()
|
||
|
|
end
|
||
|
|
|
||
|
|
if (spellId == 98021) then --spirit link totem
|
||
|
|
GameTooltip:SetOwner(spellBar, "ANCHOR_TOPLEFT")
|
||
|
|
GameTooltip:AddLine(Loc ["STRING_SPIRIT_LINK_TOTEM_DESC"])
|
||
|
|
GameTooltip:Show()
|
||
|
|
end
|
||
|
|
|
||
|
|
---@type trinketdata
|
||
|
|
local trinketData = Details:GetTrinketData()
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local blockIndex = 1
|
||
|
|
|
||
|
|
--get the first spell block to use as summary
|
||
|
|
---@type breakdownspellblock
|
||
|
|
local summaryBlock = spellBlockContainer:GetBlock(blockIndex)
|
||
|
|
summaryBlock:Show()
|
||
|
|
summaryBlock:SetValue(50)
|
||
|
|
summaryBlock:SetValue(100)
|
||
|
|
|
||
|
|
if (mainAttribute == DETAILS_ATTRIBUTE_DAMAGE) then
|
||
|
|
--bounce to damage class to handle the spell details
|
||
|
|
if (subAttribute == 1 or subAttribute == 2 or subAttribute == 6) then
|
||
|
|
Details.atributo_damage:BuildSpellDetails(spellBar, spellBlockContainer, blockIndex, summaryBlock, spellId, elapsedTime, actorName, spellTable, trinketData, combatObject)
|
||
|
|
end
|
||
|
|
|
||
|
|
--need to know how many blocks the damage class used
|
||
|
|
local blocksInUse = spellBlockContainer:GetBlocksInUse()
|
||
|
|
local maxBlocks = spellBlockContainer:GetBlocksAmount()
|
||
|
|
|
||
|
|
for i = blocksInUse + 1, math.min(maxBlocks, 4) do --in the current state of the breakdown, showing 5 will overlap with the phase container
|
||
|
|
spellBlockContainer:ShowEmptyBlock(i)
|
||
|
|
end
|
||
|
|
|
||
|
|
elseif (mainAttribute == DETAILS_ATTRIBUTE_HEAL) then --this should run within the heal class ~healing
|
||
|
|
---@type number
|
||
|
|
local totalHits = spellTable.counter
|
||
|
|
|
||
|
|
--healing section showing healing done sub section
|
||
|
|
blockIndex = blockIndex + 1
|
||
|
|
|
||
|
|
do --update the texts in the summary block
|
||
|
|
local blockLine1, blockLine2, blockLine3 = summaryBlock:GetLines()
|
||
|
|
|
||
|
|
local totalCasts = spellBar.amountCasts > 0 and spellBar.amountCasts or "(?)"
|
||
|
|
blockLine1.leftText:SetText(Loc ["STRING_CAST"] .. ": " .. totalCasts) --total amount of casts
|
||
|
|
blockLine1.rightText:SetText(Loc ["STRING_HITS"]..": " .. totalHits) --hits and uptime
|
||
|
|
|
||
|
|
blockLine2.leftText:SetText(Loc ["STRING_HEAL"]..": " .. Details:Format(spellTable.total)) --total damage
|
||
|
|
blockLine2.rightText:SetText(Details:GetSpellSchoolFormatedName(spellTable.spellschool)) --spell school
|
||
|
|
|
||
|
|
blockLine3.leftText:SetText(Loc ["STRING_AVERAGE"] .. ": " .. Details:Format(spellBar.average)) --average damage
|
||
|
|
blockLine3.rightText:SetText(Loc ["STRING_HPS"] .. ": " .. Details:CommaValue(spellBar.perSecond)) --dps
|
||
|
|
end
|
||
|
|
|
||
|
|
--check if there's normal hits and build the block
|
||
|
|
---@type number
|
||
|
|
local normalHitsAmt = spellTable.n_amt
|
||
|
|
|
||
|
|
if (normalHitsAmt > 0) then
|
||
|
|
---@type breakdownspellblock
|
||
|
|
local normalHitsBlock = spellBlockContainer:GetBlock(blockIndex)
|
||
|
|
normalHitsBlock:Show()
|
||
|
|
blockIndex = blockIndex + 1
|
||
|
|
|
||
|
|
local percent = normalHitsAmt / math.max(totalHits, 0.0001) * 100
|
||
|
|
normalHitsBlock:SetValue(percent)
|
||
|
|
normalHitsBlock.sparkTexture:SetPoint("left", normalHitsBlock, "left", percent / 100 * normalHitsBlock:GetWidth() + Details.breakdown_spell_tab.blockspell_spark_offset, 0)
|
||
|
|
|
||
|
|
local blockLine1, blockLine2, blockLine3 = normalHitsBlock:GetLines()
|
||
|
|
blockLine1.leftText:SetText(Loc ["STRING_NORMAL_HITS"])
|
||
|
|
blockLine1.rightText:SetText(normalHitsAmt .. " [|cFFC0C0C0" .. string.format("%.1f", normalHitsAmt / math.max(totalHits, 0.0001) * 100) .. "%|r]")
|
||
|
|
|
||
|
|
blockLine2.leftText:SetText(Loc ["STRING_MINIMUM_SHORT"] .. ": " .. Details:CommaValue(spellTable.n_min))
|
||
|
|
blockLine2.rightText:SetText(Loc ["STRING_MAXIMUM_SHORT"] .. ": " .. Details:CommaValue(spellTable.n_max))
|
||
|
|
|
||
|
|
local normalAverage = spellTable.n_total / math.max(normalHitsAmt, 0.0001)
|
||
|
|
blockLine3.leftText:SetText(Loc ["STRING_AVERAGE"] .. ": " .. Details:CommaValue(normalAverage))
|
||
|
|
|
||
|
|
local tempo = (elapsedTime * spellTable.n_total) / math.max(spellTable.total, 0.001)
|
||
|
|
local normalAveragePercent = spellBar.average / normalAverage * 100
|
||
|
|
local normalTempoPercent = normalAveragePercent * tempo / 100
|
||
|
|
blockLine3.rightText:SetText(Loc ["STRING_HPS"] .. ": " .. Details:CommaValue(spellTable.n_total / normalTempoPercent))
|
||
|
|
end
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local criticalHitsAmt = spellTable.c_amt
|
||
|
|
if (criticalHitsAmt > 0) then
|
||
|
|
---@type breakdownspellblock
|
||
|
|
local critHitsBlock = spellBlockContainer:GetBlock(blockIndex)
|
||
|
|
critHitsBlock:Show()
|
||
|
|
blockIndex = blockIndex + 1
|
||
|
|
|
||
|
|
local percent = criticalHitsAmt / math.max(totalHits, 0.0001) * 100
|
||
|
|
critHitsBlock:SetValue(percent)
|
||
|
|
critHitsBlock.sparkTexture:SetPoint("left", critHitsBlock, "left", percent / 100 * critHitsBlock:GetWidth() + Details.breakdown_spell_tab.blockspell_spark_offset, 0)
|
||
|
|
|
||
|
|
local blockLine1, blockLine2, blockLine3 = critHitsBlock:GetLines()
|
||
|
|
blockLine1.leftText:SetText(Loc ["STRING_CRITICAL_HITS"])
|
||
|
|
blockLine1.rightText:SetText(criticalHitsAmt .. " [|cFFC0C0C0" .. string.format("%.1f", criticalHitsAmt / math.max(totalHits, 0.0001) * 100) .. "%|r]")
|
||
|
|
|
||
|
|
blockLine2.leftText:SetText(Loc ["STRING_MINIMUM_SHORT"] .. ": " .. Details:CommaValue(spellTable.c_min))
|
||
|
|
blockLine2.rightText:SetText(Loc ["STRING_MAXIMUM_SHORT"] .. ": " .. Details:CommaValue(spellTable.c_max))
|
||
|
|
|
||
|
|
local critAverage = spellTable.c_total / math.max(criticalHitsAmt, 0.0001)
|
||
|
|
blockLine3.leftText:SetText(Loc ["STRING_AVERAGE"] .. ": " .. Details:CommaValue(critAverage))
|
||
|
|
|
||
|
|
local tempo = (elapsedTime * spellTable.c_total) / math.max(spellTable.total, 0.001)
|
||
|
|
local critAveragePercent = spellBar.average / critAverage * 100
|
||
|
|
local critTempoPercent = critAveragePercent * tempo / 100
|
||
|
|
blockLine3.rightText:SetText(Loc ["STRING_HPS"] .. ": " .. Details:CommaValue(spellTable.c_total / critTempoPercent))
|
||
|
|
end
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local overheal = spellTable.overheal or 0
|
||
|
|
if (overheal > 0) then
|
||
|
|
--blockIndex = blockIndex + 1 --skip one block
|
||
|
|
---@type breakdownspellblock
|
||
|
|
local overhealBlock = spellBlockContainer:GetBlock(blockIndex)
|
||
|
|
overhealBlock:Show()
|
||
|
|
blockIndex = blockIndex + 1
|
||
|
|
|
||
|
|
local blockName
|
||
|
|
if (spellTable.is_shield) then
|
||
|
|
blockName = Loc ["STRING_SHIELD_OVERHEAL"]
|
||
|
|
else
|
||
|
|
blockName = Loc ["STRING_OVERHEAL"]
|
||
|
|
end
|
||
|
|
|
||
|
|
local percent = overheal / (overheal + spellTable.total) * 100
|
||
|
|
overhealBlock:SetValue(percent)
|
||
|
|
overhealBlock.sparkTexture:SetPoint("left", overhealBlock, "left", percent / 100 * overhealBlock:GetWidth() + Details.breakdown_spell_tab.blockspell_spark_offset, 0)
|
||
|
|
|
||
|
|
overhealBlock:SetColor(1, 0, 0, 0.4)
|
||
|
|
|
||
|
|
local blockLine1, blockLine2, blockLine3 = overhealBlock:GetLines()
|
||
|
|
blockLine1.leftText:SetText(blockName)
|
||
|
|
|
||
|
|
local overhealString = Details:CommaValue(overheal)
|
||
|
|
local overhealText = overhealString .. " / " .. string.format("%.1f", percent) .. "%"
|
||
|
|
blockLine1.rightText:SetText(overhealText)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--effects on entering the bar line
|
||
|
|
spellBar:SetHeight(CONST_SPELLSCROLL_LINEHEIGHT + 1)
|
||
|
|
spellBar:SetAlpha(1)
|
||
|
|
spellBar.spellIcon:SetSize(CONST_SPELLSCROLL_LINEHEIGHT + 2, CONST_SPELLSCROLL_LINEHEIGHT + 2)
|
||
|
|
spellBar.spellIcon:SetAlpha(1)
|
||
|
|
end
|
||
|
|
|
||
|
|
---run this function when the mouse leaves a breakdownspellbar
|
||
|
|
---@param spellBar breakdownspellbar
|
||
|
|
local onLeaveSpellBar = function(spellBar)
|
||
|
|
spellsTab.currentSpellBar = nil
|
||
|
|
|
||
|
|
--remove effects on entering the bar line
|
||
|
|
spellBar:SetHeight(CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
spellBar:SetAlpha(0.9)
|
||
|
|
|
||
|
|
GameTooltip:Hide()
|
||
|
|
GameCooltip:Hide()
|
||
|
|
|
||
|
|
--clear spell blocks
|
||
|
|
if (not spellsTab.HasSelectedSpellBar()) then
|
||
|
|
spellsTab.GetSpellBlockFrame():ClearBlocks()
|
||
|
|
end
|
||
|
|
|
||
|
|
if (breakdownWindow.dumpDataFrame:IsShown()) then
|
||
|
|
breakdownWindow.dumpDataFrame:Hide()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
---on mouse down a breakdownspellbar in the breakdown window
|
||
|
|
---@param spellBar breakdownspellbar
|
||
|
|
---@param button string
|
||
|
|
local onMouseDownBreakdownSpellBar = function(spellBar, button)
|
||
|
|
local x, y = _G.GetCursorPosition()
|
||
|
|
spellBar.cursorPosX = math.floor(x)
|
||
|
|
spellBar.cursorPosY = math.floor(y)
|
||
|
|
end
|
||
|
|
|
||
|
|
---on mouse up a breakdownspellbar in the breakdown window
|
||
|
|
---@param spellBar breakdownspellbar
|
||
|
|
---@param button string
|
||
|
|
local onMouseUpBreakdownSpellBar = function(spellBar, button)
|
||
|
|
spellBar.onMouseUpTime = GetTime()
|
||
|
|
|
||
|
|
---@type number, number
|
||
|
|
local x, y = _G.GetCursorPosition()
|
||
|
|
x = math.floor(x)
|
||
|
|
y = math.floor(y)
|
||
|
|
|
||
|
|
---@type boolean
|
||
|
|
local bIsMouseInTheSamePosition = (x == spellBar.cursorPosX) and (y == spellBar.cursorPosY)
|
||
|
|
|
||
|
|
--if the mouse is in the same position, then the user clicked the bar
|
||
|
|
if (bIsMouseInTheSamePosition) then
|
||
|
|
spellsTab.SelectSpellBar(spellBar)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local onEnterSpellIconFrame = function(self)
|
||
|
|
local line = self:GetParent()
|
||
|
|
if (line.spellId and type(line.spellId) == "number") then
|
||
|
|
local spellName = _GetSpellInfo(line.spellId)
|
||
|
|
if (spellName) then
|
||
|
|
GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT")
|
||
|
|
Details:GameTooltipSetSpellByID(line.spellId)
|
||
|
|
GameTooltip:Show()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
line:GetScript("OnEnter")(line)
|
||
|
|
end
|
||
|
|
|
||
|
|
local onLeaveSpellIconFrame = function(self)
|
||
|
|
GameTooltip:Hide()
|
||
|
|
self:GetParent():GetScript("OnLeave")(self:GetParent())
|
||
|
|
end
|
||
|
|
|
||
|
|
--------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
|
--Spell Blocks
|
||
|
|
|
||
|
|
local spellBlockMixin = {
|
||
|
|
---get one of the three lines containing fontstrings to show data
|
||
|
|
---line 1 is the top line, line 2 is the middle line and line 3 is the bottom line
|
||
|
|
---@param self breakdownspellblock
|
||
|
|
---@param lineIndex number
|
||
|
|
---@return breakdownspellblockline
|
||
|
|
GetLine = function(self, lineIndex)
|
||
|
|
---@type breakdownspellblockline
|
||
|
|
local line = self.Lines[lineIndex]
|
||
|
|
return line
|
||
|
|
end,
|
||
|
|
|
||
|
|
---return all lines in the spell block, all spell block have 3 lines
|
||
|
|
---@param self breakdownspellblock
|
||
|
|
---@return breakdownspellblockline, breakdownspellblockline, breakdownspellblockline
|
||
|
|
GetLines = function(self)
|
||
|
|
return unpack(self.Lines)
|
||
|
|
end,
|
||
|
|
|
||
|
|
---@param self breakdownspellblock
|
||
|
|
SetColor = function(self, ...)
|
||
|
|
local r, g, b, a = DF:ParseColors(...)
|
||
|
|
self.statusBarTexture:SetColorTexture(r, g, b, a)
|
||
|
|
end,
|
||
|
|
}
|
||
|
|
|
||
|
|
---create a spell block into the spellblockcontainer
|
||
|
|
---@param spellBlockContainer breakdownspellblockframe
|
||
|
|
---@param index number
|
||
|
|
---@return breakdownspellblock
|
||
|
|
function spellsTab.CreateSpellBlock(spellBlockContainer, index) --~breakdownspellblock ~create ~spellblocks
|
||
|
|
---@type breakdownspellblock
|
||
|
|
local spellBlock = CreateFrame("statusbar", "$parentBlock" .. index, spellBlockContainer, "BackdropTemplate")
|
||
|
|
DetailsFramework:Mixin(spellBlock, spellBlockMixin)
|
||
|
|
|
||
|
|
local statusBarTexture = spellBlock:CreateTexture("$parentTexture", "artwork")
|
||
|
|
statusBarTexture:SetColorTexture(unpack(CONST_SPELLBLOCK_DEFAULT_COLOR))
|
||
|
|
statusBarTexture:SetPoint("topleft", spellBlock, "topleft", 1, -1)
|
||
|
|
statusBarTexture:SetPoint("bottomleft", spellBlock, "bottomleft", 1, 1)
|
||
|
|
spellBlock.statusBarTexture = statusBarTexture
|
||
|
|
|
||
|
|
spellBlock:SetScript("OnEnter", onEnterSpellBlock)
|
||
|
|
spellBlock:SetScript("OnLeave", onLeaveSpellBlock)
|
||
|
|
spellBlock:SetScript("OnValueChanged", function()
|
||
|
|
statusBarTexture:SetWidth(spellBlock:GetValue() / 100 * spellBlock:GetWidth())
|
||
|
|
end)
|
||
|
|
|
||
|
|
spellBlock:SetMinMaxValues(0, 100)
|
||
|
|
spellBlock:SetValue(100)
|
||
|
|
|
||
|
|
--set the backdrop to have a 8x8 edge file
|
||
|
|
spellsTab.ApplyStandardBackdrop(spellBlock)
|
||
|
|
|
||
|
|
--create the lines which will host the texts
|
||
|
|
spellBlock.Lines = {}
|
||
|
|
for i = 1, spellBlockContainerSettings.lineAmount do
|
||
|
|
---@type breakdownspellblockline
|
||
|
|
local line = CreateFrame("frame", "$parentLine" .. i, spellBlock)
|
||
|
|
spellBlock.Lines[i] = line
|
||
|
|
|
||
|
|
line.leftText = line:CreateFontString("$parentLeftText", "overlay", "GameFontHighlightSmall")
|
||
|
|
line.centerText = line:CreateFontString("$parentLeftText", "overlay", "GameFontHighlightSmall")
|
||
|
|
line.rightText = line:CreateFontString("$parentLeftText", "overlay", "GameFontHighlightSmall")
|
||
|
|
|
||
|
|
line.leftText:SetPoint("left", line, "left", 2, 0)
|
||
|
|
line.leftText:SetJustifyH("left")
|
||
|
|
line.centerText:SetPoint("center", line, "center", 0, 0)
|
||
|
|
line.centerText:SetJustifyH("center")
|
||
|
|
line.rightText:SetPoint("right", line, "right", -2, 0)
|
||
|
|
line.rightText:SetJustifyH("right")
|
||
|
|
end
|
||
|
|
|
||
|
|
--overlay texture which fade in and out when the spell block is hovered over
|
||
|
|
--is only possible to hover over a spell block when the spellbar is selected
|
||
|
|
spellBlock.overlay = spellBlock:CreateTexture("$parentOverlay", "artwork")
|
||
|
|
spellBlock.overlay:SetTexture("Interface\\AddOns\\Details\\images\\overlay_detalhes")
|
||
|
|
spellBlock.overlay:SetPoint("topleft", spellBlock, "topleft", -8, 8)
|
||
|
|
spellBlock.overlay:SetPoint("bottomright", spellBlock, "bottomright", 26, -14)
|
||
|
|
Details.FadeHandler.Fader(spellBlock.overlay, 1) --hide
|
||
|
|
|
||
|
|
--report button, also only shown when the spell block is hovered over
|
||
|
|
spellBlock.reportButton = Details.gump:NewDetailsButton(spellBlock, nil, nil, Details.Reportar, Details.playerDetailWindow, 10 + index, 16, 16,
|
||
|
|
"Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", nil, "DetailsJanelaInfoReport1")
|
||
|
|
Details.FadeHandler.Fader(spellBlock.reportButton, 1) --hide
|
||
|
|
spellBlock.reportButton:SetScript("OnEnter", onEnterInfoReport)
|
||
|
|
spellBlock.reportButton:SetScript("OnLeave", onLeaveInfoReport)
|
||
|
|
|
||
|
|
--spark texture
|
||
|
|
spellBlock.sparkTexture = spellBlock:CreateTexture("$parentOverlaySparkTexture", "overlay")
|
||
|
|
spellBlock.sparkTexture:SetTexture("Interface\\AddOns\\Details\\images\\bar_detalhes2_end")
|
||
|
|
spellBlock.sparkTexture:SetBlendMode("ADD")
|
||
|
|
|
||
|
|
local gradientDown = DetailsFramework:CreateTexture(spellBlock, {gradient = "vertical", fromColor = {0, 0, 0, 0.1}, toColor = "transparent"}, 1, spellBlock:GetHeight(), "background", {0, 1, 0, 1})
|
||
|
|
gradientDown:SetPoint("bottoms")
|
||
|
|
spellBlock.gradientTexture = gradientDown
|
||
|
|
spellBlock.gradientTexture:Hide()
|
||
|
|
|
||
|
|
return spellBlock
|
||
|
|
end
|
||
|
|
|
||
|
|
local spellBlockContainerMixin = {
|
||
|
|
---refresh all the spellblocks in the container ~UpdateBlocks
|
||
|
|
---this function adjust the frame properties, does not update the data shown on them
|
||
|
|
---@param self breakdownspellblockframe
|
||
|
|
UpdateBlocks = function(self) --~update
|
||
|
|
---@type number, number
|
||
|
|
local width, height = Details.breakdown_spell_tab.blockcontainer_width, Details.breakdown_spell_tab.blockcontainer_height
|
||
|
|
local blockHeight = Details.breakdown_spell_tab.blockspell_height
|
||
|
|
local backgroundColor = Details.breakdown_spell_tab.blockspell_backgroundcolor
|
||
|
|
local borderColor = Details.breakdown_spell_tab.blockspell_bordercolor
|
||
|
|
local padding = Details.breakdown_spell_tab.blockspell_padding * -1
|
||
|
|
local color = Details.breakdown_spell_tab.blockspell_color
|
||
|
|
|
||
|
|
self:SetSize(width, height)
|
||
|
|
|
||
|
|
backgroundColor[1], backgroundColor[2], backgroundColor[3], backgroundColor[4] = 0.05, 0.05, 0.05, 0.2
|
||
|
|
color[1], color[2], color[3], color[4] = 0.6, 0.6, 0.6, 0.55
|
||
|
|
|
||
|
|
for i = 1, #self.SpellBlocks do
|
||
|
|
---@type breakdownspellblock
|
||
|
|
local spellBlock = self.SpellBlocks[i]
|
||
|
|
|
||
|
|
spellBlock:SetSize(width - 2, blockHeight)
|
||
|
|
spellBlock:SetPoint("topleft", self, "topleft", 1, (blockHeight * (i - 1) - i) * -1 - (i*2) + ((i-1) * padding))
|
||
|
|
spellBlock:SetPoint("topright", self, "topright", 1, (blockHeight * (i - 1) - i) * -1 - (i*2) + ((i-1) * padding))
|
||
|
|
|
||
|
|
spellBlock.sparkTexture:SetSize(Details.breakdown_spell_tab.blockspell_spark_width, blockHeight)
|
||
|
|
spellBlock.sparkTexture:SetShown(Details.breakdown_spell_tab.blockspell_spark_show)
|
||
|
|
spellBlock.sparkTexture:SetVertexColor(unpack(Details.breakdown_spell_tab.blockspell_spark_color))
|
||
|
|
spellBlock.reportButton:SetPoint("bottomright", spellBlock.overlay, "bottomright", -2, 2)
|
||
|
|
spellBlock.gradientTexture:SetHeight(blockHeight)
|
||
|
|
|
||
|
|
spellBlock:SetBackdropBorderColor(unpack(borderColor)) --border color
|
||
|
|
spellBlock.statusBarTexture:SetVertexColor(unpack(Details.breakdown_spell_tab.blockspell_color)) --bar color
|
||
|
|
|
||
|
|
local lineHeight = blockHeight * 0.2687
|
||
|
|
|
||
|
|
--update the lines
|
||
|
|
local previousLine
|
||
|
|
for o = 1, spellBlockContainerSettings.lineAmount do
|
||
|
|
---@type breakdownspellblockline
|
||
|
|
local line = spellBlock.Lines[o]
|
||
|
|
line:SetSize(width - 2, lineHeight)
|
||
|
|
if (previousLine) then
|
||
|
|
line:SetPoint("topleft", previousLine, "bottomleft", 0, -2)
|
||
|
|
else
|
||
|
|
line:SetPoint("topleft", spellBlock, "topleft", 1, -2)
|
||
|
|
end
|
||
|
|
previousLine = line
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end,
|
||
|
|
|
||
|
|
---@param self breakdownspellblockframe
|
||
|
|
ClearBlocks = function(self)
|
||
|
|
for i = 1, self:GetBlocksAmount() do
|
||
|
|
---@type breakdownspellblock
|
||
|
|
local spellBlock = self.SpellBlocks[i]
|
||
|
|
spellBlock:Hide()
|
||
|
|
|
||
|
|
spellBlock:SetColor(unpack(CONST_SPELLBLOCK_DEFAULT_COLOR))
|
||
|
|
|
||
|
|
--set the status bar value to zero
|
||
|
|
spellBlock:SetValue(0)
|
||
|
|
spellBlock.statusBarTexture:Show()
|
||
|
|
spellBlock.sparkTexture:Show()
|
||
|
|
|
||
|
|
--clear the text shown in their lines
|
||
|
|
for o = 1, 3 do
|
||
|
|
spellBlock.Lines[o].leftText:SetText("")
|
||
|
|
|
||
|
|
--set the color of the top left text in the block, the text is used as header text
|
||
|
|
if (o == 1) then
|
||
|
|
DF:SetFontColor(spellBlock.Lines[o].leftText, CONST_SPELLBLOCK_HEADERTEXT_COLOR)
|
||
|
|
DF:SetFontSize(spellBlock.Lines[o].leftText, CONST_SPELLBLOCK_HEADERTEXT_SIZE)
|
||
|
|
end
|
||
|
|
|
||
|
|
spellBlock.Lines[o].centerText:SetText("")
|
||
|
|
spellBlock.Lines[o].rightText:SetText("")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
for i = 1, math.min(self:GetBlocksAmount(), 4) do
|
||
|
|
self:ShowEmptyBlock(i)
|
||
|
|
end
|
||
|
|
|
||
|
|
self.blocksInUse = 0
|
||
|
|
end,
|
||
|
|
|
||
|
|
---show the empty block in the container, this is done to preview where the rectangle will be
|
||
|
|
---@param self breakdownspellblockframe
|
||
|
|
---@param index number
|
||
|
|
ShowEmptyBlock = function(self, index)
|
||
|
|
local spellBlock = self.SpellBlocks[index]
|
||
|
|
spellBlock:Show()
|
||
|
|
spellBlock:SetValue(0)
|
||
|
|
spellBlock.statusBarTexture:Hide()
|
||
|
|
spellBlock.sparkTexture:Hide()
|
||
|
|
end,
|
||
|
|
|
||
|
|
---get a breakdownspellblock from the container
|
||
|
|
---@param self breakdownspellblockframe
|
||
|
|
---@param index number
|
||
|
|
---@return breakdownspellblock
|
||
|
|
GetBlock = function(self, index)
|
||
|
|
self.blocksInUse = self.blocksInUse + 1
|
||
|
|
local spellBlock = self.SpellBlocks[index]
|
||
|
|
spellBlock.statusBarTexture:Show()
|
||
|
|
spellBlock.sparkTexture:Show()
|
||
|
|
return self.SpellBlocks[index]
|
||
|
|
end,
|
||
|
|
|
||
|
|
---get the amount of blocks in use
|
||
|
|
---@param self breakdownspellblockframe
|
||
|
|
---@return number
|
||
|
|
GetBlocksInUse = function(self)
|
||
|
|
return self.blocksInUse
|
||
|
|
end,
|
||
|
|
|
||
|
|
---get the total blocks created
|
||
|
|
---@param self breakdownspellblockframe
|
||
|
|
---@return number
|
||
|
|
GetBlocksAmount = function(self)
|
||
|
|
return #self.SpellBlocks
|
||
|
|
end,
|
||
|
|
}
|
||
|
|
|
||
|
|
---create the spell blocks which shows the critical hits, normal hits, etc
|
||
|
|
---@param tabFrame tabframe
|
||
|
|
---@return breakdownspellblockframe
|
||
|
|
function spellsTab.CreateSpellBlockContainer(tabFrame) --~create ~createblock ~spellblock ~block ~container
|
||
|
|
--create a container for the scrollframe
|
||
|
|
local options = {
|
||
|
|
width = Details.breakdown_spell_tab.blockcontainer_width,
|
||
|
|
height = Details.breakdown_spell_tab.blockcontainer_height,
|
||
|
|
is_locked = Details.breakdown_spell_tab.blockcontainer_islocked,
|
||
|
|
can_move = false,
|
||
|
|
can_move_children = false,
|
||
|
|
use_bottom_resizer = true,
|
||
|
|
use_right_resizer = true,
|
||
|
|
}
|
||
|
|
|
||
|
|
---@type df_framecontainer
|
||
|
|
local container = DF:CreateFrameContainer(tabFrame, options, tabFrame:GetName() .. "SpellScrollContainer")
|
||
|
|
container:SetPoint("topleft", spellsTab.GetSpellScrollContainer(), "topright", 26, 0)
|
||
|
|
container:SetFrameLevel(tabFrame:GetFrameLevel() + 10)
|
||
|
|
spellsTab.BlocksContainerFrame = container
|
||
|
|
|
||
|
|
local settingChangedCallbackFunction = function(frameContainer, settingName, settingValue)
|
||
|
|
if (frameContainer:IsShown()) then
|
||
|
|
if (settingName == "UpdateSize") then
|
||
|
|
--get the tabFrame width and height
|
||
|
|
local width, height = tabFrame:GetSize()
|
||
|
|
local containerWidth
|
||
|
|
|
||
|
|
--get with of the container holding the spellscrollframe
|
||
|
|
if (spellsTab.GetSpellScrollContainer():IsShown()) then
|
||
|
|
containerWidth = spellsTab.GetSpellScrollContainer():GetWidth()
|
||
|
|
|
||
|
|
elseif (spellsTab.GetGenericScrollContainer():IsShown()) then
|
||
|
|
containerWidth = spellsTab.GetGenericScrollContainer():GetWidth()
|
||
|
|
end
|
||
|
|
|
||
|
|
--calculate the widh of the spellblockcontainer by subtracting the width of the spellscrollframe container from the tabFrame width
|
||
|
|
local spellBlockContainerWidth = width - containerWidth - 38
|
||
|
|
--set the width of the spellblockcontainer
|
||
|
|
container:SetWidth(spellBlockContainerWidth)
|
||
|
|
|
||
|
|
elseif (settingName == "height") then
|
||
|
|
---@type number
|
||
|
|
local currentHeight = spellsTab.GetSpellScrollFrame():GetHeight()
|
||
|
|
Details.breakdown_spell_tab.blockcontainer_height = settingValue
|
||
|
|
spellsTab.GetSpellScrollFrame():SetNumFramesShown(math.floor(currentHeight / CONST_SPELLSCROLL_LINEHEIGHT) - 1)
|
||
|
|
|
||
|
|
elseif (settingName == "width") then
|
||
|
|
Details.breakdown_spell_tab.blockcontainer_width = settingValue
|
||
|
|
|
||
|
|
elseif (settingName == "is_locked") then
|
||
|
|
Details.breakdown_spell_tab.blockcontainer_islocked = settingValue
|
||
|
|
end
|
||
|
|
|
||
|
|
--update the spell blocks
|
||
|
|
spellsTab.GetSpellBlockFrame():UpdateBlocks()
|
||
|
|
|
||
|
|
if (spellsTab.GetSelectedSpellBar()) then
|
||
|
|
onEnterSpellBar(spellsTab.GetSelectedSpellBar())
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
container:SetSettingChangedCallback(settingChangedCallbackFunction)
|
||
|
|
|
||
|
|
--create the container which will hold the spell blocks
|
||
|
|
---@type breakdownspellblockframe
|
||
|
|
local spellBlockFrame = CreateFrame("Frame", "$parentSpellBlockContainer", container, "BackdropTemplate")
|
||
|
|
spellBlockFrame:EnableMouse(false)
|
||
|
|
spellBlockFrame:SetResizable(false)
|
||
|
|
spellBlockFrame:SetMovable(false)
|
||
|
|
spellBlockFrame:SetAllPoints()
|
||
|
|
DetailsFramework:Mixin(spellBlockFrame, spellBlockContainerMixin)
|
||
|
|
|
||
|
|
tabFrame.SpellBlockFrame = spellBlockFrame
|
||
|
|
spellsTab.SpellBlockFrame = spellBlockFrame
|
||
|
|
|
||
|
|
container:RegisterChildForDrag(spellBlockFrame)
|
||
|
|
|
||
|
|
spellBlockFrame.SpellBlocks = {}
|
||
|
|
spellBlockFrame.blocksInUse = 0
|
||
|
|
|
||
|
|
--create the spell blocks within the spellBlockFrame
|
||
|
|
for i = 1, spellBlockContainerSettings.amount do
|
||
|
|
---@type breakdownspellblock
|
||
|
|
local spellBlock = spellsTab.CreateSpellBlock(spellBlockFrame, i)
|
||
|
|
table.insert(spellBlockFrame.SpellBlocks, spellBlock)
|
||
|
|
--size and point are set on ~UpdateBlocks
|
||
|
|
end
|
||
|
|
|
||
|
|
spellBlockFrame:UpdateBlocks()
|
||
|
|
|
||
|
|
return spellBlockFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
function spellsTab.UpdateShownSpellBlock()
|
||
|
|
if (spellsTab.currentSpellBar) then
|
||
|
|
onEnterSpellBar(spellsTab.currentSpellBar)
|
||
|
|
|
||
|
|
elseif (spellsTab.GetSelectedSpellBar()) then
|
||
|
|
onEnterSpellBar(spellsTab.GetSelectedSpellBar())
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
---get a spell bar from the scroll box, if it doesn't exist, return nil
|
||
|
|
---@param scrollFrame table
|
||
|
|
---@param lineIndex number
|
||
|
|
---@return breakdowntargetbar
|
||
|
|
local getTargetBar = function(scrollFrame, lineIndex)
|
||
|
|
---@type breakdowntargetbar
|
||
|
|
local targetBar = scrollFrame:GetLine(lineIndex)
|
||
|
|
|
||
|
|
--reset header alignment
|
||
|
|
targetBar:ResetFramesToHeaderAlignment()
|
||
|
|
|
||
|
|
spellsTab.UpdateBarSettings(targetBar)
|
||
|
|
|
||
|
|
--reset columns, hiding them
|
||
|
|
targetBar.Icon:Hide()
|
||
|
|
for inLineIndex = 1, #targetBar.InLineTexts do
|
||
|
|
targetBar.InLineTexts[inLineIndex]:SetText("")
|
||
|
|
end
|
||
|
|
|
||
|
|
return targetBar
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
---update a line using the data passed
|
||
|
|
---@param targetBar breakdowntargetbar
|
||
|
|
---@param index number spell position (from best to wrost)
|
||
|
|
---@param combatObject combat
|
||
|
|
---@param scrollFrame table
|
||
|
|
---@param headerTable table
|
||
|
|
---@param bkTargetData breakdowntargettable
|
||
|
|
---@param totalValue number
|
||
|
|
---@param topValue number the amount done of the first target, used to calculate the length of the statusbar
|
||
|
|
---@param sortKey string
|
||
|
|
local updateTargetBar = function(targetBar, index, combatObject, scrollFrame, headerTable, bkTargetData, totalValue, topValue, sortKey) --~target ~update ~targetbar ~updatetargetbar
|
||
|
|
--scrollFrame is defined as a table which is false, scrollFrame is a frame
|
||
|
|
|
||
|
|
local textIndex = 1
|
||
|
|
|
||
|
|
for headerIndex = 1, #headerTable do
|
||
|
|
---@type number
|
||
|
|
local value
|
||
|
|
|
||
|
|
targetBar.bkTargetData = bkTargetData
|
||
|
|
value = bkTargetData.total
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local combatTime = combatObject:GetCombatTime()
|
||
|
|
|
||
|
|
local actorContainer = combatObject:GetContainer(spellsTab.mainAttribute)
|
||
|
|
local targetActorObject = actorContainer:GetActor(bkTargetData.name)
|
||
|
|
|
||
|
|
targetBar.statusBar.backgroundTexture:SetAlpha(Details.breakdown_spell_tab.spellbar_background_alpha)
|
||
|
|
|
||
|
|
--statusbar size by percent
|
||
|
|
if (topValue > 0) then
|
||
|
|
targetBar.statusBar:SetValue(bkTargetData[sortKey] / topValue * 100)
|
||
|
|
else
|
||
|
|
targetBar.statusBar:SetValue(0)
|
||
|
|
end
|
||
|
|
|
||
|
|
--statusbar color
|
||
|
|
targetBar.statusBar:SetStatusBarColor(1, 1, 1, 1)
|
||
|
|
targetBar.combatTime = combatTime
|
||
|
|
targetBar.actorName = bkTargetData.name
|
||
|
|
|
||
|
|
---@type fontstring
|
||
|
|
local text = targetBar.InLineTexts[textIndex]
|
||
|
|
local header = headerTable[headerIndex]
|
||
|
|
|
||
|
|
if (header.name == "icon") then --ok
|
||
|
|
targetBar.Icon:Show()
|
||
|
|
|
||
|
|
if (targetActorObject) then
|
||
|
|
Details.SetClassIcon(targetActorObject, targetBar.Icon, spellsTab.GetInstance(), targetActorObject:Class())
|
||
|
|
else
|
||
|
|
targetBar.Icon:SetTexture([[Interface\AddOns\Details\images\classes_small_alpha]])
|
||
|
|
---@type {key1: number, key2: number, key3: number, key4: number}
|
||
|
|
local texCoords = Details.class_coords["ENEMY"]
|
||
|
|
targetBar.Icon:SetTexCoord(unpack(texCoords))
|
||
|
|
end
|
||
|
|
|
||
|
|
targetBar:AddFrameToHeaderAlignment(targetBar.Icon)
|
||
|
|
|
||
|
|
elseif (header.name == "rank") then --ok
|
||
|
|
text:SetText(index)
|
||
|
|
targetBar:AddFrameToHeaderAlignment(text)
|
||
|
|
targetBar.rank = index
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "name") then --ok
|
||
|
|
text:SetText(DF:RemoveRealmName(bkTargetData.name))
|
||
|
|
targetBar.name = bkTargetData.name
|
||
|
|
targetBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "amount") then --ok
|
||
|
|
text:SetText(Details:Format(value))
|
||
|
|
targetBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "percent") then --ok
|
||
|
|
targetBar.percent = value / totalValue * 100 --totalValue is nil
|
||
|
|
---@type string
|
||
|
|
local percentFormatted = string.format("%.1f", targetBar.percent) .. "%"
|
||
|
|
text:SetText(percentFormatted)
|
||
|
|
|
||
|
|
targetBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "overheal" and bkTargetData.overheal) then
|
||
|
|
if (bkTargetData.overheal > 0) then
|
||
|
|
local totalHeal = bkTargetData.overheal + value
|
||
|
|
text:SetText(string.format("%.1f", bkTargetData.overheal / totalHeal * 100) .. "%")
|
||
|
|
else
|
||
|
|
text:SetText("0%")
|
||
|
|
end
|
||
|
|
targetBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "absorbed") then
|
||
|
|
text:SetText(Details:Format(bkTargetData.absorbed or 0))
|
||
|
|
targetBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
targetBar:AlignWithHeader(scrollFrame.Header, "left")
|
||
|
|
end
|
||
|
|
|
||
|
|
---refresh the data shown in the spells scroll box
|
||
|
|
---@param scrollFrame table
|
||
|
|
---@param scrollData breakdowntargettablelist
|
||
|
|
---@param offset number
|
||
|
|
---@param totalLines number
|
||
|
|
local refreshTargetsFunc = function(scrollFrame, scrollData, offset, totalLines) --~refresh ~target ~refreshtargets
|
||
|
|
---@type number
|
||
|
|
local topValue = scrollFrame.topValue
|
||
|
|
---@type number
|
||
|
|
local totalValue = scrollData.totalValue
|
||
|
|
---@type actor
|
||
|
|
local actorObject = spellsTab.GetActor()
|
||
|
|
---@type string
|
||
|
|
local actorName = actorObject:Name()
|
||
|
|
---@type combat
|
||
|
|
local combatObject = spellsTab.GetCombat()
|
||
|
|
---@type instance
|
||
|
|
local instanceObject = spellsTab.GetInstance()
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local mainAttribute = spellsTab.mainAttribute
|
||
|
|
|
||
|
|
local sortKey = scrollFrame.SortKey
|
||
|
|
local headerTable = spellsTab.targetsHeaderData
|
||
|
|
|
||
|
|
local lineIndex = 1
|
||
|
|
|
||
|
|
for i = 1, totalLines do
|
||
|
|
local index = i + offset
|
||
|
|
|
||
|
|
---@type breakdowntargettable
|
||
|
|
local bkTargetData = scrollData[index]
|
||
|
|
if (bkTargetData) then
|
||
|
|
---called mainSpellBar because it is the line that shows the sum of all spells merged (if any)
|
||
|
|
---@type breakdowntargetbar
|
||
|
|
local targetBar = getTargetBar(scrollFrame, lineIndex)
|
||
|
|
do
|
||
|
|
if (targetBar) then
|
||
|
|
lineIndex = lineIndex + 1
|
||
|
|
updateTargetBar(targetBar, index, combatObject, scrollFrame, headerTable, bkTargetData, totalValue, topValue, sortKey)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (lineIndex > totalLines) then
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
---create a targetbar within the target scroll
|
||
|
|
---@param self breakdownphasescrollframe
|
||
|
|
---@param index number
|
||
|
|
---@return breakdownphasebar
|
||
|
|
function spellsTab.CreatePhaseBar(self, index) --~create ~createphase ~phasebar
|
||
|
|
---@type breakdownphasebar
|
||
|
|
local phaseBar = CreateFrame("button", self:GetName() .. "PhaseBarButton" .. index, self)
|
||
|
|
phaseBar.index = index
|
||
|
|
|
||
|
|
--size and positioning
|
||
|
|
phaseBar:SetHeight(CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
local y = (index-1) * CONST_SPELLSCROLL_LINEHEIGHT * -1 + (1 * -index) - 15
|
||
|
|
phaseBar:SetPoint("topleft", self, "topleft", 1, y)
|
||
|
|
phaseBar:SetPoint("topright", self, "topright", -1, y)
|
||
|
|
|
||
|
|
phaseBar:EnableMouse(true)
|
||
|
|
|
||
|
|
phaseBar:SetAlpha(0.823)
|
||
|
|
phaseBar:SetFrameStrata("HIGH")
|
||
|
|
phaseBar:SetScript("OnEnter", nil)
|
||
|
|
phaseBar:SetScript("OnLeave", nil)
|
||
|
|
|
||
|
|
DF:Mixin(phaseBar, DF.HeaderFunctions)
|
||
|
|
|
||
|
|
---@type breakdownspellbarstatusbar
|
||
|
|
local statusBar = CreateFrame("StatusBar", "$parentStatusBar", phaseBar)
|
||
|
|
statusBar:SetAllPoints()
|
||
|
|
statusBar:SetAlpha(0.5)
|
||
|
|
statusBar:SetMinMaxValues(0, 100)
|
||
|
|
statusBar:SetValue(50)
|
||
|
|
statusBar:EnableMouse(false)
|
||
|
|
statusBar:SetFrameLevel(phaseBar:GetFrameLevel() - 1)
|
||
|
|
phaseBar.statusBar = statusBar
|
||
|
|
|
||
|
|
---@type texture this is the statusbar texture
|
||
|
|
local statusBarTexture = statusBar:CreateTexture("$parentTexture", "artwork")
|
||
|
|
statusBarTexture:SetTexture(SharedMedia:Fetch("statusbar", "Details Hyanda"))
|
||
|
|
statusBar:SetStatusBarTexture(statusBarTexture)
|
||
|
|
statusBar:SetStatusBarColor(1, 1, 1, 1)
|
||
|
|
|
||
|
|
---@type texture shown when the mouse hoverover this bar
|
||
|
|
local hightlightTexture = statusBar:CreateTexture("$parentTextureHighlight", "highlight")
|
||
|
|
hightlightTexture:SetColorTexture(1, 1, 1, 0.2)
|
||
|
|
hightlightTexture:SetAllPoints()
|
||
|
|
statusBar.highlightTexture = hightlightTexture
|
||
|
|
|
||
|
|
---@type texture background texture
|
||
|
|
local backgroundTexture = statusBar:CreateTexture("$parentTextureBackground", "border")
|
||
|
|
backgroundTexture:SetAllPoints()
|
||
|
|
backgroundTexture:SetColorTexture(.05, .05, .05)
|
||
|
|
backgroundTexture:SetAlpha(1)
|
||
|
|
statusBar.backgroundTexture = backgroundTexture
|
||
|
|
|
||
|
|
--create an icon
|
||
|
|
---@type texture
|
||
|
|
local icon = statusBar:CreateTexture("$parentTexture", "overlay")
|
||
|
|
icon:SetPoint("left", statusBar, "left", 0, 0)
|
||
|
|
icon:SetSize(CONST_SPELLSCROLL_LINEHEIGHT-2, CONST_SPELLSCROLL_LINEHEIGHT-2)
|
||
|
|
icon:SetTexCoord(.1, .9, .1, .9)
|
||
|
|
phaseBar.Icon = icon
|
||
|
|
|
||
|
|
phaseBar:AddFrameToHeaderAlignment(icon)
|
||
|
|
|
||
|
|
phaseBar.InLineTexts = {}
|
||
|
|
|
||
|
|
for i = 1, 5 do
|
||
|
|
---@type fontstring
|
||
|
|
local fontString = phaseBar:CreateFontString("$parentFontString" .. i, "overlay", "GameFontHighlightSmall")
|
||
|
|
fontString:SetJustifyH("left")
|
||
|
|
fontString:SetTextColor(1, 1, 1, 1)
|
||
|
|
fontString:SetNonSpaceWrap(true)
|
||
|
|
fontString:SetWordWrap(false)
|
||
|
|
phaseBar["lineText" .. i] = fontString
|
||
|
|
phaseBar.InLineTexts[i] = fontString
|
||
|
|
fontString:SetTextColor(1, 1, 1, 1)
|
||
|
|
phaseBar:AddFrameToHeaderAlignment(fontString)
|
||
|
|
end
|
||
|
|
|
||
|
|
phaseBar:AlignWithHeader(self.Header, "left")
|
||
|
|
|
||
|
|
return phaseBar
|
||
|
|
end
|
||
|
|
|
||
|
|
---get a spell bar from the scroll box, if it doesn't exist, return nil
|
||
|
|
---@param scrollFrame table
|
||
|
|
---@param lineIndex number
|
||
|
|
---@return breakdownphasebar
|
||
|
|
local getGenericBar = function(scrollFrame, lineIndex)
|
||
|
|
---@type breakdowngenericbar
|
||
|
|
local genericBar = scrollFrame:GetLine(lineIndex)
|
||
|
|
|
||
|
|
--reset header alignment
|
||
|
|
genericBar:ResetFramesToHeaderAlignment()
|
||
|
|
|
||
|
|
--reset columns, hiding them
|
||
|
|
genericBar.Icon:Hide()
|
||
|
|
for inLineIndex = 1, #genericBar.InLineTexts do
|
||
|
|
genericBar.InLineTexts[inLineIndex]:SetText("")
|
||
|
|
end
|
||
|
|
|
||
|
|
return genericBar
|
||
|
|
end
|
||
|
|
|
||
|
|
---get a spell bar from the scroll box, if it doesn't exist, return nil
|
||
|
|
---@param scrollFrame table
|
||
|
|
---@param lineIndex number
|
||
|
|
---@return breakdownphasebar
|
||
|
|
local getPhaseBar = function(scrollFrame, lineIndex)
|
||
|
|
---@type breakdownphasebar
|
||
|
|
local phaseBar = scrollFrame:GetLine(lineIndex)
|
||
|
|
|
||
|
|
--reset header alignment
|
||
|
|
phaseBar:ResetFramesToHeaderAlignment()
|
||
|
|
|
||
|
|
spellsTab.UpdateBarSettings(phaseBar)
|
||
|
|
|
||
|
|
--reset columns, hiding them
|
||
|
|
phaseBar.Icon:Hide()
|
||
|
|
for inLineIndex = 1, #phaseBar.InLineTexts do
|
||
|
|
phaseBar.InLineTexts[inLineIndex]:SetText("")
|
||
|
|
end
|
||
|
|
|
||
|
|
return phaseBar
|
||
|
|
end
|
||
|
|
|
||
|
|
---@param scrollFrame table
|
||
|
|
---@param scrollData table
|
||
|
|
---@param offset number
|
||
|
|
---@param totalLines number
|
||
|
|
local refreshGenericFunc = function(scrollFrame, scrollData, offset, totalLines) --~refreshgeneric ~refreshfunc ~refresh ~refreshg ~updategenericbar
|
||
|
|
local lineIndex = 1
|
||
|
|
local combatTime = scrollData.combatTime
|
||
|
|
local totalValue = scrollData.totalValue
|
||
|
|
|
||
|
|
for i = 1, totalLines do
|
||
|
|
local index = i + offset
|
||
|
|
local dataTable = scrollData[index]
|
||
|
|
|
||
|
|
if (dataTable) then
|
||
|
|
local genericBar = getGenericBar(scrollFrame, lineIndex)
|
||
|
|
genericBar.statusBar:SetValue(dataTable.total / scrollFrame.topValue * 100)
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local textIndex = 1
|
||
|
|
|
||
|
|
if (scrollData.headersAllowed.icon) then
|
||
|
|
---@type texturetable
|
||
|
|
local dataIcon = dataTable.icon
|
||
|
|
genericBar.Icon:Show()
|
||
|
|
genericBar.Icon:SetTexture(dataIcon.texture)
|
||
|
|
genericBar.Icon:SetTexCoord(dataIcon.coords.left, dataIcon.coords.right, dataIcon.coords.top, dataIcon.coords.bottom)
|
||
|
|
genericBar.Icon:SetSize(CONST_SPELLSCROLL_LINEHEIGHT-2, CONST_SPELLSCROLL_LINEHEIGHT-2)
|
||
|
|
genericBar:AddFrameToHeaderAlignment(genericBar.Icon)
|
||
|
|
end
|
||
|
|
|
||
|
|
if (scrollData.headersAllowed.name) then
|
||
|
|
---@type fontstring
|
||
|
|
local fontString = genericBar.InLineTexts[textIndex]
|
||
|
|
genericBar:AddFrameToHeaderAlignment(fontString)
|
||
|
|
local nameWithoutRealm = DF:RemoveRealmName(dataTable.name)
|
||
|
|
fontString:SetText(nameWithoutRealm or dataTable.name)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
if (scrollData.headersAllowed.rank) then
|
||
|
|
---@type fontstring
|
||
|
|
local fontString = genericBar.InLineTexts[textIndex]
|
||
|
|
genericBar:AddFrameToHeaderAlignment(fontString)
|
||
|
|
fontString:SetText(index)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
if (scrollData.headersAllowed.amount) then
|
||
|
|
---@type fontstring
|
||
|
|
local fontString = genericBar.InLineTexts[textIndex]
|
||
|
|
genericBar:AddFrameToHeaderAlignment(fontString)
|
||
|
|
fontString:SetText(Details:Format(dataTable.total))
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
if (scrollData.headersAllowed.persecond) then
|
||
|
|
---@type fontstring
|
||
|
|
local fontString = genericBar.InLineTexts[textIndex]
|
||
|
|
genericBar:AddFrameToHeaderAlignment(fontString)
|
||
|
|
fontString:SetText(Details:Format(dataTable.total / combatTime))
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
if (scrollData.headersAllowed.percent) then
|
||
|
|
---@type fontstring
|
||
|
|
local fontString = genericBar.InLineTexts[textIndex]
|
||
|
|
genericBar:AddFrameToHeaderAlignment(fontString)
|
||
|
|
fontString:SetText(string.format("%.1f", dataTable.total / totalValue * 100) .. "%")
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
lineIndex = lineIndex + 1
|
||
|
|
if (lineIndex > totalLines) then
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
---@param scrollFrame table
|
||
|
|
---@param scrollData table
|
||
|
|
---@param offset number
|
||
|
|
---@param totalLines number
|
||
|
|
local refreshPhaseFunc = function(scrollFrame, scrollData, offset, totalLines) --~refreshphases ~refreshfunc ~refresh ~refreshp ~updatephasebar
|
||
|
|
local lineIndex = 1
|
||
|
|
local formatFunc = Details:GetCurrentToKFunction()
|
||
|
|
local phaseElapsedTime = scrollData.phaseElapsed
|
||
|
|
|
||
|
|
for i = 1, totalLines do
|
||
|
|
local index = i + offset
|
||
|
|
local dataTable = scrollData[index]
|
||
|
|
|
||
|
|
if (dataTable) then
|
||
|
|
local phaseBar = getPhaseBar(scrollFrame, lineIndex)
|
||
|
|
|
||
|
|
phaseBar.statusBar:SetValue(100)
|
||
|
|
|
||
|
|
local totalDone = dataTable.amountDone
|
||
|
|
local phaseName = dataTable.phaseName
|
||
|
|
local phaseNameFormatted = "Phase: " .. phaseName
|
||
|
|
local amountDoneFormatted = formatFunc(nil, totalDone)
|
||
|
|
local positionWithInPhase = math.floor(dataTable.positionWithInPhase)
|
||
|
|
local percentDone = string.format("%.1f", dataTable.percentDone)
|
||
|
|
|
||
|
|
local elapsedTime = phaseElapsedTime[phaseName]
|
||
|
|
local phaseDps = formatFunc(nil, totalDone / elapsedTime)
|
||
|
|
|
||
|
|
phaseBar.Icon:Show()
|
||
|
|
phaseBar.Icon:SetTexture([[Interface\Garrison\orderhall-missions-mechanic9]])
|
||
|
|
phaseBar.Icon:SetTexCoord(11/64, 53/64, 11/64, 53/64)
|
||
|
|
phaseBar.Icon:SetSize(CONST_SPELLSCROLL_LINEHEIGHT-2, CONST_SPELLSCROLL_LINEHEIGHT-2)
|
||
|
|
phaseBar:AddFrameToHeaderAlignment(phaseBar.Icon)
|
||
|
|
|
||
|
|
for inLineIndex = 1, #phaseBar.InLineTexts do
|
||
|
|
phaseBar.InLineTexts[inLineIndex]:SetText("")
|
||
|
|
end
|
||
|
|
|
||
|
|
local text1 = phaseBar.InLineTexts[1]
|
||
|
|
phaseBar:AddFrameToHeaderAlignment(text1)
|
||
|
|
text1:SetText(phaseNameFormatted)
|
||
|
|
|
||
|
|
local text2 = phaseBar.InLineTexts[2]
|
||
|
|
phaseBar:AddFrameToHeaderAlignment(text2)
|
||
|
|
text2:SetText("#" .. positionWithInPhase)
|
||
|
|
|
||
|
|
local text3 = phaseBar.InLineTexts[3]
|
||
|
|
phaseBar:AddFrameToHeaderAlignment(text3)
|
||
|
|
text3:SetText(amountDoneFormatted)
|
||
|
|
|
||
|
|
local text4 = phaseBar.InLineTexts[4]
|
||
|
|
phaseBar:AddFrameToHeaderAlignment(text4)
|
||
|
|
text4:SetText(phaseDps)
|
||
|
|
|
||
|
|
local text5 = phaseBar.InLineTexts[5]
|
||
|
|
phaseBar:AddFrameToHeaderAlignment(text5)
|
||
|
|
text5:SetText(percentDone .. "%")
|
||
|
|
|
||
|
|
lineIndex = lineIndex + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
---create a container to show value per phase
|
||
|
|
---@param tabFrame tabframe
|
||
|
|
---@return breakdowntargetscrollframe
|
||
|
|
function spellsTab.CreatePhasesContainer(tabFrame) --~phase ~createphasecontainer ~createphasescroll
|
||
|
|
---@type width
|
||
|
|
local width = Details.breakdown_spell_tab.phasecontainer_width
|
||
|
|
---@type height
|
||
|
|
local height = Details.breakdown_spell_tab.phasecontainer_height
|
||
|
|
|
||
|
|
local defaultAmountOfLines = 10
|
||
|
|
|
||
|
|
--create a container for the scrollframe
|
||
|
|
local options = {
|
||
|
|
width = Details.breakdown_spell_tab.phasecontainer_width,
|
||
|
|
height = Details.breakdown_spell_tab.phasecontainer_height,
|
||
|
|
is_locked = Details.breakdown_spell_tab.phasecontainer_islocked,
|
||
|
|
can_move = false,
|
||
|
|
can_move_children = false,
|
||
|
|
use_top_resizer = true,
|
||
|
|
use_right_resizer = true,
|
||
|
|
use_left_resizer = true,
|
||
|
|
use_bottom_resizer = true,
|
||
|
|
}
|
||
|
|
|
||
|
|
---@type df_framecontainer
|
||
|
|
local container = DF:CreateFrameContainer(tabFrame, options, tabFrame:GetName() .. "PhaseScrollContainer")
|
||
|
|
container:SetPoint("topleft", spellsTab.GetTargetScrollContainer(), "topright", 26, 0)
|
||
|
|
container:SetFrameLevel(tabFrame:GetFrameLevel() + 10)
|
||
|
|
spellsTab.PhaseContainerFrame = container
|
||
|
|
|
||
|
|
local settingChangedCallbackFunction = function(frameContainer, settingName, settingValue)
|
||
|
|
if (frameContainer:IsShown()) then
|
||
|
|
if (settingName == "height") then
|
||
|
|
---@type number
|
||
|
|
local currentHeight = spellsTab.GetPhaseScrollFrame():GetHeight()
|
||
|
|
Details.breakdown_spell_tab.phasecontainer_height = settingValue
|
||
|
|
local lineAmount = math.floor(currentHeight / CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
spellsTab.GetPhaseScrollFrame():SetNumFramesShown(lineAmount)
|
||
|
|
|
||
|
|
elseif (settingName == "width") then
|
||
|
|
Details.breakdown_spell_tab.phasecontainer_width = settingValue
|
||
|
|
|
||
|
|
elseif (settingName == "is_locked") then
|
||
|
|
Details.breakdown_spell_tab.phasecontainer_islocked = settingValue
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
container:SetSettingChangedCallback(settingChangedCallbackFunction)
|
||
|
|
|
||
|
|
---@type breakdowntargetscrollframe not sure is this is correct
|
||
|
|
local phaseScrollFrame = DF:CreateScrollBox(container, "$parentPhaseScroll", refreshPhaseFunc, {}, width, height, defaultAmountOfLines, CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
DF:ReskinSlider(phaseScrollFrame)
|
||
|
|
|
||
|
|
phaseScrollFrame:SetBackdrop({})
|
||
|
|
phaseScrollFrame:SetAllPoints()
|
||
|
|
|
||
|
|
container:RegisterChildForDrag(phaseScrollFrame)
|
||
|
|
|
||
|
|
phaseScrollFrame.DontHideChildrenOnPreRefresh = false
|
||
|
|
tabFrame.PhaseScrollFrame = phaseScrollFrame
|
||
|
|
spellsTab.PhaseScrollFrame = phaseScrollFrame
|
||
|
|
|
||
|
|
spellsTab.ApplyStandardBackdrop(container, phaseScrollFrame)
|
||
|
|
|
||
|
|
function phaseScrollFrame:RefreshMe() --~refreshme (phases) ~refreshmep
|
||
|
|
--get the value of the top 1 ranking spell
|
||
|
|
---@type actor
|
||
|
|
local actorObject = spellsTab.GetActor()
|
||
|
|
---@type combat
|
||
|
|
local combatObject = spellsTab.GetCombat()
|
||
|
|
local actorName = actorObject:Name()
|
||
|
|
---@type instance
|
||
|
|
local instanceObject = spellsTab.GetInstance()
|
||
|
|
|
||
|
|
local mainAttribute = instanceObject:GetDisplay()
|
||
|
|
|
||
|
|
local data = {
|
||
|
|
--playerObject = playerObject,
|
||
|
|
--attribute = attribute,
|
||
|
|
--combatObject = combatObject,
|
||
|
|
combatTime = combatObject:GetCombatTime(),
|
||
|
|
}
|
||
|
|
|
||
|
|
local playerPhases = {}
|
||
|
|
local totalDamage = 0
|
||
|
|
local phaseElapsed = {}
|
||
|
|
|
||
|
|
local phasesInfo = combatObject:GetPhases()
|
||
|
|
|
||
|
|
if (not phasesInfo) then
|
||
|
|
spellsTab.PhaseContainerFrame:Hide()
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if (#phasesInfo == 1) then
|
||
|
|
--if there's only one phase, then there's no need to show phases
|
||
|
|
spellsTab.PhaseContainerFrame:Hide()
|
||
|
|
return
|
||
|
|
else
|
||
|
|
spellsTab.PhaseContainerFrame:Show()
|
||
|
|
end
|
||
|
|
|
||
|
|
if (#phasesInfo >= 1) then
|
||
|
|
--get phase elapsed time
|
||
|
|
for i = 1, #phasesInfo do
|
||
|
|
local thisPhase = phasesInfo[i]
|
||
|
|
local phaseName = thisPhase[1]
|
||
|
|
local startTime = thisPhase[2]
|
||
|
|
|
||
|
|
local nextPhase = phasesInfo[i + 1]
|
||
|
|
if (nextPhase) then
|
||
|
|
--if there's a next phase, use it's start time as end time to calcule elapsed time
|
||
|
|
local endTime = nextPhase[2]
|
||
|
|
local elapsedTime = endTime - startTime
|
||
|
|
phaseElapsed[phaseName] = (phaseElapsed[phaseName] or 0) + elapsedTime
|
||
|
|
else
|
||
|
|
--if there's no next phase, use the combat end time as end time to calcule elapsed time
|
||
|
|
local endTime = combatObject:GetCombatTime()
|
||
|
|
local elapsedTime = endTime - startTime
|
||
|
|
phaseElapsed[phaseName] = (phaseElapsed[phaseName] or 0) + elapsedTime
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--get damage info
|
||
|
|
local dataTable = mainAttribute == 1 and phasesInfo.damage or phasesInfo.heal
|
||
|
|
for phaseName, playersTable in pairs(dataTable) do --each phase
|
||
|
|
local allPlayers = {} --all players for this phase
|
||
|
|
for playerName, amount in pairs(playersTable) do
|
||
|
|
tinsert(allPlayers, {playerName, amount})
|
||
|
|
totalDamage = totalDamage + amount
|
||
|
|
end
|
||
|
|
table.sort(allPlayers, function(a, b)
|
||
|
|
return a[2] > b[2]
|
||
|
|
end)
|
||
|
|
|
||
|
|
local myRank = 0
|
||
|
|
for i = 1, #allPlayers do
|
||
|
|
if (allPlayers[i][1] == actorName) then
|
||
|
|
myRank = i
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
tinsert(playerPhases, {phaseName, playersTable[actorName] or 0, myRank, (playersTable[actorName] or 0) / totalDamage * 100})
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
table.sort(playerPhases, function(a, b) return a[1] < b[1] end)
|
||
|
|
|
||
|
|
for i = 1, #playerPhases do
|
||
|
|
data[#data+1] = {
|
||
|
|
phaseName = playerPhases[i][1],
|
||
|
|
amountDone = playerPhases[i][2],
|
||
|
|
positionWithInPhase = playerPhases[i][3],
|
||
|
|
percentDone = playerPhases[i][4],
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
data.totalDamage = totalDamage
|
||
|
|
data.phaseElapsed = phaseElapsed
|
||
|
|
|
||
|
|
phaseScrollFrame:SetData(data)
|
||
|
|
phaseScrollFrame:Refresh()
|
||
|
|
end
|
||
|
|
|
||
|
|
--~header
|
||
|
|
local headerOptions = {
|
||
|
|
padding = 2,
|
||
|
|
header_height = 14,
|
||
|
|
|
||
|
|
reziser_shown = true,
|
||
|
|
reziser_width = 2,
|
||
|
|
reziser_color = {.5, .5, .5, 0.7},
|
||
|
|
reziser_max_width = 246,
|
||
|
|
|
||
|
|
header_click_callback = onAnyColumnHeaderClickCallback,
|
||
|
|
|
||
|
|
header_backdrop_color = {0.1, 0.1, 0.1, 0.4},
|
||
|
|
text_color = {1, 1, 1, 0.823},
|
||
|
|
}
|
||
|
|
|
||
|
|
---@type df_headerframe
|
||
|
|
local header = DetailsFramework:CreateHeader(container, phaseContainerColumnData, headerOptions)
|
||
|
|
phaseScrollFrame.Header = header
|
||
|
|
phaseScrollFrame.Header:SetPoint("topleft", phaseScrollFrame, "topleft", 0, 1)
|
||
|
|
phaseScrollFrame.Header:SetColumnSettingChangedCallback(onHeaderColumnOptionChanged)
|
||
|
|
|
||
|
|
--cache the type of this container
|
||
|
|
headerContainerType[phaseScrollFrame.Header] = "phases"
|
||
|
|
|
||
|
|
--create the scroll lines
|
||
|
|
for i = 1, defaultAmountOfLines do
|
||
|
|
phaseScrollFrame:CreateLine(spellsTab.CreatePhaseBar)
|
||
|
|
end
|
||
|
|
|
||
|
|
tabFrame.phases = container:CreateFontString(nil, "overlay", "QuestFont_Large")
|
||
|
|
tabFrame.phases:SetPoint("bottomleft", container, "topleft", 2, 2)
|
||
|
|
tabFrame.phases:SetText("Phases:") --localize-me
|
||
|
|
|
||
|
|
return phaseScrollFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---create a genericbar within the generic scroll
|
||
|
|
---@param self breakdowngenericscrollframe
|
||
|
|
---@param index number
|
||
|
|
---@return breakdowngenericbar
|
||
|
|
function spellsTab.CreateGenericBar(self, index) --~create ~generic ~creategeneric ~genericbar
|
||
|
|
---@type breakdowngenericbar
|
||
|
|
local genericBar = CreateFrame("button", self:GetName() .. "GenericBarButton" .. index, self)
|
||
|
|
genericBar.index = index
|
||
|
|
|
||
|
|
--size and positioning
|
||
|
|
genericBar:SetHeight(CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
local y = (index-1) * CONST_SPELLSCROLL_LINEHEIGHT * -1 + (1 * -index) - 15
|
||
|
|
genericBar:SetPoint("topleft", self, "topleft", 0, y)
|
||
|
|
genericBar:SetPoint("topright", self, "topright", 0, y)
|
||
|
|
|
||
|
|
genericBar:EnableMouse(true)
|
||
|
|
|
||
|
|
genericBar:SetAlpha(0.9)
|
||
|
|
genericBar:SetFrameStrata("HIGH")
|
||
|
|
genericBar:SetScript("OnEnter", onEnterBreakdownGenericBar)
|
||
|
|
genericBar:SetScript("OnLeave", onLeaveBreakdownGenericBar)
|
||
|
|
|
||
|
|
DF:Mixin(genericBar, DF.HeaderFunctions)
|
||
|
|
|
||
|
|
---@type breakdownspellbarstatusbar
|
||
|
|
local statusBar = CreateFrame("StatusBar", "$parentStatusBar", genericBar)
|
||
|
|
statusBar:SetAllPoints()
|
||
|
|
statusBar:SetAlpha(0.5)
|
||
|
|
statusBar:SetMinMaxValues(0, 100)
|
||
|
|
statusBar:SetValue(50)
|
||
|
|
statusBar:EnableMouse(false)
|
||
|
|
statusBar:SetFrameLevel(genericBar:GetFrameLevel() - 1)
|
||
|
|
genericBar.statusBar = statusBar
|
||
|
|
|
||
|
|
---@type texture this is the statusbar texture
|
||
|
|
local statusBarTexture = statusBar:CreateTexture("$parentTexture", "artwork")
|
||
|
|
statusBarTexture:SetTexture(SharedMedia:Fetch("statusbar", "Details Hyanda"))
|
||
|
|
statusBar:SetStatusBarTexture(statusBarTexture)
|
||
|
|
statusBar:SetStatusBarColor(1, 1, 1, 1)
|
||
|
|
|
||
|
|
---@type texture shown when the mouse hoverover this bar
|
||
|
|
local hightlightTexture = statusBar:CreateTexture("$parentTextureHighlight", "highlight")
|
||
|
|
hightlightTexture:SetColorTexture(1, 1, 1, 0.2)
|
||
|
|
hightlightTexture:SetAllPoints()
|
||
|
|
statusBar.highlightTexture = hightlightTexture
|
||
|
|
|
||
|
|
---@type texture background texture
|
||
|
|
local backgroundTexture = statusBar:CreateTexture("$parentTextureBackground", "border")
|
||
|
|
backgroundTexture:SetAllPoints()
|
||
|
|
backgroundTexture:SetColorTexture(.05, .05, .05)
|
||
|
|
backgroundTexture:SetAlpha(1)
|
||
|
|
statusBar.backgroundTexture = backgroundTexture
|
||
|
|
|
||
|
|
--create an icon
|
||
|
|
---@type texture
|
||
|
|
local icon = statusBar:CreateTexture("$parentTexture", "overlay")
|
||
|
|
icon:SetPoint("left", statusBar, "left", 0, 0)
|
||
|
|
icon:SetSize(CONST_SPELLSCROLL_LINEHEIGHT-2, CONST_SPELLSCROLL_LINEHEIGHT-2)
|
||
|
|
icon:SetTexCoord(.1, .9, .1, .9)
|
||
|
|
genericBar.Icon = icon
|
||
|
|
|
||
|
|
genericBar:AddFrameToHeaderAlignment(icon)
|
||
|
|
|
||
|
|
genericBar.InLineTexts = {}
|
||
|
|
|
||
|
|
for i = 1, 5 do
|
||
|
|
---@type fontstring
|
||
|
|
local fontString = genericBar:CreateFontString("$parentFontString" .. i, "overlay", "GameFontHighlightSmall")
|
||
|
|
fontString:SetJustifyH("left")
|
||
|
|
fontString:SetTextColor(1, 1, 1, 1)
|
||
|
|
fontString:SetNonSpaceWrap(true)
|
||
|
|
fontString:SetWordWrap(false)
|
||
|
|
genericBar["lineText" .. i] = fontString
|
||
|
|
genericBar.InLineTexts[i] = fontString
|
||
|
|
fontString:SetTextColor(1, 1, 1, 1)
|
||
|
|
genericBar:AddFrameToHeaderAlignment(fontString)
|
||
|
|
end
|
||
|
|
|
||
|
|
genericBar:AlignWithHeader(self.Header, "left")
|
||
|
|
|
||
|
|
return genericBar
|
||
|
|
end
|
||
|
|
|
||
|
|
---create the generic container, this container hold bars that can show any type of data
|
||
|
|
---@param tabFrame tabframe
|
||
|
|
---@return breakdowngenericscrollframe
|
||
|
|
function spellsTab.CreateGenericContainer(tabFrame) --~create ~generic ~creategenericcontainer ~creategenericscroll ~creategeneric
|
||
|
|
---@type width
|
||
|
|
local width = Details.breakdown_spell_tab.genericcontainer_width
|
||
|
|
---@type height
|
||
|
|
local height = Details.breakdown_spell_tab.genericcontainer_height
|
||
|
|
|
||
|
|
local defaultAmountOfLines = 50
|
||
|
|
|
||
|
|
--create a container for the scrollframe
|
||
|
|
local options = {
|
||
|
|
width = Details.breakdown_spell_tab.genericcontainer_width,
|
||
|
|
height = Details.breakdown_spell_tab.genericcontainer_height,
|
||
|
|
is_locked = Details.breakdown_spell_tab.genericcontainer_islocked,
|
||
|
|
can_move = false,
|
||
|
|
can_move_children = false,
|
||
|
|
use_top_resizer = true,
|
||
|
|
use_right_resizer = true,
|
||
|
|
use_bottom_resizer = true,
|
||
|
|
use_left_resizer = true,
|
||
|
|
}
|
||
|
|
|
||
|
|
---@type df_framecontainer
|
||
|
|
local container = DF:CreateFrameContainer(tabFrame, options, tabFrame:GetName() .. "GenericScrollContainer")
|
||
|
|
container:SetPoint("topleft", tabFrame, "topleft", 0, 0)
|
||
|
|
container:SetFrameLevel(tabFrame:GetFrameLevel()+1)
|
||
|
|
spellsTab.GenericContainerFrame = container
|
||
|
|
|
||
|
|
--when a setting is changed in the container, it will call this function, it is registered below with SetSettingChangedCallback()
|
||
|
|
local settingChangedCallbackFunction = function(frameContainer, settingName, settingValue)
|
||
|
|
if (frameContainer:IsShown()) then
|
||
|
|
if (settingName == "height") then
|
||
|
|
---@type number
|
||
|
|
local currentHeight = spellsTab.GetGenericScrollFrame():GetHeight()
|
||
|
|
Details.breakdown_spell_tab.genericcontainer_height = settingValue
|
||
|
|
spellsTab.GetGenericScrollFrame():SetNumFramesShown(math.floor(currentHeight / CONST_SPELLSCROLL_LINEHEIGHT) - 2)
|
||
|
|
|
||
|
|
elseif (settingName == "width") then
|
||
|
|
Details.breakdown_spell_tab.genericcontainer_width = settingValue
|
||
|
|
|
||
|
|
elseif (settingName == "is_locked") then
|
||
|
|
Details.breakdown_spell_tab.genericcontainer_islocked = settingValue
|
||
|
|
end
|
||
|
|
|
||
|
|
spellsTab.GetSpellBlockContainer():SendSettingChangedCallback("UpdateSize", -1)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
container:SetSettingChangedCallback(settingChangedCallbackFunction)
|
||
|
|
|
||
|
|
--create a scrollframe
|
||
|
|
local genericScrollFrame = DF:CreateScrollBox(container, "$parentGenericScroll", refreshGenericFunc, {}, width, height, defaultAmountOfLines, CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
DF:ReskinSlider(genericScrollFrame)
|
||
|
|
genericScrollFrame:SetBackdrop({})
|
||
|
|
genericScrollFrame:SetAllPoints()
|
||
|
|
|
||
|
|
container:RegisterChildForDrag(genericScrollFrame)
|
||
|
|
|
||
|
|
genericScrollFrame.DontHideChildrenOnPreRefresh = false
|
||
|
|
tabFrame.GenericScrollFrame = genericScrollFrame
|
||
|
|
spellsTab.GenericScrollFrame = genericScrollFrame
|
||
|
|
|
||
|
|
--settingChangedCallbackFunction(container, "height", Details.breakdown_spell_tab.genericcontainer_height)
|
||
|
|
|
||
|
|
function genericScrollFrame:RefreshMe(data) --~refreshme (generic) ~refreshg
|
||
|
|
--get which column is currently selected and the sort order
|
||
|
|
local columnIndex, order, key = genericScrollFrame.Header:GetSelectedColumn()
|
||
|
|
genericScrollFrame.SortKey = key
|
||
|
|
|
||
|
|
---@type string
|
||
|
|
local keyToSort = key
|
||
|
|
|
||
|
|
if (order == "DESC") then
|
||
|
|
table.sort(data,
|
||
|
|
function(t1, t2)
|
||
|
|
return t1[keyToSort] > t2[keyToSort]
|
||
|
|
end)
|
||
|
|
genericScrollFrame.topValue = data[1] and data[1][keyToSort]
|
||
|
|
else
|
||
|
|
table.sort(data,
|
||
|
|
function(t1, t2)
|
||
|
|
return t1[keyToSort] < t2[keyToSort]
|
||
|
|
end)
|
||
|
|
genericScrollFrame.topValue = data[#data] and data[#data][keyToSort]
|
||
|
|
end
|
||
|
|
|
||
|
|
genericScrollFrame:SetData(data)
|
||
|
|
genericScrollFrame:Refresh()
|
||
|
|
end
|
||
|
|
|
||
|
|
--~header
|
||
|
|
local headerOptions = {
|
||
|
|
padding = 2,
|
||
|
|
header_height = 14,
|
||
|
|
|
||
|
|
reziser_shown = true,
|
||
|
|
reziser_width = 2,
|
||
|
|
reziser_color = {.5, .5, .5, 0.7},
|
||
|
|
reziser_max_width = 246,
|
||
|
|
|
||
|
|
header_click_callback = onAnyColumnHeaderClickCallback,
|
||
|
|
|
||
|
|
header_backdrop_color = {0.1, 0.1, 0.1, 0.4},
|
||
|
|
text_color = {1, 1, 1, 0.823},
|
||
|
|
}
|
||
|
|
|
||
|
|
---@type df_headerframe
|
||
|
|
local header = DetailsFramework:CreateHeader(container, genericContainerColumnData, headerOptions)
|
||
|
|
genericScrollFrame.Header = header
|
||
|
|
genericScrollFrame.Header:SetPoint("topleft", genericScrollFrame, "topleft", 0, 1)
|
||
|
|
genericScrollFrame.Header:SetColumnSettingChangedCallback(onHeaderColumnOptionChanged)
|
||
|
|
|
||
|
|
--cache the type of this container
|
||
|
|
headerContainerType[genericScrollFrame.Header] = "generic"
|
||
|
|
|
||
|
|
--create the scroll lines
|
||
|
|
for i = 1, defaultAmountOfLines do
|
||
|
|
genericScrollFrame:CreateLine(spellsTab.CreateGenericBar)
|
||
|
|
end
|
||
|
|
|
||
|
|
--need to create the second scroll frame to show the details about the spelltable/actor hovered over
|
||
|
|
|
||
|
|
return genericScrollFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---create the target container
|
||
|
|
---@param tabFrame tabframe
|
||
|
|
---@return breakdowntargetscrollframe
|
||
|
|
function spellsTab.CreateTargetContainer(tabFrame) --~create ~target ~createtargetcontainer ~createtargetscroll ~createtarget
|
||
|
|
---@type width
|
||
|
|
local width = Details.breakdown_spell_tab.targetcontainer_width
|
||
|
|
---@type height
|
||
|
|
local height = Details.breakdown_spell_tab.targetcontainer_height
|
||
|
|
|
||
|
|
local defaultAmountOfLines = 50
|
||
|
|
|
||
|
|
--create a container for the scrollframe
|
||
|
|
local options = {
|
||
|
|
width = Details.breakdown_spell_tab.targetcontainer_width,
|
||
|
|
height = Details.breakdown_spell_tab.targetcontainer_height,
|
||
|
|
is_locked = Details.breakdown_spell_tab.targetcontainer_islocked,
|
||
|
|
can_move = false,
|
||
|
|
can_move_children = false,
|
||
|
|
use_top_resizer = true,
|
||
|
|
use_right_resizer = true,
|
||
|
|
}
|
||
|
|
|
||
|
|
---@type df_framecontainer
|
||
|
|
local container = DF:CreateFrameContainer(tabFrame, options, tabFrame:GetName() .. "TargetScrollContainer")
|
||
|
|
container:SetPoint("topleft", spellsTab.GetSpellScrollContainer(), "bottomleft", 0, -25)
|
||
|
|
container:SetFrameLevel(tabFrame:GetFrameLevel() + 10)
|
||
|
|
spellsTab.TargetsContainerFrame = container
|
||
|
|
|
||
|
|
local settingChangedCallbackFunction = function(frameContainer, settingName, settingValue)
|
||
|
|
if (frameContainer:IsShown()) then
|
||
|
|
if (settingName == "height") then
|
||
|
|
---@type number
|
||
|
|
local currentHeight = spellsTab.GetTargetScrollFrame():GetHeight()
|
||
|
|
Details.breakdown_spell_tab.targetcontainer_height = settingValue
|
||
|
|
--the -0.1 is the avoid the random fraction of 1.9999999990 to 2.0000000001
|
||
|
|
local lineAmount = currentHeight / CONST_SPELLSCROLL_LINEHEIGHT - 0.1
|
||
|
|
lineAmount = math.floor(lineAmount)
|
||
|
|
spellsTab.GetTargetScrollFrame():SetNumFramesShown(lineAmount)
|
||
|
|
|
||
|
|
elseif (settingName == "width") then
|
||
|
|
Details.breakdown_spell_tab.targetcontainer_width = settingValue
|
||
|
|
|
||
|
|
elseif (settingName == "is_locked") then
|
||
|
|
Details.breakdown_spell_tab.targetcontainer_islocked = settingValue
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
container:SetSettingChangedCallback(settingChangedCallbackFunction)
|
||
|
|
|
||
|
|
--create the scrollframe similar to scrollframe used in the spellscrollframe
|
||
|
|
--replace this with a framework scrollframe
|
||
|
|
---@type breakdowntargetscrollframe
|
||
|
|
local targetScrollFrame = DF:CreateScrollBox(container, "$parentTargetScroll", refreshTargetsFunc, {}, width, height, defaultAmountOfLines, CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
DF:ReskinSlider(targetScrollFrame)
|
||
|
|
targetScrollFrame:SetBackdrop({})
|
||
|
|
targetScrollFrame:SetAllPoints()
|
||
|
|
|
||
|
|
container:RegisterChildForDrag(targetScrollFrame)
|
||
|
|
|
||
|
|
targetScrollFrame.DontHideChildrenOnPreRefresh = false
|
||
|
|
tabFrame.TargetScrollFrame = targetScrollFrame
|
||
|
|
spellsTab.TargetScrollFrame = targetScrollFrame
|
||
|
|
|
||
|
|
spellsTab.ApplyStandardBackdrop(container, targetScrollFrame)
|
||
|
|
|
||
|
|
---@param data breakdowntargettablelist
|
||
|
|
function targetScrollFrame:RefreshMe(data) --~refreshme (targets) ~refreshmet
|
||
|
|
--get which column is currently selected and the sort order
|
||
|
|
local columnIndex, order, key = targetScrollFrame.Header:GetSelectedColumn()
|
||
|
|
targetScrollFrame.SortKey = key
|
||
|
|
|
||
|
|
---@type string
|
||
|
|
local keyToSort = key
|
||
|
|
|
||
|
|
if (order == "DESC") then
|
||
|
|
table.sort(data,
|
||
|
|
function(t1, t2)
|
||
|
|
return t1[keyToSort] > t2[keyToSort]
|
||
|
|
end)
|
||
|
|
targetScrollFrame.topValue = data[1] and data[1][keyToSort]
|
||
|
|
else
|
||
|
|
table.sort(data,
|
||
|
|
function(t1, t2)
|
||
|
|
return t1[keyToSort] < t2[keyToSort]
|
||
|
|
end)
|
||
|
|
targetScrollFrame.topValue = data[#data] and data[#data][keyToSort]
|
||
|
|
end
|
||
|
|
|
||
|
|
if (key == "overheal") then
|
||
|
|
data.totalValue = data.totalValueOverheal
|
||
|
|
end
|
||
|
|
--default: data.totalValue
|
||
|
|
--data.totalValueOverheal
|
||
|
|
|
||
|
|
targetScrollFrame:SetData(data)
|
||
|
|
targetScrollFrame:Refresh()
|
||
|
|
end
|
||
|
|
|
||
|
|
--~header
|
||
|
|
local headerOptions = {
|
||
|
|
padding = 2,
|
||
|
|
header_height = 14,
|
||
|
|
|
||
|
|
reziser_shown = true,
|
||
|
|
reziser_width = 2,
|
||
|
|
reziser_color = {.5, .5, .5, 0.7},
|
||
|
|
reziser_max_width = 246,
|
||
|
|
|
||
|
|
header_click_callback = onAnyColumnHeaderClickCallback,
|
||
|
|
|
||
|
|
header_backdrop_color = {0.1, 0.1, 0.1, 0.4},
|
||
|
|
text_color = {1, 1, 1, 0.823},
|
||
|
|
}
|
||
|
|
|
||
|
|
---@type df_headerframe
|
||
|
|
local header = DetailsFramework:CreateHeader(container, targetContainerColumnData, headerOptions)
|
||
|
|
targetScrollFrame.Header = header
|
||
|
|
targetScrollFrame.Header:SetPoint("topleft", targetScrollFrame, "topleft", 0, 1)
|
||
|
|
targetScrollFrame.Header:SetColumnSettingChangedCallback(onHeaderColumnOptionChanged)
|
||
|
|
|
||
|
|
--cache the type of this container
|
||
|
|
headerContainerType[targetScrollFrame.Header] = "targets"
|
||
|
|
|
||
|
|
--create the scroll lines
|
||
|
|
for i = 1, defaultAmountOfLines do
|
||
|
|
targetScrollFrame:CreateLine(spellsTab.CreateTargetBar)
|
||
|
|
end
|
||
|
|
|
||
|
|
tabFrame.targets = targetScrollFrame:CreateFontString(nil, "overlay", "QuestFont_Large")
|
||
|
|
tabFrame.targets:SetPoint("bottomleft", container, "topleft", 2, 2)
|
||
|
|
tabFrame.targets:SetText(Loc ["STRING_TARGETS"] .. ":")
|
||
|
|
|
||
|
|
return targetScrollFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
--logistics: class_damage build the list of spells, send it to window_playerbreakdown, which gets the current summary tab and send the data for it
|
||
|
|
--in this tab, the data is sent to the refresh function
|
||
|
|
|
||
|
|
local onClickExpandButton = function(expandButton, button)
|
||
|
|
---@type breakdownspellbar
|
||
|
|
local spellBar = expandButton:GetParent()
|
||
|
|
---@type table
|
||
|
|
local scrolFrame = spellBar:GetParent()
|
||
|
|
---@type boolean
|
||
|
|
local bIsSpellExpaded = expandButton.bIsSpellExpaded
|
||
|
|
|
||
|
|
--check if the one of the expanded bars was a selected spellbar and deselect
|
||
|
|
--get the current selected spellbar
|
||
|
|
---@type breakdownspellbar
|
||
|
|
local selectedSpellBar = spellsTab.GetSelectedSpellBar()
|
||
|
|
|
||
|
|
if (bIsSpellExpaded) then --it's already expended, it'll close the expanded spellbars
|
||
|
|
--check if the selected spellbar is one of the expanded spellbars and deselect it
|
||
|
|
for i = 1, #spellBar.ExpandedChildren do
|
||
|
|
---@type breakdownspellbar
|
||
|
|
local expandedSpellBar = spellBar.ExpandedChildren[i]
|
||
|
|
if (expandedSpellBar == selectedSpellBar) then
|
||
|
|
--deselect the spellbar
|
||
|
|
spellsTab.UnSelectSpellBar()
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
spellsTab.UnSelectSpellBar()
|
||
|
|
end
|
||
|
|
|
||
|
|
--todo: check is any other bar has expanded state true, and close the expand (or not)
|
||
|
|
|
||
|
|
--toggle this spell expand mode
|
||
|
|
Details222.BreakdownWindow.SetSpellAsExpanded(expandButton.petName or expandButton.spellId, not bIsSpellExpaded)
|
||
|
|
|
||
|
|
--call the refresh function of the window
|
||
|
|
---@type instance
|
||
|
|
local instanceObject = spellsTab.GetInstance()
|
||
|
|
instanceObject:RefreshWindow(true)
|
||
|
|
end
|
||
|
|
|
||
|
|
local formatPetName = function(petName, spellName, ownerName)
|
||
|
|
--petName is raw (with the owner name)
|
||
|
|
local petNameWithoutOwner = petName:gsub((" <.*"), "")
|
||
|
|
|
||
|
|
local texture = [[Interface\AddOns\Details\images\classes_small]]
|
||
|
|
|
||
|
|
local bUseAlphaIcons = true
|
||
|
|
local specIcon = false
|
||
|
|
local iconSize = 14
|
||
|
|
|
||
|
|
if (petName:len() == 0) then
|
||
|
|
return Details:AddClassOrSpecIcon(spellName, "PET", specIcon, iconSize, bUseAlphaIcons)
|
||
|
|
end
|
||
|
|
|
||
|
|
petNameWithoutOwner = Details:AddClassOrSpecIcon(petNameWithoutOwner, "PET", specIcon, iconSize, bUseAlphaIcons)
|
||
|
|
|
||
|
|
return spellName .. " |cFFCCBBBB" .. petNameWithoutOwner .. "|r"
|
||
|
|
end
|
||
|
|
|
||
|
|
---update a line using the data passed
|
||
|
|
---@param spellBar breakdownspellbar
|
||
|
|
---@param index number spell position (from best to wrost)
|
||
|
|
---@param actorName string
|
||
|
|
---@param combatObject combat
|
||
|
|
---@param scrollFrame table
|
||
|
|
---@param headerTable table
|
||
|
|
---@param bkSpellData spelltableadv
|
||
|
|
---@param spellTableIndex number
|
||
|
|
---@param totalValue number
|
||
|
|
---@param topValue number
|
||
|
|
---@param bIsMainLine boolean if true this is the line which has all the values of the spell merged
|
||
|
|
---@param sortKey string
|
||
|
|
---@param spellTablesAmount number
|
||
|
|
local updateSpellBar = function(spellBar, index, actorName, combatObject, scrollFrame, headerTable, bkSpellData, spellTableIndex, totalValue, topValue, bIsMainLine, sortKey, spellTablesAmount)
|
||
|
|
--scrollFrame is defined as a table which is false, scrollFrame is a frame
|
||
|
|
|
||
|
|
local textIndex = 1
|
||
|
|
for headerIndex = 1, #headerTable do
|
||
|
|
---@type number
|
||
|
|
local spellId
|
||
|
|
---@type number
|
||
|
|
local value
|
||
|
|
---@type spelltable
|
||
|
|
local spellTable
|
||
|
|
|
||
|
|
spellBar.bkSpellData = bkSpellData
|
||
|
|
|
||
|
|
local petName = ""
|
||
|
|
---@type boolean @if true, this is the main line of an actor which has its spells nested in the bkSpellData.nestedData
|
||
|
|
local bIsActorHeader = bkSpellData.bIsActorHeader
|
||
|
|
|
||
|
|
if (bIsMainLine and bIsActorHeader) then
|
||
|
|
spellTable = bkSpellData
|
||
|
|
value = bkSpellData.total
|
||
|
|
spellId = 0
|
||
|
|
petName = actorName
|
||
|
|
|
||
|
|
elseif (bIsMainLine) then
|
||
|
|
spellTable = bkSpellData
|
||
|
|
value = bkSpellData.total
|
||
|
|
spellId = bkSpellData.id
|
||
|
|
petName = bkSpellData.nestedData[spellTableIndex].actorName
|
||
|
|
|
||
|
|
else
|
||
|
|
spellTable = bkSpellData.nestedData[spellTableIndex].spellTable
|
||
|
|
value = spellTable.total
|
||
|
|
spellId = spellTable.id
|
||
|
|
|
||
|
|
--if isn't a spell from a nested actor, then it can use the pet name in the spell name
|
||
|
|
if (not bkSpellData.nestedData[spellTableIndex].bIsActorHeader) then
|
||
|
|
petName = bkSpellData.nestedData[spellTableIndex].actorName
|
||
|
|
end
|
||
|
|
|
||
|
|
spellBar.bIsExpandedSpell = true
|
||
|
|
end
|
||
|
|
|
||
|
|
spellBar.spellId = spellId
|
||
|
|
|
||
|
|
---@cast spellTable spelltable
|
||
|
|
spellBar.spellTable = spellTable
|
||
|
|
|
||
|
|
---@type string, number, string
|
||
|
|
local spellName, _, spellIcon = Details.GetSpellInfo(spellId)
|
||
|
|
if (not spellName) then
|
||
|
|
spellName = actorName
|
||
|
|
spellIcon = bkSpellData.actorIcon or ""
|
||
|
|
end
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local amtCasts = combatObject:GetSpellCastAmount(actorName, spellName)
|
||
|
|
spellBar.amountCasts = amtCasts
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local uptime = combatObject:GetSpellUptime(actorName, spellId)
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local combatTime = combatObject:GetCombatTime()
|
||
|
|
|
||
|
|
--statusbar size by percent
|
||
|
|
if (topValue > 0) then
|
||
|
|
local barValue = spellTable[sortKey] or getValueForHeaderSortKey(combatObject, spellTable, sortKey)
|
||
|
|
spellBar.statusBar:SetValue(barValue / topValue * 100)
|
||
|
|
else
|
||
|
|
spellBar.statusBar:SetValue(0)
|
||
|
|
end
|
||
|
|
|
||
|
|
if (petName ~= "") then
|
||
|
|
--if is a pet spell and has more pets nested || nop, now is a pet with its spells nested
|
||
|
|
if (spellTablesAmount > 1 and bIsMainLine) then
|
||
|
|
spellName = formatPetName("", spellName, "") --causing error as spellName is nil
|
||
|
|
elseif (bIsMainLine) then
|
||
|
|
spellName = formatPetName(petName, spellName, actorName)
|
||
|
|
else
|
||
|
|
spellName = formatPetName(petName, "", "")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
spellBar.spellId = spellId
|
||
|
|
spellBar.spellIconFrame.spellId = spellId
|
||
|
|
|
||
|
|
spellBar.statusBar.backgroundTexture:SetAlpha(Details.breakdown_spell_tab.spellbar_background_alpha)
|
||
|
|
|
||
|
|
--statusbar color by school
|
||
|
|
local r, g, b = Details:GetSpellSchoolColor(spellTable.spellschool or 1)
|
||
|
|
spellBar.statusBar:SetStatusBarColor(r, g, b, 0.963)
|
||
|
|
|
||
|
|
spellBar.average = value / spellTable.counter
|
||
|
|
spellBar.combatTime = combatTime
|
||
|
|
|
||
|
|
---@type fontstring
|
||
|
|
local text = spellBar.InLineTexts[textIndex]
|
||
|
|
local header = headerTable[headerIndex]
|
||
|
|
|
||
|
|
if (header.name == "icon") then
|
||
|
|
spellBar.spellIcon:Show()
|
||
|
|
spellBar.spellIcon:SetTexture(spellIcon)
|
||
|
|
spellBar.spellIcon:SetAlpha(0.92)
|
||
|
|
spellBar:AddFrameToHeaderAlignment(spellBar.spellIconFrame)
|
||
|
|
|
||
|
|
elseif (header.name == "target") then --the tab does not have knownledge about the targets of the spell, it must be passed over
|
||
|
|
---@type breakdowntargetframe
|
||
|
|
local targetsSquareFrame = spellBar.targetsSquareFrame
|
||
|
|
targetsSquareFrame:Show()
|
||
|
|
targetsSquareFrame.spellId = spellId
|
||
|
|
targetsSquareFrame.bkSpellData = spellTable
|
||
|
|
targetsSquareFrame.spellTable = spellTable
|
||
|
|
targetsSquareFrame.bIsMainLine = bIsMainLine
|
||
|
|
spellBar:AddFrameToHeaderAlignment(targetsSquareFrame)
|
||
|
|
|
||
|
|
elseif (header.name == "rank") then
|
||
|
|
text:SetText(index)
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
spellBar.rank = index
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "expand") then
|
||
|
|
text:SetText("")
|
||
|
|
spellBar:AddFrameToHeaderAlignment(spellBar.expandButton)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
if (bkSpellData.bCanExpand and bIsMainLine) then
|
||
|
|
spellBar.expandButton:Show()
|
||
|
|
local bIsSpellExpaded = Details222.BreakdownWindow.IsSpellExpanded(bIsActorHeader and actorName or spellId)
|
||
|
|
spellBar.expandButton.spellId = bIsActorHeader and actorName or spellId
|
||
|
|
spellBar.expandButton.bIsSpellExpaded = bIsSpellExpaded
|
||
|
|
spellBar.expandButton:SetScript("OnClick", onClickExpandButton)
|
||
|
|
|
||
|
|
--update the texture taking the state of the expanded value
|
||
|
|
if (bIsSpellExpaded) then
|
||
|
|
spellBar.expandButton.texture:SetTexture([[Interface\AddOns\Details\images\arrow_face_down]])
|
||
|
|
spellBar.expandButton.texture:SetTexCoord(0, 1, 1, 0)
|
||
|
|
else
|
||
|
|
spellBar.expandButton.texture:SetTexture([[Interface\AddOns\Details\images\arrow_face_down]])
|
||
|
|
spellBar.expandButton.texture:SetTexCoord(0, 1, 0, 1)
|
||
|
|
end
|
||
|
|
|
||
|
|
spellBar.expandButton.texture:SetAlpha(0.7)
|
||
|
|
spellBar.expandButton.texture:SetSize(16, 16)
|
||
|
|
end
|
||
|
|
|
||
|
|
elseif (header.name == "name") then
|
||
|
|
text:SetText(Details:RemoveOwnerName(spellName))
|
||
|
|
spellBar.name = spellName
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "amount") then
|
||
|
|
text:SetText(Details:Format(value))
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "persecond") then
|
||
|
|
spellBar.perSecond = value / combatTime
|
||
|
|
|
||
|
|
---@type string
|
||
|
|
local perSecondFormatted = Details:Format(spellBar.perSecond)
|
||
|
|
text:SetText(perSecondFormatted)
|
||
|
|
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "percent") then
|
||
|
|
spellBar.percent = value / totalValue * 100
|
||
|
|
---@type string
|
||
|
|
local percentFormatted = string.format("%.1f", spellBar.percent) .. "%"
|
||
|
|
text:SetText(percentFormatted)
|
||
|
|
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "casts") then
|
||
|
|
text:SetText(amtCasts)
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "critpercent") then
|
||
|
|
text:SetText(string.format("%.1f", spellTable.c_amt / (spellTable.counter) * 100) .. "%")
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "hits") then
|
||
|
|
text:SetText(spellTable.counter)
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "castavg") then
|
||
|
|
if (amtCasts > 0) then
|
||
|
|
spellBar.castAverage = value / amtCasts
|
||
|
|
text:SetText(Details:Format(spellBar.castAverage))
|
||
|
|
else
|
||
|
|
text:SetText("0")
|
||
|
|
end
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "uptime") then --need to get the uptime of the spell with the biggest uptime
|
||
|
|
text:SetText(string.format("%.1f", uptime / combatTime * 100) .. "%")
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "overheal" and spellTable.overheal) then
|
||
|
|
if (spellTable.overheal > 0) then
|
||
|
|
local totalHeal = spellTable.overheal + value
|
||
|
|
text:SetText(Details:ToK2(spellTable.overheal) .. " (" .. math.floor(spellTable.overheal / totalHeal * 100) .. "%)")
|
||
|
|
else
|
||
|
|
text:SetText("0%")
|
||
|
|
end
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
|
||
|
|
elseif (header.name == "absorbed") then
|
||
|
|
text:SetText(Details:Format(spellTable.absorbed or 0))
|
||
|
|
spellBar:AddFrameToHeaderAlignment(text)
|
||
|
|
textIndex = textIndex + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
spellBar:AlignWithHeader(scrollFrame.Header, "left")
|
||
|
|
end
|
||
|
|
|
||
|
|
---get a spell bar from the scroll box, if it doesn't exist, return nil
|
||
|
|
---@param scrollFrame table
|
||
|
|
---@param lineIndex number
|
||
|
|
---@return breakdownspellbar
|
||
|
|
local getSpellBar = function(scrollFrame, lineIndex)
|
||
|
|
---@type breakdownspellbar
|
||
|
|
local spellBar = scrollFrame:GetLine(lineIndex)
|
||
|
|
|
||
|
|
spellBar.bIsExpandedSpell = false
|
||
|
|
|
||
|
|
wipe(spellBar.ExpandedChildren)
|
||
|
|
|
||
|
|
--reset header alignment
|
||
|
|
spellBar:ResetFramesToHeaderAlignment()
|
||
|
|
|
||
|
|
spellsTab.UpdateBarSettings(spellBar)
|
||
|
|
|
||
|
|
--reset columns, hiding them
|
||
|
|
spellBar.spellIcon:Hide()
|
||
|
|
spellBar.expandButton:Hide()
|
||
|
|
spellBar.targetsSquareFrame:Hide()
|
||
|
|
for inLineIndex = 1, #spellBar.InLineTexts do
|
||
|
|
spellBar.InLineTexts[inLineIndex]:SetText("")
|
||
|
|
end
|
||
|
|
|
||
|
|
return spellBar
|
||
|
|
end
|
||
|
|
|
||
|
|
---refresh the data shown in the spells scroll box
|
||
|
|
---@param scrollFrame table
|
||
|
|
---@param scrollData breakdownspelldatalist
|
||
|
|
---@param offset number
|
||
|
|
---@param totalLines number
|
||
|
|
local refreshSpellsFunc = function(scrollFrame, scrollData, offset, totalLines) --~refreshspells ~refreshfunc ~refresh ~refreshs
|
||
|
|
---@type number
|
||
|
|
local topValue = scrollFrame.topValue
|
||
|
|
---@type number
|
||
|
|
local totalValue = scrollData.totalValue
|
||
|
|
---@type actor
|
||
|
|
local actorObject = spellsTab.GetActor()
|
||
|
|
---@type string
|
||
|
|
local actorName = actorObject:Name()
|
||
|
|
|
||
|
|
---@type combat
|
||
|
|
local combatObject = spellsTab.GetCombat()
|
||
|
|
---@type instance
|
||
|
|
local instanceObject = spellsTab.GetInstance()
|
||
|
|
|
||
|
|
local keyToSort = scrollFrame.SortKey
|
||
|
|
local orderToSort = scrollFrame.SortKey
|
||
|
|
local headerTable = spellsTab.spellsHeaderData
|
||
|
|
|
||
|
|
--todo: when swapping sort orders, close already expanded spells
|
||
|
|
|
||
|
|
local lineIndex = 1
|
||
|
|
for i = 1, totalLines do
|
||
|
|
local index = i + offset
|
||
|
|
|
||
|
|
---@type spelltableadv
|
||
|
|
local bkSpellData = scrollData[index]
|
||
|
|
|
||
|
|
if (bkSpellData) then
|
||
|
|
---@type number
|
||
|
|
local spellTablesAmount = #bkSpellData.nestedData
|
||
|
|
|
||
|
|
---called mainSpellBar because it is the line that shows the sum of all spells merged (if any)
|
||
|
|
---@type breakdownspellbar
|
||
|
|
local mainSpellBar = getSpellBar(scrollFrame, lineIndex)
|
||
|
|
do
|
||
|
|
--main line of the spell, where the sum of all spells merged is shown
|
||
|
|
if (mainSpellBar) then
|
||
|
|
lineIndex = lineIndex + 1
|
||
|
|
local bIsMainLine = true
|
||
|
|
local bIsActorHeader = bkSpellData.bIsActorHeader
|
||
|
|
local spellTableIndex = 1
|
||
|
|
local spellBar = mainSpellBar
|
||
|
|
|
||
|
|
local nameToUse = actorName
|
||
|
|
if (bIsActorHeader) then
|
||
|
|
nameToUse = bkSpellData.actorName
|
||
|
|
end
|
||
|
|
|
||
|
|
---@debug both calls are equal but the traceback will be different in case of an error
|
||
|
|
if (bIsActorHeader) then
|
||
|
|
updateSpellBar(spellBar, index, nameToUse, combatObject, scrollFrame, headerTable, bkSpellData, spellTableIndex, totalValue, topValue, bIsMainLine, keyToSort, spellTablesAmount)
|
||
|
|
else
|
||
|
|
--here
|
||
|
|
updateSpellBar(spellBar, index, nameToUse, combatObject, scrollFrame, headerTable, bkSpellData, spellTableIndex, totalValue, topValue, bIsMainLine, keyToSort, spellTablesAmount)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--if the spell is expanded
|
||
|
|
--then it adds the lines for each spell merged, but it cannot use the bkSpellData, it needs the spellTable, it's kinda using bkSpellData, need to debug
|
||
|
|
if (bkSpellData.bIsExpanded and (spellTablesAmount > 1)) then
|
||
|
|
--filling necessary information to sort the data by the selected header column
|
||
|
|
for spellTableIndex = 1, spellTablesAmount do
|
||
|
|
---@type bknesteddata
|
||
|
|
local nestedBkSpellData = bkSpellData.nestedData[spellTableIndex]
|
||
|
|
---@type spelltable
|
||
|
|
local spellTable = nestedBkSpellData.spellTable
|
||
|
|
nestedBkSpellData.value = spellTable[keyToSort] or getValueForHeaderSortKey(combatObject, spellTable, keyToSort)
|
||
|
|
end
|
||
|
|
|
||
|
|
--sort the nested data
|
||
|
|
if (orderToSort == "DESC") then
|
||
|
|
table.sort(bkSpellData.nestedData,
|
||
|
|
function(t1, t2)
|
||
|
|
return t1.value < t2.value
|
||
|
|
end)
|
||
|
|
else
|
||
|
|
table.sort(bkSpellData.nestedData,
|
||
|
|
function(t1, t2)
|
||
|
|
return t1.value > t2.value
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
for spellTableIndex = 1, spellTablesAmount do
|
||
|
|
---@type breakdownspellbar
|
||
|
|
local spellBar = getSpellBar(scrollFrame, lineIndex)
|
||
|
|
if (spellBar) then
|
||
|
|
---@type bknesteddata
|
||
|
|
local nestedBkSpellData = bkSpellData.nestedData[spellTableIndex]
|
||
|
|
|
||
|
|
lineIndex = lineIndex + 1
|
||
|
|
---@type string
|
||
|
|
local petName = nestedBkSpellData.actorName
|
||
|
|
---@type string
|
||
|
|
local nameToUse = petName ~= "" and petName or actorName
|
||
|
|
local bIsMainLine = false
|
||
|
|
|
||
|
|
bkSpellData[keyToSort] = nestedBkSpellData.value
|
||
|
|
|
||
|
|
updateSpellBar(spellBar, index, nameToUse, combatObject, scrollFrame, headerTable, bkSpellData, spellTableIndex, totalValue, topValue, bIsMainLine, keyToSort, spellTablesAmount)
|
||
|
|
mainSpellBar.ExpandedChildren[#mainSpellBar.ExpandedChildren + 1] = spellBar
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (lineIndex > totalLines) then
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
---creates a scrollframe which show breakdownspellbar to show the spells used by an actor
|
||
|
|
---@param tabFrame tabframe
|
||
|
|
---@return breakdownspellscrollframe
|
||
|
|
function spellsTab.CreateSpellScrollContainer(tabFrame) --~scroll ~create ~spell ~container ~createspellcontainer
|
||
|
|
---@type width
|
||
|
|
local width = Details.breakdown_spell_tab.spellcontainer_width
|
||
|
|
---@type height
|
||
|
|
local height = Details.breakdown_spell_tab.spellcontainer_height
|
||
|
|
|
||
|
|
local options = {
|
||
|
|
width = Details.breakdown_spell_tab.spellcontainer_width,
|
||
|
|
height = Details.breakdown_spell_tab.spellcontainer_height,
|
||
|
|
is_locked = Details.breakdown_spell_tab.spellcontainer_islocked,
|
||
|
|
can_move = false,
|
||
|
|
can_move_children = false,
|
||
|
|
use_bottom_resizer = true,
|
||
|
|
use_right_resizer = false,
|
||
|
|
}
|
||
|
|
|
||
|
|
---create a container for the scrollframe
|
||
|
|
---@type df_framecontainer
|
||
|
|
local container = DF:CreateFrameContainer(tabFrame, options, tabFrame:GetName() .. "SpellScrollContainer")
|
||
|
|
container:SetPoint("topleft", tabFrame, "topleft", 5, -5)
|
||
|
|
container:SetFrameLevel(tabFrame:GetFrameLevel() + 10)
|
||
|
|
spellsTab.SpellContainerFrame = container
|
||
|
|
|
||
|
|
--when a setting is changed in the container, it will call this function, it is registered below with SetSettingChangedCallback()
|
||
|
|
local settingChangedCallbackFunction = function(frameContainer, settingName, settingValue) --doing here the callback for thge settings changed in the container
|
||
|
|
if (frameContainer:IsShown()) then
|
||
|
|
if (settingName == "height") then
|
||
|
|
---@type number
|
||
|
|
local currentHeight = spellsTab.GetSpellScrollFrame():GetHeight()
|
||
|
|
Details.breakdown_spell_tab.spellcontainer_height = settingValue
|
||
|
|
spellsTab.GetSpellScrollFrame():SetNumFramesShown(math.floor(currentHeight / CONST_SPELLSCROLL_LINEHEIGHT) - 1)
|
||
|
|
|
||
|
|
elseif (settingName == "width") then
|
||
|
|
Details.breakdown_spell_tab.spellcontainer_width = settingValue
|
||
|
|
|
||
|
|
elseif (settingName == "is_locked") then
|
||
|
|
Details.breakdown_spell_tab.spellcontainer_islocked = settingValue
|
||
|
|
end
|
||
|
|
|
||
|
|
spellsTab.GetSpellBlockContainer():SendSettingChangedCallback("UpdateSize", -1)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
container:SetSettingChangedCallback(settingChangedCallbackFunction)
|
||
|
|
|
||
|
|
--amount of lines which will be created for the scrollframe
|
||
|
|
local defaultAmountOfLines = 50
|
||
|
|
|
||
|
|
--replace this with a framework scrollframe
|
||
|
|
---@type breakdownspellscrollframe
|
||
|
|
local scrollFrame = DF:CreateScrollBox(container, "$parentSpellScroll", refreshSpellsFunc, {}, width, height, defaultAmountOfLines, CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
DF:ReskinSlider(scrollFrame)
|
||
|
|
scrollFrame:SetPoint("topleft", container, "topleft", 0, 0) --need to set the points
|
||
|
|
scrollFrame:SetPoint("bottomright", container, "bottomright", 0, 0) --need to set the points
|
||
|
|
|
||
|
|
container:RegisterChildForDrag(scrollFrame)
|
||
|
|
|
||
|
|
scrollFrame.DontHideChildrenOnPreRefresh = true
|
||
|
|
tabFrame.SpellScrollFrame = scrollFrame
|
||
|
|
spellsTab.SpellScrollFrame = scrollFrame
|
||
|
|
|
||
|
|
spellsTab.ApplyStandardBackdrop(container, scrollFrame)
|
||
|
|
|
||
|
|
--~header
|
||
|
|
local headerOptions = {
|
||
|
|
padding = 2,
|
||
|
|
|
||
|
|
header_height = 14,
|
||
|
|
reziser_shown = true,
|
||
|
|
reziser_width = 2,
|
||
|
|
reziser_color = {.5, .5, .5, 0.7},
|
||
|
|
reziser_max_width = 246,
|
||
|
|
|
||
|
|
header_click_callback = onColumnHeaderClickCallback,
|
||
|
|
|
||
|
|
header_backdrop_color = {0.1, 0.1, 0.1, 0.4},
|
||
|
|
text_color = {1, 1, 1, 0.823},
|
||
|
|
}
|
||
|
|
|
||
|
|
local headerTable = {}
|
||
|
|
|
||
|
|
---create the header frame, the header frame is the frame which shows the columns names to describe the data shown in the scrollframe
|
||
|
|
---@type df_headerframe
|
||
|
|
local header = DetailsFramework:CreateHeader(container, headerTable, headerOptions)
|
||
|
|
scrollFrame.Header = header
|
||
|
|
scrollFrame.Header:SetPoint("topleft", scrollFrame, "topleft", 0, 1)
|
||
|
|
scrollFrame.Header:SetColumnSettingChangedCallback(onHeaderColumnOptionChanged)
|
||
|
|
|
||
|
|
--cache the containerType which this header is used for
|
||
|
|
headerContainerType[scrollFrame.Header] = "spells"
|
||
|
|
|
||
|
|
--create the scroll lines
|
||
|
|
for i = 1, defaultAmountOfLines do
|
||
|
|
scrollFrame:CreateLine(spellsTab.CreateSpellBar)
|
||
|
|
end
|
||
|
|
|
||
|
|
---set the data and refresh the scrollframe
|
||
|
|
---@param self breakdownspellscrollframe
|
||
|
|
---@param data breakdownspelldatalist
|
||
|
|
function scrollFrame:RefreshMe(data) --~refreshme (spells) ~refreshmes
|
||
|
|
--get which column is currently selected and the sort order
|
||
|
|
local columnIndex, order, key = scrollFrame.Header:GetSelectedColumn()
|
||
|
|
scrollFrame.SortKey = key
|
||
|
|
scrollFrame.SortOrder = order
|
||
|
|
|
||
|
|
---@type string
|
||
|
|
local keyToSort = key
|
||
|
|
|
||
|
|
---@type combat
|
||
|
|
local combatObject = spellsTab.GetCombat()
|
||
|
|
---@type number, number
|
||
|
|
local mainAttribute, subAttribute = spellsTab.GetInstance():GetDisplay()
|
||
|
|
|
||
|
|
--filling necessary information to sort the data by the selected header column
|
||
|
|
for i = 1, #data do
|
||
|
|
---@type spelltableadv
|
||
|
|
local bkSpellData = data[i]
|
||
|
|
if (not bkSpellData[keyToSort]) then
|
||
|
|
local value = getValueForHeaderSortKey(combatObject, bkSpellData, keyToSort)
|
||
|
|
bkSpellData[keyToSort] = value
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (order == "DESC") then
|
||
|
|
table.sort(data,
|
||
|
|
---@param t1 spelltableadv
|
||
|
|
---@param t2 spelltableadv
|
||
|
|
function(t1, t2)
|
||
|
|
return t1[keyToSort] > t2[keyToSort]
|
||
|
|
end)
|
||
|
|
self.topValue = data[1] and data[1][keyToSort]
|
||
|
|
else
|
||
|
|
table.sort(data,
|
||
|
|
---@param t1 spelltableadv
|
||
|
|
---@param t2 spelltableadv
|
||
|
|
function(t1, t2)
|
||
|
|
return t1[keyToSort] < t2[keyToSort]
|
||
|
|
end)
|
||
|
|
self.topValue = data[#data] and data[#data][keyToSort]
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetData(data)
|
||
|
|
self:Refresh()
|
||
|
|
end
|
||
|
|
|
||
|
|
return scrollFrame
|
||
|
|
end
|
||
|
|
|
||
|
|
---on enter function for the spell target frame
|
||
|
|
---@param targetFrame breakdowntargetframe
|
||
|
|
local onEnterSpellTarget = function(targetFrame)
|
||
|
|
--the spell target frame is created in the statusbar which is placed above the line frame
|
||
|
|
local lineBar = targetFrame:GetParent():GetParent()
|
||
|
|
local spellId = targetFrame.spellId
|
||
|
|
|
||
|
|
---@type actor
|
||
|
|
local actorObject = Details:GetActorObjectFromBreakdownWindow()
|
||
|
|
|
||
|
|
local targets
|
||
|
|
if (targetFrame.bIsMainLine) then
|
||
|
|
---@type spelltableadv
|
||
|
|
local bkSpellData = targetFrame.bkSpellData
|
||
|
|
targets = actorObject:BuildSpellTargetFromBreakdownSpellData(bkSpellData)
|
||
|
|
else
|
||
|
|
local spellTable = targetFrame.spellTable
|
||
|
|
targets = actorObject:BuildSpellTargetFromSpellTable(spellTable)
|
||
|
|
end
|
||
|
|
|
||
|
|
---@type number the top value of targets
|
||
|
|
local topValue = targets[1] and targets[1][2] or 0
|
||
|
|
|
||
|
|
local cooltip = GameCooltip
|
||
|
|
cooltip:Preset(2)
|
||
|
|
|
||
|
|
for targetIndex, targetTable in ipairs(targets) do
|
||
|
|
local targetName = targetTable[1]
|
||
|
|
local value = targetTable[2]
|
||
|
|
cooltip:AddLine(targetIndex .. ". " .. targetName, Details:Format(value))
|
||
|
|
GameCooltip:AddIcon(CONST_TARGET_TEXTURE, 1, 1, 14, 14)
|
||
|
|
Details:AddTooltipBackgroundStatusbar(false, value / topValue * 100)
|
||
|
|
end
|
||
|
|
|
||
|
|
cooltip:SetOwner(targetFrame)
|
||
|
|
cooltip:Show()
|
||
|
|
end
|
||
|
|
|
||
|
|
local onLeaveSpellTarget = function(self)
|
||
|
|
GameTooltip:Hide()
|
||
|
|
GameCooltip:Hide()
|
||
|
|
self:GetParent():GetParent():GetScript("OnLeave")(self:GetParent():GetParent())
|
||
|
|
self.texture:SetAlpha(.7)
|
||
|
|
self:SetAlpha(.7)
|
||
|
|
end
|
||
|
|
|
||
|
|
---@param targetBar breakdowntargetbar
|
||
|
|
local onEnterBreakdownTargetBar = function(targetBar)
|
||
|
|
targetBar:SetAlpha(1)
|
||
|
|
|
||
|
|
---@type string @the name of the target
|
||
|
|
local targetName = targetBar.actorName
|
||
|
|
|
||
|
|
Details:FormatCooltipForSpells()
|
||
|
|
GameCooltip:SetOwner(targetBar, "bottom", "top", 4, -5)
|
||
|
|
GameCooltip:SetOption("MinWidth", math.max(230, targetBar:GetWidth() * 0.98))
|
||
|
|
|
||
|
|
--build a list of spells which the target was hit by
|
||
|
|
local spellsSortedResult = {}
|
||
|
|
local total = 0
|
||
|
|
|
||
|
|
---@type actor
|
||
|
|
local actorObject = spellsTab.GetActor()
|
||
|
|
|
||
|
|
---@type combat
|
||
|
|
local combatObject = spellsTab.GetCombat()
|
||
|
|
|
||
|
|
---@type instance
|
||
|
|
local instanceObject = spellsTab.GetInstance()
|
||
|
|
|
||
|
|
---@type number
|
||
|
|
local mainAttribute = instanceObject:GetDisplay()
|
||
|
|
|
||
|
|
---@type spellcontainer
|
||
|
|
local spellContainer = actorObject:GetSpellContainer("spell")
|
||
|
|
|
||
|
|
local targetScrollFrame = spellsTab.GetTargetScrollFrame()
|
||
|
|
|
||
|
|
---@type number, string, string
|
||
|
|
local columnIndex, order, key = targetScrollFrame.Header:GetSelectedColumn()
|
||
|
|
|
||
|
|
---@type string the label shown at the top of the tooltip
|
||
|
|
local labelTooltipTitle = Loc ["STRING_DAMAGE_FROM"]
|
||
|
|
|
||
|
|
local targetTableName = "targets"
|
||
|
|
if (mainAttribute == DETAILS_ATTRIBUTE_HEAL) then
|
||
|
|
if (key == "total") then
|
||
|
|
labelTooltipTitle = Loc ["STRING_HEALING_FROM"]
|
||
|
|
|
||
|
|
elseif (key == "overheal") then
|
||
|
|
targetTableName = "targets_overheal"
|
||
|
|
labelTooltipTitle = Loc ["STRING_OVERHEALED"]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--this part kinda belong top damage or healing class, shouldn't be here
|
||
|
|
|
||
|
|
---@type number, spelltable
|
||
|
|
for spellId, spellTable in spellContainer:ListActors() do
|
||
|
|
if (spellTable.isReflection) then
|
||
|
|
---@type string, number
|
||
|
|
for spellTargetName, amount in pairs(spellTable.targets) do
|
||
|
|
if (spellTargetName == targetName) then
|
||
|
|
for reflectedSpellId, reflectedAmount in pairs(spellTable.extra) do
|
||
|
|
local spellName, _, spellIcon = _GetSpellInfo(reflectedSpellId)
|
||
|
|
table.insert(spellsSortedResult, {reflectedSpellId, reflectedAmount, spellName .. " (|cFFCCBBBBreflected|r)", spellIcon})
|
||
|
|
total = total + reflectedAmount
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
for spellTargetName, amount in pairs(spellTable[targetTableName]) do
|
||
|
|
if (spellTargetName == targetName) then
|
||
|
|
local spellName, _, spellIcon = _GetSpellInfo(spellId)
|
||
|
|
table.insert(spellsSortedResult, {spellId, amount, spellName, spellIcon})
|
||
|
|
total = total + amount
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--add pets
|
||
|
|
local petArray = actorObject:GetPets()
|
||
|
|
for _, petName in ipairs(petArray) do
|
||
|
|
local petActorObject = combatObject(mainAttribute, petName)
|
||
|
|
if (petActorObject) then
|
||
|
|
---@type spellcontainer
|
||
|
|
local petSpellContainer = petActorObject:GetSpellContainer("spell")
|
||
|
|
|
||
|
|
---@type number, spelltable
|
||
|
|
for spellId, spellTable in petSpellContainer:ListActors() do
|
||
|
|
for spellTargetName, amount in pairs(spellTable[targetTableName]) do
|
||
|
|
if (spellTargetName == targetName) then
|
||
|
|
local spellName, _, spellIcon = _GetSpellInfo(spellId)
|
||
|
|
table.insert(spellsSortedResult, {spellId, amount, spellName .. " (" .. petName:gsub((" <.*"), "") .. ")", spellIcon})
|
||
|
|
total = total + amount
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
table.sort(spellsSortedResult, Details.Sort2)
|
||
|
|
|
||
|
|
--need to change is this is a healing
|
||
|
|
Details:AddTooltipSpellHeaderText(labelTooltipTitle .. ":", {1, 0.9, 0.0, 1}, 1, Details.tooltip_spell_icon.file, unpack(Details.tooltip_spell_icon.coords))
|
||
|
|
Details:AddTooltipHeaderStatusbar(1, 1, 1, 1)
|
||
|
|
|
||
|
|
---@type tablesize
|
||
|
|
local iconSize = Details.tooltip.icon_size
|
||
|
|
---@type tablecoords
|
||
|
|
local iconBorder = Details.tooltip.icon_border_texcoord
|
||
|
|
|
||
|
|
local topValue = spellsSortedResult[1] and spellsSortedResult[1][2]
|
||
|
|
|
||
|
|
if (topValue) then
|
||
|
|
for index, tabela in ipairs(spellsSortedResult) do
|
||
|
|
local spellId, amount, spellName, spellIcon = unpack(tabela)
|
||
|
|
if (amount < 1) then
|
||
|
|
break
|
||
|
|
end
|
||
|
|
GameCooltip:AddLine(spellName, Details:Format(amount) .. " (" .. string.format("%.1f", amount / total * 100) .. "%)")
|
||
|
|
GameCooltip:AddIcon(spellIcon, nil, nil, iconSize.W + 4, iconSize.H + 4, iconBorder.L, iconBorder.R, iconBorder.T, iconBorder.B)
|
||
|
|
Details:AddTooltipBackgroundStatusbar(false, amount / topValue * 100)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
GameCooltip:Show()
|
||
|
|
end
|
||
|
|
|
||
|
|
---@param self breakdowntargetbar
|
||
|
|
local onLeaveBreakdownTargetBar = function(self)
|
||
|
|
self:SetAlpha(0.9)
|
||
|
|
GameCooltip:Hide()
|
||
|
|
end
|
||
|
|
|
||
|
|
---create a targetbar within the target scroll
|
||
|
|
---@param self breakdowntargetscrollframe
|
||
|
|
---@param index number
|
||
|
|
---@return breakdowntargetbar
|
||
|
|
function spellsTab.CreateTargetBar(self, index) --~create ~target ~createtarget ~targetbar
|
||
|
|
---@type breakdowntargetbar
|
||
|
|
local targetBar = CreateFrame("button", self:GetName() .. "TargetBarButton" .. index, self)
|
||
|
|
targetBar.index = index
|
||
|
|
|
||
|
|
--size and positioning
|
||
|
|
targetBar:SetHeight(CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
local y = (index-1) * CONST_SPELLSCROLL_LINEHEIGHT * -1 + (1 * -index) - 15
|
||
|
|
targetBar:SetPoint("topleft", self, "topleft", 1, y)
|
||
|
|
targetBar:SetPoint("topright", self, "topright", -1, y)
|
||
|
|
targetBar:EnableMouse(true)
|
||
|
|
|
||
|
|
targetBar:SetAlpha(0.823)
|
||
|
|
targetBar:SetFrameStrata("HIGH")
|
||
|
|
targetBar:SetScript("OnEnter", onEnterBreakdownTargetBar)
|
||
|
|
targetBar:SetScript("OnLeave", onLeaveBreakdownTargetBar)
|
||
|
|
|
||
|
|
DF:Mixin(targetBar, DF.HeaderFunctions)
|
||
|
|
|
||
|
|
---@type breakdownspellbarstatusbar
|
||
|
|
local statusBar = CreateFrame("StatusBar", "$parentStatusBar", targetBar)
|
||
|
|
statusBar:SetAllPoints()
|
||
|
|
statusBar:SetAlpha(0.5)
|
||
|
|
statusBar:SetMinMaxValues(0, 100)
|
||
|
|
statusBar:SetValue(50)
|
||
|
|
statusBar:EnableMouse(false)
|
||
|
|
statusBar:SetFrameLevel(targetBar:GetFrameLevel() - 1)
|
||
|
|
targetBar.statusBar = statusBar
|
||
|
|
|
||
|
|
---@type texture this is the statusbar texture
|
||
|
|
local statusBarTexture = statusBar:CreateTexture("$parentTexture", "artwork")
|
||
|
|
statusBarTexture:SetTexture(SharedMedia:Fetch("statusbar", "Details Hyanda"))
|
||
|
|
statusBar:SetStatusBarTexture(statusBarTexture)
|
||
|
|
statusBar:SetStatusBarColor(1, 1, 1, 1)
|
||
|
|
|
||
|
|
---@type texture shown when the mouse hoverover this bar
|
||
|
|
local hightlightTexture = statusBar:CreateTexture("$parentTextureHighlight", "highlight")
|
||
|
|
hightlightTexture:SetColorTexture(1, 1, 1, 0.2)
|
||
|
|
hightlightTexture:SetAllPoints()
|
||
|
|
statusBar.highlightTexture = hightlightTexture
|
||
|
|
|
||
|
|
---@type texture background texture
|
||
|
|
local backgroundTexture = statusBar:CreateTexture("$parentTextureBackground", "border")
|
||
|
|
backgroundTexture:SetAllPoints()
|
||
|
|
backgroundTexture:SetColorTexture(.05, .05, .05)
|
||
|
|
backgroundTexture:SetAlpha(1)
|
||
|
|
statusBar.backgroundTexture = backgroundTexture
|
||
|
|
|
||
|
|
--create an icon
|
||
|
|
---@type texture
|
||
|
|
local icon = statusBar:CreateTexture("$parentTexture", "overlay")
|
||
|
|
icon:SetPoint("left", statusBar, "left", 0, 0)
|
||
|
|
icon:SetSize(CONST_SPELLSCROLL_LINEHEIGHT-2, CONST_SPELLSCROLL_LINEHEIGHT-2)
|
||
|
|
icon:SetTexCoord(.1, .9, .1, .9)
|
||
|
|
targetBar.Icon = icon
|
||
|
|
|
||
|
|
targetBar:AddFrameToHeaderAlignment(icon)
|
||
|
|
|
||
|
|
targetBar.InLineTexts = {}
|
||
|
|
|
||
|
|
for i = 1, 5 do
|
||
|
|
---@type fontstring
|
||
|
|
local fontString = targetBar:CreateFontString("$parentFontString" .. i, "overlay", "GameFontHighlightSmall")
|
||
|
|
fontString:SetJustifyH("left")
|
||
|
|
fontString:SetTextColor(1, 1, 1, 1)
|
||
|
|
fontString:SetNonSpaceWrap(true)
|
||
|
|
fontString:SetWordWrap(false)
|
||
|
|
targetBar["lineText" .. i] = fontString
|
||
|
|
targetBar.InLineTexts[i] = fontString
|
||
|
|
fontString:SetTextColor(1, 1, 1, 1)
|
||
|
|
targetBar:AddFrameToHeaderAlignment(fontString)
|
||
|
|
end
|
||
|
|
|
||
|
|
targetBar:AlignWithHeader(self.Header, "left")
|
||
|
|
|
||
|
|
return targetBar
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
function spellsTab.UpdateBarSettings(bar)
|
||
|
|
if (bar.statusBar) then
|
||
|
|
bar.statusBar:SetAlpha(Details.breakdown_spell_tab.statusbar_alpha) --could be moved to when the bar is updated
|
||
|
|
bar.statusBar:GetStatusBarTexture():SetTexture(Details.breakdown_spell_tab.statusbar_texture)
|
||
|
|
bar.statusBar.backgroundTexture:SetColorTexture(unpack(Details.breakdown_spell_tab.statusbar_background_color))
|
||
|
|
bar.statusBar.backgroundTexture:SetAlpha(Details.breakdown_spell_tab.statusbar_background_alpha)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
---create a spellbar within the spell scroll
|
||
|
|
---@param self breakdownspellscrollframe
|
||
|
|
---@param index number
|
||
|
|
---@return breakdownspellbar
|
||
|
|
function spellsTab.CreateSpellBar(self, index) --~spellbar ~spellline ~spell ~create ~createline ~createspell ~createspellbar
|
||
|
|
---@type breakdownspellbar
|
||
|
|
local spellBar = CreateFrame("button", self:GetName() .. "SpellBarButton" .. index, self)
|
||
|
|
spellBar.index = index
|
||
|
|
|
||
|
|
--size and positioning
|
||
|
|
spellBar:SetHeight(CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
local y = (index-1) * CONST_SPELLSCROLL_LINEHEIGHT * -1 + (1 * -index) - 15
|
||
|
|
spellBar:SetPoint("topleft", self, "topleft", 1, y)
|
||
|
|
spellBar:SetPoint("topright", self, "topright", -1, y)
|
||
|
|
|
||
|
|
spellBar:EnableMouse(true)
|
||
|
|
spellBar:RegisterForClicks("AnyUp", "AnyDown")
|
||
|
|
spellBar:SetAlpha(0.823)
|
||
|
|
spellBar:SetFrameStrata("HIGH")
|
||
|
|
spellBar:SetScript("OnEnter", onEnterSpellBar)
|
||
|
|
spellBar:SetScript("OnLeave", onLeaveSpellBar)
|
||
|
|
spellBar:SetScript("OnMouseDown", onMouseDownBreakdownSpellBar)
|
||
|
|
spellBar:SetScript("OnMouseUp", onMouseUpBreakdownSpellBar)
|
||
|
|
spellBar.onMouseUpTime = 0
|
||
|
|
spellBar.ExpandedChildren = {}
|
||
|
|
|
||
|
|
DF:Mixin(spellBar, DF.HeaderFunctions)
|
||
|
|
|
||
|
|
---@type breakdownspellbarstatusbar
|
||
|
|
local statusBar = CreateFrame("StatusBar", "$parentStatusBar", spellBar)
|
||
|
|
statusBar:SetAllPoints()
|
||
|
|
statusBar:SetAlpha(0.5)
|
||
|
|
statusBar:SetMinMaxValues(0, 100)
|
||
|
|
statusBar:SetValue(50)
|
||
|
|
statusBar:EnableMouse(false)
|
||
|
|
statusBar:SetFrameLevel(spellBar:GetFrameLevel() - 1)
|
||
|
|
spellBar.statusBar = statusBar
|
||
|
|
|
||
|
|
---@type texture this is the statusbar texture
|
||
|
|
local statusBarTexture = statusBar:CreateTexture("$parentTexture", "artwork")
|
||
|
|
statusBar:SetStatusBarTexture(statusBarTexture)
|
||
|
|
statusBar:SetStatusBarColor(1, 1, 1, 1)
|
||
|
|
|
||
|
|
---@type texture background texture
|
||
|
|
local backgroundTexture = statusBar:CreateTexture("$parentTextureBackground", "border")
|
||
|
|
backgroundTexture:SetAllPoints()
|
||
|
|
statusBar.backgroundTexture = backgroundTexture
|
||
|
|
|
||
|
|
---@type texture overlay texture to use when the spellbar is selected
|
||
|
|
local statusBarOverlayTexture = statusBar:CreateTexture("$parentTextureOverlay", "overlay", nil, 7)
|
||
|
|
statusBarOverlayTexture:SetTexture([[Interface/AddOns/Details/images/overlay_indicator_1]])
|
||
|
|
statusBarOverlayTexture:SetVertexColor(1, 1, 1, 0.2)
|
||
|
|
statusBarOverlayTexture:SetAllPoints()
|
||
|
|
statusBarOverlayTexture:Hide()
|
||
|
|
spellBar.overlayTexture = statusBarOverlayTexture
|
||
|
|
statusBar.overlayTexture = statusBarOverlayTexture
|
||
|
|
|
||
|
|
---@type texture shown when the mouse hoverover this spellbar
|
||
|
|
local hightlightTexture = statusBar:CreateTexture("$parentTextureHighlight", "highlight")
|
||
|
|
hightlightTexture:SetColorTexture(1, 1, 1, 0.2)
|
||
|
|
hightlightTexture:SetAllPoints()
|
||
|
|
statusBar.highlightTexture = hightlightTexture
|
||
|
|
|
||
|
|
--button to expand the bar when there's spells merged
|
||
|
|
---@type breakdownexpandbutton
|
||
|
|
local expandButton = CreateFrame("button", "$parentExpandButton", spellBar, "BackdropTemplate")
|
||
|
|
expandButton:SetSize(CONST_BAR_HEIGHT, CONST_BAR_HEIGHT)
|
||
|
|
expandButton:RegisterForClicks("LeftButtonDown")
|
||
|
|
spellBar.expandButton = expandButton
|
||
|
|
|
||
|
|
---@type texture
|
||
|
|
local expandButtonTexture = expandButton:CreateTexture("$parentTexture", "artwork")
|
||
|
|
expandButtonTexture:SetPoint("center", expandButton, "center", 0, 0)
|
||
|
|
expandButtonTexture:SetSize(CONST_BAR_HEIGHT-2, CONST_BAR_HEIGHT-2)
|
||
|
|
expandButton.texture = expandButtonTexture
|
||
|
|
|
||
|
|
--frame which will show the spell tooltip
|
||
|
|
---@type frame
|
||
|
|
local spellIconFrame = CreateFrame("frame", "$parentIconFrame", spellBar, "BackdropTemplate")
|
||
|
|
spellIconFrame:SetSize(CONST_BAR_HEIGHT - 2, CONST_BAR_HEIGHT - 2)
|
||
|
|
spellIconFrame:SetScript("OnEnter", onEnterSpellIconFrame)
|
||
|
|
spellIconFrame:SetScript("OnLeave", onLeaveSpellIconFrame)
|
||
|
|
spellBar.spellIconFrame = spellIconFrame
|
||
|
|
|
||
|
|
--create the icon to show the spell texture
|
||
|
|
---@type texture
|
||
|
|
local spellIcon = spellIconFrame:CreateTexture("$parentTexture", "overlay")
|
||
|
|
spellIcon:SetAllPoints()
|
||
|
|
spellIcon:SetTexCoord(.1, .9, .1, .9)
|
||
|
|
spellBar.spellIcon = spellIcon
|
||
|
|
|
||
|
|
--create a square frame which is placed at the right side of the line to show which targets for damaged by the spell
|
||
|
|
---@type breakdowntargetframe
|
||
|
|
local targetsSquareFrame = CreateFrame("frame", "$parentTargetsFrame", statusBar, "BackdropTemplate")
|
||
|
|
targetsSquareFrame:SetSize(CONST_SPELLSCROLL_LINEHEIGHT, CONST_SPELLSCROLL_LINEHEIGHT)
|
||
|
|
targetsSquareFrame:SetAlpha(.7)
|
||
|
|
targetsSquareFrame:SetScript("OnEnter", onEnterSpellTarget)
|
||
|
|
targetsSquareFrame:SetScript("OnLeave", onLeaveSpellTarget)
|
||
|
|
targetsSquareFrame:SetFrameLevel(statusBar:GetFrameLevel()+2)
|
||
|
|
spellBar.targetsSquareFrame = targetsSquareFrame
|
||
|
|
|
||
|
|
---@type texture
|
||
|
|
local targetTexture = targetsSquareFrame:CreateTexture("$parentTexture", "overlay")
|
||
|
|
targetTexture:SetTexture(CONST_TARGET_TEXTURE)
|
||
|
|
targetTexture:SetAllPoints()
|
||
|
|
targetTexture:SetDesaturated(true)
|
||
|
|
spellBar.targetsSquareTexture = targetTexture
|
||
|
|
targetsSquareFrame.texture = targetTexture
|
||
|
|
|
||
|
|
spellBar:AddFrameToHeaderAlignment(spellIconFrame)
|
||
|
|
spellBar:AddFrameToHeaderAlignment(targetsSquareFrame)
|
||
|
|
|
||
|
|
--create texts
|
||
|
|
---@type fontstring[]
|
||
|
|
spellBar.InLineTexts = {}
|
||
|
|
|
||
|
|
for i = 1, 16 do
|
||
|
|
---@type fontstring
|
||
|
|
local fontString = spellBar:CreateFontString("$parentFontString" .. i, "overlay", "GameFontHighlightSmall")
|
||
|
|
fontString:SetJustifyH("left")
|
||
|
|
fontString:SetTextColor(1, 1, 1, 1)
|
||
|
|
fontString:SetNonSpaceWrap(true)
|
||
|
|
fontString:SetWordWrap(false)
|
||
|
|
spellBar["lineText" .. i] = fontString
|
||
|
|
spellBar.InLineTexts[i] = fontString
|
||
|
|
fontString:SetTextColor(1, 1, 1, 1)
|
||
|
|
spellBar:AddFrameToHeaderAlignment(fontString)
|
||
|
|
end
|
||
|
|
|
||
|
|
spellBar:AlignWithHeader(self.Header, "left")
|
||
|
|
return spellBar
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------------------------------------------------------------------
|
||
|
|
--> create the new tab
|
||
|
|
function Details.InitializeSpellBreakdownTab()
|
||
|
|
local tabButton, tabFrame = Details:CreatePlayerDetailsTab(
|
||
|
|
"Summary", --[1] tab name
|
||
|
|
Loc ["STRING_SPELLS"], --[2] localized name
|
||
|
|
function(tabOBject, playerObject) --[3] condition
|
||
|
|
if (playerObject) then
|
||
|
|
return true
|
||
|
|
else
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end,
|
||
|
|
|
||
|
|
function() --[4] fill function | passing a fill function, it'll set a OnShow() script on the tabFrame | only run if the actor is different
|
||
|
|
spellsTab.OnShownTab()
|
||
|
|
end,
|
||
|
|
|
||
|
|
function(tabButton, tabFrame) --[5] onclick
|
||
|
|
tabFrame:Show()
|
||
|
|
end,
|
||
|
|
|
||
|
|
spellsTab.OnCreateTabCallback, --[6] oncreate
|
||
|
|
iconTableSummary, --[7] icon table
|
||
|
|
nil, --[8] replace tab
|
||
|
|
true --[9] is default tab
|
||
|
|
)
|
||
|
|
|
||
|
|
spellsTab.TabButton = tabButton
|
||
|
|
spellsTab.TabFrame = tabFrame
|
||
|
|
|
||
|
|
---on receive data from a class
|
||
|
|
---@param data breakdownspelldatalist
|
||
|
|
---@param actorObject actor
|
||
|
|
---@param combatObject combat
|
||
|
|
---@param instance instance
|
||
|
|
function tabButton.OnReceiveSpellData(data, actorObject, combatObject, instance)
|
||
|
|
spellsTab.currentActor = actorObject
|
||
|
|
spellsTab.combatObject = combatObject
|
||
|
|
spellsTab.instance = instance
|
||
|
|
|
||
|
|
---@type number, number
|
||
|
|
local mainAttribute, subAttribute = instance:GetDisplay()
|
||
|
|
spellsTab.mainAttribute = mainAttribute
|
||
|
|
spellsTab.subAttribute = subAttribute
|
||
|
|
|
||
|
|
--show the regular containers
|
||
|
|
spellsTab.GetSpellScrollContainer():Show()
|
||
|
|
spellsTab.GetPhaseScrollContainer():Show()
|
||
|
|
spellsTab.GetTargetScrollContainer():Show()
|
||
|
|
|
||
|
|
--hide the generic container
|
||
|
|
spellsTab.GetGenericScrollContainer():Hide()
|
||
|
|
|
||
|
|
--refresh the data
|
||
|
|
spellsTab.GetSpellScrollFrame():RefreshMe(data)
|
||
|
|
spellsTab.GetPhaseScrollFrame():RefreshMe(data)
|
||
|
|
end
|
||
|
|
|
||
|
|
---@param data breakdowntargettablelist
|
||
|
|
---@param actorObject actor
|
||
|
|
---@param combatObject combat
|
||
|
|
---@param instance instance
|
||
|
|
function tabButton.OnReceiveTargetData(data, actorObject, combatObject, instance)
|
||
|
|
---@type number, number
|
||
|
|
local mainAttribute, subAttribute = instance:GetDisplay()
|
||
|
|
spellsTab.mainAttribute = mainAttribute
|
||
|
|
spellsTab.subAttribute = subAttribute
|
||
|
|
spellsTab.GetTargetScrollFrame():RefreshMe(data)
|
||
|
|
end
|
||
|
|
|
||
|
|
---when the window handler sends data which is not a spell or target data
|
||
|
|
---@param data table
|
||
|
|
---@param actorObject actor
|
||
|
|
---@param combatObject combat
|
||
|
|
---@param instance instance
|
||
|
|
function tabButton.OnReceiveGenericData(data, actorObject, combatObject, instance)
|
||
|
|
---@type number, number
|
||
|
|
local mainAttribute, subAttribute = instance:GetDisplay()
|
||
|
|
spellsTab.mainAttribute = mainAttribute
|
||
|
|
spellsTab.subAttribute = subAttribute
|
||
|
|
|
||
|
|
if (spellsTab.headersAllowed ~= data.headersAllowed) then
|
||
|
|
--refresh the header frame
|
||
|
|
spellsTab.UpdateHeadersSettings("generic")
|
||
|
|
--bug: now allowing to sort
|
||
|
|
end
|
||
|
|
|
||
|
|
--when generic data is shown, the damage-healing-targets-scrolls / spell details blocks/ can be removed
|
||
|
|
spellsTab.GetSpellScrollContainer():Hide()
|
||
|
|
spellsTab.GetPhaseScrollContainer():Hide()
|
||
|
|
spellsTab.GetTargetScrollContainer():Hide()
|
||
|
|
|
||
|
|
--show the generic scroll
|
||
|
|
spellsTab.GetGenericScrollContainer():Show()
|
||
|
|
|
||
|
|
--refresh the data
|
||
|
|
spellsTab.GetGenericScrollFrame():RefreshMe(data)
|
||
|
|
end
|
||
|
|
|
||
|
|
---@type detailseventlistener
|
||
|
|
local eventListener = Details:CreateEventListener()
|
||
|
|
eventListener:RegisterEvent("DETAILS_PROFILE_APPLYED", function()
|
||
|
|
--this event don't trigger at details startup
|
||
|
|
spellsTab.OnProfileChange()
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------------------------------------------------------------------
|
||
|
|
--> report data
|
||
|
|
|
||
|
|
function spellsTab.CreateReportButtons(tabFrame) --deprecated?
|
||
|
|
--spell list report button
|
||
|
|
tabFrame.report_esquerda = Details.gump:NewDetailsButton(tabFrame, tabFrame, nil, Details.Reportar, tabFrame, 1, 16, 16, "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", nil, "DetailsJanelaInfoReport2")
|
||
|
|
tabFrame.report_esquerda:SetPoint("bottomleft", spellsTab.GetSpellScrollFrame(), "TOPLEFT", 33, 3)
|
||
|
|
tabFrame.report_esquerda:SetFrameLevel(tabFrame:GetFrameLevel()+2)
|
||
|
|
tabFrame.topleft_report = tabFrame.report_esquerda
|
||
|
|
|
||
|
|
--targets report button
|
||
|
|
tabFrame.report_alvos = Details.gump:NewDetailsButton(tabFrame, tabFrame, nil, Details.Reportar, tabFrame, 3, 16, 16, "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", nil, "DetailsJanelaInfoReport3")
|
||
|
|
tabFrame.report_alvos:SetPoint("bottomright", tabFrame.container_alvos, "TOPRIGHT", -2, -1)
|
||
|
|
tabFrame.report_alvos:SetFrameLevel(3) --solved inactive problem
|
||
|
|
|
||
|
|
--special barras in the right report button
|
||
|
|
tabFrame.report_direita = Details.gump:NewDetailsButton(tabFrame, tabFrame, nil, Details.Reportar, tabFrame, 2, 16, 16, "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", "Interface\\COMMON\\VOICECHAT-ON", nil, "DetailsJanelaInfoReport4")
|
||
|
|
tabFrame.report_direita:SetPoint("TOPRIGHT", tabFrame, "TOPRIGHT", -10, -70)
|
||
|
|
tabFrame.report_direita:Show()
|
||
|
|
end
|
||
|
|
|
||
|
|
function spellsTab.monta_relatorio(botao) --deprecated?
|
||
|
|
---@type attributeid
|
||
|
|
local mainSection = breakdownWindow.atributo
|
||
|
|
---@type attributeid
|
||
|
|
local subSection = breakdownWindow.sub_atributo
|
||
|
|
---@type actor
|
||
|
|
local player = breakdownWindow.jogador
|
||
|
|
---@type instance
|
||
|
|
local instance = breakdownWindow.instancia
|
||
|
|
---@type number
|
||
|
|
local amt = Details.report_lines
|
||
|
|
|
||
|
|
local tabFrame = spellsTab.TabFrame
|
||
|
|
|
||
|
|
if (not player) then
|
||
|
|
Details:Msg("Player not found.")
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local report_lines
|
||
|
|
|
||
|
|
if (botao == 1) then --spell data
|
||
|
|
if (mainSection == 1 and subSection == 4) then --friendly fire
|
||
|
|
report_lines = {"Details!: " .. player.nome .. " " .. Loc ["STRING_ATTRIBUTE_DAMAGE_FRIENDLYFIRE"] .. ":"}
|
||
|
|
|
||
|
|
elseif (mainSection == 1 and subSection == 3) then --damage taken
|
||
|
|
report_lines = {"Details!: " .. player.nome .. " " .. Loc ["STRING_ATTRIBUTE_DAMAGE_TAKEN"] .. ":"}
|
||
|
|
|
||
|
|
else
|
||
|
|
report_lines = {"Details!: " .. player.nome .. " - " .. Details.sub_atributos [mainSection].lista [subSection] .. ""}
|
||
|
|
end
|
||
|
|
|
||
|
|
for index, barra in ipairs(tabFrame.barras1) do
|
||
|
|
if (barra:IsShown()) then
|
||
|
|
local spellid = barra.show
|
||
|
|
if (mainSection == 1 and subSection == 4) then --friendly fire
|
||
|
|
report_lines [#report_lines+1] = barra.lineText1:GetText() .. ": " .. barra.lineText4:GetText()
|
||
|
|
|
||
|
|
elseif (type(spellid) == "number" and spellid > 10) then
|
||
|
|
local link = GetSpellLink(spellid)
|
||
|
|
report_lines [#report_lines+1] = index .. ". " .. link .. ": " .. barra.lineText4:GetText()
|
||
|
|
else
|
||
|
|
local spellname = barra.lineText1:GetText():gsub((".*%."), "")
|
||
|
|
spellname = spellname:gsub("|c%x%x%x%x%x%x%x%x", "")
|
||
|
|
spellname = spellname:gsub("|r", "")
|
||
|
|
report_lines [#report_lines+1] = index .. ". " .. spellname .. ": " .. barra.lineText4:GetText()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (index == amt) then
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
elseif (botao == 3) then --targets
|
||
|
|
if (mainSection == 1 and subSection == 3) then
|
||
|
|
Details:Msg(Loc ["STRING_ACTORFRAME_NOTHING"])
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
report_lines = {"Details! " .. Loc ["STRING_ACTORFRAME_REPORTTARGETS"] .. " " .. Details.sub_atributos [1].lista [1] .. " " .. Loc ["STRING_ACTORFRAME_REPORTOF"] .. " " .. player.nome}
|
||
|
|
|
||
|
|
for index, barra in ipairs(tabFrame.barras2) do
|
||
|
|
if (barra:IsShown()) then
|
||
|
|
report_lines[#report_lines+1] = barra.lineText1:GetText().. " -> " .. barra.lineText4:GetText()
|
||
|
|
end
|
||
|
|
if (index == amt) then
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
elseif (botao == 2) then --spell blocks
|
||
|
|
--dano --damage done --dps --heal
|
||
|
|
if ((mainSection == 1 and (subSection == 1 or subSection == 2)) or (mainSection == 2)) then
|
||
|
|
if (not player.detalhes) then
|
||
|
|
Details:Msg(Loc ["STRING_ACTORFRAME_NOTHING"])
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local nome = _GetSpellInfo(player.detalhes)
|
||
|
|
|
||
|
|
report_lines = {"Details! " .. Loc ["STRING_ACTORFRAME_REPORTTO"] .. " " .. Details.sub_atributos [mainSection].lista [subSection] .. " " .. Loc ["STRING_ACTORFRAME_REPORTOF"] .. " " .. player.nome,
|
||
|
|
Loc ["STRING_ACTORFRAME_SPELLDETAILS"] .. ": " .. nome}
|
||
|
|
|
||
|
|
for i = 1, 5 do
|
||
|
|
local caixa = Details.playerDetailWindow.grupos_detalhes[i]
|
||
|
|
if (caixa.bg:IsShown()) then
|
||
|
|
|
||
|
|
local linha = ""
|
||
|
|
|
||
|
|
local nome2 = caixa.nome2:GetText() --golpes
|
||
|
|
if (nome2 and nome2 ~= "") then
|
||
|
|
if (i == 1) then
|
||
|
|
linha = linha..nome2 .. " / "
|
||
|
|
else
|
||
|
|
linha = linha .. caixa.nome:GetText() .. " " .. nome2 .. " / "
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local dano = caixa.dano:GetText() --dano
|
||
|
|
if (dano and dano ~= "") then
|
||
|
|
linha = linha .. dano .. " / "
|
||
|
|
end
|
||
|
|
|
||
|
|
local media = caixa.dano_media:GetText() --media
|
||
|
|
if (media and media ~= "") then
|
||
|
|
linha = linha..media .. " / "
|
||
|
|
end
|
||
|
|
|
||
|
|
local dano_dps = caixa.dano_dps:GetText()
|
||
|
|
if (dano_dps and dano_dps ~= "") then
|
||
|
|
linha = linha..dano_dps.." / "
|
||
|
|
end
|
||
|
|
|
||
|
|
local dano_porcento = caixa.dano_porcento:GetText()
|
||
|
|
if (dano_porcento and dano_porcento ~= "") then
|
||
|
|
linha = linha..dano_porcento.." "
|
||
|
|
end
|
||
|
|
|
||
|
|
report_lines [#report_lines+1] = linha
|
||
|
|
end
|
||
|
|
|
||
|
|
if (i == amt) then
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--dano --damage tanken
|
||
|
|
elseif ( (mainSection == 1 and subSection == 3) or mainSection == 3) then
|
||
|
|
if (player.detalhes) then
|
||
|
|
report_lines = {"Details! " .. Loc ["STRING_ACTORFRAME_REPORTTO"] .. " " .. Details.sub_atributos [1].lista [1] .. " " .. Loc ["STRING_ACTORFRAME_REPORTOF"] .. " " .. player.detalhes.. " " .. Loc ["STRING_ACTORFRAME_REPORTAT"] .. " " .. player.nome}
|
||
|
|
for index, barra in ipairs(tabFrame.barras3) do
|
||
|
|
if (barra:IsShown()) then
|
||
|
|
report_lines [#report_lines+1] = barra.lineText1:GetText() .. " ....... " .. barra.lineText4:GetText()
|
||
|
|
end
|
||
|
|
if (index == amt) then
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
report_lines = {}
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
elseif (botao >= 11) then --primeira caixa dos detalhes
|
||
|
|
botao = botao - 10
|
||
|
|
|
||
|
|
local nome
|
||
|
|
if (type(spellid) == "string") then --unknown spellid value
|
||
|
|
--is a pet
|
||
|
|
else
|
||
|
|
nome = _GetSpellInfo(player.detalhes)
|
||
|
|
local spelllink = GetSpellLink(player.detalhes)
|
||
|
|
if (spelllink) then
|
||
|
|
nome = spelllink
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if (not nome) then
|
||
|
|
nome = ""
|
||
|
|
end
|
||
|
|
|
||
|
|
report_lines = {"Details! " .. Loc ["STRING_ACTORFRAME_REPORTTO"] .. " " .. Details.sub_atributos [mainSection].lista [subSection].. " " .. Loc ["STRING_ACTORFRAME_REPORTOF"] .. " " .. player.nome,
|
||
|
|
Loc ["STRING_ACTORFRAME_SPELLDETAILS"] .. ": " .. nome}
|
||
|
|
|
||
|
|
local caixa = Details.playerDetailWindow.grupos_detalhes[botao]
|
||
|
|
|
||
|
|
local linha = ""
|
||
|
|
local nome2 = caixa.nome2:GetText() --golpes
|
||
|
|
if (nome2 and nome2 ~= "") then
|
||
|
|
if (botao == 1) then
|
||
|
|
linha = linha .. nome2 .. " / "
|
||
|
|
else
|
||
|
|
linha = linha .. caixa.nome:GetText() .. " " .. nome2 .. " / "
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local dano = caixa.dano:GetText() --dano
|
||
|
|
if (dano and dano ~= "") then
|
||
|
|
linha = linha..dano.." / "
|
||
|
|
end
|
||
|
|
|
||
|
|
local media = caixa.dano_media:GetText() --media
|
||
|
|
if (media and media ~= "") then
|
||
|
|
linha = linha..media.." / "
|
||
|
|
end
|
||
|
|
|
||
|
|
local dano_dps = caixa.dano_dps:GetText()
|
||
|
|
if (dano_dps and dano_dps ~= "") then
|
||
|
|
linha = linha..dano_dps.." / "
|
||
|
|
end
|
||
|
|
|
||
|
|
local dano_porcento = caixa.dano_porcento:GetText()
|
||
|
|
if (dano_porcento and dano_porcento ~= "") then
|
||
|
|
linha = linha..dano_porcento.." "
|
||
|
|
end
|
||
|
|
|
||
|
|
--remove a cor da school
|
||
|
|
linha = linha:gsub("|c%x?%x?%x?%x?%x?%x?%x?%x?", "")
|
||
|
|
linha = linha:gsub("|r", "")
|
||
|
|
|
||
|
|
report_lines [#report_lines+1] = linha
|
||
|
|
end
|
||
|
|
|
||
|
|
return instance:envia_relatorio(report_lines)
|
||
|
|
end
|