update
This commit is contained in:
+1
-2
@@ -361,10 +361,9 @@
|
||||
---@field BreakdownPluginSelectionFrame frame frame which has buttons to select a plugin to show in the breakdown window
|
||||
---@field BreakdownTabsFrame frame where the tab buttons are located (parent frame)
|
||||
---@field RegisteredPluginButtons button[] table which contains plugins buttons that are registered to the breakdown window
|
||||
---@field RegisterPluginButton fun(button: button) register a plugin button to the breakdown window
|
||||
---@field RegisterPluginButton fun(button: button, pluginObject: table, pluginAbsolutename: string) register a plugin button to the breakdown window
|
||||
---@field GetShownPluginObject fun() : table get the plugin object that is currently shown in the breakdown window
|
||||
|
||||
|
||||
---@class breakdownscrolldata : table
|
||||
---@field totalValue number total done by the actor
|
||||
---@field combatTime number
|
||||
|
||||
@@ -37,7 +37,7 @@ if (WOW_PROJECT_ID ~= WOW_PROJECT_MAINLINE and not isExpansion_Dragonflight()) t
|
||||
end
|
||||
|
||||
local major = "LibOpenRaid-1.0"
|
||||
local CONST_LIB_VERSION = 103
|
||||
local CONST_LIB_VERSION = 104
|
||||
|
||||
if (not LIB_OPEN_RAID_MAX_VERSION) then
|
||||
LIB_OPEN_RAID_MAX_VERSION = CONST_LIB_VERSION
|
||||
|
||||
@@ -647,7 +647,8 @@ do
|
||||
[235219] = {cooldown = 300, duration = 0, specs = {64}, talent = false, charges = 1, class = "MAGE", type = 2}, --Cold Snap
|
||||
[190319] = {cooldown = 120, duration = 10, specs = {63}, talent = false, charges = 1, class = "MAGE", type = 1}, --Combustion
|
||||
[12051] = {cooldown = 90, duration = 6, specs = {62}, talent = false, charges = 1, class = "MAGE", type = 1}, --Evocation
|
||||
[110960] = {cooldown = 120, duration = 20, specs = {62}, talent = false, charges = 1, class = "MAGE", type = 2}, --Greater Invisibility | 110959
|
||||
--[110960] = {cooldown = 120, duration = 20, specs = {62}, talent = false, charges = 1, class = "MAGE", type = 2}, --Greater Invisibility | 110959
|
||||
[110959] = {cooldown = 120, duration = 20, specs = {62}, talent = false, charges = 1, class = "MAGE", type = 2}, --Greater Invisibility | 110959
|
||||
[11426] = {cooldown = 25, duration = 60, specs = {64}, talent = false, charges = 1, class = "MAGE", type = 2}, --Ice Barrier
|
||||
[45438] = {cooldown = 240, duration = 10, specs = {62, 63, 64}, talent = false, charges = 1, class = "MAGE", type = 2}, --Ice Block
|
||||
[12472] = {cooldown = 180, duration = 20, specs = {64}, talent = false, charges = 1, class = "MAGE", type = 1}, --Icy Veins
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
Details222.ClassCache.ByName = {}
|
||||
Details222.ClassCache.ByGUID = {}
|
||||
Details222.UnitIdCache = {}
|
||||
Details222.Roskash = {}
|
||||
|
||||
Details222.Actors = {}
|
||||
|
||||
|
||||
+58
-14
@@ -405,6 +405,7 @@ end
|
||||
|
||||
--total: amount of damage done
|
||||
total = alphabetical,
|
||||
extra_bar = 0,
|
||||
--totalabsorbed: amount of damage done absorbed by shields
|
||||
totalabsorbed = alphabetical,
|
||||
--total_without_pet: amount of damage done without pet damage
|
||||
@@ -2125,18 +2126,17 @@ function damageClass:RefreshWindow(instancia, combatObject, forcar, exportar, re
|
||||
instancia.top = actorTableContent[1] and actorTableContent[1][keyName]
|
||||
|
||||
elseif (windowMode == modo_ALL) then --mostrando ALL
|
||||
|
||||
--faz o sort da categoria e retorna o amount corrigido
|
||||
--print(keyName)
|
||||
if (subAttribute == 2) then
|
||||
local combat_time = instancia.showing:GetCombatTime()
|
||||
total = damageClass:ContainerRefreshDps (actorTableContent, combat_time)
|
||||
total = damageClass:ContainerRefreshDps(actorTableContent, combat_time)
|
||||
else
|
||||
--pega o total ja aplicado na tabela do combate
|
||||
total = combatObject.totals [class_type]
|
||||
total = combatObject.totals[class_type]
|
||||
end
|
||||
|
||||
amount = Details:ContainerSort (actorTableContent, amount, keyName)
|
||||
amount = Details:ContainerSort(actorTableContent, amount, keyName)
|
||||
|
||||
--grava o total
|
||||
instancia.top = actorTableContent[1][keyName]
|
||||
@@ -2589,10 +2589,11 @@ local actor_class_color_r, actor_class_color_g, actor_class_color_b
|
||||
perSecondText = perSecondText or ""
|
||||
percentText = percentText or ""
|
||||
|
||||
-- local actorSerial = thisLine:GetActor().serial
|
||||
-- local currentDps = Details.CurrentDps.GetCurrentDps(actorSerial) or perSecondText
|
||||
-- perSecondText = currentDps
|
||||
-- end
|
||||
if (Details.time_type == 3 and Details.in_combat) then --real time
|
||||
local actorSerial = thisLine:GetActor().serial
|
||||
local currentDps = Details.CurrentDps.GetCurrentDps(actorSerial) or perSecondText
|
||||
perSecondText = currentDps
|
||||
end
|
||||
|
||||
--check if the instance is showing total, dps and percent
|
||||
local instanceSettings = instance.row_info
|
||||
@@ -2628,7 +2629,7 @@ local actor_class_color_r, actor_class_color_g, actor_class_color_b
|
||||
end
|
||||
|
||||
-- ~atualizar ~barra ~update
|
||||
function damageClass:RefreshLine(instance, lineContainer, whichRowLine, rank, total, sub_atributo, forcar, keyName, combat_time, percentage_type, use_animations, bars_show_data, bars_brackets, bars_separator)
|
||||
function damageClass:RefreshLine(instance, lineContainer, whichRowLine, rank, total, sub_atributo, forcar, keyName, combat_time, percentage_type, bUseAnimations, bars_show_data, bars_brackets, bars_separator)
|
||||
local thisLine = lineContainer[whichRowLine]
|
||||
|
||||
if (not thisLine) then
|
||||
@@ -2888,11 +2889,34 @@ function damageClass:RefreshLine(instance, lineContainer, whichRowLine, rank, to
|
||||
|
||||
actor_class_color_r, actor_class_color_g, actor_class_color_b = self:GetBarColor()
|
||||
|
||||
return self:RefreshLineValue(thisLine, instance, previousData, forcar, percentNumber, whichRowLine, lineContainer, use_animations)
|
||||
return self:RefreshLineValue(thisLine, instance, previousData, forcar, percentNumber, whichRowLine, lineContainer, bUseAnimations)
|
||||
end
|
||||
|
||||
local alignExtraBar = function(thisLine, actorObject, instanceObject, percentAmount)
|
||||
local extraAmount = actorObject.extra_bar
|
||||
if (extraAmount > 0 and Details.combat_log.evoker_calc_damage) then
|
||||
local bIsUsingBarStartAfterIcon = instanceObject.row_info.start_after_icon
|
||||
local initialOffset = 0
|
||||
if (bIsUsingBarStartAfterIcon) then
|
||||
initialOffset = thisLine.icone_classe:GetWidth()
|
||||
end
|
||||
|
||||
local whiteBarStartOffset = initialOffset + thisLine:GetWidth() * percentAmount / 100
|
||||
local whiteBarWidth = (extraAmount / actorObject.total) * (percentAmount / 100) * thisLine:GetWidth()
|
||||
|
||||
thisLine.extraTexture:SetPoint("left", thisLine, "left", whiteBarStartOffset - 7, 0)
|
||||
thisLine.extraTexture:SetWidth(whiteBarWidth)
|
||||
|
||||
thisLine.extraTexture:SetHeight(thisLine:GetHeight())
|
||||
thisLine.extraTexture:Show()
|
||||
end
|
||||
end
|
||||
|
||||
function Details:RefreshLineValue(thisLine, instance, previousData, isForceRefresh, percent, whichRowLine, lineContainer, bUseAnimations) --[[ exported]]
|
||||
if (self.spec ~= 1473) then
|
||||
thisLine.extraTexture:Hide()
|
||||
end
|
||||
|
||||
function Details:RefreshLineValue(thisLine, instance, previousData, isForceRefresh, percent, whichRowLine, lineContainer, useAnimations) --[[ exported]]
|
||||
if (thisLine.colocacao == 1) then
|
||||
thisLine.animacao_ignorar = true
|
||||
|
||||
@@ -2910,7 +2934,7 @@ function Details:RefreshLineValue(thisLine, instance, previousData, isForceRefre
|
||||
else
|
||||
if (thisLine.hidden or thisLine.fading_in or thisLine.faded) then
|
||||
--setando o valor mesmo com anima��es pq o barra esta hidada com o value do �ltimo actor que ela mostrou
|
||||
if (useAnimations) then
|
||||
if (bUseAnimations and self.spec ~= 1473) then
|
||||
thisLine.animacao_fim = percent
|
||||
thisLine:SetValue(percent)
|
||||
else
|
||||
@@ -2920,11 +2944,15 @@ function Details:RefreshLineValue(thisLine, instance, previousData, isForceRefre
|
||||
|
||||
Details.FadeHandler.Fader(thisLine, "out")
|
||||
|
||||
if (self.spec == 1473) then
|
||||
alignExtraBar(thisLine, self, instance, percent)
|
||||
end
|
||||
|
||||
return self:RefreshBarra(thisLine, instance)
|
||||
else
|
||||
--agora esta comparando se a tabela da barra � diferente da tabela na atualiza��o anterior
|
||||
if (not previousData or previousData ~= thisLine.minha_tabela or isForceRefresh) then --aqui diz se a barra do jogador mudou de posi��o ou se ela apenas ser� atualizada
|
||||
if (useAnimations) then
|
||||
if (bUseAnimations and self.spec ~= 1473) then
|
||||
thisLine.animacao_fim = percent
|
||||
else
|
||||
thisLine:SetValue(percent)
|
||||
@@ -2933,17 +2961,25 @@ function Details:RefreshLineValue(thisLine, instance, previousData, isForceRefre
|
||||
|
||||
thisLine.last_value = percent --reseta o ultimo valor da barra
|
||||
|
||||
if (self.spec == 1473) then
|
||||
alignExtraBar(thisLine, self, instance, percent)
|
||||
end
|
||||
|
||||
return self:RefreshBarra(thisLine, instance)
|
||||
|
||||
elseif (percent ~= thisLine.last_value) then --continua mostrando a mesma tabela ent�o compara a porcentagem
|
||||
--apenas atualizar
|
||||
if (useAnimations) then
|
||||
if (bUseAnimations and self.spec ~= 1473) then
|
||||
thisLine.animacao_fim = percent
|
||||
else
|
||||
thisLine:SetValue(percent)
|
||||
end
|
||||
thisLine.last_value = percent
|
||||
|
||||
if (self.spec == 1473) then
|
||||
alignExtraBar(thisLine, self, instance, percent)
|
||||
end
|
||||
|
||||
return self:RefreshBarra(thisLine, instance)
|
||||
end
|
||||
end
|
||||
@@ -3044,6 +3080,14 @@ function Details:SetBarColors(bar, instance, r, g, b, a) --[[exported]]
|
||||
a = a or 1
|
||||
|
||||
if (instance.row_info.texture_class_colors) then
|
||||
if (self.classe == "UNGROUPPLAYER") then
|
||||
if (self.spec) then
|
||||
local specId, specName, specDescription, specIcon, specRole, specClass = DetailsFramework.GetSpecializationInfoByID(self.spec)
|
||||
if (specClass) then
|
||||
self.classe = specClass
|
||||
end
|
||||
end
|
||||
end
|
||||
bar.textura:SetVertexColor(r, g, b, a)
|
||||
end
|
||||
|
||||
|
||||
@@ -477,18 +477,30 @@ end
|
||||
end
|
||||
|
||||
if (actorFlags) then
|
||||
--check if the actor is a player
|
||||
if (bitBand(actorFlags, OBJECT_TYPE_PLAYER) ~= 0) then
|
||||
actorObject.classe = "UNGROUPPLAYER"
|
||||
return
|
||||
|
||||
elseif (bitBand(actorFlags, OBJECT_TYPE_PETGUARDIAN) ~= 0) then
|
||||
if (bitBand(actorFlags, OBJECT_TYPE_PETGUARDIAN) ~= 0) then
|
||||
actorObject.classe = "PET"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if (specId) then
|
||||
local specId, specName, specDescription, specIcon, specRole, specClass = DetailsFramework.GetSpecializationInfoByID(specId)
|
||||
if (specClass) then
|
||||
actorObject.classe = specClass
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if (actorFlags) then
|
||||
--check if the actor is a player
|
||||
if (bitBand(actorFlags, OBJECT_TYPE_PLAYER) ~= 0) then
|
||||
actorObject.classe = "UNGROUPPLAYER"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
actorObject.classe = "UNKNOW" --it's a typo, can't be changed at this point
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
+65
-32
@@ -580,7 +580,7 @@
|
||||
end
|
||||
|
||||
--~spell ~spelldamage
|
||||
function parser:spell_dmg(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetRaidFlags, spellId, spellName, spellType, amount, overkill, school, resisted, blocked, absorbed, critical, glacing, crushing, isoffhand, isreflected)
|
||||
function parser:spell_dmg(token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, targetRaidFlags, spellId, spellName, spellType, amount, overkill, school, resisted, blocked, absorbed, critical, glacing, crushing, isoffhand, isreflected, A1, A2, A3)
|
||||
--early checks and fixes
|
||||
if (sourceSerial == "") then
|
||||
if (sourceFlags and bitBand(sourceFlags, OBJECT_TYPE_PETS) ~= 0) then
|
||||
@@ -1181,7 +1181,19 @@
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------
|
||||
--amount add
|
||||
--amount add ~roskash
|
||||
if (Details222.Roskash[sourceSerial]) then
|
||||
local rSourceSerial, rSourceName, rSourceFlags = unpack(Details222.Roskash[sourceSerial])
|
||||
local roskashActor = damage_cache[rSourceSerial]
|
||||
|
||||
if (not roskashActor) then
|
||||
roskashActor = _current_damage_container:PegarCombatente(rSourceSerial, rSourceName, rSourceFlags, true)
|
||||
end
|
||||
|
||||
if (roskashActor) then
|
||||
roskashActor.extra_bar = roskashActor.extra_bar + (amount * 0.14)
|
||||
end
|
||||
end
|
||||
|
||||
--actor owner (if any)
|
||||
if (ownerActor) then --se for dano de um Pet
|
||||
@@ -2447,6 +2459,10 @@
|
||||
sourceSerial = ""
|
||||
end
|
||||
|
||||
if (spellId == 395152) then --~roskash
|
||||
Details222.Roskash[targetSerial] = {sourceSerial, sourceName, sourceFlags}
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------
|
||||
--spell reflection
|
||||
if (reflection_spellid[spellId]) then --~reflect
|
||||
@@ -2731,6 +2747,10 @@
|
||||
return
|
||||
end
|
||||
|
||||
if (spellid == 395152) then --~roskash
|
||||
Details222.Roskash[alvo_serial] = {sourceSerial, sourceName, sourceFlags}
|
||||
end
|
||||
|
||||
if (sourceName == alvo_name and raid_members_cache [sourceSerial] and _in_combat) then
|
||||
--call record buffs uptime
|
||||
parser:add_buff_uptime (token, time, sourceSerial, sourceName, sourceFlags, alvo_serial, alvo_name, alvo_flags, alvo_flags2, spellid, spellName, "BUFF_UPTIME_REFRESH")
|
||||
@@ -2800,36 +2820,40 @@
|
||||
end
|
||||
|
||||
if (tipo == "BUFF") then
|
||||
if (spellid == 272790 and cacheAnything.track_hunter_frenzy) then --hunter pet Frenzy spellid
|
||||
if (not pet_frenzy_cache[sourceName]) then
|
||||
return
|
||||
end
|
||||
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, sourceSerial, sourceName, sourceFlags, 0x0, spellid, spellName, "BUFF_UPTIME_OUT")
|
||||
pet_frenzy_cache[sourceName] = nil
|
||||
if (spellid == 395152) then --~roskash
|
||||
Details222.Roskash[targetSerial] = nil
|
||||
end
|
||||
|
||||
if (spellid == 272790 and cacheAnything.track_hunter_frenzy) then --hunter pet Frenzy spellid
|
||||
if (not pet_frenzy_cache[sourceName]) then
|
||||
return
|
||||
end
|
||||
parser:add_buff_uptime(token, time, sourceSerial, sourceName, sourceFlags, sourceSerial, sourceName, sourceFlags, 0x0, spellid, spellName, "BUFF_UPTIME_OUT")
|
||||
pet_frenzy_cache[sourceName] = nil
|
||||
return
|
||||
end
|
||||
|
||||
if (sourceName == targetName and raid_members_cache [sourceSerial] and _in_combat) then
|
||||
--call record buffs uptime
|
||||
parser:add_buff_uptime (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, alvo_flags2, spellid, spellName, "BUFF_UPTIME_OUT")
|
||||
elseif (container_pets [sourceSerial] and container_pets [sourceSerial][2] == targetSerial) then
|
||||
--um pet colocando uma aura do dono
|
||||
parser:add_buff_uptime (token, time, targetSerial, targetName, targetFlags, targetSerial, targetName, targetFlags, alvo_flags2, spellid, spellName, "BUFF_UPTIME_OUT")
|
||||
if (sourceName == targetName and raid_members_cache [sourceSerial] and _in_combat) then
|
||||
--call record buffs uptime
|
||||
parser:add_buff_uptime (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, alvo_flags2, spellid, spellName, "BUFF_UPTIME_OUT")
|
||||
elseif (container_pets [sourceSerial] and container_pets [sourceSerial][2] == targetSerial) then
|
||||
--um pet colocando uma aura do dono
|
||||
parser:add_buff_uptime (token, time, targetSerial, targetName, targetFlags, targetSerial, targetName, targetFlags, alvo_flags2, spellid, spellName, "BUFF_UPTIME_OUT")
|
||||
|
||||
elseif (buffs_to_other_players[spellid]) then
|
||||
parser:add_buff_uptime(token, time, targetSerial, targetName, targetFlags, targetSerial, targetName, targetFlags, alvo_flags2, spellid, spellName, "BUFF_UPTIME_OUT")
|
||||
elseif (buffs_to_other_players[spellid]) then
|
||||
parser:add_buff_uptime(token, time, targetSerial, targetName, targetFlags, targetSerial, targetName, targetFlags, alvo_flags2, spellid, spellName, "BUFF_UPTIME_OUT")
|
||||
end
|
||||
|
||||
if (spellid == SPELLID_MONK_GUARD) then
|
||||
--BfA monk talent
|
||||
if (monk_guard_talent [sourceSerial]) then
|
||||
local damage_prevented = monk_guard_talent [sourceSerial] - (amount or 0)
|
||||
parser:heal (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, alvo_flags2, spellid, spellName, spellSchool, damage_prevented, ceil (amount or 0), 0, 0, true)
|
||||
end
|
||||
|
||||
if (spellid == SPELLID_MONK_GUARD) then
|
||||
--BfA monk talent
|
||||
if (monk_guard_talent [sourceSerial]) then
|
||||
local damage_prevented = monk_guard_talent [sourceSerial] - (amount or 0)
|
||||
parser:heal (token, time, sourceSerial, sourceName, sourceFlags, targetSerial, targetName, targetFlags, alvo_flags2, spellid, spellName, spellSchool, damage_prevented, ceil (amount or 0), 0, 0, true)
|
||||
end
|
||||
|
||||
elseif (spellid == 388007 or spellid == 388011) then --buff: bleesing of the summer
|
||||
cacheAnything.paladin_vivaldi_blessings[targetSerial] = nil
|
||||
end
|
||||
elseif (spellid == 388007 or spellid == 388011) then --buff: bleesing of the summer
|
||||
cacheAnything.paladin_vivaldi_blessings[targetSerial] = nil
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------
|
||||
--shield overheal
|
||||
@@ -5934,14 +5958,20 @@ local SPELL_POWER_PAIN = SPELL_POWER_PAIN or (PowerEnum and PowerEnum.Pain) or 1
|
||||
end
|
||||
|
||||
local parserDebug = {}
|
||||
function Details.OnParserEventDebug()
|
||||
local time, token, hidding, who_serial, who_name, who_flags, who_flags2, target_serial, target_name, target_flags, target_flags2, spellId, spellName, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, unknown1, unknown2, unknown3, unknown4, unknown5 = CombatLogGetCurrentEventInfo()
|
||||
function Details.OnParserEventDebug() --buffs: spellschool, auraType, amount, arg1, arg2, arg3
|
||||
local time, token, hidding, sourceSerial, sourceName, sourceFlags, who_flags2, targetSerial, targetName, targetFlags, target_flags2, spellId, spellName, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, unknown1, unknown2, unknown3, unknown4, unknown5 = CombatLogGetCurrentEventInfo()
|
||||
|
||||
if (not parserDebug[token]) then
|
||||
parserDebug[token] = true
|
||||
print(token)
|
||||
end
|
||||
|
||||
if ( spellId == 409632 ) then
|
||||
--print(who_serial, who_name, who_flags, who_flags2, target_serial, target_name, target_flags, target_flags2, spellId, spellName, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, unknown1, unknown2, unknown3, unknown4, unknown5)
|
||||
elseif( spellId == 395160 ) then
|
||||
--print(who_serial, who_name, who_flags, who_flags2, target_serial, target_name, target_flags, target_flags2, spellId, spellName, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, unknown1, unknown2, unknown3, unknown4, unknown5)
|
||||
end
|
||||
|
||||
if (token == "SPELL_DAMAGE") then
|
||||
if (A13 ~= nil or unknown1 ~= nil or unknown2 ~= nil or unknown3 ~= nil or unknown4 ~= nil or unknown5) then
|
||||
--print(time, token, hidding, who_serial, who_name, who_flags, who_flags2, target_serial, target_name, target_flags, target_flags2, spellId, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)
|
||||
@@ -5988,7 +6018,7 @@ local SPELL_POWER_PAIN = SPELL_POWER_PAIN or (PowerEnum and PowerEnum.Pain) or 1
|
||||
["8"] = 5061347,
|
||||
--]=]
|
||||
|
||||
if (who_serial == UnitGUID("player")) then
|
||||
if (sourceSerial == UnitGUID("player")) then
|
||||
GLOB = GLOB or {}
|
||||
--table.insert(GLOB, {time, token, hidding, who_serial, who_name, who_flags, who_flags2, target_serial, target_name, target_flags, target_flags2, spellId, spellName, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18})
|
||||
--print(time, token, hidding, who_serial, who_name, who_flags, who_flags2, target_serial, target_name, target_flags, target_flags2, spellId, spellName, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18)
|
||||
@@ -6004,12 +6034,14 @@ local SPELL_POWER_PAIN = SPELL_POWER_PAIN or (PowerEnum and PowerEnum.Pain) or 1
|
||||
--print(time, token, hidding, who_serial, who_name, who_flags, who_flags2, target_serial, target_name, target_flags, target_flags2, spellId, spellName, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, unknown1, unknown2, unknown3, unknown4, unknown5)
|
||||
end
|
||||
|
||||
if (spellName== "Ebon Might") then
|
||||
--print(token, spellName, spellId)
|
||||
if (spellName == "Ebon Might") then
|
||||
--6/30 14:19:19.299 SPELL_AURA_REMOVED,Player-5764-00018FF1,"Termøhead-Iridikron",0x518,0x0,Player-5764-0001977A,"Drgndeesnutz-Fyrakk",0x518,0x0,395152,"Ebon Might",0xc,BUFF
|
||||
local spellschool, auraType, amount = A3, A4, A5
|
||||
print(token, spellName, sourceName, targetName, spellschool, auraType, amount, A6, A7, A8, A9, A10)
|
||||
end
|
||||
|
||||
if (token == "SPELL_CAST_START") then
|
||||
if (who_serial == UnitGUID("player")) then
|
||||
if (sourceSerial == UnitGUID("player")) then
|
||||
--print(token, spellName, spellId)
|
||||
end
|
||||
end
|
||||
@@ -6166,6 +6198,7 @@ local SPELL_POWER_PAIN = SPELL_POWER_PAIN or (PowerEnum and PowerEnum.Pain) or 1
|
||||
|
||||
Details:Destroy(cacheAnything.paladin_vivaldi_blessings)
|
||||
Details:Destroy(cacheAnything.rampage_cast_amount)
|
||||
Details:Destroy(Details222.Roskash) --~roskash
|
||||
|
||||
cacheAnything.track_hunter_frenzy = Details.combat_log.track_hunter_frenzy
|
||||
|
||||
|
||||
+62
-103
@@ -632,54 +632,6 @@
|
||||
end
|
||||
end
|
||||
|
||||
local highlightPluginButtonOnBreakdownWindow = function(pluginAbsoluteName)
|
||||
for index, button in ipairs(breakdownWindowFrame.RegisteredPluginButtons) do
|
||||
---@cast button df_button
|
||||
button:Show()
|
||||
|
||||
if (button.PluginAbsName == pluginAbsoluteName) then
|
||||
button:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTONSELECTED_TEMPLATE"))
|
||||
else
|
||||
button:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTON_TEMPLATE"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function pluginContainerFrame.OnMenuClickFromBreakdownWindow(_, _, pluginAbsoluteName, callRefresh)
|
||||
local pluginObject = getPluginObject(pluginAbsoluteName)
|
||||
if (not pluginObject) then
|
||||
return
|
||||
end
|
||||
|
||||
--hide other plugin windows
|
||||
hideOtherPluginFrames(pluginObject)
|
||||
|
||||
---@type breakdownwindow
|
||||
local breakdownWindowFrame = Details.BreakdownWindowFrame
|
||||
--re set the point of the frame within the main plugin window
|
||||
pluginContainerFrame.RefreshFrame(pluginObject.Frame, breakdownWindowFrame)
|
||||
C_Timer.After(0, function()
|
||||
pluginContainerFrame.RefreshFrame(pluginObject.Frame, breakdownWindowFrame)
|
||||
end)
|
||||
|
||||
--show the plugin window
|
||||
if (pluginObject.RefreshWindow and callRefresh) then
|
||||
DetailsFramework:QuickDispatch(pluginObject.RefreshWindow)
|
||||
end
|
||||
|
||||
--highlight the plugin button on the menu
|
||||
highlightPluginButtonOnBreakdownWindow(pluginAbsoluteName)
|
||||
|
||||
--check if the plugin has a callback for when showing the frame
|
||||
if (pluginObject.__OnClickFromOptionsCallback) then
|
||||
--safe run the plugin callback
|
||||
DetailsFramework:QuickDispatch(pluginObject.__OnClickFromOptionsCallback)
|
||||
end
|
||||
|
||||
Details222.BreakdownWindow.OnShowPluginFrame(pluginObject)
|
||||
return true
|
||||
end
|
||||
|
||||
function pluginContainerFrame.OnMenuClick(_, _, pluginAbsoluteName, callRefresh)
|
||||
local pluginObject = getPluginObject(pluginAbsoluteName)
|
||||
if (not pluginObject) then
|
||||
@@ -770,72 +722,72 @@
|
||||
return
|
||||
end
|
||||
|
||||
--create a button for this plugin
|
||||
local pluginButton = Details:CreatePluginMenuButton(pluginObject, bIsUtility, pluginContainerFrame, pluginContainerFrame.OnMenuClick, pluginContainerFrame.MenuButtonWidth, pluginContainerFrame.MenuButtonHeight)
|
||||
--add it to menu table
|
||||
table.insert(pluginContainerFrame.MenuButtons, pluginButton)
|
||||
if (bIsUtility) then
|
||||
--create a button for this plugin
|
||||
local pluginButton = Details:CreatePluginMenuButton(pluginObject, bIsUtility, pluginContainerFrame, pluginContainerFrame.OnMenuClick, pluginContainerFrame.MenuButtonWidth, pluginContainerFrame.MenuButtonHeight)
|
||||
|
||||
pluginObject.__var_Frame = frame
|
||||
--only register button if it's a utility, plugins now are placed into the breakdown window
|
||||
table.insert(pluginContainerFrame.MenuButtons, pluginButton)
|
||||
|
||||
--create a button to be hosted in the player breakdown window
|
||||
if (not bIsUtility) then
|
||||
local breakdownWindowFrame = Details.BreakdownWindowFrame
|
||||
local breakdownButton = Details:CreatePluginMenuButton(pluginObject, bIsUtility, breakdownWindowFrame.BreakdownPluginSelectionFrame, pluginContainerFrame.OnMenuClickFromBreakdownWindow, pluginContainerFrame.MenuButtonWidth, pluginContainerFrame.MenuButtonHeight)
|
||||
breakdownWindowFrame.RegisterPluginButton(breakdownButton)
|
||||
else
|
||||
--utility is true when the object isn't a real plugin, but instead a tool frame from the main addon being embed on this panel
|
||||
pluginObject.__var_Frame = frame
|
||||
pluginObject.__var_Utility = true
|
||||
end
|
||||
|
||||
--sort buttons alphabetically, put utilities at the end
|
||||
table.sort(pluginContainerFrame.MenuButtons, function(t1, t2)
|
||||
if (t1.IsUtility and t2.IsUtility) then
|
||||
return t1.PluginName < t2.PluginName
|
||||
elseif (t1.IsUtility) then
|
||||
return false
|
||||
elseif (t2.IsUtility) then
|
||||
return true
|
||||
else
|
||||
return t1.PluginName < t2.PluginName
|
||||
end
|
||||
end)
|
||||
|
||||
--reset the buttons points
|
||||
local addingTools = false
|
||||
for index, button in ipairs(pluginContainerFrame.MenuButtons) do
|
||||
button:ClearAllPoints()
|
||||
PixelUtil.SetPoint(button, "center", menuBackground, "center", 0, 0)
|
||||
|
||||
if (button.IsUtility) then
|
||||
if (not addingTools) then
|
||||
--add the header
|
||||
addingTools = true
|
||||
--add -20 to add a gap between plugins and utilities
|
||||
PixelUtil.SetPoint(titleBarTools, "topleft", menuBackground, "topleft", 2, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index - 20)
|
||||
PixelUtil.SetPoint(titleBarTools, "topright", menuBackground, "topright", -2, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index - 20)
|
||||
--sort buttons alphabetically, put utilities at the end
|
||||
table.sort(pluginContainerFrame.MenuButtons, function(t1, t2)
|
||||
if (t1.IsUtility and t2.IsUtility) then
|
||||
return t1.PluginName < t2.PluginName
|
||||
elseif (t1.IsUtility) then
|
||||
return false
|
||||
elseif (t2.IsUtility) then
|
||||
return true
|
||||
else
|
||||
return t1.PluginName < t2.PluginName
|
||||
end
|
||||
end)
|
||||
|
||||
PixelUtil.SetPoint(button, "top", menuBackground, "top", 0, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index - 40)
|
||||
else
|
||||
PixelUtil.SetPoint(button, "top", menuBackground, "top", 0, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index)
|
||||
--reset the buttons points
|
||||
local addingTools = false
|
||||
for index, button in ipairs(pluginContainerFrame.MenuButtons) do
|
||||
button:ClearAllPoints()
|
||||
PixelUtil.SetPoint(button, "center", menuBackground, "center", 0, 0)
|
||||
|
||||
if (button.IsUtility) then
|
||||
if (not addingTools) then
|
||||
--add the header
|
||||
addingTools = true
|
||||
--add -20 to add a gap between plugins and utilities
|
||||
PixelUtil.SetPoint(titleBarTools, "topleft", menuBackground, "topleft", 2, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index - 20)
|
||||
PixelUtil.SetPoint(titleBarTools, "topright", menuBackground, "topright", -2, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index - 20)
|
||||
end
|
||||
|
||||
PixelUtil.SetPoint(button, "top", menuBackground, "top", 0, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index - 40)
|
||||
else
|
||||
PixelUtil.SetPoint(button, "top", menuBackground, "top", 0, pluginContainerFrame.MenuY +((index-1) * -pluginContainerFrame.MenuButtonHeight ) - index)
|
||||
end
|
||||
end
|
||||
|
||||
--format the plugin main frame
|
||||
pluginContainerFrame.RefreshFrame(frame)
|
||||
setupFrameFunctions(frame)
|
||||
|
||||
--save the callback function for when clicking in the button from the options panel
|
||||
pluginObject.__OnClickFromOptionsCallback = callback
|
||||
|
||||
--add the plugin to embed table
|
||||
table.insert(pluginContainerFrame.EmbedPlugins, pluginObject)
|
||||
frame:SetParent(pluginContainerFrame)
|
||||
|
||||
pluginContainerFrame.DebugMsg("plugin added", pluginObject.__name)
|
||||
end
|
||||
|
||||
--format the plugin main frame
|
||||
pluginContainerFrame.RefreshFrame(frame)
|
||||
setupFrameFunctions(frame)
|
||||
|
||||
--save the callback function for when clicking in the button from the options panel
|
||||
pluginObject.__OnClickFromOptionsCallback = callback
|
||||
|
||||
--add the plugin to embed table
|
||||
table.insert(pluginContainerFrame.EmbedPlugins, pluginObject)
|
||||
frame:SetParent(pluginContainerFrame)
|
||||
|
||||
pluginContainerFrame.DebugMsg("plugin added", pluginObject.__name)
|
||||
end
|
||||
|
||||
function pluginContainerFrame.OpenPlugin(pluginObject)
|
||||
if (pluginObject.__breakdownwindow) then
|
||||
breakdownWindowFrame.ShowPluginOnBreakdown(pluginObject)
|
||||
return
|
||||
end
|
||||
|
||||
--simulate a click on the menu button
|
||||
pluginContainerFrame.OnMenuClick(_, _, pluginObject.real_name)
|
||||
end
|
||||
@@ -854,7 +806,6 @@
|
||||
Details:OpenPlugin(PLUGIN_ABSOLUTE_NAME)
|
||||
Details:OpenPlugin(PluginObject)
|
||||
Details:OpenPlugin("Plugin Name")
|
||||
|
||||
Example: /run Details:OpenPlugin("Time Line")
|
||||
--]=]
|
||||
|
||||
@@ -868,6 +819,10 @@
|
||||
--check if passed a plugin absolute name
|
||||
local pluginObject = Details:GetPlugin(wildCard)
|
||||
if (pluginObject) then
|
||||
if (pluginObject.__breakdownwindow) then
|
||||
breakdownWindowFrame.ShowPluginOnBreakdown(pluginObject)
|
||||
return
|
||||
end
|
||||
pluginContainerFrame.OpenPlugin(pluginObject)
|
||||
return true
|
||||
end
|
||||
@@ -883,6 +838,10 @@
|
||||
|
||||
if (pluginName == wildCard) then
|
||||
local pluginObject = pluginInfoTable[3]
|
||||
if (pluginObject.__breakdownwindow) then
|
||||
breakdownWindowFrame.ShowPluginOnBreakdown(pluginObject)
|
||||
return
|
||||
end
|
||||
pluginContainerFrame.OpenPlugin(pluginObject)
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -952,7 +952,6 @@ local updateSpellBar = function(spellBar, index, actorName, combatObject, scroll
|
||||
|
||||
spellBar.spellId = spellId
|
||||
spellBar.spellIconFrame.spellId = spellId
|
||||
|
||||
spellBar.statusBar.backgroundTexture:SetAlpha(Details.breakdown_spell_tab.spellbar_background_alpha)
|
||||
|
||||
--statusbar color by school
|
||||
|
||||
@@ -59,7 +59,6 @@ end
|
||||
---@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
|
||||
@@ -93,7 +92,7 @@ local updateTargetBar = function(targetBar, index, combatObject, scrollFrame, he
|
||||
local text = targetBar.InLineTexts[textIndex]
|
||||
local header = headerTable[headerIndex]
|
||||
|
||||
if (header.name == "icon") then --ok
|
||||
if (header.name == "icon") then
|
||||
targetBar.Icon:Show()
|
||||
|
||||
if (targetActorObject) then
|
||||
@@ -107,13 +106,13 @@ local updateTargetBar = function(targetBar, index, combatObject, scrollFrame, he
|
||||
|
||||
targetBar:AddFrameToHeaderAlignment(targetBar.Icon)
|
||||
|
||||
elseif (header.name == "rank") then --ok
|
||||
elseif (header.name == "rank") then
|
||||
text:SetText(index)
|
||||
targetBar:AddFrameToHeaderAlignment(text)
|
||||
targetBar.rank = index
|
||||
textIndex = textIndex + 1
|
||||
|
||||
elseif (header.name == "name") then --ok
|
||||
elseif (header.name == "name") then
|
||||
local noRealmName = DF:RemoveRealmName(bkTargetData.name)
|
||||
local noOwnerName = noRealmName:gsub((" <.*"), "")
|
||||
text:SetText(noOwnerName)
|
||||
@@ -121,12 +120,12 @@ local updateTargetBar = function(targetBar, index, combatObject, scrollFrame, he
|
||||
targetBar:AddFrameToHeaderAlignment(text)
|
||||
textIndex = textIndex + 1
|
||||
|
||||
elseif (header.name == "amount") then --ok
|
||||
elseif (header.name == "amount") then
|
||||
text:SetText(Details:Format(value))
|
||||
targetBar:AddFrameToHeaderAlignment(text)
|
||||
textIndex = textIndex + 1
|
||||
|
||||
elseif (header.name == "percent") then --ok
|
||||
elseif (header.name == "percent") then
|
||||
targetBar.percent = value / totalValue * 100 --totalValue is nil
|
||||
---@type string
|
||||
local percentFormatted = string.format("%.1f", targetBar.percent) .. "%"
|
||||
@@ -425,8 +424,8 @@ local onEnterBreakdownTargetBar = function(targetBar)
|
||||
---@type spellcontainer
|
||||
local petSpellContainer = petActorObject:GetSpellContainer("spell")
|
||||
|
||||
---@type number, spelltable
|
||||
for spellId, spellTable in petSpellContainer:ListActors() do
|
||||
---@type spellid, spelltable
|
||||
for spellId, spellTable in petSpellContainer:ListActors() do --user reported petSpellContainer is nil x1
|
||||
for spellTargetName, amount in pairs(spellTable[targetTableName]) do
|
||||
if (spellTargetName == targetName) then
|
||||
local spellName, _, spellIcon = _GetSpellInfo(spellId)
|
||||
|
||||
@@ -20,12 +20,66 @@ local breakdownWindowFrame = Details.BreakdownWindowFrame
|
||||
|
||||
---@type button[]
|
||||
breakdownWindowFrame.RegisteredPluginButtons = {}
|
||||
breakdownWindowFrame.RegisteredPlugins = {}
|
||||
|
||||
---register a plugin button to be shown in the breakdown window
|
||||
---@param button button
|
||||
function breakdownWindowFrame.RegisterPluginButton(button)
|
||||
button:SetParent(DetailsBreakdownLeftMenuPluginsFrame)
|
||||
table.insert(breakdownWindowFrame.RegisteredPluginButtons, button)
|
||||
---@param newPluginButton df_button
|
||||
---@param newPluginAbsoluteName string
|
||||
function breakdownWindowFrame.RegisterPluginButton(newPluginButton, newPluginObject, newPluginAbsoluteName)
|
||||
newPluginButton:SetParent(DetailsBreakdownLeftMenuPluginsFrame)
|
||||
|
||||
newPluginButton.PluginObject = newPluginObject
|
||||
newPluginButton.PluginAbsoluteName = newPluginAbsoluteName
|
||||
newPluginButton.PluginFrame = newPluginObject.Frame
|
||||
|
||||
newPluginButton:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTON_TEMPLATE"))
|
||||
|
||||
newPluginObject.__breakdownwindow = true
|
||||
|
||||
local newClickFunction = function(UIObjectButton)
|
||||
--GetCapsule() returns the table which encapsulates the UIButton
|
||||
local button = UIObjectButton:GetCapsule()
|
||||
local pluginObject = button.PluginObject
|
||||
breakdownWindowFrame.ShowPluginOnBreakdown(pluginObject, button)
|
||||
end
|
||||
|
||||
newPluginButton:SetScript("OnClick", newClickFunction)
|
||||
|
||||
table.insert(breakdownWindowFrame.RegisteredPluginButtons, newPluginButton)
|
||||
table.insert(breakdownWindowFrame.RegisteredPlugins, newPluginObject)
|
||||
end
|
||||
|
||||
function breakdownWindowFrame.ShowPluginOnBreakdown(pluginObject, button)
|
||||
--hide all frames
|
||||
for _, thisPluginObject in ipairs(breakdownWindowFrame.RegisteredPlugins) do
|
||||
thisPluginObject.Frame:Hide()
|
||||
end
|
||||
|
||||
--reset the template on all plugin buttons
|
||||
for _, thisPluginButton in ipairs(breakdownWindowFrame.RegisteredPluginButtons) do
|
||||
---@cast thisPluginButton df_button
|
||||
thisPluginButton:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTON_TEMPLATE"))
|
||||
end
|
||||
|
||||
local pluginMainFrame = pluginObject.Frame
|
||||
|
||||
--> sets the plugin main frame: pluginObject.Frame, as the frame to be shown in the breakdown window
|
||||
pluginMainFrame:EnableMouse(false)
|
||||
pluginMainFrame:SetSize(DetailsBreakdownWindow:GetSize())
|
||||
pluginMainFrame:ClearAllPoints()
|
||||
PixelUtil.SetPoint(pluginMainFrame, "topleft", DetailsBreakdownWindow, "topleft", 0, 0)
|
||||
pluginMainFrame:SetParent(DetailsBreakdownWindow)
|
||||
pluginMainFrame:Show()
|
||||
|
||||
--> this click is what selects the plugin tab within the plugin code
|
||||
--may this be confused as we set OnClick right below, but the :Click() from framework buttons are different than the Blizzard ones
|
||||
if (button) then
|
||||
button:Click()
|
||||
button:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTONSELECTED_TEMPLATE"))
|
||||
end
|
||||
|
||||
--> hide the current shown tab in the breakdown window
|
||||
Details222.BreakdownWindow.OnShowPluginFrame(pluginObject)
|
||||
end
|
||||
|
||||
local PLAYER_DETAILS_WINDOW_WIDTH = 925
|
||||
@@ -52,8 +106,6 @@ breakdownWindowFrame.BreakdownSideMenuFrame = breakdownSideMenu
|
||||
local pluginsFrame = CreateFrame("frame", "DetailsBreakdownLeftMenuPluginsFrame", breakdownSideMenu, "BackdropTemplate")
|
||||
breakdownWindowFrame.BreakdownPluginSelectionFrame = pluginsFrame
|
||||
|
||||
|
||||
|
||||
--create the frame to hold tab buttons
|
||||
local tabButtonsFrame = CreateFrame("frame", "DetailsBreakdownTabsFrame", breakdownWindowFrame, "BackdropTemplate")
|
||||
breakdownWindowFrame.BreakdownTabsFrame = tabButtonsFrame
|
||||
@@ -109,6 +161,12 @@ function Details222.BreakdownWindow.HidePluginFrame()
|
||||
breakdownWindowFrame.avatar_bg:Show()
|
||||
breakdownWindowFrame.avatar_attribute:Show()
|
||||
breakdownWindowFrame.avatar_nick:Show()
|
||||
|
||||
--reset the template on all plugin buttons
|
||||
for _, thisPluginButton in ipairs(breakdownWindowFrame.RegisteredPluginButtons) do
|
||||
---@cast thisPluginButton df_button
|
||||
thisPluginButton:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTON_TEMPLATE"))
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -19,7 +19,7 @@ local scrollbox_line_backdrop_color = {0.2, 0.2, 0.2, 0.5}
|
||||
local scrollbox_line_backdrop_color_selected = {.6, .6, .1, 0.7}
|
||||
local scrollbox_line_backdrop_color_highlight = {.9, .9, .9, 0.5}
|
||||
local player_scroll_size = {195, 288}
|
||||
local player_scroll_y = -166
|
||||
local player_scroll_y = -300
|
||||
|
||||
function breakdownWindowPlayerList.CreatePlayerListFrame()
|
||||
---@type breakdownwindow
|
||||
@@ -35,31 +35,72 @@ function breakdownWindowPlayerList.CreatePlayerListFrame()
|
||||
detailsFramework:ApplyStandardBackdrop(breakdownSideMenu)
|
||||
breakdownSideMenu.RightEdge:Hide()
|
||||
|
||||
pluginsFrame:SetPoint("topleft", breakdownSideMenu, "topleft", 0, 0)
|
||||
pluginsFrame:SetPoint("bottomright", breakdownSideMenu, "topright", 0, player_scroll_y + 26)
|
||||
local titleHeight = 20
|
||||
--plugins menu title bar
|
||||
local titleBarPlugins = CreateFrame("frame", nil, breakdownSideMenu, "BackdropTemplate")
|
||||
PixelUtil.SetPoint(titleBarPlugins, "topleft", breakdownSideMenu, "topleft", 2, -3)
|
||||
PixelUtil.SetPoint(titleBarPlugins, "topright", breakdownSideMenu, "topright", -2, -3)
|
||||
titleBarPlugins:SetHeight(titleHeight)
|
||||
titleBarPlugins:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]], tileSize = 64, tile = true})
|
||||
titleBarPlugins:SetBackdropColor(.5, .5, .5, 1)
|
||||
titleBarPlugins:SetBackdropBorderColor(0, 0, 0, 1)
|
||||
|
||||
--pluginsFrame:SetSize(player_scroll_size[1], player_scroll_y + 26)
|
||||
--title label
|
||||
local titleBarPlugins_TitleLabel = detailsFramework:NewLabel(titleBarPlugins, titleBarPlugins, nil, "titulo", "Plugins", "GameFontHighlightLeft", 12, {227/255, 186/255, 4/255})
|
||||
PixelUtil.SetPoint(titleBarPlugins_TitleLabel, "center", titleBarPlugins , "center", 0, 0)
|
||||
PixelUtil.SetPoint(titleBarPlugins_TitleLabel, "top", titleBarPlugins , "top", 0, -5)
|
||||
|
||||
detailsFramework:ApplyStandardBackdrop(pluginsFrame)
|
||||
--plugins menu title bar
|
||||
local titleBarPlayerSeparator = CreateFrame("frame", nil, breakdownSideMenu, "BackdropTemplate")
|
||||
titleBarPlayerSeparator:SetHeight(titleHeight)
|
||||
titleBarPlayerSeparator:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]], tileSize = 64, tile = true})
|
||||
titleBarPlayerSeparator:SetBackdropColor(.5, .5, .5, 1)
|
||||
titleBarPlayerSeparator:SetBackdropBorderColor(0, 0, 0, 1)
|
||||
|
||||
local refreshPluginButtons = function()
|
||||
for i = 1, #breakdownWindowFrame.RegisteredPluginButtons do
|
||||
---@type button
|
||||
local pluginButton = breakdownWindowFrame.RegisteredPluginButtons[i]
|
||||
pluginButton:Show()
|
||||
pluginButton:Hide() --not ready yet
|
||||
pluginButton:ClearAllPoints()
|
||||
--title label
|
||||
local titleBarTools_TitleLabel = detailsFramework:NewLabel(titleBarPlayerSeparator, titleBarPlayerSeparator, nil, "titulo", "Players", "GameFontHighlightLeft", 12, {227/255, 186/255, 4/255})
|
||||
PixelUtil.SetPoint(titleBarTools_TitleLabel, "center", titleBarPlayerSeparator , "center", 0, 0)
|
||||
PixelUtil.SetPoint(titleBarTools_TitleLabel, "top", titleBarPlayerSeparator , "top", 0, -5)
|
||||
|
||||
if (i == 1) then
|
||||
pluginButton:SetPoint("topleft", pluginsFrame, "topleft", 2, -2)
|
||||
titleBarPlayerSeparator:SetPoint("topleft", pluginsFrame, "bottomleft", 0, -1)
|
||||
titleBarPlayerSeparator:SetPoint("topright", pluginsFrame, "bottomright", 0, -1)
|
||||
|
||||
local highlightPluginButtonOnBreakdownWindow = function(pluginAbsoluteName)
|
||||
for index, button in ipairs(breakdownWindowFrame.RegisteredPluginButtons) do
|
||||
---@cast button df_button
|
||||
button:Show()
|
||||
|
||||
if (button.PluginAbsName == pluginAbsoluteName) then
|
||||
button:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTONSELECTED_TEMPLATE"))
|
||||
else
|
||||
pluginButton:SetPoint("topleft", breakdownWindowFrame.RegisteredPluginButtons[i - 1], "bottomleft", 0, -2)
|
||||
button:SetTemplate(detailsFramework:GetTemplate("button", "DETAILS_PLUGINPANEL_BUTTON_TEMPLATE"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
refreshPluginButtons()
|
||||
local refreshPluginButtons = function()
|
||||
local amountPluginButtons = #breakdownWindowFrame.RegisteredPluginButtons
|
||||
local pluginButtonHeight = 20
|
||||
|
||||
for i = 1, amountPluginButtons do
|
||||
---@type button
|
||||
local pluginButton = breakdownWindowFrame.RegisteredPluginButtons[i]
|
||||
pluginButton:Show()
|
||||
pluginButton:SetWidth(pluginsFrame:GetWidth() - 4)
|
||||
pluginButton:SetHeight(pluginButtonHeight)
|
||||
pluginButton:ClearAllPoints()
|
||||
|
||||
if (i == 1) then
|
||||
pluginButton:SetPoint("topleft", pluginsFrame, "topleft", 2, -22)
|
||||
else
|
||||
pluginButton:SetPoint("topleft", breakdownWindowFrame.RegisteredPluginButtons[i - 1], "bottomleft", 0, -2)
|
||||
end
|
||||
end
|
||||
|
||||
pluginsFrame:SetPoint("topleft", breakdownSideMenu, "topleft", 0, 0)
|
||||
pluginsFrame:SetWidth(breakdownSideMenu:GetWidth())
|
||||
pluginsFrame:SetHeight(amountPluginButtons * pluginButtonHeight + 22 + (amountPluginButtons * 2))
|
||||
end
|
||||
|
||||
local refreshScrollFunc = function(self, data, offset, totalLines)
|
||||
--update the scroll
|
||||
@@ -250,9 +291,9 @@ function breakdownWindowPlayerList.CreatePlayerListFrame()
|
||||
upFrame:SetAllPoints()
|
||||
|
||||
--set its parameters
|
||||
line:SetPoint("topleft", self, "topleft", 1, -((index) * (player_line_height+1)) - 1)
|
||||
--line:SetPoint("topleft", self, "topleft", 1, -((index) * (player_line_height+1)) - 1)
|
||||
line:SetPoint("topleft", breakdownWindowFrame.Header, "topleft", 1, -((index) * (player_line_height*1.02)))
|
||||
line:SetSize(scrollbox_size[1]-2, player_line_height)
|
||||
--line:SetSize(scrollbox_size[1]-19, player_line_height)
|
||||
line:RegisterForClicks("LeftButtonDown", "RightButtonDown")
|
||||
|
||||
line:SetScript("OnEnter", lineOnEnter)
|
||||
@@ -346,8 +387,7 @@ function breakdownWindowPlayerList.CreatePlayerListFrame()
|
||||
playerScroll.ScrollBar:SetPoint("topright", playerScroll, "topright", -2, -37)
|
||||
playerScroll.ScrollBar:SetPoint("bottomright", playerScroll, "bottomright", -2, 17)
|
||||
playerScroll.ScrollBar:Hide()
|
||||
playerScroll:SetPoint("topleft", breakdownSideMenu, "topleft", 0, player_scroll_y)
|
||||
playerScroll:SetPoint("bottomright", breakdownSideMenu, "bottomright", -1, 0)
|
||||
|
||||
playerScroll:SetBackdrop({})
|
||||
playerScroll:SetBackdropColor(0, 0, 0, 0)
|
||||
playerScroll:SetBackdropBorderColor(0, 0, 0, 0)
|
||||
@@ -355,16 +395,18 @@ function breakdownWindowPlayerList.CreatePlayerListFrame()
|
||||
|
||||
--need to be created before
|
||||
breakdownWindowFrame.Header = DetailsFramework:CreateHeader(playerScroll, headerTable, headerOptions)
|
||||
breakdownWindowFrame.Header:SetPoint("topleft", playerScroll, "topleft", 0, -1)
|
||||
breakdownWindowFrame.Header:SetPoint("topright", playerScroll, "topright", 0, -1)
|
||||
breakdownWindowFrame.Header:SetAlpha(0.823)
|
||||
breakdownWindowFrame.Header:SetPoint("topleft", titleBarPlayerSeparator, "bottomleft", 0, -2)
|
||||
breakdownWindowFrame.Header:SetPoint("topright", titleBarPlayerSeparator, "bottomright", 0, -2)
|
||||
|
||||
playerScroll:SetPoint("topleft", breakdownWindowFrame.Header, "bottomleft", 0, -2)
|
||||
playerScroll:SetPoint("topright", breakdownWindowFrame.Header, "bottomright", 0, -2)
|
||||
playerScroll:SetPoint("bottomleft", breakdownSideMenu, "bottomleft", 0, 0)
|
||||
playerScroll:SetPoint("bottomright", breakdownSideMenu, "bottomright", 0, 0)
|
||||
|
||||
detailsFramework:ApplyStandardBackdrop(breakdownWindowFrame.Header)
|
||||
breakdownWindowFrame.Header.__background:SetColorTexture(.60, .60, .60)
|
||||
|
||||
local playerSelectionLabel = detailsFramework:CreateLabel(playerScroll, "Click to select a player", 14)
|
||||
playerSelectionLabel:SetPoint("bottom", breakdownWindowFrame.Header, "top", 0, 1)
|
||||
|
||||
--create the scrollbox lines
|
||||
for i = 1, scrollbox_lines do
|
||||
playerScroll:CreateLine(createPlayerLine)
|
||||
@@ -428,8 +470,13 @@ function breakdownWindowPlayerList.CreatePlayerListFrame()
|
||||
end
|
||||
|
||||
local updatePlayerList = function()
|
||||
refreshPluginButtons()
|
||||
|
||||
playerScroll:SetNumFramesShown(math.floor(playerScroll:GetHeight() / player_line_height))
|
||||
|
||||
---@type actor[]
|
||||
local playerList = breakdownWindowPlayerList.BuildPlayerList()
|
||||
|
||||
playerScroll:SetData(playerList)
|
||||
playerScroll:Refresh()
|
||||
playerScroll:Show()
|
||||
|
||||
@@ -4055,6 +4055,12 @@ function gump:CreateNewLine(instance, index)
|
||||
newLine.textura:SetVertTile(false)
|
||||
newLine.statusbar:SetStatusBarTexture(newLine.textura)
|
||||
|
||||
newLine.extraTexture = newLine.statusbar:CreateTexture(nil, "overlay")
|
||||
|
||||
local evokerColor = Details.class_colors["EVOKER"]
|
||||
newLine.extraTexture:SetColorTexture(unpack(evokerColor))
|
||||
newLine.extraTexture:Hide()
|
||||
|
||||
--frame for hold the backdrop border
|
||||
newLine.border = CreateFrame("Frame", "DetailsBarra_Border_" .. instance.meu_id .. "_" .. index, newLine.statusbar, "BackdropTemplate")
|
||||
newLine.border:SetFrameLevel(newLine.statusbar:GetFrameLevel()+2)
|
||||
|
||||
@@ -204,6 +204,7 @@ do
|
||||
--localize-me
|
||||
{value = 1, label = "Activity Time", onclick = onSelectTimeType, icon = "Interface\\Icons\\Achievement_Quests_Completed_Daily_08", iconcolor = {1, .9, .9}, texcoord = {0.078125, 0.921875, 0.078125, 0.921875}},
|
||||
{value = 2, label = "Effective Time", onclick = onSelectTimeType, icon = "Interface\\Icons\\Achievement_Quests_Completed_08"},
|
||||
{value = 3, label = "Real Time", onclick = onSelectTimeType, icon = "Interface\\Icons\\Ability_Evoker_TipTheScales"},
|
||||
}
|
||||
local buildTimeTypeMenu = function()
|
||||
return timetypeOptions
|
||||
@@ -7044,7 +7045,7 @@ do
|
||||
{type = "blank"},
|
||||
{type = "label", get = function() return "Class Options:" end, text_template = subSectionTitleTextTemplate},
|
||||
|
||||
{--damage taken everything
|
||||
{--hunter track pet frenzy
|
||||
type = "toggle",
|
||||
get = function() return Details.combat_log.track_hunter_frenzy end,
|
||||
set = function(self, fixedparam, value)
|
||||
@@ -7057,6 +7058,19 @@ do
|
||||
boxfirst = true,
|
||||
},
|
||||
|
||||
{--show evoker bar
|
||||
type = "toggle",
|
||||
get = function() return Details.combat_log.evoker_calc_damage end,
|
||||
set = function(self, fixedparam, value)
|
||||
Details.combat_log.evoker_calc_damage = value
|
||||
afterUpdate()
|
||||
Details:ClearParserCache()
|
||||
end,
|
||||
name = DF:AddClassIconToText("Predict Augmentation Damage", false, "EVOKER"),
|
||||
desc = "Predict Augmentation Damage",
|
||||
boxfirst = true,
|
||||
},
|
||||
|
||||
{type = "blank"},
|
||||
{type = "label", get = function() return "Parser Options:" end, text_template = subSectionTitleTextTemplate},
|
||||
|
||||
|
||||
+15
-10
@@ -146,12 +146,14 @@ function Details:CreateCallbackListeners()
|
||||
local dbm_timer_callback = function(bar_type, id, msg, timer, icon, bartype, spellId, colorId, modid)
|
||||
local currentCombat = Details:GetCurrentCombat()
|
||||
if (not currentCombat.__destroyed) then --async events, need to check for combat destruction
|
||||
table.insert(currentCombat.bossTimers, {"dbm", bar_type, id, msg, timer, icon, bartype, spellId, colorId, modid})
|
||||
---@type combattime
|
||||
local combatTime = currentCombat:GetCombatTime()
|
||||
table.insert(currentCombat.bossTimers, {"dbm", combatTime, bar_type, id, msg, timer, icon, bartype, spellId, colorId, modid})
|
||||
--print("dbm event", bar_type, id, msg, timer, icon, bartype, spellId, colorId, modid)
|
||||
|
||||
local spell = tostring(spellId)
|
||||
if (spell and not current_table_dbm [spell]) then
|
||||
current_table_dbm [spell] = {spell, id, msg, timer, icon, bartype, spellId, colorId, modid}
|
||||
if (spell and not current_table_dbm[spell]) then
|
||||
current_table_dbm[spell] = {spell, id, msg, timer, icon, bartype, spellId, colorId, modid}
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -161,21 +163,24 @@ function Details:CreateCallbackListeners()
|
||||
--record Bigwigs timers shown at /details spells.
|
||||
--this is also usage to create weakauras directly from details!
|
||||
function Details:RegisterBigWigsCallBack()
|
||||
if (BigWigsLoader) then
|
||||
function Details:BigWigs_StartBar (event, module, spellid, bar_text, time, icon, ...)
|
||||
--if the user is also using DBM, ignore registering another callback
|
||||
if (BigWigsLoader and not _G.DBM) then
|
||||
function Details:BigWigs_StartBar(event, module, spellid, bar_text, time, icon, ...)
|
||||
local currentCombat = Details:GetCurrentCombat()
|
||||
if (not currentCombat.__destroyed) then --async events, need to check for combat destruction
|
||||
table.insert(currentCombat.bossTimers, {"bw", event, spellid, bar_text, time, icon})
|
||||
--print("bw event", event, spellid, bar_text, time, icon)
|
||||
---@type combattime
|
||||
local combatTime = currentCombat:GetCombatTime()
|
||||
table.insert(currentCombat.bossTimers, {"bw", combatTime, spellid, bar_text, time, icon})
|
||||
|
||||
spellid = tostring(spellid)
|
||||
if (not current_table_bigwigs [spellid]) then
|
||||
current_table_bigwigs [spellid] = {(type(module) == "string" and module) or (module and module.moduleName) or "", spellid or "", bar_text or "", time or 0, icon or ""}
|
||||
if (not current_table_bigwigs[spellid]) then
|
||||
current_table_bigwigs[spellid] = {(type(module) == "string" and module) or (module and module.moduleName) or "", spellid or "", bar_text or "", time or 0, icon or ""}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (BigWigsLoader.RegisterMessage) then
|
||||
BigWigsLoader.RegisterMessage (Details, "BigWigs_StartBar")
|
||||
BigWigsLoader.RegisterMessage(Details, "BigWigs_StartBar")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
+74
-35
@@ -2,70 +2,106 @@
|
||||
local Details = _G.Details
|
||||
local addonName, Details222 = ...
|
||||
|
||||
local bIsEnabled = false
|
||||
local testCharacterName = "Ditador"
|
||||
local bIsEnabled = true
|
||||
|
||||
---@type combat
|
||||
local currentCombatObject = nil
|
||||
|
||||
---@class details_currentdps_actorcache
|
||||
---@field totalDamage number
|
||||
---@field currentDps number
|
||||
---@field latestDamageAmount number
|
||||
---@field cache number[]
|
||||
|
||||
--namespace
|
||||
Details.CurrentDps = {
|
||||
---@type table<serial, details_currentdps_actorcache>
|
||||
Dps = {},
|
||||
---@type table<serial, details_currentdps_actorcache>
|
||||
Hps = {},
|
||||
}
|
||||
|
||||
---create a new cache table
|
||||
---@return details_currentdps_actorcache
|
||||
local createDpsCacheTable = function()
|
||||
---@type details_currentdps_actorcache
|
||||
local cache = {
|
||||
totalDamage = 0,
|
||||
currentDps = 0,
|
||||
latestDamageAmount = 0,
|
||||
cache = {},
|
||||
}
|
||||
return cache
|
||||
end
|
||||
|
||||
---get the actor cache from the current dps table
|
||||
---@param serial serial
|
||||
---@return details_currentdps_actorcache
|
||||
local getActorDpsCache = function(serial)
|
||||
local dpsCache = Details.CurrentDps.Dps[serial]
|
||||
if (not dpsCache) then
|
||||
dpsCache = createDpsCacheTable()
|
||||
Details.CurrentDps.Dps[serial] = dpsCache
|
||||
end
|
||||
return dpsCache
|
||||
end
|
||||
|
||||
---@type frame
|
||||
local currentDpsFrame = CreateFrame("frame", "DetailsCurrentDpsUpdaterFrame", UIParent)
|
||||
|
||||
--amount of time to wait between each sample collection
|
||||
local delayTimeBetweenUpdates = 0.10
|
||||
|
||||
--sample size in time to use to calculate the current dps
|
||||
local secondsOfData = 5
|
||||
|
||||
--amount of time to wait until next update
|
||||
local currentDelay = 0
|
||||
local cacheSize = 40 --4 seconds of data
|
||||
|
||||
--amount of small ticks that will be stored in the cache
|
||||
local cacheSize = secondsOfData / delayTimeBetweenUpdates
|
||||
|
||||
--amount of time in seconds that the cache will hold
|
||||
local dpsTime = delayTimeBetweenUpdates * cacheSize
|
||||
|
||||
--the index of the cache that will be removed when the cache is full
|
||||
local cacheOverflowIndex = cacheSize + 1
|
||||
|
||||
---on tick function
|
||||
---@param self frame
|
||||
---@param deltaTime number time elapsed between frames
|
||||
currentDpsFrame.OnUpdateFunc = function(self, deltaTime)
|
||||
currentDelay = currentDelay + deltaTime
|
||||
if (currentDelay < delayTimeBetweenUpdates) then
|
||||
return
|
||||
end
|
||||
|
||||
local combatObject = Details.CurrentDps.CombatObject
|
||||
---@type actorcontainer
|
||||
local damageContainer = currentCombatObject:GetContainer(DETAILS_ATTRIBUTE_DAMAGE)
|
||||
|
||||
local damageContainer = combatObject:GetContainer(DETAILS_ATTRIBUTE_DAMAGE)
|
||||
for index, actorObject in damageContainer:ListActors() do
|
||||
if (actorObject:IsPlayer()) then
|
||||
local actorTable = Details.CurrentDps.Dps[actorObject.serial]
|
||||
if (not actorTable) then
|
||||
actorTable = {
|
||||
totalDamage = 0, --hold a sum of all dps done in the latest #cacheSize delayed OnUpdate ticks
|
||||
currentDps = 0,
|
||||
latestDamageAmount = 0,
|
||||
cache = {},
|
||||
}
|
||||
Details.CurrentDps.Dps[actorObject.serial] = actorTable
|
||||
end
|
||||
---@cast actorObject actor
|
||||
|
||||
--if (actorObject:IsPlayer()) then
|
||||
---@type details_currentdps_actorcache
|
||||
local dpsCache = getActorDpsCache(actorObject.serial)
|
||||
|
||||
--get the damage done on this tick
|
||||
local totalDamageThisTick = actorObject.total - actorTable.latestDamageAmount
|
||||
local totalDamageThisTick = actorObject.total - dpsCache.latestDamageAmount
|
||||
--add the damage to the cache
|
||||
table.insert(actorTable.cache, 1, totalDamageThisTick)
|
||||
table.insert(dpsCache.cache, 1, totalDamageThisTick)
|
||||
--set the latest damage amount
|
||||
actorTable.latestDamageAmount = actorObject.total
|
||||
dpsCache.latestDamageAmount = actorObject.total
|
||||
--sum the total damage the actor inflicted
|
||||
actorTable.totalDamage = actorTable.totalDamage + totalDamageThisTick
|
||||
dpsCache.totalDamage = dpsCache.totalDamage + totalDamageThisTick
|
||||
|
||||
--cut the damage
|
||||
local damageRemoved = table.remove(actorTable.cache, cacheOverflowIndex)
|
||||
local damageRemoved = table.remove(dpsCache.cache, cacheOverflowIndex)
|
||||
if (damageRemoved) then
|
||||
actorTable.totalDamage = actorTable.totalDamage - damageRemoved
|
||||
actorTable.totalDamage = math.max(0, actorTable.totalDamage) --safe guard
|
||||
dpsCache.totalDamage = dpsCache.totalDamage - damageRemoved
|
||||
dpsCache.totalDamage = math.max(0, dpsCache.totalDamage) --safe guard
|
||||
end
|
||||
|
||||
actorTable.currentDps = actorTable.totalDamage / dpsTime
|
||||
if (actorObject.nome == testCharacterName) then --debug
|
||||
local formatToKFunc = Details:GetCurrentToKFunction()
|
||||
print(actorTable.totalDamage, #actorTable.cache, dpsTime, formatToKFunc(nil, actorTable.currentDps))
|
||||
end
|
||||
|
||||
if (actorObject.nome == testCharacterName) then --debug
|
||||
print("Dps:", actorTable.currentDps)
|
||||
end
|
||||
end
|
||||
--end
|
||||
end
|
||||
|
||||
currentDelay = 0
|
||||
@@ -73,11 +109,12 @@ end
|
||||
|
||||
--start the proccess of updating the current dps and hps for each player
|
||||
function Details.CurrentDps.StartCurrentDpsTracker()
|
||||
Details.CurrentDps.CombatObject = Details:GetCurrentCombat()
|
||||
currentCombatObject = Details:GetCurrentCombat()
|
||||
Details:Destroy(Details.CurrentDps.Dps)
|
||||
Details:Destroy(Details.CurrentDps.Hps)
|
||||
currentDpsFrame:SetScript("OnUpdate", currentDpsFrame.OnUpdateFunc)
|
||||
end
|
||||
|
||||
--stop what the function above started
|
||||
function Details.CurrentDps.StopCurrentDpsTracker()
|
||||
currentDpsFrame:SetScript("OnUpdate", nil)
|
||||
@@ -89,12 +126,14 @@ function Details.CurrentDps.GetCurrentDps(serial)
|
||||
if (actorTable) then
|
||||
local currentDps = actorTable.currentDps
|
||||
local formatToKFunc = Details:GetCurrentToKFunction()
|
||||
--print("returning:", currentDps)
|
||||
return formatToKFunc(nil, currentDps)
|
||||
end
|
||||
end
|
||||
|
||||
--handle internal details! events
|
||||
local eventListener = Details:CreateEventListener()
|
||||
|
||||
eventListener:RegisterEvent("COMBAT_PLAYER_ENTER", function()
|
||||
if (bIsEnabled) then
|
||||
Details.CurrentDps.StartCurrentDpsTracker()
|
||||
|
||||
@@ -1152,6 +1152,7 @@ local default_player_data = {
|
||||
track_hunter_frenzy = false,
|
||||
merge_gemstones_1007 = false,
|
||||
merge_critical_heals = false,
|
||||
evoker_calc_damage = false,
|
||||
},
|
||||
|
||||
--this is used by the new data capture for charts
|
||||
@@ -1412,7 +1413,7 @@ local default_global_data = {
|
||||
},
|
||||
},
|
||||
|
||||
--/run Details.breakdown_spell_tab.statusbar_alpha = 0.823
|
||||
--/run Details.breakdown_spell_tab.spellcontainer_height = 311 --352
|
||||
--breakdown spell tab
|
||||
breakdown_spell_tab = {
|
||||
--player spells
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 MiB After Width: | Height: | Size: 4.0 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 367 KiB |
Reference in New Issue
Block a user