Files
coa-details/frames/window_playerbreakdown_spells.lua
T
2023-04-30 23:23:56 -03:00

2553 lines
93 KiB
Lua

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 GetCursorPosition = GetCursorPosition
local CreateFrame = CreateFrame
local GetSpellLink = GetSpellLink
local _GetSpellInfo = Details.GetSpellInfo
local GameTooltip = GameTooltip
local IsShiftKeyDown = IsShiftKeyDown
local DF = DetailsFramework
---@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 spellBreakdownSettings = {}
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
---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 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
function spellsTab.OnProfileChange()
--no need to cache, just call the db from there
spellsTab.UpdateHeadersSettings("spells")
spellsTab.UpdateHeadersSettings("targets")
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
---@class headercolumndatasaved : {enabled: boolean, width: number, align: string}
local settingsPrototype = {
enabled = true,
width = 100,
align = "left",
}
---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 = "left", enabled = true, offset = columnOffset, dataType = "number"},
{name = "expand", label = "^", width = 16, align = "center", enabled = true, offset = columnOffset},
{name = "name", label = "spell name", width = 246, 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 = true, 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 = true, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
{name = "critpercent", label = "crit %", key = "critpercent", width = 40, align = "left", enabled = true, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
{name = "hits", label = "hits", key = "counter", width = 40, align = "left", enabled = true, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
{name = "castavg", label = "cast avg", key = "castavg", width = 50, align = "left", enabled = true, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
{name = "uptime", label = "uptime", key = "uptime", width = 45, align = "left", enabled = true, canSort = true, offset = columnOffset, order = "DESC", dataType = "number"},
{name = "overheal", label = "overheal", key = "overheal", width = 55, align = "left", enabled = false, 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 = 200, 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 = 50, 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"},
}
---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"
local containerType = headerContainerType[headerFrame]
---@type table
local settings
if (containerType == "spells") then
settings = Details.breakdown_spell_tab.spellcontainer_headers
elseif (containerType == "targets") then
settings = Details.breakdown_spell_tab.targetcontainer_headers
end
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]
if (containerType == "spells") then
spellsTab.GetSpellScrollFrame():Refresh()
elseif (containerType == "targets") then
spellsTab.GetTargetScrollFrame():Refresh()
end
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"
function spellsTab.UpdateHeadersSettings(containerType)
---details table which hold the settings for a container header
---@type table
local settings
---@type table
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
end
--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("spells")
spellsTab.GetSpellScrollFrame().Header:SetHeaderTable(spellsTab.spellsHeaderData)
elseif (containerType == "targets") then
spellsTab.targetsHeaderData = spellsTab.BuildHeaderTable("targets")
spellsTab.GetTargetScrollFrame().Header:SetHeaderTable(spellsTab.targetsHeaderData)
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"
---@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
---@type table
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
end
for i = 1, #containerColumnData do
local columnData = containerColumnData[i]
---@type {enabled: boolean, width: number, align: string}
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,
}
headerTable[#headerTable+1] = headerColumnData
end
end
end
return headerTable
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")
end
---called when the tab is getting created, run only once
---@param tabButton button
---@param tabFrame breakdownspellstab
function spellsTab.OnCreateTabCallback(tabButton, tabFrame) --~init
spellBreakdownSettings = Details.breakdown_spell_tab
DetailsFramework:ApplyStandardBackdrop(tabFrame)
--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 the report buttons for each container
--spellsTab.CreateReportButtons(tabFrame)
spellsTab.TabFrame = tabFrame
--create a button in the breakdown window to open the options for this tab
local optionsButton = DF:CreateButton(Details.playerDetailWindow, Details.OpenSpellBreakdownOptions, 130, 20, "Open Options", 10, nil, nil, nil, nil, nil, DF:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE"))
optionsButton:SetPoint("topleft", Details.playerDetailWindow, "topleft", 210, -45)
optionsButton.textsize = 15
optionsButton.textcolor = "white"
--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 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 spelltable
local spellTable = spellBar.spellTable
if (IsShiftKeyDown()) then
if (type(spellId) == "number") then
GameCooltip:Preset(2)
GameCooltip:SetOwner(spellBar, "ANCHOR_TOPRIGHT")
GameCooltip:AddLine(Loc ["ABILITY_ID"] .. ": " .. spellBar.spellId)
GameCooltip:Show()
end
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 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 --this should run within the damage class ~damage
local bShowDamageDone = subAttribute == DETAILS_SUBATTRIBUTE_DAMAGEDONE or subAttribute == DETAILS_SUBATTRIBUTE_DPS
---@type number
local totalHits = spellTable.counter
--damage section showing damage 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_DAMAGE"]..": " .. 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_DPS"] .. ": " .. 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_DPS"] .. ": " .. 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 = Details.SpellTableMixin.GetCritPercent(spellTable)
critHitsBlock:SetValue(percent)
critHitsBlock.sparkTexture:SetPoint("left", critHitsBlock, "left", percent / 100 * critHitsBlock:GetWidth() + spellBreakdownSettings.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 = Details.SpellTableMixin.GetCritAverage(spellTable)
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_DPS"] .. ": " .. Details:CommaValue(spellTable.c_total / critTempoPercent))
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() + spellBreakdownSettings.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() + spellBreakdownSettings.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() + spellBreakdownSettings.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
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
spellBlock:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1})
local backgroundTexture = spellBlock:CreateTexture("$parentBackground", "artwork")
backgroundTexture:SetColorTexture(1, 1, 1, 1)
backgroundTexture:SetAllPoints()
spellBlock.backgroundTexture = backgroundTexture
--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
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(spellBreakdownSettings.blockspell_spark_width, blockHeight)
spellBlock.sparkTexture:SetShown(spellBreakdownSettings.blockspell_spark_show)
spellBlock.sparkTexture:SetVertexColor(unpack(spellBreakdownSettings.blockspell_spark_color))
spellBlock.reportButton:SetPoint("bottomright", spellBlock.overlay, "bottomright", -2, 2)
spellBlock.gradientTexture:SetHeight(blockHeight)
spellBlock:SetBackdropBorderColor(unpack(borderColor)) --border color
spellBlock.backgroundTexture:SetVertexColor(unpack(backgroundColor)) --background color
spellBlock.statusBarTexture:SetVertexColor(unpack(Details.breakdown_spell_tab.blockspell_color)) --bar color
--update the lines
local previousLine
for o = 1, spellBlockContainerSettings.lineAmount do
---@type breakdownspellblockline
local line = spellBlock.Lines[o]
line:SetSize(width - 2, spellBreakdownSettings.blockspellline_height)
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.SpellBlocks do
---@type breakdownspellblock
local spellBlock = self.SpellBlocks[i]
spellBlock:Hide()
spellBlock:SetColor(unpack(CONST_SPELLBLOCK_DEFAULT_COLOR))
--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
end,
---get a breakdownspellblock from the container
---@param self breakdownspellblockframe
---@param index number
---@return breakdownspellblock
GetBlock = function(self, index)
return self.SpellBlocks[index]
end,
}
---create the spell blocks which shows the critical hits, normal hits, etc
---@param tabFrame tabframe
---@return breakdownspellblockframe
function spellsTab.CreateSpellBlockContainer(tabFrame) --~create
--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()
--get with of the container holding the spellscrollframe
local containerWidth = spellsTab.GetSpellScrollContainer():GetWidth()
--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 = {}
--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()
--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
local updateTargetBar = function(targetBar, index, combatObject, scrollFrame, headerTable, bkTargetData, totalValue, topValue) --~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.statusBarValue / 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(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") then
text:SetText(Details:Format(bkTargetData.overheal or 0))
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 refreshFuncTargets = function(scrollFrame, scrollData, offset, totalLines) --~refresh ~target ~refreshtargets
---@type number
local maxValue = scrollFrame.maxValue
---@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 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, maxValue)
end
end
if (lineIndex > totalLines) then
break
end
end
end
end
---create the target container
---@param tabFrame tabframe
---@return breakdowntargetscrollframe
function spellsTab.CreateTargetContainer(tabFrame) --~create ~target
---@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
local lineAmount = math.floor(currentHeight / CONST_SPELLSCROLL_LINEHEIGHT)
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, "$parentSpellScroll", refreshFuncTargets, {}, 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
---@param data breakdowntargettablelist
function targetScrollFrame:RefreshMe(data) --~refreshme (targets) ~refreshmetargets
--get which column is currently selected and the sort order
local columnIndex, order, key = targetScrollFrame.Header:GetSelectedColumn()
---@type string
local keyToSort = key
for i = 1, #data do
---@type spelltableadv
local bkSpellData = data[i]
bkSpellData.statusBarValue = bkSpellData[keyToSort]
end
if (order == "DESC") then
table.sort(data,
function(t1, t2)
return t1[keyToSort] > t2[keyToSort]
end)
targetScrollFrame.maxValue = data[1] and data[1][keyToSort]
else
table.sort(data,
function(t1, t2)
return t1[keyToSort] < t2[keyToSort]
end)
targetScrollFrame.maxValue = 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,
}
---@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 = tabFrame: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.spellId, not bIsSpellExpaded)
--refresh the scrollFrame
scrolFrame:Refresh()
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 bkSpellStableIndex 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
local updateSpellBar = function(spellBar, index, actorName, combatObject, scrollFrame, headerTable, bkSpellData, bkSpellStableIndex, totalValue, topValue, bIsMainLine)
--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
local petName = ""
spellBar.bkSpellData = bkSpellData
if (bIsMainLine) then
spellTable = bkSpellData
value = bkSpellData.total
spellId = bkSpellData.id
petName = bkSpellData.petNames[bkSpellStableIndex]
else
spellTable = bkSpellData.spellTables[bkSpellStableIndex]
value = spellTable.total
spellId = spellTable.id
petName = bkSpellData.petNames[bkSpellStableIndex]
spellBar.bIsExpandedSpell = true
end
spellBar.spellId = spellId
---@cast spellTable spelltable
spellBar.spellTable = spellTable
---@type string, number, string
local spellName, _, spellIcon = Details.GetSpellInfo(spellId)
---@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()
if (petName ~= "") then
spellName = spellName .. " (" .. petName .. ")"
end
spellBar.spellId = spellId
spellBar.spellIconFrame.spellId = spellId
spellBar.statusBar.backgroundTexture:SetAlpha(Details.breakdown_spell_tab.spellbar_background_alpha)
--statusbar size by percent
if (topValue > 0) then
spellBar.statusBar:SetValue(bkSpellData.statusBarValue / topValue * 100)
else
spellBar.statusBar:SetValue(0)
end
--statusbar color by school
--print("spell school:", spellTable.spellschool) --healing has the spellschool not filled, it's nil
local r, g, b = Details:GetSpellSchoolColor(spellTable.spellschool or 1)
spellBar.statusBar:SetStatusBarColor(r, g, b, 1)
spellBar.average = value / spellTable.counter
spellBar.combatTime = combatTime
---@type fontstring
local text = spellBar.InLineTexts[textIndex]
local header = headerTable[headerIndex]
if (header.name == "icon") then --ok
spellBar.spellIcon:Show()
spellBar.spellIcon:SetTexture(spellIcon)
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 --ok
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(spellId)
spellBar.expandButton.spellId = spellId
spellBar.expandButton.bIsSpellExpaded = bIsSpellExpaded
spellBar.expandButton:SetScript("OnClick", onClickExpandButton)
--update the texture taking the state of the expanded value
spellBar.expandButton.texture:SetTexture(bIsSpellExpaded and [[Interface\BUTTONS\Arrow-Up-Down]] or [[Interface\BUTTONS\Arrow-Down-Down]])
end
elseif (header.name == "name") then --ok
text:SetText(spellName)
spellBar.name = spellName
spellBar:AddFrameToHeaderAlignment(text)
textIndex = textIndex + 1
elseif (header.name == "amount") then --ok
text:SetText(Details:Format(value))
spellBar:AddFrameToHeaderAlignment(text)
textIndex = textIndex + 1
elseif (header.name == "persecond") then --ok
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 --ok
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") then
text:SetText(Details:Format(spellTable.overheal or 0))
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()
--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 refreshFunc = function(scrollFrame, scrollData, offset, totalLines) --~refreshspells ~refreshfunc ~refresh
---@type number
local maxValue = scrollFrame.maxValue
---@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 headerTable = spellsTab.spellsHeaderData
--todo: when swapping sort orders, close allexpanded spells
local lineIndex = 1
for i = 1, totalLines do
local index = i + offset
---@type spelltableadv
local bkSpellData = scrollData[index]
if (bkSpellData) then
--before getting a line, check if the data for the line is a expanded line and if the spell is expanded
local expandedIndex = bkSpellData.expandedIndex
local spellId = bkSpellData.id
local value = math.floor(bkSpellData.total)
---@type number[]
local spellIds = bkSpellData.spellIds --array with spellIds
---@type spelltable[]
local spellTables = bkSpellData.spellTables --array with spellTables
---@type number
local spellTablesAmount = #spellTables
---@type string[]
local petNames = bkSpellData.petNames --array with pet names
---@type boolean
---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
updateSpellBar(mainSpellBar, index, actorName, combatObject, scrollFrame, headerTable, bkSpellData, 1, totalValue, maxValue, bIsMainLine)
end
end
--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
---@type number spellTableIndex is the same counter as bkSpellStableIndex
for spellTableIndex = 1, spellTablesAmount do
---@type breakdownspellbar
local spellBar = getSpellBar(scrollFrame, lineIndex)
if (spellBar) then
lineIndex = lineIndex + 1
---@type string
local petName = petNames[spellTableIndex]
---@type string
local nameToUse = petName ~= "" and petName or actorName
local bIsMainLine = false
updateSpellBar(spellBar, index, nameToUse, combatObject, scrollFrame, headerTable, bkSpellData, spellTableIndex, totalValue, maxValue, bIsMainLine)
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
---@type width
local width = Details.breakdown_spell_tab.spellcontainer_width
---@type height
local height = Details.breakdown_spell_tab.spellcontainer_height
--create a container for the scrollframe
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 = true,
}
---@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
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
local defaultAmountOfLines = 50
container:SetSettingChangedCallback(settingChangedCallbackFunction)
--replace this with a framework scrollframe
---@type breakdownspellscrollframe
local scrollFrame = DF:CreateScrollBox(container, "$parentSpellScroll", refreshFunc, {}, width, height, defaultAmountOfLines, CONST_SPELLSCROLL_LINEHEIGHT)
DF:ReskinSlider(scrollFrame)
scrollFrame:SetBackdrop({})
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
--~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,
}
local headerTable = {}
---@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 type of this container
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 any
---@param data breakdownspelldatalist
function scrollFrame:RefreshMe(data) --~refreshme (spells)
--get which column is currently selected and the sort order
local columnIndex, order, key = scrollFrame.Header:GetSelectedColumn()
---@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 in the order the header wants
for i = 1, #data do
---@type spelltableadv
local bkSpellData = data[i]
--crit percent
bkSpellData.critpercent = bkSpellData:GetCritPercent()
--cast amount
bkSpellData.casts = bkSpellData:GetCastAmount(spellsTab.GetActor():Name(), combatObject)
--cast avg
bkSpellData.castavg = bkSpellData:GetCastAverage(bkSpellData.casts)
--uptime
local uptime = combatObject:GetSpellUptime(spellsTab:GetActor():Name(), bkSpellData.id)
bkSpellData.uptime = uptime
if (mainAttribute == DETAILS_ATTRIBUTE_HEAL) then
bkSpellData.healabsorbed = bkSpellData.absorbed
end
bkSpellData.statusBarValue = bkSpellData[keyToSort]
end
if (order == "DESC") then
table.sort(data,
---@param t1 spelltableadv
---@param t2 spelltableadv
function(t1, t2)
return t1[keyToSort] > t2[keyToSort]
end)
self.maxValue = 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.maxValue = 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
---@type number @amount done of the target, at this point the code doesn't know if it's damage, healing, etc
local totalValue = targetBar.bkTargetData.statusBarValue
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", 0, y)
targetBar:SetPoint("topright", self, "topright", 0, y)
targetBar:EnableMouse(true)
targetBar:SetAlpha(0.9)
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
---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
---@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", 0, y)
spellBar:SetPoint("topright", self, "topright", 0, y)
spellBar:EnableMouse(true)
spellBar:RegisterForClicks("AnyUp", "AnyDown")
spellBar:SetAlpha(0.9)
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")
statusBarTexture:SetTexture(SharedMedia:Fetch("statusbar", "Details Hyanda"))
statusBar:SetStatusBarTexture(statusBarTexture)
statusBar:SetStatusBarColor(1, 1, 1, 1)
---@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
---@type texture background texture
local backgroundTexture = statusBar:CreateTexture("$parentTextureBackground", "border")
backgroundTexture:SetAllPoints()
backgroundTexture:SetColorTexture(.05, .05, .05)
backgroundTexture:SetAlpha(1)
statusBar.backgroundTexture = backgroundTexture
--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
spellsTab.GetSpellScrollFrame():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
---@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, _detalhes.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, _detalhes.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, _detalhes.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 = _detalhes.report_lines
local tabFrame = spellsTab.TabFrame
if (not player) then
_detalhes: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 .. " - " .. _detalhes.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"] .. " " .. _detalhes.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"] .. " " .. _detalhes.sub_atributos [mainSection].lista [subSection] .. " " .. Loc ["STRING_ACTORFRAME_REPORTOF"] .. " " .. player.nome,
Loc ["STRING_ACTORFRAME_SPELLDETAILS"] .. ": " .. nome}
for i = 1, 5 do
local caixa = _detalhes.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"] .. " " .. _detalhes.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"] .. " " .. _detalhes.sub_atributos [mainSection].lista [subSection].. " " .. Loc ["STRING_ACTORFRAME_REPORTOF"] .. " " .. player.nome,
Loc ["STRING_ACTORFRAME_SPELLDETAILS"] .. ": " .. nome}
local caixa = _detalhes.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