Maintenance Update and Mythic Dungeon Plus development progress
- Dungeon followers now correctly show into the damage done section. - Fixed an error while statusbar plugin options. - Framework update. - Mythic Dungeon Plus code has been separated into six files (was just 2), this will help with the organization and maintenance of the code.
This commit is contained in:
@@ -45,3 +45,4 @@ photoshop/ten_years_skin.tga
|
|||||||
plugins/Details_EncounterDetails/Libs/LibLuaServer/LuaServerDefinitions.lua
|
plugins/Details_EncounterDetails/Libs/LibLuaServer/LuaServerDefinitions.lua
|
||||||
plugins/Details_EncounterDetails/Definitions.lua
|
plugins/Details_EncounterDetails/Definitions.lua
|
||||||
*.afphoto~lock~
|
*.afphoto~lock~
|
||||||
|
annotations.txt
|
||||||
|
|||||||
+5
-2
@@ -57,9 +57,10 @@ functions\currentdps.lua
|
|||||||
functions\report.lua
|
functions\report.lua
|
||||||
functions\rowanimation.lua
|
functions\rowanimation.lua
|
||||||
functions\raidinfo.lua
|
functions\raidinfo.lua
|
||||||
functions\dungeon.lua
|
functions\mythicdungeon\mythicdungeon.lua
|
||||||
|
functions\mythicdungeon\data_capture.lua
|
||||||
|
functions\mythicdungeon\segments.lua
|
||||||
functions\pack.lua
|
functions\pack.lua
|
||||||
functions\mythicdungeon.lua
|
|
||||||
functions\immersion.lua
|
functions\immersion.lua
|
||||||
functions\schedules.lua
|
functions\schedules.lua
|
||||||
functions\autorun.lua
|
functions\autorun.lua
|
||||||
@@ -98,6 +99,8 @@ frames\window_breakdown\breakdown_spells_spellframes.lua
|
|||||||
frames\window_breakdown\breakdown_spells_targetframes.lua
|
frames\window_breakdown\breakdown_spells_targetframes.lua
|
||||||
frames\window_breakdown\breakdown_spells_phaseframes.lua
|
frames\window_breakdown\breakdown_spells_phaseframes.lua
|
||||||
frames\window_mythicplus\window_mythic_breakdown.lua
|
frames\window_mythicplus\window_mythic_breakdown.lua
|
||||||
|
frames\window_mythicplus\window_end_of_run.lua
|
||||||
|
frames\window_mythicplus\window_chart.lua
|
||||||
frames\window_report.lua
|
frames\window_report.lua
|
||||||
frames\window_main.lua
|
frames\window_main.lua
|
||||||
frames\window_custom.lua
|
frames\window_custom.lua
|
||||||
|
|||||||
+4
-2
@@ -54,9 +54,10 @@ functions\currentdps.lua
|
|||||||
functions\report.lua
|
functions\report.lua
|
||||||
functions\rowanimation.lua
|
functions\rowanimation.lua
|
||||||
functions\raidinfo.lua
|
functions\raidinfo.lua
|
||||||
functions\dungeon.lua
|
functions\mythicdungeon\segments.lua
|
||||||
|
functions\mythicdungeon\mythicdungeon.lua
|
||||||
|
functions\mythicdungeon\data_capture.lua
|
||||||
functions\pack.lua
|
functions\pack.lua
|
||||||
functions\mythicdungeon.lua
|
|
||||||
functions\immersion.lua
|
functions\immersion.lua
|
||||||
functions\schedules.lua
|
functions\schedules.lua
|
||||||
functions\autorun.lua
|
functions\autorun.lua
|
||||||
@@ -93,6 +94,7 @@ frames\window_breakdown\breakdown_spells_spellframes.lua
|
|||||||
frames\window_breakdown\breakdown_spells_targetframes.lua
|
frames\window_breakdown\breakdown_spells_targetframes.lua
|
||||||
frames\window_breakdown\breakdown_spells_phaseframes.lua
|
frames\window_breakdown\breakdown_spells_phaseframes.lua
|
||||||
frames\window_mythicplus\window_mythic_breakdown.lua
|
frames\window_mythicplus\window_mythic_breakdown.lua
|
||||||
|
frames\window_mythicplus\window_end_of_run.lua
|
||||||
frames\window_report.lua
|
frames\window_report.lua
|
||||||
frames\window_main.lua
|
frames\window_main.lua
|
||||||
frames\window_custom.lua
|
frames\window_custom.lua
|
||||||
|
|||||||
+4
-2
@@ -54,9 +54,10 @@ functions\currentdps.lua
|
|||||||
functions\report.lua
|
functions\report.lua
|
||||||
functions\rowanimation.lua
|
functions\rowanimation.lua
|
||||||
functions\raidinfo.lua
|
functions\raidinfo.lua
|
||||||
functions\dungeon.lua
|
functions\mythicdungeon\segments.lua
|
||||||
|
functions\mythicdungeon\mythicdungeon.lua
|
||||||
|
functions\mythicdungeon\data_capture.lua
|
||||||
functions\pack.lua
|
functions\pack.lua
|
||||||
functions\mythicdungeon.lua
|
|
||||||
functions\immersion.lua
|
functions\immersion.lua
|
||||||
functions\schedules.lua
|
functions\schedules.lua
|
||||||
functions\autorun.lua
|
functions\autorun.lua
|
||||||
@@ -93,6 +94,7 @@ frames\window_breakdown\breakdown_spells_spellframes.lua
|
|||||||
frames\window_breakdown\breakdown_spells_targetframes.lua
|
frames\window_breakdown\breakdown_spells_targetframes.lua
|
||||||
frames\window_breakdown\breakdown_spells_phaseframes.lua
|
frames\window_breakdown\breakdown_spells_phaseframes.lua
|
||||||
frames\window_mythicplus\window_mythic_breakdown.lua
|
frames\window_mythicplus\window_mythic_breakdown.lua
|
||||||
|
frames\window_mythicplus\window_end_of_run.lua
|
||||||
frames\window_report.lua
|
frames\window_report.lua
|
||||||
frames\window_main.lua
|
frames\window_main.lua
|
||||||
frames\window_custom.lua
|
frames\window_custom.lua
|
||||||
|
|||||||
@@ -48,6 +48,7 @@
|
|||||||
---@field internalFunctions table
|
---@field internalFunctions table
|
||||||
---@field OptionsFunctions df_optionsmixin
|
---@field OptionsFunctions df_optionsmixin
|
||||||
---@field GlobalWidgetControlNames table
|
---@field GlobalWidgetControlNames table
|
||||||
|
---@field DefaultRoundedCornerPreset table
|
||||||
---@field RoundedCornerPanelMixin df_roundedcornermixin
|
---@field RoundedCornerPanelMixin df_roundedcornermixin
|
||||||
---@field Schedules df_schedule
|
---@field Schedules df_schedule
|
||||||
---@field HeaderFunctions df_headerfunctions
|
---@field HeaderFunctions df_headerfunctions
|
||||||
@@ -142,6 +143,8 @@
|
|||||||
---@field IsHtmlColor fun(self:table, colorName:any) : unknown return true if DF.alias_text_colors has the colorName as a key
|
---@field IsHtmlColor fun(self:table, colorName:any) : unknown return true if DF.alias_text_colors has the colorName as a key
|
||||||
---@field CreateColorTable fun(self:table, r:number, g:number, b:number, a:number) : table return a table with {r, g, b, a}
|
---@field CreateColorTable fun(self:table, r:number, g:number, b:number, a:number) : table return a table with {r, g, b, a}
|
||||||
---@field FormatColor fun(self:table, newFormat:string, r:number|string, g:number?, b:number?, a:number?, decimalsAmount:number?) : string|table|number|nil, number|nil, number|nil, number|nil takes in a color in one format and converts it to another specified format.
|
---@field FormatColor fun(self:table, newFormat:string, r:number|string, g:number?, b:number?, a:number?, decimalsAmount:number?) : string|table|number|nil, number|nil, number|nil, number|nil takes in a color in one format and converts it to another specified format.
|
||||||
---@field
|
---@field CreateEditor fun(self:table, parent:frame, name:string?, options:df_editor_defaultoptions?) : df_editor
|
||||||
|
---@field RandomBool fun(self:table, odds: number?) : boolean return a random boolean
|
||||||
|
---@field CreateHighlightTexture fun(self:table, parent:frame, parentKey:string?, alpha:number?, name:string?) : texture
|
||||||
---@field
|
---@field
|
||||||
|
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ function DropDownMetaFunctions:Select(optionName, byOptionNumber, bOnlyShown, ru
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local optionsTable = DF:Dispatch(self.func, self) --399
|
local runOkay, optionsTable = xpcall(self.func, geterrorhandler(), self)
|
||||||
|
|
||||||
if (#optionsTable == 0) then
|
if (#optionsTable == 0) then
|
||||||
self:NoOption(true)
|
self:NoOption(true)
|
||||||
@@ -563,6 +563,11 @@ function DropDownMetaFunctions:Selected(thisOption)
|
|||||||
self.statusbar:SetTexture([[Interface\Tooltips\CHATBUBBLE-BACKGROUND]])
|
self.statusbar:SetTexture([[Interface\Tooltips\CHATBUBBLE-BACKGROUND]])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if (self.widget.__rcorners) then
|
||||||
|
self.statusbar:SetPoint("topleft", self.widget, "topleft", 2, -2)
|
||||||
|
self.statusbar:SetPoint("bottomright", self.widget, "bottomright", -2, 2)
|
||||||
|
end
|
||||||
|
|
||||||
if (thisOption.color) then
|
if (thisOption.color) then
|
||||||
local r, g, b, a = DF:ParseColors(thisOption.color)
|
local r, g, b, a = DF:ParseColors(thisOption.color)
|
||||||
self.label:SetTextColor(r, g, b, a)
|
self.label:SetTextColor(r, g, b, a)
|
||||||
|
|||||||
+164
-89
@@ -21,8 +21,25 @@ local _
|
|||||||
--the editor doesn't know which key in the profileTable holds the current value for an attribute, so it uses a map table to find it.
|
--the editor doesn't know which key in the profileTable holds the current value for an attribute, so it uses a map table to find it.
|
||||||
--the mapTable is a table with the attribute name as a key, and the value is the profile key. For example, {["size"] = "text_size"} means profileTable["text_size"] = 10.
|
--the mapTable is a table with the attribute name as a key, and the value is the profile key. For example, {["size"] = "text_size"} means profileTable["text_size"] = 10.
|
||||||
|
|
||||||
|
---@class df_editor : frame, df_optionsmixin, df_editormixin
|
||||||
|
---@field options table
|
||||||
|
---@field registeredObjects df_editor_objectinfo[]
|
||||||
|
---@field registeredObjectsByID table<any, df_editor_objectinfo>
|
||||||
|
---@field editingObject uiobject
|
||||||
|
---@field editingProfileTable table
|
||||||
|
---@field editingProfileMap table
|
||||||
|
---@field editingOptions df_editobjectoptions
|
||||||
|
---@field editingExtraOptions table
|
||||||
|
---@field moverGuideLines table<string, texture>
|
||||||
|
---@field onEditCallback function
|
||||||
|
---@field optionsFrame frame
|
||||||
|
---@field overTheTopFrame frame
|
||||||
|
---@field objectSelector df_scrollbox
|
||||||
|
---@field moverFrame frame
|
||||||
|
---@field canvasScrollBox df_canvasscrollbox
|
||||||
|
|
||||||
---@class df_editor_attribute
|
---@class df_editor_attribute
|
||||||
---@field name string?
|
---@field key string?
|
||||||
---@field label string?
|
---@field label string?
|
||||||
---@field widget string
|
---@field widget string
|
||||||
---@field default any?
|
---@field default any?
|
||||||
@@ -32,19 +49,31 @@ local _
|
|||||||
---@field usedecimals boolean?
|
---@field usedecimals boolean?
|
||||||
---@field subkey string?
|
---@field subkey string?
|
||||||
|
|
||||||
|
---@class df_editor_objectinfo : table
|
||||||
|
---@field object uiobject
|
||||||
|
---@field label string
|
||||||
|
---@field id any
|
||||||
|
---@field profiletable table
|
||||||
|
---@field profilekeymap table
|
||||||
|
---@field subtablepath string?
|
||||||
|
---@field extraoptions table
|
||||||
|
---@field callback function?
|
||||||
|
---@field options df_editobjectoptions
|
||||||
|
---@field selectButton button
|
||||||
|
|
||||||
--which object attributes are used to build the editor menu for each object type
|
--which object attributes are used to build the editor menu for each object type
|
||||||
local attributes = {
|
local attributes = {
|
||||||
---@type df_editor_attribute[]
|
---@type df_editor_attribute[]
|
||||||
FontString = {
|
FontString = {
|
||||||
{
|
{
|
||||||
name = "text",
|
key = "text",
|
||||||
label = "Text",
|
label = "Text",
|
||||||
widget = "textentry",
|
widget = "textentry",
|
||||||
default = "font string text",
|
default = "font string text",
|
||||||
setter = function(widget, value) widget:SetText(value) end,
|
setter = function(widget, value) widget:SetText(value) end,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "size",
|
key = "size",
|
||||||
label = "Size",
|
label = "Size",
|
||||||
widget = "range",
|
widget = "range",
|
||||||
minvalue = 5,
|
minvalue = 5,
|
||||||
@@ -52,7 +81,7 @@ local attributes = {
|
|||||||
setter = function(widget, value) widget:SetFont(widget:GetFont(), value, select(3, widget:GetFont())) end
|
setter = function(widget, value) widget:SetFont(widget:GetFont(), value, select(3, widget:GetFont())) end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "font",
|
key = "font",
|
||||||
label = "Font",
|
label = "Font",
|
||||||
widget = "fontdropdown",
|
widget = "fontdropdown",
|
||||||
setter = function(widget, value)
|
setter = function(widget, value)
|
||||||
@@ -61,32 +90,32 @@ local attributes = {
|
|||||||
end
|
end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "color",
|
key = "color",
|
||||||
label = "Color",
|
label = "Color",
|
||||||
widget = "color",
|
widget = "color",
|
||||||
setter = function(widget, value) widget:SetTextColor(unpack(value)) end
|
setter = function(widget, value) widget:SetTextColor(unpack(value)) end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "alpha",
|
key = "alpha",
|
||||||
label = "Alpha",
|
label = "Alpha",
|
||||||
widget = "range",
|
widget = "range",
|
||||||
setter = function(widget, value) widget:SetAlpha(value) end
|
setter = function(widget, value) widget:SetAlpha(value) end
|
||||||
},
|
},
|
||||||
{widget = "blank"},
|
{widget = "blank"},
|
||||||
{
|
{
|
||||||
name = "shadow",
|
key = "shadow",
|
||||||
label = "Draw Shadow",
|
label = "Draw Shadow",
|
||||||
widget = "toggle",
|
widget = "toggle",
|
||||||
setter = function(widget, value) widget:SetShadowColor(widget:GetShadowColor(), select(2, widget:GetShadowColor()), select(3, widget:GetShadowColor()), value and 0.5 or 0) end
|
setter = function(widget, value) widget:SetShadowColor(widget:GetShadowColor(), select(2, widget:GetShadowColor()), select(3, widget:GetShadowColor()), value and 0.5 or 0) end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "shadowcolor",
|
key = "shadowcolor",
|
||||||
label = "Shadow Color",
|
label = "Shadow Color",
|
||||||
widget = "color",
|
widget = "color",
|
||||||
setter = function(widget, value) widget:SetShadowColor(unpack(value)) end
|
setter = function(widget, value) widget:SetShadowColor(unpack(value)) end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "shadowoffsetx",
|
key = "shadowoffsetx",
|
||||||
label = "Shadow X Offset",
|
label = "Shadow X Offset",
|
||||||
widget = "range",
|
widget = "range",
|
||||||
minvalue = -10,
|
minvalue = -10,
|
||||||
@@ -94,7 +123,7 @@ local attributes = {
|
|||||||
setter = function(widget, value) widget:SetShadowOffset(value, select(2, widget:GetShadowOffset())) end
|
setter = function(widget, value) widget:SetShadowOffset(value, select(2, widget:GetShadowOffset())) end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "shadowoffsety",
|
key = "shadowoffsety",
|
||||||
label = "Shadow Y Offset",
|
label = "Shadow Y Offset",
|
||||||
widget = "range",
|
widget = "range",
|
||||||
minvalue = -10,
|
minvalue = -10,
|
||||||
@@ -102,20 +131,20 @@ local attributes = {
|
|||||||
setter = function(widget, value) widget:SetShadowOffset(widget:GetShadowOffset(), value) end
|
setter = function(widget, value) widget:SetShadowOffset(widget:GetShadowOffset(), value) end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "outline",
|
key = "outline",
|
||||||
label = "Outline",
|
label = "Outline",
|
||||||
widget = "outlinedropdown",
|
widget = "outlinedropdown",
|
||||||
setter = function(widget, value) widget:SetFont(widget:GetFont(), select(2, widget:GetFont()), value) end
|
setter = function(widget, value) widget:SetFont(widget:GetFont(), select(2, widget:GetFont()), value) end
|
||||||
},
|
},
|
||||||
{widget = "blank"},
|
{widget = "blank"},
|
||||||
{
|
{
|
||||||
name = "anchor",
|
key = "anchor",
|
||||||
label = "Anchor",
|
label = "Anchor",
|
||||||
widget = "anchordropdown",
|
widget = "anchordropdown",
|
||||||
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "anchoroffsetx",
|
key = "anchoroffsetx",
|
||||||
label = "Anchor X Offset",
|
label = "Anchor X Offset",
|
||||||
widget = "range",
|
widget = "range",
|
||||||
minvalue = -100,
|
minvalue = -100,
|
||||||
@@ -123,7 +152,7 @@ local attributes = {
|
|||||||
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "anchoroffsety",
|
key = "anchoroffsety",
|
||||||
label = "Anchor Y Offset",
|
label = "Anchor Y Offset",
|
||||||
widget = "range",
|
widget = "range",
|
||||||
minvalue = -100,
|
minvalue = -100,
|
||||||
@@ -131,7 +160,7 @@ local attributes = {
|
|||||||
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "rotation",
|
key = "rotation",
|
||||||
label = "Rotation",
|
label = "Rotation",
|
||||||
widget = "range",
|
widget = "range",
|
||||||
usedecimals = true,
|
usedecimals = true,
|
||||||
@@ -140,7 +169,7 @@ local attributes = {
|
|||||||
setter = function(widget, value) widget:SetRotation(value) end
|
setter = function(widget, value) widget:SetRotation(value) end
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name = "scale",
|
key = "scale",
|
||||||
label = "Scale",
|
label = "Scale",
|
||||||
widget = "range",
|
widget = "range",
|
||||||
usedecimals = true,
|
usedecimals = true,
|
||||||
@@ -161,24 +190,38 @@ local attributes = {
|
|||||||
---@field GetOptionsFrame fun(self:df_editor):frame
|
---@field GetOptionsFrame fun(self:df_editor):frame
|
||||||
---@field GetCanvasScrollBox fun(self:df_editor):df_canvasscrollbox
|
---@field GetCanvasScrollBox fun(self:df_editor):df_canvasscrollbox
|
||||||
---@field GetObjectSelector fun(self:df_editor):df_scrollbox
|
---@field GetObjectSelector fun(self:df_editor):df_scrollbox
|
||||||
---@field EditObject fun(self:df_editor, object:uiobject, profileTable:table, profileKeyMap:table, extraOptions:table?, callback:function?, options:df_editobjectoptions?)
|
---@field EditObject fun(self:df_editor, object:uiobject, profileTable:table?, profileKeyMap:table?, extraOptions:table?, callback:function?, options:df_editobjectoptions?)
|
||||||
---@field PrepareObjectForEditing fun(self:df_editor)
|
---@field PrepareObjectForEditing fun(self:df_editor)
|
||||||
---@field CreateMoverGuideLines fun(self:df_editor)
|
---@field CreateMoverGuideLines fun(self:df_editor)
|
||||||
---@field GetOverTheTopFrame fun(self:df_editor):frame
|
---@field GetOverTheTopFrame fun(self:df_editor):frame
|
||||||
---@field GetMoverFrame fun(self:df_editor):frame
|
---@field GetMoverFrame fun(self:df_editor):frame
|
||||||
---@field StartObjectMovement fun(self:df_editor, anchorSettings:df_anchor)
|
---@field StartObjectMovement fun(self:df_editor, anchorSettings:df_anchor)
|
||||||
---@field StopObjectMovement fun(self:df_editor)
|
---@field StopObjectMovement fun(self:df_editor)
|
||||||
|
---@field RegisterObject fun(self:df_editor, object:uiobject, localizedLabel:string, id:any, profileTable:table, subTablePath:string, profileKeyMap:table, extraOptions:table?, callback:function?, options:df_editobjectoptions?):df_editor_objectinfo
|
||||||
|
---@field UnregisterObject fun(self:df_editor, object:uiobject)
|
||||||
|
---@field EditObjectById fun(self:df_editor, id:any)
|
||||||
|
---@field EditObjectByIndex fun(self:df_editor, index:number)
|
||||||
|
---@field UpdateGuideLinesAnchors fun(self:df_editor)
|
||||||
|
---@field GetObjectByRef fun(self:df_editor, object:uiobject):df_editor_objectinfo
|
||||||
|
---@field GetObjectByIndex fun(self:df_editor, index:number):df_editor_objectinfo
|
||||||
|
---@field GetObjectById fun(self:df_editor, id:any):df_editor_objectinfo
|
||||||
|
---@field CreateObjectSelectionList fun(self:df_editor, scroll_width:number, scroll_height:number, scroll_lines:number, scroll_line_height:number):df_scrollbox
|
||||||
|
---@field OnHide fun(self:df_editor)
|
||||||
|
---@field UpdateProfileTableOnAllRegisteredObjects fun(self:df_editor, profileTable:table)
|
||||||
|
---@field GetProfileTableFromObject fun(self:df_editor, object:df_editor_objectinfo):table
|
||||||
|
|
||||||
---@class df_editobjectoptions : table
|
---@class df_editobjectoptions : table
|
||||||
---@field use_colon boolean if true a colon is shown after the option name
|
---@field use_colon boolean if true a colon is shown after the option name
|
||||||
---@field can_move boolean if true the object can be moved
|
---@field can_move boolean if true the object can be moved
|
||||||
---@field use_guide_lines boolean if true guide lines are shown when the object is being moved
|
---@field use_guide_lines boolean if true guide lines are shown when the object is being moved
|
||||||
|
---@field text_template table
|
||||||
|
|
||||||
---@type df_editobjectoptions
|
---@type df_editobjectoptions
|
||||||
local editObjectDefaultOptions = {
|
local editObjectDefaultOptions = {
|
||||||
use_colon = true,
|
use_colon = false,
|
||||||
can_move = true,
|
can_move = true,
|
||||||
use_guide_lines = true,
|
use_guide_lines = true,
|
||||||
|
text_template = detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE"),
|
||||||
}
|
}
|
||||||
|
|
||||||
local getParentTable = function(profileTable, profileKey)
|
local getParentTable = function(profileTable, profileKey)
|
||||||
@@ -269,12 +312,14 @@ detailsFramework.EditorMixin = {
|
|||||||
self.onEditCallback = nil
|
self.onEditCallback = nil
|
||||||
|
|
||||||
local object = registeredObject.object
|
local object = registeredObject.object
|
||||||
local profileTable = registeredObject.profiletable
|
|
||||||
local profileKeyMap = registeredObject.profilekeymap
|
local profileKeyMap = registeredObject.profilekeymap
|
||||||
local extraOptions = registeredObject.extraoptions
|
local extraOptions = registeredObject.extraoptions
|
||||||
local callback = registeredObject.callback
|
local callback = registeredObject.callback
|
||||||
local options = registeredObject.options
|
local options = registeredObject.options
|
||||||
|
|
||||||
|
local profileTable = self:GetProfileTableFromObject(registeredObject)
|
||||||
|
assert(type(profileTable) == "table", "EditObject() profileTable is invalid.")
|
||||||
|
|
||||||
--as there's no other place which this members are set, there is no need to create setter functions
|
--as there's no other place which this members are set, there is no need to create setter functions
|
||||||
self.editingObject = object
|
self.editingObject = object
|
||||||
self.editingProfileMap = profileKeyMap
|
self.editingProfileMap = profileKeyMap
|
||||||
@@ -338,7 +383,7 @@ detailsFramework.EditorMixin = {
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
|
||||||
PrepareObjectForEditing = function(self)
|
PrepareObjectForEditing = function(self) --~edit
|
||||||
--get the object and its profile table with the current values
|
--get the object and its profile table with the current values
|
||||||
local object = self:GetEditingObject()
|
local object = self:GetEditingObject()
|
||||||
local profileTable, profileMap = self:GetEditingProfile()
|
local profileTable, profileMap = self:GetEditingProfile()
|
||||||
@@ -390,7 +435,7 @@ detailsFramework.EditorMixin = {
|
|||||||
menuOptions[#menuOptions+1] = {type = "blank"}
|
menuOptions[#menuOptions+1] = {type = "blank"}
|
||||||
else
|
else
|
||||||
--get the key to be used on profile table
|
--get the key to be used on profile table
|
||||||
local profileKey = profileMap[option.name]
|
local profileKey = profileMap[option.key]
|
||||||
local value
|
local value
|
||||||
|
|
||||||
--if the key contains a dot or a bracket, it means it's a table path, example: "text_settings[1].width"
|
--if the key contains a dot or a bracket, it means it's a table path, example: "text_settings[1].width"
|
||||||
@@ -410,10 +455,10 @@ detailsFramework.EditorMixin = {
|
|||||||
local minValue = option.minvalue
|
local minValue = option.minvalue
|
||||||
local maxValue = option.maxvalue
|
local maxValue = option.maxvalue
|
||||||
|
|
||||||
if (option.name == "anchoroffsetx") then
|
if (option.key == "anchoroffsetx") then
|
||||||
minValue = -object:GetParent():GetWidth()/2
|
minValue = -object:GetParent():GetWidth()/2
|
||||||
maxValue = object:GetParent():GetWidth()/2
|
maxValue = object:GetParent():GetWidth()/2
|
||||||
elseif (option.name == "anchoroffsety") then
|
elseif (option.key == "anchoroffsety") then
|
||||||
minValue = -object:GetParent():GetHeight()/2
|
minValue = -object:GetParent():GetHeight()/2
|
||||||
maxValue = object:GetParent():GetHeight()/2
|
maxValue = object:GetParent():GetHeight()/2
|
||||||
end
|
end
|
||||||
@@ -421,7 +466,7 @@ detailsFramework.EditorMixin = {
|
|||||||
if (bHasValue) then
|
if (bHasValue) then
|
||||||
local parentTable = getParentTable(profileTable, profileKey)
|
local parentTable = getParentTable(profileTable, profileKey)
|
||||||
|
|
||||||
if (option.name == "anchor" or option.name == "anchoroffsetx" or option.name == "anchoroffsety") then
|
if (option.key == "anchor" or option.key == "anchoroffsetx" or option.key == "anchoroffsety") then
|
||||||
anchorSettings = parentTable
|
anchorSettings = parentTable
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -446,20 +491,20 @@ detailsFramework.EditorMixin = {
|
|||||||
parentTable[4] = alpha
|
parentTable[4] = alpha
|
||||||
|
|
||||||
newValue = parentTable
|
newValue = parentTable
|
||||||
else
|
|
||||||
detailsFramework.table.setfrompath(profileTable, profileKey, newValue)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
detailsFramework.table.setfrompath(profileTable, profileKey, newValue)
|
||||||
|
|
||||||
if (self:GetOnEditCallback()) then
|
if (self:GetOnEditCallback()) then
|
||||||
self:GetOnEditCallback()(object, option.name, newValue, profileTable, profileKey)
|
self:GetOnEditCallback()(object, option.key, newValue, profileTable, profileKey)
|
||||||
end
|
end
|
||||||
|
|
||||||
--update the widget visual
|
--update the widget visual
|
||||||
--anchoring uses SetAnchor() which require the anchorTable to be passed
|
--anchoring uses SetAnchor() which require the anchorTable to be passed
|
||||||
if (option.name == "anchor" or option.name == "anchoroffsetx" or option.name == "anchoroffsety") then
|
if (option.key == "anchor" or option.key == "anchoroffsetx" or option.key == "anchoroffsety") then
|
||||||
anchorSettings = parentTable
|
anchorSettings = parentTable
|
||||||
|
|
||||||
if (option.name == "anchor") then
|
if (option.key == "anchor") then
|
||||||
anchorSettings.x = 0
|
anchorSettings.x = 0
|
||||||
anchorSettings.y = 0
|
anchorSettings.y = 0
|
||||||
end
|
end
|
||||||
@@ -479,7 +524,7 @@ detailsFramework.EditorMixin = {
|
|||||||
max = maxValue,
|
max = maxValue,
|
||||||
step = option.step,
|
step = option.step,
|
||||||
usedecimals = option.usedecimals,
|
usedecimals = option.usedecimals,
|
||||||
id = option.name,
|
id = option.key,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -504,13 +549,14 @@ detailsFramework.EditorMixin = {
|
|||||||
optionsFrame:SetHeight(optionsFrameHeight)
|
optionsFrame:SetHeight(optionsFrameHeight)
|
||||||
|
|
||||||
--templates
|
--templates
|
||||||
local options_text_template = detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")
|
local options_text_template = self.options.text_template or detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")
|
||||||
local options_dropdown_template = detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE")
|
local options_dropdown_template = detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE")
|
||||||
local options_switch_template = detailsFramework:GetTemplate("switch", "OPTIONS_CHECKBOX_TEMPLATE")
|
local options_switch_template = detailsFramework:GetTemplate("switch", "OPTIONS_CHECKBOX_TEMPLATE")
|
||||||
local options_slider_template = detailsFramework:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE")
|
local options_slider_template = detailsFramework:GetTemplate("slider", "OPTIONS_SLIDER_TEMPLATE")
|
||||||
local options_button_template = detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")
|
local options_button_template = detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")
|
||||||
|
|
||||||
detailsFramework:BuildMenuVolatile(optionsFrame, menuOptions, 0, -2, maxHeight, bUseColon, options_text_template, options_dropdown_template, options_switch_template, bSwitchIsCheckbox, options_slider_template, options_button_template)
|
--~build ~menu ~volatile
|
||||||
|
detailsFramework:BuildMenuVolatile(optionsFrame, menuOptions, 2, -2, maxHeight, bUseColon, options_text_template, options_dropdown_template, options_switch_template, bSwitchIsCheckbox, options_slider_template, options_button_template)
|
||||||
|
|
||||||
if (editingOptions.can_move) then
|
if (editingOptions.can_move) then
|
||||||
self:StartObjectMovement(anchorSettings)
|
self:StartObjectMovement(anchorSettings)
|
||||||
@@ -539,8 +585,14 @@ detailsFramework.EditorMixin = {
|
|||||||
|
|
||||||
local optionsFrame = self:GetOptionsFrame()
|
local optionsFrame = self:GetOptionsFrame()
|
||||||
|
|
||||||
|
--getting the size this way due to the cascade of different scales that are applyed to unitFrame objects
|
||||||
|
moverFrame:ClearAllPoints()
|
||||||
|
moverFrame:SetPoint("topleft", object, "topleft", -5, 5)
|
||||||
|
moverFrame:SetPoint("bottomright", object, "bottomright", 5, -5)
|
||||||
|
local moverWidth, moverHeight = moverFrame:GetSize()
|
||||||
|
|
||||||
local objectWidth, objectHeight = object:GetSize()
|
local objectWidth, objectHeight = object:GetSize()
|
||||||
moverFrame:SetSize(objectWidth, objectHeight)
|
moverFrame:SetSize(moverWidth, moverHeight)
|
||||||
detailsFramework:SetAnchor(moverFrame, anchorSettings, object:GetParent())
|
detailsFramework:SetAnchor(moverFrame, anchorSettings, object:GetParent())
|
||||||
local currentPosX, currentPosY
|
local currentPosX, currentPosY
|
||||||
|
|
||||||
@@ -557,6 +609,10 @@ detailsFramework.EditorMixin = {
|
|||||||
moverFrame:StopMovingOrSizing()
|
moverFrame:StopMovingOrSizing()
|
||||||
moverFrame.bIsMoving = false
|
moverFrame.bIsMoving = false
|
||||||
|
|
||||||
|
--0.64 UIParent
|
||||||
|
--0.96 object
|
||||||
|
--local scale = object:GetEffectiveScale() / UIParent:GetEffectiveScale() --1.5
|
||||||
|
|
||||||
local originX = anchorSettings.x
|
local originX = anchorSettings.x
|
||||||
local originY = anchorSettings.y
|
local originY = anchorSettings.y
|
||||||
|
|
||||||
@@ -565,8 +621,11 @@ detailsFramework.EditorMixin = {
|
|||||||
local xOffset = newPosX - currentPosX
|
local xOffset = newPosX - currentPosX
|
||||||
local yOffset = newPosY - currentPosY
|
local yOffset = newPosY - currentPosY
|
||||||
|
|
||||||
anchorSettings.x = originX + xOffset
|
xOffset = xOffset
|
||||||
anchorSettings.y = originY + yOffset
|
yOffset = yOffset
|
||||||
|
|
||||||
|
anchorSettings.x = (originX + xOffset)
|
||||||
|
anchorSettings.y = (originY + yOffset)
|
||||||
|
|
||||||
local anchorXSlider = optionsFrame:GetWidgetById("anchoroffsetx")
|
local anchorXSlider = optionsFrame:GetWidgetById("anchoroffsetx")
|
||||||
anchorXSlider:SetValueNoCallback(anchorSettings.x)
|
anchorXSlider:SetValueNoCallback(anchorSettings.x)
|
||||||
@@ -576,12 +635,24 @@ detailsFramework.EditorMixin = {
|
|||||||
|
|
||||||
object:ClearAllPoints()
|
object:ClearAllPoints()
|
||||||
detailsFramework:SetAnchor(object, anchorSettings, object:GetParent())
|
detailsFramework:SetAnchor(object, anchorSettings, object:GetParent())
|
||||||
|
|
||||||
|
--save the new position
|
||||||
|
local profileTable, profileMap = self:GetEditingProfile()
|
||||||
|
local profileKey = profileMap.anchor
|
||||||
|
local parentTable = getParentTable(profileTable, profileKey)
|
||||||
|
parentTable.x = anchorSettings.x
|
||||||
|
parentTable.y = anchorSettings.y
|
||||||
|
|
||||||
|
if (self:GetOnEditCallback()) then
|
||||||
|
self:GetOnEditCallback()(object, "x", anchorSettings.x, profileTable, profileKey)
|
||||||
|
self:GetOnEditCallback()(object, "y", anchorSettings.x, profileTable, profileKey)
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--detailsFramework:SetAnchor(moverFrame, anchorSettings)
|
--detailsFramework:SetAnchor(moverFrame, anchorSettings)
|
||||||
--detailsFramework:SetAnchor(object, anchorSettings, moverFrame)
|
--detailsFramework:SetAnchor(object, anchorSettings, moverFrame)
|
||||||
|
|
||||||
moverFrame:SetScript("OnUpdate", function()
|
moverFrame:SetScript("OnUpdate", function() --not in use
|
||||||
--if the object isn't moving, make the mover follow the object position
|
--if the object isn't moving, make the mover follow the object position
|
||||||
if (false and moverFrame.bIsMoving) then
|
if (false and moverFrame.bIsMoving) then
|
||||||
--object:ClearAllPoints()
|
--object:ClearAllPoints()
|
||||||
@@ -607,19 +678,6 @@ detailsFramework.EditorMixin = {
|
|||||||
|
|
||||||
currentPosX, currentPosY = newPosX, newPosY
|
currentPosX, currentPosY = newPosX, newPosY
|
||||||
end
|
end
|
||||||
|
|
||||||
--[=[
|
|
||||||
--update the mover frame size to match the object size
|
|
||||||
if (object:GetObjectType() == "FontString") then
|
|
||||||
---@cast object fontstring
|
|
||||||
local width = object:GetStringWidth()
|
|
||||||
local height = object:GetStringHeight()
|
|
||||||
moverFrame:SetSize(width, height)
|
|
||||||
else
|
|
||||||
local width, height = object:GetSize()
|
|
||||||
moverFrame:SetSize(width, height)
|
|
||||||
end
|
|
||||||
--]=]
|
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
@@ -638,7 +696,36 @@ detailsFramework.EditorMixin = {
|
|||||||
moverFrame:Hide()
|
moverFrame:Hide()
|
||||||
end,
|
end,
|
||||||
|
|
||||||
RegisterObject = function(self, object, localizedLabel, id, profileTable, profileKeyMap, extraOptions, callback, options)
|
---@param self df_editor
|
||||||
|
---@param object df_editor_objectinfo
|
||||||
|
GetProfileTableFromObject = function(self, object)
|
||||||
|
local profileTable = object.profiletable
|
||||||
|
local subTablePath = object.subtablepath
|
||||||
|
|
||||||
|
if (type(subTablePath) == "string" and subTablePath ~= "") then
|
||||||
|
local subTable = detailsFramework.table.getfrompath(profileTable, subTablePath)
|
||||||
|
assert(type(subTable) == "table", "GetProfileTableFromObject() subTablePath is invalid.")
|
||||||
|
return subTable
|
||||||
|
end
|
||||||
|
|
||||||
|
return profileTable
|
||||||
|
end,
|
||||||
|
|
||||||
|
UpdateProfileTableOnAllRegisteredObjects = function(self, profileTable)
|
||||||
|
assert(type(profileTable) == "table", "UpdateProfileTableOnAllRegisteredObjects() expects a table on #1 parameter.")
|
||||||
|
|
||||||
|
local registeredObjects = self:GetAllRegisteredObjects()
|
||||||
|
|
||||||
|
for i = 1, #registeredObjects do
|
||||||
|
local objectRegistered = registeredObjects[i]
|
||||||
|
objectRegistered.profiletable = profileTable
|
||||||
|
end
|
||||||
|
|
||||||
|
local objectSelector = self:GetObjectSelector()
|
||||||
|
objectSelector:RefreshMe()
|
||||||
|
end,
|
||||||
|
|
||||||
|
RegisterObject = function(self, object, localizedLabel, id, profileTable, subTablePath, profileKeyMap, extraOptions, callback, options)
|
||||||
assert(type(object) == "table", "RegisterObjectToEdit() expects an UIObject on #1 parameter.")
|
assert(type(object) == "table", "RegisterObjectToEdit() expects an UIObject on #1 parameter.")
|
||||||
assert(object.GetObjectType, "RegisterObjectToEdit() expects an UIObject on #1 parameter.")
|
assert(object.GetObjectType, "RegisterObjectToEdit() expects an UIObject on #1 parameter.")
|
||||||
assert(type(profileTable) == "table", "RegisterObjectToEdit() expects a table on #4 parameter.")
|
assert(type(profileTable) == "table", "RegisterObjectToEdit() expects a table on #4 parameter.")
|
||||||
@@ -671,6 +758,7 @@ detailsFramework.EditorMixin = {
|
|||||||
label = localizedLabel,
|
label = localizedLabel,
|
||||||
id = id,
|
id = id,
|
||||||
profiletable = profileTable,
|
profiletable = profileTable,
|
||||||
|
subtablepath = subTablePath,
|
||||||
profilekeymap = profileKeyMap,
|
profilekeymap = profileKeyMap,
|
||||||
extraoptions = extraOptions or {},
|
extraoptions = extraOptions or {},
|
||||||
callback = callback,
|
callback = callback,
|
||||||
@@ -741,6 +829,10 @@ detailsFramework.EditorMixin = {
|
|||||||
local editorFrame = self
|
local editorFrame = self
|
||||||
|
|
||||||
local refreshFunc = function(self, data, offset, totalLines) --~refresh
|
local refreshFunc = function(self, data, offset, totalLines) --~refresh
|
||||||
|
self.SelectionTexture:Hide()
|
||||||
|
self.SelectionTexture:ClearAllPoints()
|
||||||
|
local objectCurrentBeingEdited = editorFrame:GetEditingObject()
|
||||||
|
|
||||||
for i = 1, totalLines do
|
for i = 1, totalLines do
|
||||||
local index = i + offset
|
local index = i + offset
|
||||||
---@type df_editor_objectinfo
|
---@type df_editor_objectinfo
|
||||||
@@ -749,16 +841,20 @@ detailsFramework.EditorMixin = {
|
|||||||
if (objectRegistered) then
|
if (objectRegistered) then
|
||||||
local line = self:GetLine(i)
|
local line = self:GetLine(i)
|
||||||
line.index = index
|
line.index = index
|
||||||
if (objectRegistered.object:GetObjectType() == "Texture") then
|
|
||||||
line.Icon:SetTexture([[Interface\AnimCreate\AnimCreateIcons]])
|
|
||||||
line.Icon:SetTexCoord(1/4, 2/4, 1/4, 2/4)
|
|
||||||
|
|
||||||
elseif (objectRegistered.object:GetObjectType() == "Texture") then
|
if (objectRegistered.object:GetObjectType() == "Texture") then
|
||||||
line.Icon:SetTexture([[Interface\AnimCreate\AnimCreateIcons]])
|
line.Icon:SetAtlas("AnimCreate_Icon_Texture")
|
||||||
line.Icon:SetTexCoord(2/4, 3/4, 0, 1/4)
|
|
||||||
|
elseif (objectRegistered.object:GetObjectType() == "FontString") then
|
||||||
|
line.Icon:SetAtlas("AnimCreate_Icon_Text")
|
||||||
end
|
end
|
||||||
|
|
||||||
line.Label:SetText(objectRegistered.label)
|
line.Label:SetText(objectRegistered.label)
|
||||||
|
|
||||||
|
if (objectRegistered.object == objectCurrentBeingEdited) then
|
||||||
|
self.SelectionTexture:SetAllPoints(line)
|
||||||
|
self.SelectionTexture:Show()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -775,14 +871,13 @@ detailsFramework.EditorMixin = {
|
|||||||
line:SetBackdropColor(.1, .1, .1, .4)
|
line:SetBackdropColor(.1, .1, .1, .4)
|
||||||
end
|
end
|
||||||
|
|
||||||
detailsFramework:Mixin(line, detailsFramework.HeaderFunctions)
|
detailsFramework:CreateHighlightTexture(line, "HighlightTexture")
|
||||||
|
detailsFramework:Mixin(line, detailsFramework.HeaderFunctions)
|
||||||
--line:SetScript("OnEnter", lineOnEnter)
|
|
||||||
--line:SetScript("OnLeave", lineOnLeave)
|
|
||||||
|
|
||||||
line:SetScript("OnClick", function(self)
|
line:SetScript("OnClick", function(self)
|
||||||
local objectRegistered = editorFrame:GetObjectByIndex(self.index)
|
local objectRegistered = editorFrame:GetObjectByIndex(self.index)
|
||||||
editorFrame:EditObject(objectRegistered)
|
editorFrame:EditObject(objectRegistered)
|
||||||
|
editorFrame.objectSelector:RefreshMe()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
--icon
|
--icon
|
||||||
@@ -804,6 +899,10 @@ detailsFramework.EditorMixin = {
|
|||||||
local selectObjectScrollBox = detailsFramework:CreateScrollBox(self:GetParent(), "$parentSelectObjectScrollBox", refreshFunc, editorFrame:GetAllRegisteredObjects(), scroll_width, scroll_height, scroll_lines, scroll_line_height)
|
local selectObjectScrollBox = detailsFramework:CreateScrollBox(self:GetParent(), "$parentSelectObjectScrollBox", refreshFunc, editorFrame:GetAllRegisteredObjects(), scroll_width, scroll_height, scroll_lines, scroll_line_height)
|
||||||
detailsFramework:ReskinSlider(selectObjectScrollBox)
|
detailsFramework:ReskinSlider(selectObjectScrollBox)
|
||||||
|
|
||||||
|
local selectionTexture = selectObjectScrollBox:CreateTexture(nil, "overlay")
|
||||||
|
selectionTexture:SetColorTexture(1, 1, 0, 0.2)
|
||||||
|
selectObjectScrollBox.SelectionTexture = selectionTexture
|
||||||
|
|
||||||
function selectObjectScrollBox:RefreshMe()
|
function selectObjectScrollBox:RefreshMe()
|
||||||
selectObjectScrollBox:SetData(editorFrame:GetAllRegisteredObjects())
|
selectObjectScrollBox:SetData(editorFrame:GetAllRegisteredObjects())
|
||||||
selectObjectScrollBox:Refresh()
|
selectObjectScrollBox:Refresh()
|
||||||
@@ -831,8 +930,11 @@ detailsFramework.EditorMixin = {
|
|||||||
---@field object_list_height number
|
---@field object_list_height number
|
||||||
---@field object_list_lines number
|
---@field object_list_lines number
|
||||||
---@field object_list_line_height number
|
---@field object_list_line_height number
|
||||||
|
---@field text_template table
|
||||||
|
|
||||||
---@class df_editor_defaultoptions
|
--editorFrame.options.text_template
|
||||||
|
|
||||||
|
---@type df_editor_defaultoptions
|
||||||
local editorDefaultOptions = {
|
local editorDefaultOptions = {
|
||||||
width = 400,
|
width = 400,
|
||||||
height = 548,
|
height = 548,
|
||||||
@@ -842,36 +944,9 @@ local editorDefaultOptions = {
|
|||||||
object_list_height = 420,
|
object_list_height = 420,
|
||||||
object_list_lines = 20,
|
object_list_lines = 20,
|
||||||
object_list_line_height = 20,
|
object_list_line_height = 20,
|
||||||
|
text_template = detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE"),
|
||||||
}
|
}
|
||||||
|
|
||||||
---@class df_editor : frame, df_optionsmixin, df_editormixin
|
|
||||||
---@field options table
|
|
||||||
---@field registeredObjects df_editor_objectinfo[]
|
|
||||||
---@field registeredObjectsByID table<any, df_editor_objectinfo>
|
|
||||||
---@field editingObject uiobject
|
|
||||||
---@field editingProfileTable table
|
|
||||||
---@field editingProfileMap table
|
|
||||||
---@field editingOptions df_editobjectoptions
|
|
||||||
---@field editingExtraOptions table
|
|
||||||
---@field moverGuideLines table<string, texture>
|
|
||||||
---@field onEditCallback function
|
|
||||||
---@field optionsFrame frame
|
|
||||||
---@field overTheTopFrame frame
|
|
||||||
---@field objectSelector df_scrollbox
|
|
||||||
---@field moverFrame frame
|
|
||||||
---@field canvasScrollBox df_canvasscrollbox
|
|
||||||
|
|
||||||
---@class df_editor_objectinfo : table
|
|
||||||
---@field object uiobject
|
|
||||||
---@field label string
|
|
||||||
---@field id any
|
|
||||||
---@field profiletable table
|
|
||||||
---@field profilekeymap table
|
|
||||||
---@field extraoptions table
|
|
||||||
---@field callback function
|
|
||||||
---@field options df_editobjectoptions
|
|
||||||
---@field selectButton button
|
|
||||||
|
|
||||||
function detailsFramework:CreateEditor(parent, name, options)
|
function detailsFramework:CreateEditor(parent, name, options)
|
||||||
name = name or ("DetailsFrameworkEditor" .. math.random(100000, 10000000))
|
name = name or ("DetailsFrameworkEditor" .. math.random(100000, 10000000))
|
||||||
local editorFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
|
local editorFrame = CreateFrame("frame", name, parent, "BackdropTemplate")
|
||||||
|
|||||||
+23
-2
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
local dversion = 507
|
local dversion = 510
|
||||||
local major, minor = "DetailsFramework-1.0", dversion
|
local major, minor = "DetailsFramework-1.0", dversion
|
||||||
local DF, oldminor = LibStub:NewLibrary(major, minor)
|
local DF, oldminor = LibStub:NewLibrary(major, minor)
|
||||||
|
|
||||||
@@ -49,6 +49,12 @@ function DF:MsgWarning(msg, ...)
|
|||||||
print("|cFFFFFFAA" .. (self.__name or "Details!Framework") .. "|r |cFFFFAA00[Warning]|r", msg, ...)
|
print("|cFFFFFFAA" .. (self.__name or "Details!Framework") .. "|r |cFFFFAA00[Warning]|r", msg, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
DF.DefaultRoundedCornerPreset = {
|
||||||
|
roundness = 6,
|
||||||
|
color = {.1, .1, .1, 0.98},
|
||||||
|
border_color = {.05, .05, .05, 0.834},
|
||||||
|
}
|
||||||
|
|
||||||
DF.internalFunctions = DF.internalFunctions or {}
|
DF.internalFunctions = DF.internalFunctions or {}
|
||||||
|
|
||||||
local PixelUtil = PixelUtil or DFPixelUtil
|
local PixelUtil = PixelUtil or DFPixelUtil
|
||||||
@@ -506,6 +512,16 @@ function DF:FadeFrame(frame, t)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------------------------------------
|
||||||
|
function DF:RandomBool(odds)
|
||||||
|
if (odds) then
|
||||||
|
local chance = math.random()
|
||||||
|
return chance <= odds
|
||||||
|
else
|
||||||
|
return math.random(1, 2) == 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------
|
||||||
--table
|
--table
|
||||||
|
|
||||||
@@ -804,6 +820,7 @@ function DF.table.deploy(t1, t2)
|
|||||||
return t1
|
return t1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--/run print (DetailsFramework.table.dump({{1, 2}, {2, 3}, {4, 5}}))
|
||||||
local function tableToString(t, resultString, deep, seenTables)
|
local function tableToString(t, resultString, deep, seenTables)
|
||||||
resultString = resultString or ""
|
resultString = resultString or ""
|
||||||
deep = deep or 0
|
deep = deep or 0
|
||||||
@@ -853,7 +870,11 @@ local function tableToString(t, resultString, deep, seenTables)
|
|||||||
resultString = resultString .. space .. "[\"" .. key .. "\"] = \"|cFFfff1c1" .. value .. "|r\",\n"
|
resultString = resultString .. space .. "[\"" .. key .. "\"] = \"|cFFfff1c1" .. value .. "|r\",\n"
|
||||||
|
|
||||||
elseif (valueType == "number") then
|
elseif (valueType == "number") then
|
||||||
resultString = resultString .. space .. "[\"" .. key .. "\"] = |cFF94CEA8" .. value .. "|r,\n"
|
if (type(key) == "number") then
|
||||||
|
resultString = resultString .. space .. "[" .. key .. "] = |cFFffc1f4" .. value .. "|r,\n"
|
||||||
|
else
|
||||||
|
resultString = resultString .. space .. "[\"" .. key .. "\"] = |cFF94CEA8" .. value .. "|r,\n"
|
||||||
|
end
|
||||||
|
|
||||||
elseif (valueType == "function") then
|
elseif (valueType == "function") then
|
||||||
resultString = resultString .. space .. "[\"" .. key .. "\"] = |cFFC586C0function|r,\n"
|
resultString = resultString .. space .. "[\"" .. key .. "\"] = |cFFC586C0function|r,\n"
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ local default_load_conditions_frame_options = {
|
|||||||
|
|
||||||
function detailsFramework:CreateLoadFilterParser(callback)
|
function detailsFramework:CreateLoadFilterParser(callback)
|
||||||
local filterFrame = CreateFrame("frame")
|
local filterFrame = CreateFrame("frame")
|
||||||
|
|
||||||
if IS_WOW_PROJECT_MAINLINE then
|
if IS_WOW_PROJECT_MAINLINE then
|
||||||
filterFrame:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
|
filterFrame:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED")
|
||||||
filterFrame:RegisterEvent("TRAIT_CONFIG_LIST_UPDATED")
|
filterFrame:RegisterEvent("TRAIT_CONFIG_LIST_UPDATED")
|
||||||
@@ -117,11 +117,47 @@ function detailsFramework:CreateLoadFilterParser(callback)
|
|||||||
filterFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
|
filterFrame:RegisterEvent("PLAYER_REGEN_ENABLED")
|
||||||
filterFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
|
filterFrame:RegisterEvent("PLAYER_REGEN_DISABLED")
|
||||||
|
|
||||||
|
filterFrame:RegisterEvent("CHAT_MSG_LOOT")
|
||||||
|
|
||||||
filterFrame:SetScript("OnEvent", function(self, event, ...)
|
filterFrame:SetScript("OnEvent", function(self, event, ...)
|
||||||
if (event == "ENCOUNTER_START") then --triggers before regen_disabled
|
if (event == "ENCOUNTER_START") then --triggers before regen_disabled
|
||||||
local encounterID = ...
|
local encounterID = ...
|
||||||
filterFrame.EncounterIDCached = encounterID
|
filterFrame.EncounterIDCached = encounterID
|
||||||
|
|
||||||
|
elseif (event == "CHAT_MSG_LOOT") then
|
||||||
|
local message = ...
|
||||||
|
local itemId = message:match("|Hitem:(%d+):")
|
||||||
|
itemId = tonumber(itemId)
|
||||||
|
|
||||||
|
if (itemId == 191140) then
|
||||||
|
xpcall(callback, geterrorhandler(), "RACE_START")
|
||||||
|
--monitor the player backpack each second to know when the item is removed from the bag
|
||||||
|
|
||||||
|
C_Timer.After(5, function()
|
||||||
|
filterFrame.FindBackpackItem = C_Timer.NewTicker(1, function()
|
||||||
|
local bFoundItem = false
|
||||||
|
for bagId = 0, 4 do
|
||||||
|
for slotId = 1, 32 do
|
||||||
|
local bagItemID = C_Container.GetContainerItemID(bagId, slotId)
|
||||||
|
if (bagItemID) then
|
||||||
|
if (bagItemID == itemId) then
|
||||||
|
--bronze timepiece is on the player backpack
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (not bFoundItem) then
|
||||||
|
filterFrame.FindBackpackItem:Cancel()
|
||||||
|
xpcall(callback, geterrorhandler(), "RACE_STOP")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
|
||||||
elseif (event == "PLAYER_REGEN_DISABLED") then
|
elseif (event == "PLAYER_REGEN_DISABLED") then
|
||||||
|
|
||||||
elseif (event == "ENCOUNTER_END") then
|
elseif (event == "ENCOUNTER_END") then
|
||||||
@@ -157,7 +193,8 @@ function detailsFramework:CreateLoadFilterParser(callback)
|
|||||||
detailsFramework.CurrentPlayerRole = assignedRole
|
detailsFramework.CurrentPlayerRole = assignedRole
|
||||||
end
|
end
|
||||||
|
|
||||||
detailsFramework:QuickDispatch(callback, filterFrame.EncounterIDCached)
|
--problem: this xpcall won't tell where the error happened in the callback code
|
||||||
|
xpcall(callback, geterrorhandler(), filterFrame.EncounterIDCached)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2085,7 +2085,7 @@ local no_options = {}
|
|||||||
---NoCloseButton = false, --if true, won't show the close button
|
---NoCloseButton = false, --if true, won't show the close button
|
||||||
---NoTitleBar = false, --if true, don't create the title bar
|
---NoTitleBar = false, --if true, don't create the title bar
|
||||||
---RoundedCorners = false, --use rounded corners if true
|
---RoundedCorners = false, --use rounded corners if true
|
||||||
---@class simplepanel
|
---@class simplepanel : frame
|
||||||
---@field TitleBar frame
|
---@field TitleBar frame
|
||||||
---@field Title fontstring
|
---@field Title fontstring
|
||||||
---@field Close button
|
---@field Close button
|
||||||
|
|||||||
@@ -367,3 +367,22 @@ detailsFramework:Mixin(ImageMetaFunctions, detailsFramework.ScriptHookMixin)
|
|||||||
|
|
||||||
return ImageObject
|
return ImageObject
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function detailsFramework:CreateHighlightTexture(parent, parentKey, alpha, name)
|
||||||
|
if (not name) then
|
||||||
|
name = "DetailsFrameworkPictureNumber" .. detailsFramework.PictureNameCounter
|
||||||
|
detailsFramework.PictureNameCounter = detailsFramework.PictureNameCounter + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local highlightTexture = parent:CreateTexture(name, "highlight")
|
||||||
|
highlightTexture:SetTexture([[Interface\Buttons\WHITE8X8]])
|
||||||
|
highlightTexture:SetAlpha(alpha or 0.1)
|
||||||
|
highlightTexture:SetBlendMode("ADD")
|
||||||
|
highlightTexture:SetAllPoints()
|
||||||
|
|
||||||
|
if (parentKey) then
|
||||||
|
parent[parentKey] = highlightTexture
|
||||||
|
end
|
||||||
|
|
||||||
|
return highlightTexture
|
||||||
|
end
|
||||||
@@ -411,6 +411,11 @@ detailsFramework.RoundedCornerPanelMixin = {
|
|||||||
alignment = alignment:lower()
|
alignment = alignment:lower()
|
||||||
|
|
||||||
if (alignment == "vertical") then
|
if (alignment == "vertical") then
|
||||||
|
if (self.tabSide) then
|
||||||
|
if (self.tabSide == "top" or self.tabSide == "bottom") then
|
||||||
|
return self:GetHeight() - (borderTexture:GetHeight() * 2) + 2 - borderTexture:GetHeight()
|
||||||
|
end
|
||||||
|
end
|
||||||
return self:GetHeight() - (borderTexture:GetHeight() * 2) + 2
|
return self:GetHeight() - (borderTexture:GetHeight() * 2) + 2
|
||||||
|
|
||||||
elseif (alignment == "horizontal") then
|
elseif (alignment == "horizontal") then
|
||||||
@@ -678,6 +683,68 @@ function detailsFramework:AddRoundedCornersToFrame(frame, preset)
|
|||||||
applyPreset(frame, preset)
|
applyPreset(frame, preset)
|
||||||
else
|
else
|
||||||
applyPreset(frame, defaultPreset)
|
applyPreset(frame, defaultPreset)
|
||||||
|
preset = defaultPreset
|
||||||
|
end
|
||||||
|
|
||||||
|
if (preset.tab_side) then
|
||||||
|
if (preset.tab_side == "top") then
|
||||||
|
--hide the bottom textures of the rounded corner, the top and middle textures will be used to fill the tab
|
||||||
|
frame.BottomHorizontalEdge:Hide()
|
||||||
|
frame.BottomLeft:Hide()
|
||||||
|
frame.BottomRight:Hide()
|
||||||
|
|
||||||
|
local point1, relativeTo, point2, x, y = frame.CornerTextures["TopLeft"]:GetPoint(1)
|
||||||
|
frame.CornerTextures["TopLeft"]:SetPoint(point1, relativeTo, point2, x, math.abs(preset.roundness -16))
|
||||||
|
|
||||||
|
point1, relativeTo, point2, x, y = frame.CornerTextures["TopRight"]:GetPoint(1)
|
||||||
|
frame.CornerTextures["TopRight"]:SetPoint(point1, relativeTo, point2, x, math.abs(preset.roundness -16))
|
||||||
|
|
||||||
|
if (frame.BorderCornerTextures["TopLeft"]) then
|
||||||
|
point1, relativeTo, point2, x, y = frame.BorderCornerTextures["TopLeft"]:GetPoint(1)
|
||||||
|
frame.BorderCornerTextures["TopLeft"]:SetPoint(point1, relativeTo, point2, x, math.abs(preset.roundness -16))
|
||||||
|
|
||||||
|
point1, relativeTo, point2, x, y = frame.BorderCornerTextures["TopRight"]:GetPoint(1)
|
||||||
|
frame.BorderCornerTextures["TopRight"]:SetPoint(point1, relativeTo, point2, x, math.abs(preset.roundness -16))
|
||||||
|
|
||||||
|
point1, relativeTo, point2, x, y = frame.TopEdgeBorder:GetPoint(1)
|
||||||
|
frame.TopEdgeBorder:SetPoint(point1, relativeTo, point2, x, math.abs(preset.roundness -16))
|
||||||
|
|
||||||
|
frame.BottomEdgeBorder:Hide()
|
||||||
|
|
||||||
|
frame.tabSide = "top"
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif (preset.tab_side == "bottom") then
|
||||||
|
--hide the top textures of the rounded corner, the bottom and middle textures will be used to fill the tab
|
||||||
|
frame.TopHorizontalEdge:Hide()
|
||||||
|
frame.TopLeft:Hide()
|
||||||
|
frame.TopRight:Hide()
|
||||||
|
|
||||||
|
local point1, relativeTo, point2, x, y = frame.CornerTextures["BottomLeft"]:GetPoint(1)
|
||||||
|
frame.CornerTextures["BottomLeft"]:SetPoint(point1, relativeTo, point2, x, math.abs(preset.roundness -16))
|
||||||
|
|
||||||
|
point1, relativeTo, point2, x, y = frame.CornerTextures["BottomRight"]:GetPoint(1)
|
||||||
|
frame.CornerTextures["BottomRight"]:SetPoint(point1, relativeTo, point2, x, math.abs(preset.roundness -16))
|
||||||
|
|
||||||
|
if (frame.BorderCornerTextures["BottomLeft"]) then
|
||||||
|
point1, relativeTo, point2, x, y = frame.BorderCornerTextures["BottomLeft"]:GetPoint(1)
|
||||||
|
frame.BorderCornerTextures["BottomLeft"]:SetPoint(point1, relativeTo, point2, x, math.abs(preset.roundness -16))
|
||||||
|
|
||||||
|
point1, relativeTo, point2, x, y = frame.BorderCornerTextures["BottomRight"]:GetPoint(1)
|
||||||
|
frame.BorderCornerTextures["BottomRight"]:SetPoint(point1, relativeTo, point2, x, math.abs(preset.roundness -16))
|
||||||
|
|
||||||
|
point1, relativeTo, point2, x, y = frame.BottomEdgeBorder:GetPoint(1)
|
||||||
|
frame.BottomEdgeBorder:SetPoint(point1, relativeTo, point2, x, math.abs(preset.roundness -16))
|
||||||
|
|
||||||
|
frame.TopEdgeBorder:Hide()
|
||||||
|
|
||||||
|
point1, relativeTo, point2, x, y = frame.RightEdgeBorder:GetPoint(1)
|
||||||
|
---@type height
|
||||||
|
local verticalEdgeSize = frame:CalculateBorderEdgeSize("vertical")
|
||||||
|
frame.RightEdgeBorder:SetHeight(verticalEdgeSize - 6)
|
||||||
|
frame.tabSide = "bottom"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+155
-2
@@ -15,6 +15,16 @@ local UnitGUID = UnitGUID
|
|||||||
--create namespace
|
--create namespace
|
||||||
detailsFramework.SavedVars = {}
|
detailsFramework.SavedVars = {}
|
||||||
|
|
||||||
|
function detailsFramework.SavedVars.GetCurrentProfileName(addonObject)
|
||||||
|
assert(type(addonObject) == "table", "GetCurrentProfileName: addonObject must be a table.")
|
||||||
|
|
||||||
|
local savedVariables = detailsFramework.SavedVars.GetSavedVariables(addonObject)
|
||||||
|
local playerGUID = UnitGUID("player")
|
||||||
|
local profileId = savedVariables.profile_ids[playerGUID] --get the profile name from the player guid
|
||||||
|
|
||||||
|
return profileId
|
||||||
|
end
|
||||||
|
|
||||||
---get the saved variables table for the addon
|
---get the saved variables table for the addon
|
||||||
---@param addonObject df_addon the addon object created by detailsFramework:CreateNewAddOn()
|
---@param addonObject df_addon the addon object created by detailsFramework:CreateNewAddOn()
|
||||||
---@return table
|
---@return table
|
||||||
@@ -83,7 +93,7 @@ end
|
|||||||
|
|
||||||
---@param addonObject df_addon the addon object created by detailsFramework:CreateNewAddOn()
|
---@param addonObject df_addon the addon object created by detailsFramework:CreateNewAddOn()
|
||||||
---@param profileName profilename the name of the profile to set
|
---@param profileName profilename the name of the profile to set
|
||||||
---@param bCopyFromCurrentProfile boolean if true, copy the current profile to the new profile
|
---@param bCopyFromCurrentProfile boolean? if true, copy the current profile to the new profile
|
||||||
function detailsFramework.SavedVars.SetProfile(addonObject, profileName, bCopyFromCurrentProfile)
|
function detailsFramework.SavedVars.SetProfile(addonObject, profileName, bCopyFromCurrentProfile)
|
||||||
assert(type(addonObject) == "table", "SetProfile: addonObject must be a table.")
|
assert(type(addonObject) == "table", "SetProfile: addonObject must be a table.")
|
||||||
assert(type(profileName) == "string", "SetProfile: profileName must be a string.")
|
assert(type(profileName) == "string", "SetProfile: profileName must be a string.")
|
||||||
@@ -137,4 +147,147 @@ function detailsFramework.SavedVars.SaveProfile(addonObject)
|
|||||||
savedVariables.profiles[playerProfileId] = profileTable
|
savedVariables.profiles[playerProfileId] = profileTable
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
---@class df_profilepanel : frame
|
||||||
|
---@field AddonObject df_addon
|
||||||
|
---@field ProfileNameValueLabel fontstring
|
||||||
|
---@field ProfileSelectionDropdown df_dropdown
|
||||||
|
---@field ProfileNameTextEntry df_textentry
|
||||||
|
---@field OnClickCreateNewProfile function
|
||||||
|
---@field RefreshSelectProfileDropdown function
|
||||||
|
|
||||||
|
---@param profilePanel df_profilepanel
|
||||||
|
function detailsFramework.SavedVars.RefreshProfilePanel(profilePanel)
|
||||||
|
local addonObject = profilePanel.AddonObject
|
||||||
|
|
||||||
|
--update the current profile name
|
||||||
|
---@type string
|
||||||
|
local profileName = detailsFramework.SavedVars.GetCurrentProfileName(addonObject)
|
||||||
|
profilePanel.ProfileNameValueLabel:SetText(profileName)
|
||||||
|
|
||||||
|
--update the options of the dropdown to select a profile
|
||||||
|
profilePanel:RefreshSelectProfileDropdown()
|
||||||
|
|
||||||
|
--clear the text entry for the new profile name
|
||||||
|
profilePanel.ProfileNameTextEntry:SetText("")
|
||||||
|
end
|
||||||
|
|
||||||
|
local profilePanelMixin = {
|
||||||
|
---@param self df_profilepanel
|
||||||
|
RefreshSelectProfileDropdown = function(self)
|
||||||
|
local addonObject = self.AddonObject
|
||||||
|
local savedVariables = detailsFramework.SavedVars.GetSavedVariables(addonObject)
|
||||||
|
local profiles = savedVariables.profiles
|
||||||
|
|
||||||
|
local callback = function(self, fixedValue, profileSelected)
|
||||||
|
detailsFramework.SavedVars.SetProfile(addonObject, profileSelected)
|
||||||
|
detailsFramework.SavedVars.RefreshProfilePanel(self:GetParent())
|
||||||
|
end
|
||||||
|
|
||||||
|
local dropdownOptions = {}
|
||||||
|
for profileId in pairs(profiles) do
|
||||||
|
table.insert(dropdownOptions, {value = profileId, label = profileId, onclick = callback, icon = [[Interface\CHATFRAME\UI-ChatIcon-BlizzardArcadeCollection]], iconsize = {16, 16}})
|
||||||
|
end
|
||||||
|
|
||||||
|
self.ProfileSelectionDropdown.Options = dropdownOptions
|
||||||
|
self.ProfileSelectionDropdown:Refresh()
|
||||||
|
self.ProfileSelectionDropdown:Select(detailsFramework.SavedVars.GetCurrentProfileName(addonObject))
|
||||||
|
end,
|
||||||
|
|
||||||
|
---@param self df_profilepanel
|
||||||
|
OnClickCreateNewProfile = function(self)
|
||||||
|
local addonObject = self.AddonObject
|
||||||
|
local profileName = self.ProfileNameTextEntry:GetText()
|
||||||
|
detailsFramework.SavedVars.SetProfile(addonObject, profileName)
|
||||||
|
detailsFramework.SavedVars.RefreshProfilePanel(self)
|
||||||
|
end
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
local defaultProfilePanelOptions = {
|
||||||
|
width = 600,
|
||||||
|
height = 400,
|
||||||
|
title = "Profile Management"
|
||||||
|
}
|
||||||
|
|
||||||
|
function detailsFramework.SavedVars.CreateProfilePanel(addonObject, frameName, parentFrame, options)
|
||||||
|
options = options or detailsFramework.table.copy({}, defaultProfilePanelOptions)
|
||||||
|
detailsFramework.table.deploy(options, defaultProfilePanelOptions)
|
||||||
|
|
||||||
|
local textentryTemplate, labelTemplate = detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE"), detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE")
|
||||||
|
local buttonTemplate = detailsFramework:GetTemplate("button", "OPTIONS_BUTTON_TEMPLATE")
|
||||||
|
local dropdownTemplate = detailsFramework:GetTemplate("dropdown", "OPTIONS_DROPDOWN_TEMPLATE")
|
||||||
|
|
||||||
|
--create a simple frame
|
||||||
|
local panelOptions = {}
|
||||||
|
---@type df_profilepanel
|
||||||
|
local frame = CreateFrame("frame", frameName, parentFrame)
|
||||||
|
frame:SetSize(options.width, options.height)
|
||||||
|
frame.AddonObject = addonObject
|
||||||
|
|
||||||
|
detailsFramework:Mixin(frame, profilePanelMixin)
|
||||||
|
detailsFramework:AddRoundedCornersToFrame(frame, Details.PlayerBreakdown.RoundedCornerPreset)
|
||||||
|
|
||||||
|
--create a label with the name of the profile (two labels, one for the name "Profile Name" and one for the value)
|
||||||
|
---@type fontstring
|
||||||
|
local profileNameLabel = frame:CreateFontString(nil, "overlay", "GameFontNormal")
|
||||||
|
profileNameLabel:SetPoint("topleft", frame, "topleft", 10, -10)
|
||||||
|
profileNameLabel:SetText("Current Profile:")
|
||||||
|
|
||||||
|
---@type fontstring
|
||||||
|
local profileNameValueLabel = frame:CreateFontString(nil, "overlay", "GameFontNormal")
|
||||||
|
profileNameValueLabel:SetPoint("left", profileNameLabel, "right", 5, 0)
|
||||||
|
profileNameValueLabel:SetText("")
|
||||||
|
frame.ProfileNameValueLabel = profileNameValueLabel
|
||||||
|
|
||||||
|
---@type fontstring
|
||||||
|
local selectProfileLabel = frame:CreateFontString(nil, "overlay", "GameFontNormal")
|
||||||
|
selectProfileLabel:SetPoint("topleft", profileNameLabel, "bottomleft", 0, -15)
|
||||||
|
selectProfileLabel:SetText("Select:")
|
||||||
|
|
||||||
|
--create a dropdown to select the profile
|
||||||
|
local onSelectProfileCallback = function()
|
||||||
|
return frame.ProfileSelectionDropdown.Options or {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local defaultValue = 1 -- set default to 1, latter when refreshing the entire panel, set the default to the current profile
|
||||||
|
---@type df_dropdown
|
||||||
|
local profileSelectionDropdown = detailsFramework:CreateDropDown(frame, onSelectProfileCallback, defaultValue, 180, 32, "ProfileSelectionDropdown", "$parentProfileSelectionDropdown", dropdownTemplate)
|
||||||
|
profileSelectionDropdown:SetPoint("topleft", selectProfileLabel, "bottomleft", 0, -5)
|
||||||
|
profileSelectionDropdown:SetBackdrop(nil)
|
||||||
|
detailsFramework:AddRoundedCornersToFrame(profileSelectionDropdown, Details.PlayerBreakdown.RoundedCornerPreset)
|
||||||
|
frame.ProfileSelectionDropdown = profileSelectionDropdown
|
||||||
|
|
||||||
|
---@type fontstring
|
||||||
|
local createNewProfileLabel = frame:CreateFontString(nil, "overlay", "GameFontNormal")
|
||||||
|
createNewProfileLabel:SetPoint("topleft", profileSelectionDropdown.widget, "bottomleft", 0, -10)
|
||||||
|
createNewProfileLabel:SetText("Create New:")
|
||||||
|
|
||||||
|
--create a textentry to enter the name of the profile to be created and create a button to create the new profile
|
||||||
|
local onPressEnterCallback = function()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
---@type df_textentry
|
||||||
|
local profileNameTextEntry = detailsFramework:CreateTextEntry(frame, onPressEnterCallback, 180, 32, "ProfileNameEntry", "$parentProfileNameTextEntry", "Profile Name")
|
||||||
|
profileNameTextEntry:SetPoint("topleft", createNewProfileLabel, "bottomleft", 0, -5)
|
||||||
|
profileNameTextEntry:SetBackdrop(nil)
|
||||||
|
profileNameTextEntry:SetJustifyH("left")
|
||||||
|
profileNameTextEntry.fontsize = 12
|
||||||
|
detailsFramework:AddRoundedCornersToFrame(profileNameTextEntry, Details.PlayerBreakdown.RoundedCornerPreset)
|
||||||
|
frame.ProfileNameTextEntry = profileNameTextEntry
|
||||||
|
|
||||||
|
---@type df_button
|
||||||
|
local createProfileButton = detailsFramework:CreateButton(frame, function() frame.OnClickCreateNewProfile(frame) end, 100, 32, "Create", false, false, false, "ProfileCreateButton", "$parentCreateProfileButton", buttonTemplate, labelTemplate)
|
||||||
|
createProfileButton:SetPoint("left", profileNameTextEntry, "right", 5, 0)
|
||||||
|
detailsFramework:AddRoundedCornersToFrame(createProfileButton, Details.PlayerBreakdown.RoundedCornerPreset)
|
||||||
|
|
||||||
|
frame:SetScript("OnShow", function()
|
||||||
|
detailsFramework.SavedVars.RefreshProfilePanel(frame)
|
||||||
|
end)
|
||||||
|
|
||||||
|
frame:Hide()
|
||||||
|
|
||||||
|
return frame
|
||||||
|
end
|
||||||
|
|||||||
+15
-12
@@ -8,6 +8,8 @@ local C_Timer = _G.C_Timer
|
|||||||
local unpack = table.unpack or _G.unpack
|
local unpack = table.unpack or _G.unpack
|
||||||
local GetTime = GetTime
|
local GetTime = GetTime
|
||||||
|
|
||||||
|
local CONST_DEBUG_ENABLED = false
|
||||||
|
|
||||||
--make a namespace for schedules
|
--make a namespace for schedules
|
||||||
detailsFramework.Schedules = detailsFramework.Schedules or {}
|
detailsFramework.Schedules = detailsFramework.Schedules or {}
|
||||||
|
|
||||||
@@ -67,10 +69,11 @@ local triggerScheduledLoop = function(tickerObject)
|
|||||||
local payload = tickerObject.payload
|
local payload = tickerObject.payload
|
||||||
local callback = tickerObject.callback
|
local callback = tickerObject.callback
|
||||||
|
|
||||||
local result, errortext = pcall(callback, unpack(payload))
|
--local result, errortext = pcall(callback, unpack(payload))
|
||||||
if (not result) then
|
local runOkay, result = xpcall(callback, geterrorhandler(), unpack(payload))
|
||||||
detailsFramework:Msg("error on scheduler: ",tickerObject.path , tickerObject.name, errortext)
|
--if (not result) then
|
||||||
end
|
-- detailsFramework:Msg("error on scheduler: ",tickerObject.path , tickerObject.name, errortext)
|
||||||
|
--end
|
||||||
|
|
||||||
local checkPointCallback = tickerObject.checkPointCallback
|
local checkPointCallback = tickerObject.checkPointCallback
|
||||||
if (checkPointCallback) then
|
if (checkPointCallback) then
|
||||||
@@ -127,10 +130,11 @@ local triggerScheduledTick = function(tickerObject)
|
|||||||
local payload = tickerObject.payload
|
local payload = tickerObject.payload
|
||||||
local callback = tickerObject.callback
|
local callback = tickerObject.callback
|
||||||
|
|
||||||
local result, errortext = pcall(callback, unpack(payload))
|
local runOkay, result = xpcall(callback, geterrorhandler(), unpack(payload))
|
||||||
if (not result) then
|
--local result, errortext = pcall(callback, unpack(payload))
|
||||||
detailsFramework:Msg("error on scheduler: ",tickerObject.path , tickerObject.name, errortext)
|
--if (not result) then
|
||||||
end
|
-- detailsFramework:Msg("error on scheduler: ",tickerObject.path , tickerObject.name, errortext)
|
||||||
|
--end
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -142,8 +146,8 @@ function detailsFramework.Schedules.NewTicker(time, callback, ...)
|
|||||||
newTicker.callback = callback
|
newTicker.callback = callback
|
||||||
|
|
||||||
--debug
|
--debug
|
||||||
newTicker.path = debugstack()
|
newTicker.path = CONST_DEBUG_ENABLED and debugstack() or ""
|
||||||
--
|
|
||||||
return newTicker
|
return newTicker
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -156,8 +160,7 @@ function detailsFramework.Schedules.NewTimer(time, callback, ...)
|
|||||||
newTimer.expireAt = GetTime() + time
|
newTimer.expireAt = GetTime() + time
|
||||||
|
|
||||||
--debug
|
--debug
|
||||||
newTimer.path = debugstack()
|
newTimer.path = CONST_DEBUG_ENABLED and debugstack() or ""
|
||||||
--
|
|
||||||
|
|
||||||
return newTimer
|
return newTimer
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,10 +26,12 @@ detailsFramework.ScrollBoxFunctions = {
|
|||||||
Refresh = function(self)
|
Refresh = function(self)
|
||||||
--hide all frames and tag as not in use
|
--hide all frames and tag as not in use
|
||||||
self._LinesInUse = 0
|
self._LinesInUse = 0
|
||||||
|
--self.Frames has a list of frames used by the scrollbox
|
||||||
for index, frame in ipairs(self.Frames) do
|
for index, frame in ipairs(self.Frames) do
|
||||||
if (not self.DontHideChildrenOnPreRefresh) then
|
if (not self.DontHideChildrenOnPreRefresh) then
|
||||||
frame:Hide()
|
frame:Hide()
|
||||||
end
|
end
|
||||||
|
--set the frame as not in use
|
||||||
frame._InUse = nil
|
frame._InUse = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -39,6 +41,7 @@ detailsFramework.ScrollBoxFunctions = {
|
|||||||
offset = self:GetOffsetFaux()
|
offset = self:GetOffsetFaux()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--before starting the refresh, check if there's a pre refresh function and call it
|
||||||
if (self.pre_refresh_func) then
|
if (self.pre_refresh_func) then
|
||||||
detailsFramework:Dispatch(self.pre_refresh_func, self, self.data, offset, self.LineAmount)
|
detailsFramework:Dispatch(self.pre_refresh_func, self, self.data, offset, self.LineAmount)
|
||||||
end
|
end
|
||||||
@@ -428,6 +431,24 @@ function detailsFramework:CreateGridScrollBox(parent, name, refreshFunc, data, c
|
|||||||
return scrollBox
|
return scrollBox
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function detailsFramework.CreateRoundedOptionsScrollBox(parent, name, onRefreshButton, onSelectOption, tbdData, createSelectorButton, gridScrollBoxOptions)
|
||||||
|
---when the scroll is refreshing the line, the line will call this function for each selection button on it
|
||||||
|
---@param button df_button
|
||||||
|
---@param data table
|
||||||
|
local refreshAuraSelectorFrame = function(button, data)
|
||||||
|
button.data = data
|
||||||
|
|
||||||
|
if (data.tooltip) then
|
||||||
|
button.tooltip = data.tooltip
|
||||||
|
end
|
||||||
|
|
||||||
|
xpcall(onRefreshButton, geterrorhandler(), button, data)
|
||||||
|
|
||||||
|
--set what happen when the user clicks the button
|
||||||
|
button:SetClickFunction(onSelectOption, button, data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--Need to test this and check the "same_name_spells_add(value)" on the OnEnter function
|
--Need to test this and check the "same_name_spells_add(value)" on the OnEnter function
|
||||||
--also need to make sure this can work with any data (global, class, spec) and aura type (buff, debuff)
|
--also need to make sure this can work with any data (global, class, spec) and aura type (buff, debuff)
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,10 @@ detailsFramework.TextEntryCounter = detailsFramework.TextEntryCounter or 1
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local smember_fontsize = function(object, value)
|
||||||
|
return detailsFramework:SetFontSize(object.editbox, value)
|
||||||
|
end
|
||||||
|
|
||||||
--text horizontal pos
|
--text horizontal pos
|
||||||
local smember_horizontalpos = function(object, value)
|
local smember_horizontalpos = function(object, value)
|
||||||
return object.editbox:SetJustifyH(string.lower(value))
|
return object.editbox:SetJustifyH(string.lower(value))
|
||||||
@@ -162,6 +166,8 @@ detailsFramework.TextEntryCounter = detailsFramework.TextEntryCounter or 1
|
|||||||
TextEntryMetaFunctions.SetMembers["text"] = smember_text
|
TextEntryMetaFunctions.SetMembers["text"] = smember_text
|
||||||
TextEntryMetaFunctions.SetMembers["multiline"] = smember_multiline
|
TextEntryMetaFunctions.SetMembers["multiline"] = smember_multiline
|
||||||
TextEntryMetaFunctions.SetMembers["align"] = smember_horizontalpos
|
TextEntryMetaFunctions.SetMembers["align"] = smember_horizontalpos
|
||||||
|
TextEntryMetaFunctions.SetMembers["fontsize"] = smember_fontsize
|
||||||
|
TextEntryMetaFunctions.SetMembers["textsize"] = smember_fontsize
|
||||||
|
|
||||||
TextEntryMetaFunctions.__newindex = function(object, key, value)
|
TextEntryMetaFunctions.__newindex = function(object, key, value)
|
||||||
local func = TextEntryMetaFunctions.SetMembers[key]
|
local func = TextEntryMetaFunctions.SetMembers[key]
|
||||||
@@ -544,6 +550,7 @@ end
|
|||||||
---@field text any
|
---@field text any
|
||||||
---@field multiline any
|
---@field multiline any
|
||||||
---@field align any
|
---@field align any
|
||||||
|
---@field fontsize any
|
||||||
---@field ShouldOptimizeAutoComplete boolean?
|
---@field ShouldOptimizeAutoComplete boolean?
|
||||||
---@field SetTemplate fun(self:df_textentry, template:table)
|
---@field SetTemplate fun(self:df_textentry, template:table)
|
||||||
---@field Disable fun(self:df_textentry)
|
---@field Disable fun(self:df_textentry)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -374,21 +374,24 @@ function openRaidLib.GearManager.GetPlayerGemsAndEnchantInfo()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--gems
|
--gems
|
||||||
local itemStatsTable = {}
|
--local itemStatsTable = {}
|
||||||
--fill the table above with information about the item
|
--fill the table above with information about the item
|
||||||
GetItemStats(itemLink, itemStatsTable)
|
--GetItemStats(itemLink, itemStatsTable) --deprecated in 10.2.5
|
||||||
|
local itemStatsTable = C_Item.GetItemStats(itemLink)
|
||||||
|
|
||||||
--check if the item has a socket
|
--check if the item has a socket
|
||||||
if (itemStatsTable.EMPTY_SOCKET_PRISMATIC) then
|
if (itemStatsTable) then
|
||||||
--check if the socket is empty
|
if (itemStatsTable.EMPTY_SOCKET_PRISMATIC) then
|
||||||
for i = 1, itemStatsTable.EMPTY_SOCKET_PRISMATIC do
|
--check if the socket is empty
|
||||||
local gemId = tonumber(gemsIds[i])
|
for i = 1, itemStatsTable.EMPTY_SOCKET_PRISMATIC do
|
||||||
if (not gemId or gemId == 0) then
|
local gemId = tonumber(gemsIds[i])
|
||||||
slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
|
if (not gemId or gemId == 0) then
|
||||||
|
slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
|
||||||
|
|
||||||
--check if the gem is not a valid gem (deprecated gem)
|
--check if the gem is not a valid gem (deprecated gem)
|
||||||
elseif (gemId < 180000) then
|
elseif (gemId < 180000) then
|
||||||
slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
|
slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -404,7 +407,7 @@ function openRaidLib.GearManager.BuildPlayerEquipmentList()
|
|||||||
for equipmentSlotId = 1, 17 do
|
for equipmentSlotId = 1, 17 do
|
||||||
local itemLink = GetInventoryItemLink("player", equipmentSlotId)
|
local itemLink = GetInventoryItemLink("player", equipmentSlotId)
|
||||||
if (itemLink) then
|
if (itemLink) then
|
||||||
local itemStatsTable = {}
|
--local itemStatsTable = {}
|
||||||
local itemID, enchantID, gemID1, gemID2, gemID3, gemID4, suffixID, uniqueID, linkLevel, specializationID, modifiersMask, itemContext = select(2, strsplit(":", itemLink))
|
local itemID, enchantID, gemID1, gemID2, gemID3, gemID4, suffixID, uniqueID, linkLevel, specializationID, modifiersMask, itemContext = select(2, strsplit(":", itemLink))
|
||||||
itemID = tonumber(itemID)
|
itemID = tonumber(itemID)
|
||||||
|
|
||||||
@@ -415,7 +418,8 @@ function openRaidLib.GearManager.BuildPlayerEquipmentList()
|
|||||||
openRaidLib.__errors[#openRaidLib.__errors+1] = "Fail to get Item Level: " .. (itemID or "invalid itemID") .. " " .. (itemLink and itemLink:gsub("|H", "") or "invalid itemLink")
|
openRaidLib.__errors[#openRaidLib.__errors+1] = "Fail to get Item Level: " .. (itemID or "invalid itemID") .. " " .. (itemLink and itemLink:gsub("|H", "") or "invalid itemLink")
|
||||||
end
|
end
|
||||||
|
|
||||||
GetItemStats(itemLink, itemStatsTable)
|
local itemStatsTable = C_Item.GetItemStats(itemLink)
|
||||||
|
--GetItemStats(itemLink, itemStatsTable)
|
||||||
local gemSlotsAvailable = itemStatsTable and itemStatsTable.EMPTY_SOCKET_PRISMATIC or 0
|
local gemSlotsAvailable = itemStatsTable and itemStatsTable.EMPTY_SOCKET_PRISMATIC or 0
|
||||||
|
|
||||||
local noPrefixItemLink = itemLink : gsub("^|c%x%x%x%x%x%x%x%x|Hitem", "")
|
local noPrefixItemLink = itemLink : gsub("^|c%x%x%x%x%x%x%x%x|Hitem", "")
|
||||||
|
|||||||
@@ -376,6 +376,7 @@ do
|
|||||||
[115750] = {cooldown = 90, duration = 6, specs = {65, 66, 70}, talent = false, charges = 1, class = "PALADIN", type = 8}, --Blinding Light
|
[115750] = {cooldown = 90, duration = 6, specs = {65, 66, 70}, talent = false, charges = 1, class = "PALADIN", type = 8}, --Blinding Light
|
||||||
[231895] = {cooldown = 120, duration = 25, specs = {70}, talent = false, charges = 1, class = "PALADIN", type = 1}, --Crusade
|
[231895] = {cooldown = 120, duration = 25, specs = {70}, talent = false, charges = 1, class = "PALADIN", type = 1}, --Crusade
|
||||||
[498] = {cooldown = 60, duration = 8, specs = {65}, talent = false, charges = 1, class = "PALADIN", type = 2}, --Divine Protection
|
[498] = {cooldown = 60, duration = 8, specs = {65}, talent = false, charges = 1, class = "PALADIN", type = 2}, --Divine Protection
|
||||||
|
[403876] = {cooldown = 60, duration = 8, specs = {65}, talent = false, charges = 1, class = "PALADIN", type = 2}, --Divine Protection Retribution
|
||||||
[642] = {cooldown = 300, duration = 8, specs = {65, 66, 70}, talent = false, charges = 1, class = "PALADIN", type = 2}, --Divine Shield
|
[642] = {cooldown = 300, duration = 8, specs = {65, 66, 70}, talent = false, charges = 1, class = "PALADIN", type = 2}, --Divine Shield
|
||||||
[205191] = {cooldown = 60, duration = 10, specs = {70}, talent = false, charges = 1, class = "PALADIN", type = 2}, --Eye for an Eye
|
[205191] = {cooldown = 60, duration = 10, specs = {70}, talent = false, charges = 1, class = "PALADIN", type = 2}, --Eye for an Eye
|
||||||
[86659] = {cooldown = 300, duration = 8, specs = {66}, talent = false, charges = 1, class = "PALADIN", type = 2}, --Guardian of Ancient Kings
|
[86659] = {cooldown = 300, duration = 8, specs = {66}, talent = false, charges = 1, class = "PALADIN", type = 2}, --Guardian of Ancient Kings
|
||||||
|
|||||||
@@ -97,7 +97,11 @@
|
|||||||
Details222.OptionsPanel = {}
|
Details222.OptionsPanel = {}
|
||||||
Details222.Instances = {}
|
Details222.Instances = {}
|
||||||
Details222.Combat = {}
|
Details222.Combat = {}
|
||||||
Details222.MythicPlus = {}
|
Details222.MythicPlus = {
|
||||||
|
Charts = {},
|
||||||
|
Frames = {},
|
||||||
|
}
|
||||||
|
|
||||||
Details222.MythicPlusBreakdown = {}
|
Details222.MythicPlusBreakdown = {}
|
||||||
Details222.EJCache = {}
|
Details222.EJCache = {}
|
||||||
Details222.Segments = {}
|
Details222.Segments = {}
|
||||||
|
|||||||
@@ -527,14 +527,12 @@ end
|
|||||||
return nickname
|
return nickname
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local dungeonFollowersNpcs = {}
|
||||||
|
|
||||||
--read the actor flag
|
--read the actor flag
|
||||||
local readActorFlag = function(actorObject, ownerActorObject, actorSerial, actorFlags, actorName)
|
local readActorFlag = function(actorObject, ownerActorObject, actorSerial, actorFlags, actorName)
|
||||||
if (actorFlags) then
|
if (actorFlags) then
|
||||||
local _, zoneType = GetInstanceInfo()
|
local _, zoneType, difficultyId = GetInstanceInfo()
|
||||||
|
|
||||||
--UnitIsInMyGuild
|
|
||||||
|
|
||||||
--on retail post 100200 patch, actorName is formatted as "name-realm"
|
|
||||||
|
|
||||||
--this is player actor
|
--this is player actor
|
||||||
if (bitBand(actorFlags, OBJECT_TYPE_PLAYER) ~= 0) then
|
if (bitBand(actorFlags, OBJECT_TYPE_PLAYER) ~= 0) then
|
||||||
@@ -568,6 +566,12 @@ end
|
|||||||
--check if this actor can be flagged as a unit in the player's group
|
--check if this actor can be flagged as a unit in the player's group
|
||||||
if ((bitBand(actorFlags, IS_GROUP_OBJECT) ~= 0 and actorObject.classe ~= "UNKNOW" and actorObject.classe ~= "UNGROUPPLAYER") or Details:IsInCache(actorSerial)) then
|
if ((bitBand(actorFlags, IS_GROUP_OBJECT) ~= 0 and actorObject.classe ~= "UNKNOW" and actorObject.classe ~= "UNGROUPPLAYER") or Details:IsInCache(actorSerial)) then
|
||||||
actorObject.grupo = true
|
actorObject.grupo = true
|
||||||
|
|
||||||
|
if (difficultyId == 205) then
|
||||||
|
dungeonFollowersNpcs[actorName] = true
|
||||||
|
end
|
||||||
|
|
||||||
|
--/dump Details:GetCurrentCombat():GetActor(1, "Captain Garrick").grupo
|
||||||
--check if this actor is a tank (player)
|
--check if this actor is a tank (player)
|
||||||
if (Details:IsATank(actorSerial)) then
|
if (Details:IsATank(actorSerial)) then
|
||||||
actorObject.isTank = true
|
actorObject.isTank = true
|
||||||
@@ -690,6 +694,12 @@ end
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if (difficultyId == 205) then
|
||||||
|
if (dungeonFollowersNpcs[actorName]) then
|
||||||
|
actorObject.grupo = true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1430,13 +1430,16 @@ end
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local textStyle = {
|
local textStyleDropdownFunc = function()
|
||||||
{value = 1, label = Loc ["STRING_PLUGINOPTIONS_ABBREVIATE"] .. "(105.5K)", onclick = onSelectTextStyle},
|
local textStyle = {
|
||||||
{value = 2, label = Loc ["STRING_PLUGINOPTIONS_COMMA"] .. "(105.500)", onclick = onSelectTextStyle},
|
{value = 1, label = Loc ["STRING_PLUGINOPTIONS_ABBREVIATE"] .. "(105.5K)", onclick = onSelectTextStyle},
|
||||||
{value = 3, label = Loc ["STRING_PLUGINOPTIONS_NOFORMAT"] .. "(105500)", onclick = onSelectTextStyle}
|
{value = 2, label = Loc ["STRING_PLUGINOPTIONS_COMMA"] .. "(105.500)", onclick = onSelectTextStyle},
|
||||||
}
|
{value = 3, label = Loc ["STRING_PLUGINOPTIONS_NOFORMAT"] .. "(105500)", onclick = onSelectTextStyle}
|
||||||
|
}
|
||||||
|
return textStyle
|
||||||
|
end
|
||||||
|
|
||||||
detailsFramework:NewDropDown(window, _, "$parentTextStyleDropdown", "textstyleDropdown", 200, 20, function() return textStyle end, 1) --func, default
|
detailsFramework:NewDropDown(window, _, "$parentTextStyleDropdown", "textstyleDropdown", 200, 20, textStyleDropdownFunc, 1) --func, default
|
||||||
window.textstyleDropdown:SetPoint("left", window.textstyle, "right", 2)
|
window.textstyleDropdown:SetPoint("left", window.textstyle, "right", 2)
|
||||||
|
|
||||||
--text color
|
--text color
|
||||||
|
|||||||
@@ -799,7 +799,7 @@ function Details:CreateBreakdownWindow()
|
|||||||
|
|
||||||
function breakdownWindowFrame:SetStatusbarText(text, fontSize, fontColor)
|
function breakdownWindowFrame:SetStatusbarText(text, fontSize, fontColor)
|
||||||
if (not text) then
|
if (not text) then
|
||||||
breakdownWindowFrame:SetStatusbarText("Details! Damage Meter | Use '/details stats' for statistics", 10, "gray")
|
breakdownWindowFrame:SetStatusbarText("Details! Damage Meter | Click 'Options' button for settings.", 10, "gray")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
statusBar.Text.text = text
|
statusBar.Text.text = text
|
||||||
|
|||||||
+129
-30
@@ -17,6 +17,10 @@ Details222.CooldownTracking = {
|
|||||||
cooldownPanels = {},
|
cooldownPanels = {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Details222.CooldownTracking.IsCooldownIgnored(spellId)
|
||||||
|
return Details.ocd_tracker.ignored_cooldowns[spellId]
|
||||||
|
end
|
||||||
|
|
||||||
--return a hash table with all cooldown panels created
|
--return a hash table with all cooldown panels created
|
||||||
function Details222.CooldownTracking.GetAllCooldownFrames()
|
function Details222.CooldownTracking.GetAllCooldownFrames()
|
||||||
return Details222.CooldownTracking.cooldownPanels
|
return Details222.CooldownTracking.cooldownPanels
|
||||||
@@ -131,6 +135,10 @@ end
|
|||||||
--need to get the filter name which that spell belong
|
--need to get the filter name which that spell belong
|
||||||
--and then check if that filter is enabled
|
--and then check if that filter is enabled
|
||||||
|
|
||||||
|
if (Details222.CooldownTracking.IsCooldownIgnored(spellId)) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local gotUpdate = false
|
local gotUpdate = false
|
||||||
|
|
||||||
--get a map with the filters the spell is in, the key is the filter name and the value is boolean true
|
--get a map with the filters the spell is in, the key is the filter name and the value is boolean true
|
||||||
@@ -292,27 +300,29 @@ end
|
|||||||
local allCooldownFrames = Details222.CooldownTracking.GetAllCooldownFrames()
|
local allCooldownFrames = Details222.CooldownTracking.GetAllCooldownFrames()
|
||||||
|
|
||||||
for spellId, cooldownInfo in pairs(unitCooldowns) do
|
for spellId, cooldownInfo in pairs(unitCooldowns) do
|
||||||
--get a cooldownLine
|
if (not Details222.CooldownTracking.IsCooldownIgnored(spellId)) then
|
||||||
local cooldownLine = Details222.CooldownTracking.GetOrCreateNewCooldownLine(cooldownFrame, cooldownFrame.nextLineId)
|
--get a cooldownLine
|
||||||
cooldownLine.cooldownInfo = cooldownInfo
|
local cooldownLine = Details222.CooldownTracking.GetOrCreateNewCooldownLine(cooldownFrame, cooldownFrame.nextLineId)
|
||||||
--local isReady, normalizedPercent, timeLeft, charges, minValue, maxValue, currentValue = openRaidLib.GetCooldownStatusFromCooldownInfo(cooldownInfo)
|
cooldownLine.cooldownInfo = cooldownInfo
|
||||||
|
--local isReady, normalizedPercent, timeLeft, charges, minValue, maxValue, currentValue = openRaidLib.GetCooldownStatusFromCooldownInfo(cooldownInfo)
|
||||||
|
|
||||||
cooldownLine.spellId = spellId
|
cooldownLine.spellId = spellId
|
||||||
cooldownLine.class = unitInfo.class
|
cooldownLine.class = unitInfo.class
|
||||||
cooldownLine.unitName = unitInfo.nameFull
|
cooldownLine.unitName = unitInfo.nameFull
|
||||||
|
|
||||||
--setup the cooldown in the line
|
--setup the cooldown in the line
|
||||||
Details222.CooldownTracking.SetupCooldownLine(cooldownLine)
|
Details222.CooldownTracking.SetupCooldownLine(cooldownLine)
|
||||||
|
|
||||||
--add the cooldown into the organized by class table
|
--add the cooldown into the organized by class table
|
||||||
table.insert(cooldownsOrganized[classId], cooldownLine)
|
table.insert(cooldownsOrganized[classId], cooldownLine)
|
||||||
|
|
||||||
--iterate to the next cooldown line
|
--iterate to the next cooldown line
|
||||||
cooldownFrame.nextLineId = cooldownFrame.nextLineId + 1
|
cooldownFrame.nextLineId = cooldownFrame.nextLineId + 1
|
||||||
|
|
||||||
--store the cooldown line into a cache to get the cooldown line quicker when a cooldown receives updates
|
--store the cooldown line into a cache to get the cooldown line quicker when a cooldown receives updates
|
||||||
cooldownFrame.playerCache[unitInfo.nameFull] = cooldownFrame.playerCache[unitInfo.nameFull] or {}
|
cooldownFrame.playerCache[unitInfo.nameFull] = cooldownFrame.playerCache[unitInfo.nameFull] or {}
|
||||||
cooldownFrame.playerCache[unitInfo.nameFull][spellId] = cooldownLine
|
cooldownFrame.playerCache[unitInfo.nameFull][spellId] = cooldownLine
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -775,24 +785,113 @@ end
|
|||||||
cooldownSelectionFrame:SetPoint("bottomright", f, "bottomright", 0, 10)
|
cooldownSelectionFrame:SetPoint("bottomright", f, "bottomright", 0, 10)
|
||||||
DF:ApplyStandardBackdrop(cooldownSelectionFrame)
|
DF:ApplyStandardBackdrop(cooldownSelectionFrame)
|
||||||
|
|
||||||
--lib test test warning texts
|
|
||||||
local warning1 = cooldownSelectionFrame:CreateFontString(nil, "overlay", "GameFontNormal", 5)
|
|
||||||
warning1:SetPoint("center", f, "center", 0, 0)
|
|
||||||
warning1:SetText("A cooldown tracker on Details!?\nWhat's next, a Caw counter for Elwynn Forest?")
|
|
||||||
DF:SetFontColor(warning1, "silver")
|
|
||||||
DF:SetFontSize(warning1, 14)
|
|
||||||
local animationHub = DF:CreateAnimationHub(warning1)
|
|
||||||
local anim1 = DF:CreateAnimation(animationHub, "rotation", 1, 0, 35)
|
|
||||||
anim1:SetEndDelay(10000000)
|
|
||||||
anim1:SetSmoothProgress(1)
|
|
||||||
animationHub:Play()
|
|
||||||
animationHub:Pause()
|
|
||||||
|
|
||||||
local warning2 = cooldownSelectionFrame:CreateFontString(nil, "overlay", "GameFontNormal", 5)
|
local warning2 = cooldownSelectionFrame:CreateFontString(nil, "overlay", "GameFontNormal", 5)
|
||||||
warning2:SetJustifyH("left")
|
warning2:SetJustifyH("left")
|
||||||
warning2:SetPoint("topleft", f, "topleft", 5, -160)
|
warning2:SetPoint("topleft", f, "topleft", 5, -160)
|
||||||
DF:SetFontColor(warning2, "lime")
|
DF:SetFontColor(warning2, "lime")
|
||||||
warning2:SetText("This is a concept of a cooldown tracker using the new library 'Open Raid' which uses comms to update cooldown timers.\nThe code to implement is so small that can fit inside a weakaura\nIf you're a coder, the implementation is on Details/frames/window_cdtracker.lua")
|
--warning2:SetText("This is a concept of a cooldown tracker using the new library 'Open Raid' which uses comms to update cooldown timers.\nThe code to implement is so small that can fit inside a weakaura\nIf you're a coder, the implementation is on Details/frames/window_cdtracker.lua")
|
||||||
|
|
||||||
|
cooldownSelectionFrame:RegisterEvent("GROUP_ROSTER_UPDATE")
|
||||||
|
cooldownSelectionFrame:RegisterEvent("PLAYER_STARTED_MOVING")
|
||||||
|
|
||||||
|
local maxClasses = 13
|
||||||
|
|
||||||
|
cooldownSelectionFrame.ClassCDsAnchorFrames = {}
|
||||||
|
|
||||||
|
for i = 1, maxClasses do
|
||||||
|
local anchorFrame = CreateFrame("frame", "$parentAnchorFrame"..i, cooldownSelectionFrame, "BackdropTemplate")
|
||||||
|
anchorFrame:SetSize(1, 1)
|
||||||
|
if (i == 1) then
|
||||||
|
anchorFrame:SetPoint("topleft", cooldownSelectionFrame, "topleft", 5, -5)
|
||||||
|
else
|
||||||
|
anchorFrame:SetPoint("topleft", cooldownSelectionFrame.ClassCDsAnchorFrames[i-1], "topright", 310, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
cooldownSelectionFrame.ClassCDsAnchorFrames[i] = anchorFrame
|
||||||
|
end
|
||||||
|
|
||||||
|
function cooldownSelectionFrame.ClearAllCDsAnchorFrames()
|
||||||
|
for i = 1, maxClasses do
|
||||||
|
cooldownSelectionFrame.ClassCDsAnchorFrames[i]:Hide()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
cooldownSelectionFrame:SetScript("OnEvent", function(self, event)
|
||||||
|
--show a list of players in the group, 1 player per column
|
||||||
|
--below the player name, show a list in vertical with checkboxes to enable/disable cooldowns for that class
|
||||||
|
--use DetailsFramework:BuildMenuVolatile() to build the each list
|
||||||
|
|
||||||
|
local amountOfUnits = GetNumGroupMembers()
|
||||||
|
|
||||||
|
if (amountOfUnits == 0) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local allClasses = {}
|
||||||
|
if (IsInGroup() and not IsInRaid()) then
|
||||||
|
for i = 1, amountOfUnits - 1 do
|
||||||
|
local unitId = "party"..i
|
||||||
|
local _, class = UnitClass(unitId)
|
||||||
|
if (class) then
|
||||||
|
allClasses[class] = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local unitId = "player"
|
||||||
|
local _, class = UnitClass(unitId)
|
||||||
|
allClasses[class] = {}
|
||||||
|
|
||||||
|
elseif (IsInRaid()) then
|
||||||
|
for i = 1, amountOfUnits do
|
||||||
|
local unitId = "raid"..i
|
||||||
|
local _, class = UnitClass(unitId)
|
||||||
|
if (class) then
|
||||||
|
allClasses[class] = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local index = 1
|
||||||
|
cooldownSelectionFrame.ClearAllCDsAnchorFrames()
|
||||||
|
|
||||||
|
for className, allClassCDs in pairs(allClasses) do
|
||||||
|
--menu to build with DetailsFramework:BuildMenuVolatile()
|
||||||
|
local menuOptions = {}
|
||||||
|
|
||||||
|
for spellId, spellInfo in pairs(LIB_OPEN_RAID_COOLDOWNS_INFO) do
|
||||||
|
if (spellInfo.class == className) then
|
||||||
|
local spellName, _, spellIcon = GetSpellInfo(spellId)
|
||||||
|
|
||||||
|
if (spellName) then
|
||||||
|
local smallSpellName = string.sub(spellName, 1, 12)
|
||||||
|
spellName = "|T" .. spellIcon .. ":" .. 20 .. ":" .. 20 .. ":0:0:" .. 64 .. ":" .. 64 .. "|t " .. smallSpellName
|
||||||
|
|
||||||
|
if (spellName) then
|
||||||
|
menuOptions[#menuOptions+1] = {
|
||||||
|
type = "toggle",
|
||||||
|
get = function() return Details.ocd_tracker.ignored_cooldowns[spellId] end,
|
||||||
|
set = function(self, fixedparam, value)
|
||||||
|
Details.ocd_tracker.ignored_cooldowns[spellId] = value
|
||||||
|
Details222.CooldownTracking.RefreshAllCooldownFrames()
|
||||||
|
end,
|
||||||
|
name = spellName,
|
||||||
|
desc = spellName,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local anchorFrame = cooldownSelectionFrame.ClassCDsAnchorFrames[index]
|
||||||
|
anchorFrame:Show()
|
||||||
|
|
||||||
|
menuOptions.always_boxfirst = true
|
||||||
|
|
||||||
|
DF:BuildMenuVolatile(anchorFrame, menuOptions, 5, -5, 400, false, options_text_template, options_dropdown_template, options_switch_template, true, options_slider_template, options_button_template)
|
||||||
|
|
||||||
|
index = index + 1
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
_G.DetailsPluginContainerWindow.OpenPlugin(_G.DetailsCDTrackerWindow)
|
_G.DetailsPluginContainerWindow.OpenPlugin(_G.DetailsCDTrackerWindow)
|
||||||
|
|||||||
@@ -0,0 +1,590 @@
|
|||||||
|
|
||||||
|
local Details = _G.Details
|
||||||
|
local DF = _G.DetailsFramework
|
||||||
|
local addonName, Details222 = ...
|
||||||
|
local _
|
||||||
|
|
||||||
|
local debugmode = false
|
||||||
|
local verbosemode = false
|
||||||
|
|
||||||
|
local CreateFrame = CreateFrame
|
||||||
|
local UIParent = UIParent
|
||||||
|
|
||||||
|
local mythicDungeonCharts = Details222.MythicPlus.Charts.Listener
|
||||||
|
|
||||||
|
-- /run _G.DetailsMythicDungeonChartHandler.ShowEndOfMythicPlusPanel()
|
||||||
|
-- /run _G.DetailsMythicDungeonChartHandler.ShowChart()
|
||||||
|
|
||||||
|
function mythicDungeonCharts.ShowChart()
|
||||||
|
if (not mythicDungeonCharts.Frame) then
|
||||||
|
mythicDungeonCharts.Frame = CreateFrame("frame", "DetailsMythicDungeonChartFrame", UIParent, "BackdropTemplate")
|
||||||
|
local dungeonChartFrame = mythicDungeonCharts.Frame
|
||||||
|
|
||||||
|
dungeonChartFrame:SetSize(1200, 620)
|
||||||
|
dungeonChartFrame:SetPoint("center", UIParent, "center", 0, 0)
|
||||||
|
dungeonChartFrame:SetFrameStrata("LOW")
|
||||||
|
dungeonChartFrame:EnableMouse(true)
|
||||||
|
dungeonChartFrame:SetMovable(true)
|
||||||
|
DetailsFramework:ApplyStandardBackdrop(dungeonChartFrame)
|
||||||
|
|
||||||
|
--minimized frame
|
||||||
|
mythicDungeonCharts.FrameMinimized = CreateFrame("frame", "DetailsMythicDungeonChartFrameminimized", UIParent, "BackdropTemplate")
|
||||||
|
local fMinimized = mythicDungeonCharts.FrameMinimized
|
||||||
|
|
||||||
|
fMinimized:SetSize(160, 24)
|
||||||
|
fMinimized:SetPoint("center", UIParent, "center", 0, 0)
|
||||||
|
fMinimized:SetFrameStrata("LOW")
|
||||||
|
fMinimized:EnableMouse(true)
|
||||||
|
fMinimized:SetMovable(true)
|
||||||
|
fMinimized:Hide()
|
||||||
|
DetailsFramework:ApplyStandardBackdrop(fMinimized)
|
||||||
|
|
||||||
|
dungeonChartFrame.IsMinimized = false
|
||||||
|
|
||||||
|
--titlebar
|
||||||
|
local titlebar = CreateFrame("frame", nil, dungeonChartFrame, "BackdropTemplate")
|
||||||
|
titlebar:SetPoint("topleft", dungeonChartFrame, "topleft", 2, -3)
|
||||||
|
titlebar:SetPoint("topright", dungeonChartFrame, "topright", -2, -3)
|
||||||
|
titlebar:SetHeight(20)
|
||||||
|
titlebar:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]], tileSize = 64, tile = true})
|
||||||
|
titlebar:SetBackdropColor(.5, .5, .5, 1)
|
||||||
|
titlebar:SetBackdropBorderColor(0, 0, 0, 1)
|
||||||
|
|
||||||
|
--title
|
||||||
|
local titleLabel = Details.gump:NewLabel(titlebar, titlebar, nil, "titulo", "Plugins", "GameFontHighlightLeft", 12, {227/255, 186/255, 4/255})
|
||||||
|
titleLabel:SetPoint("center", titlebar , "center")
|
||||||
|
titleLabel:SetPoint("top", titlebar , "top", 0, -5)
|
||||||
|
dungeonChartFrame.TitleText = titleLabel
|
||||||
|
|
||||||
|
--titlebar when minimized
|
||||||
|
local titlebarMinimized = CreateFrame("frame", nil, fMinimized, "BackdropTemplate")
|
||||||
|
titlebarMinimized:SetPoint("topleft", fMinimized, "topleft", 2, -3)
|
||||||
|
titlebarMinimized:SetPoint("topright", fMinimized, "topright", -2, -3)
|
||||||
|
titlebarMinimized:SetHeight(20)
|
||||||
|
titlebarMinimized:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\AddOns\Details\images\background]], tileSize = 64, tile = true})
|
||||||
|
titlebarMinimized:SetBackdropColor(.5, .5, .5, 1)
|
||||||
|
titlebarMinimized:SetBackdropBorderColor(0, 0, 0, 1)
|
||||||
|
|
||||||
|
--title
|
||||||
|
local titleLabelMinimized = Details.gump:NewLabel(titlebarMinimized, titlebarMinimized, nil, "titulo", "Dungeon Run Chart", "GameFontHighlightLeft", 10, {227/255, 186/255, 4/255})
|
||||||
|
titleLabelMinimized:SetPoint("left", titlebarMinimized , "left", 4, 0)
|
||||||
|
--titleLabelMinimized:SetPoint("top", titlebarMinimized , "top", 0, -5)
|
||||||
|
dungeonChartFrame.TitleTextMinimized = titleLabelMinimized
|
||||||
|
|
||||||
|
table.insert(UISpecialFrames, "DetailsMythicDungeonChartFrame")
|
||||||
|
|
||||||
|
--register to libwindow
|
||||||
|
local LibWindow = LibStub("LibWindow-1.1")
|
||||||
|
LibWindow.RegisterConfig(dungeonChartFrame, Details.mythic_plus.mythicrun_chart_frame)
|
||||||
|
LibWindow.RestorePosition(dungeonChartFrame)
|
||||||
|
LibWindow.MakeDraggable(dungeonChartFrame)
|
||||||
|
LibWindow.SavePosition(dungeonChartFrame)
|
||||||
|
|
||||||
|
LibWindow.RegisterConfig(fMinimized, Details.mythic_plus.mythicrun_chart_frame_minimized)
|
||||||
|
LibWindow.RestorePosition(fMinimized)
|
||||||
|
LibWindow.MakeDraggable(fMinimized)
|
||||||
|
LibWindow.SavePosition(fMinimized)
|
||||||
|
|
||||||
|
dungeonChartFrame.ChartFrame = Details:GetFramework():CreateChartPanel(dungeonChartFrame, 1200, 600, "DetailsMythicDungeonChartGraphicFrame")
|
||||||
|
dungeonChartFrame.ChartFrame:SetPoint("topleft", dungeonChartFrame, "topleft", 5, -20)
|
||||||
|
|
||||||
|
dungeonChartFrame.ChartFrame.FrameInUse = {}
|
||||||
|
dungeonChartFrame.ChartFrame.FrameFree = {}
|
||||||
|
dungeonChartFrame.ChartFrame.TextureID = 1
|
||||||
|
|
||||||
|
dungeonChartFrame.ChartFrame.ShowHeader = true
|
||||||
|
dungeonChartFrame.ChartFrame.HeaderOnlyIndicator = true
|
||||||
|
dungeonChartFrame.ChartFrame.HeaderShowOverlays = false
|
||||||
|
|
||||||
|
dungeonChartFrame.ChartFrame.Graphic.DrawLine = mythicDungeonCharts.CustomDrawLine
|
||||||
|
|
||||||
|
dungeonChartFrame.ChartFrame:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
||||||
|
dungeonChartFrame.ChartFrame:SetBackdropColor(0, 0, 0, 0.0)
|
||||||
|
dungeonChartFrame.ChartFrame:SetBackdropBorderColor(0, 0, 0, 0)
|
||||||
|
|
||||||
|
dungeonChartFrame.ChartFrame:EnableMouse(false)
|
||||||
|
|
||||||
|
dungeonChartFrame.ChartFrame.CloseButton:Hide()
|
||||||
|
|
||||||
|
dungeonChartFrame.BossWidgetsFrame = CreateFrame("frame", "$parentBossFrames", dungeonChartFrame, "BackdropTemplate")
|
||||||
|
dungeonChartFrame.BossWidgetsFrame:SetFrameLevel(dungeonChartFrame:GetFrameLevel()+10)
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.Widgets = {}
|
||||||
|
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.GraphPin = dungeonChartFrame.BossWidgetsFrame:CreateTexture(nil, "overlay")
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.GraphPin:SetTexture([[Interface\BUTTONS\UI-RadioButton]])
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.GraphPin:SetTexCoord(17/64, 32/64, 0, 1)
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.GraphPin:SetSize(16, 16)
|
||||||
|
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.GraphPinGlow = dungeonChartFrame.BossWidgetsFrame:CreateTexture(nil, "artwork")
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.GraphPinGlow:SetTexture([[Interface\Calendar\EventNotificationGlow]])
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.GraphPinGlow:SetTexCoord(0, 1, 0, 1)
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.GraphPinGlow:SetSize(14, 14)
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.GraphPinGlow:SetBlendMode("ADD")
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.GraphPinGlow:SetPoint("center", dungeonChartFrame.BossWidgetsFrame.GraphPin, "center", 0, 0)
|
||||||
|
|
||||||
|
dungeonChartFrame:Hide()
|
||||||
|
|
||||||
|
function dungeonChartFrame.ShowChartFrame()
|
||||||
|
if (dungeonChartFrame.IsMinimized) then
|
||||||
|
dungeonChartFrame.IsMinimized = false
|
||||||
|
fMinimized:Hide()
|
||||||
|
dungeonChartFrame:Show()
|
||||||
|
else
|
||||||
|
dungeonChartFrame:Show()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local closeButton = CreateFrame("button", "$parentCloseButton", dungeonChartFrame, "UIPanelCloseButton")
|
||||||
|
closeButton:GetNormalTexture():SetDesaturated(true)
|
||||||
|
closeButton:SetWidth(24)
|
||||||
|
closeButton:SetHeight(24)
|
||||||
|
closeButton:SetPoint("topright", dungeonChartFrame, "topright", 0, -1)
|
||||||
|
closeButton:SetFrameLevel(dungeonChartFrame:GetFrameLevel()+16)
|
||||||
|
|
||||||
|
local minimizeButton = CreateFrame("button", "$parentCloseButton", dungeonChartFrame, "UIPanelCloseButton")
|
||||||
|
minimizeButton:GetNormalTexture():SetDesaturated(true)
|
||||||
|
minimizeButton:SetWidth(24)
|
||||||
|
minimizeButton:SetHeight(24)
|
||||||
|
minimizeButton:SetPoint("right", closeButton, "left", 2, 0)
|
||||||
|
minimizeButton:SetFrameLevel(dungeonChartFrame:GetFrameLevel()+16)
|
||||||
|
minimizeButton:SetNormalTexture([[Interface\BUTTONS\UI-Panel-HideButton-Up]])
|
||||||
|
minimizeButton:SetPushedTexture([[Interface\BUTTONS\UI-Panel-HideButton-Down]])
|
||||||
|
minimizeButton:SetHighlightTexture([[Interface\BUTTONS\UI-Panel-MinimizeButton-Highlight]])
|
||||||
|
|
||||||
|
local closeButtonWhenMinimized = CreateFrame("button", "$parentCloseButton", fMinimized, "UIPanelCloseButton")
|
||||||
|
closeButtonWhenMinimized:GetNormalTexture():SetDesaturated(true)
|
||||||
|
closeButtonWhenMinimized:SetWidth(24)
|
||||||
|
closeButtonWhenMinimized:SetHeight(24)
|
||||||
|
closeButtonWhenMinimized:SetPoint("topright", fMinimized, "topright", 0, -1)
|
||||||
|
closeButtonWhenMinimized:SetFrameLevel(fMinimized:GetFrameLevel()+16)
|
||||||
|
|
||||||
|
local minimizeButtonWhenMinimized = CreateFrame("button", "$parentCloseButton", fMinimized, "UIPanelCloseButton")
|
||||||
|
minimizeButtonWhenMinimized:GetNormalTexture():SetDesaturated(true)
|
||||||
|
minimizeButtonWhenMinimized:SetWidth(24)
|
||||||
|
minimizeButtonWhenMinimized:SetHeight(24)
|
||||||
|
minimizeButtonWhenMinimized:SetPoint("right", closeButtonWhenMinimized, "left", 2, 0)
|
||||||
|
minimizeButtonWhenMinimized:SetFrameLevel(fMinimized:GetFrameLevel()+16)
|
||||||
|
minimizeButtonWhenMinimized:SetNormalTexture([[Interface\BUTTONS\UI-Panel-HideButton-Up]])
|
||||||
|
minimizeButtonWhenMinimized:SetPushedTexture([[Interface\BUTTONS\UI-Panel-HideButton-Down]])
|
||||||
|
minimizeButtonWhenMinimized:SetHighlightTexture([[Interface\BUTTONS\UI-Panel-MinimizeButton-Highlight]])
|
||||||
|
|
||||||
|
closeButtonWhenMinimized:SetScript("OnClick", function()
|
||||||
|
dungeonChartFrame.IsMinimized = false
|
||||||
|
fMinimized:Hide()
|
||||||
|
minimizeButtonWhenMinimized:SetNormalTexture([[Interface\BUTTONS\UI-Panel-HideButton-Up]])
|
||||||
|
minimizeButtonWhenMinimized:SetPushedTexture([[Interface\BUTTONS\UI-Panel-HideButton-Down]])
|
||||||
|
end)
|
||||||
|
|
||||||
|
--replace the default click function
|
||||||
|
local minimize_func = function(self)
|
||||||
|
if (dungeonChartFrame.IsMinimized) then
|
||||||
|
dungeonChartFrame.IsMinimized = false
|
||||||
|
fMinimized:Hide()
|
||||||
|
dungeonChartFrame:Show()
|
||||||
|
minimizeButtonWhenMinimized:SetNormalTexture([[Interface\BUTTONS\UI-Panel-HideButton-Up]])
|
||||||
|
minimizeButtonWhenMinimized:SetPushedTexture([[Interface\BUTTONS\UI-Panel-HideButton-Down]])
|
||||||
|
else
|
||||||
|
dungeonChartFrame.IsMinimized = true
|
||||||
|
dungeonChartFrame:Hide()
|
||||||
|
fMinimized:Show()
|
||||||
|
minimizeButtonWhenMinimized:SetNormalTexture([[Interface\BUTTONS\UI-Panel-CollapseButton-Up]])
|
||||||
|
minimizeButtonWhenMinimized:SetPushedTexture([[Interface\BUTTONS\UI-Panel-CollapseButton-Up]])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minimizeButton:SetScript("OnClick", minimize_func)
|
||||||
|
minimizeButtonWhenMinimized:SetScript("OnClick", minimize_func)
|
||||||
|
|
||||||
|
--enabled box
|
||||||
|
-- /run _G.DetailsMythicDungeonChartHandler.ShowChart(); DetailsMythicDungeonChartFrame.ShowChartFrame()
|
||||||
|
local on_switch_enable = function(_, _, state)
|
||||||
|
Details.mythic_plus.show_damage_graphic = state
|
||||||
|
end
|
||||||
|
local enabledSwitch, enabledLabel = Details.gump:CreateSwitch(dungeonChartFrame, on_switch_enable, Details.mythic_plus.show_damage_graphic, _, _, _, _, _, _, _, _, _, "Enabled", Details.gump:GetTemplate("switch", "OPTIONS_CHECKBOX_BRIGHT_TEMPLATE"), "GameFontHighlightLeft")
|
||||||
|
enabledSwitch:SetAsCheckBox()
|
||||||
|
enabledSwitch.tooltip = "Show this chart at the end of a mythic dungeon run.\n\nIf disabled, you can reactivate it again at the options panel > streamer settings."
|
||||||
|
enabledLabel:SetPoint("right", minimizeButton, "left", -22, 0)
|
||||||
|
enabledSwitch:SetSize(16, 16)
|
||||||
|
Details.gump:SetFontColor(enabledLabel, "gray")
|
||||||
|
enabledSwitch.checked_texture:SetVertexColor(.75, .75, .75)
|
||||||
|
|
||||||
|
local leftDivisorLine = dungeonChartFrame.BossWidgetsFrame:CreateTexture(nil, "overlay")
|
||||||
|
leftDivisorLine:SetSize(2, dungeonChartFrame.ChartFrame.Graphic:GetHeight())
|
||||||
|
leftDivisorLine:SetColorTexture(1, 1, 1, 1)
|
||||||
|
leftDivisorLine:SetPoint("bottomleft", dungeonChartFrame.ChartFrame.Graphic.TextFrame, "bottomleft", -2, 0)
|
||||||
|
|
||||||
|
local bottomDivisorLine = dungeonChartFrame.BossWidgetsFrame:CreateTexture(nil, "overlay")
|
||||||
|
bottomDivisorLine:SetSize(dungeonChartFrame.ChartFrame.Graphic:GetWidth(), 2)
|
||||||
|
bottomDivisorLine:SetColorTexture(1, 1, 1, 1)
|
||||||
|
bottomDivisorLine:SetPoint("bottomleft", dungeonChartFrame.ChartFrame.Graphic.TextFrame, "bottomleft", 0, 0)
|
||||||
|
|
||||||
|
dungeonChartFrame.ChartFrame.Graphic:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
||||||
|
dungeonChartFrame.ChartFrame.Graphic:SetBackdropColor(.5, .50, .50, 0.8)
|
||||||
|
dungeonChartFrame.ChartFrame.Graphic:SetBackdropBorderColor(0, 0, 0, 0.5)
|
||||||
|
|
||||||
|
function dungeonChartFrame.ChartFrame.RefreshBossTimeline(self, bossTable, elapsedTime)
|
||||||
|
for i, bossTable in ipairs(mythicDungeonCharts.ChartTable.BossDefeated) do
|
||||||
|
local bossWidget = dungeonChartFrame.BossWidgetsFrame.Widgets [i]
|
||||||
|
|
||||||
|
if (not bossWidget) then
|
||||||
|
local newBossWidget = CreateFrame("frame", "$parentBossWidget" .. i, dungeonChartFrame.BossWidgetsFrame, "BackdropTemplate")
|
||||||
|
newBossWidget:SetSize(64, 32)
|
||||||
|
newBossWidget:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 64, tile = true})
|
||||||
|
newBossWidget:SetBackdropColor(0, 0, 0, 0.1)
|
||||||
|
newBossWidget:SetBackdropBorderColor(0, 0, 0, 0)
|
||||||
|
|
||||||
|
local bossAvatar = Details:GetFramework():CreateImage(newBossWidget, "", 64, 32, "border")
|
||||||
|
bossAvatar:SetPoint("bottomleft", newBossWidget, "bottomleft", 0, 0)
|
||||||
|
newBossWidget.AvatarTexture = bossAvatar
|
||||||
|
|
||||||
|
local verticalLine = Details:GetFramework():CreateImage(newBossWidget, "", 1, dungeonChartFrame.ChartFrame.Graphic:GetHeight(), "overlay")
|
||||||
|
verticalLine:SetColorTexture(1, 1, 1, 0.3)
|
||||||
|
verticalLine:SetPoint("bottomleft", newBossWidget, "bottomright", 0, 0)
|
||||||
|
|
||||||
|
local timeText = Details:GetFramework():CreateLabel(newBossWidget)
|
||||||
|
timeText:SetPoint("bottomright", newBossWidget, "bottomright", 0, 0)
|
||||||
|
newBossWidget.TimeText = timeText
|
||||||
|
|
||||||
|
local timeBackground = Details:GetFramework():CreateImage(newBossWidget, "", 30, 12, "artwork")
|
||||||
|
timeBackground:SetColorTexture(0, 0, 0, 0.5)
|
||||||
|
timeBackground:SetPoint("topleft", timeText, "topleft", -2, 2)
|
||||||
|
timeBackground:SetPoint("bottomright", timeText, "bottomright", 2, 0)
|
||||||
|
|
||||||
|
dungeonChartFrame.BossWidgetsFrame.Widgets [i] = newBossWidget
|
||||||
|
bossWidget = newBossWidget
|
||||||
|
end
|
||||||
|
|
||||||
|
local chartLength = dungeonChartFrame.ChartFrame.Graphic:GetWidth()
|
||||||
|
local secondsPerPixel = chartLength / elapsedTime
|
||||||
|
local xPosition = bossTable[1] * secondsPerPixel
|
||||||
|
|
||||||
|
bossWidget:SetPoint("bottomright", dungeonChartFrame.ChartFrame.Graphic, "bottomleft", xPosition, 0)
|
||||||
|
|
||||||
|
bossWidget.TimeText:SetText(Details:GetFramework():IntegerToTimer(bossTable[1]))
|
||||||
|
|
||||||
|
if (bossTable[2].bossimage) then
|
||||||
|
bossWidget.AvatarTexture:SetTexture(bossTable[2].bossimage)
|
||||||
|
else
|
||||||
|
local bossAvatar = Details:GetBossPortrait(nil, nil, bossTable[2].name, bossTable[2].ej_instance_id)
|
||||||
|
bossWidget.AvatarTexture:SetTexture(bossAvatar)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mythicDungeonCharts.Frame.ChartFrame:Reset()
|
||||||
|
|
||||||
|
if (not mythicDungeonCharts.ChartTable) then
|
||||||
|
if (debugmode) then
|
||||||
|
--development
|
||||||
|
if (Details.mythic_plus.last_mythicrun_chart) then
|
||||||
|
--load the last mythic dungeon run chart
|
||||||
|
local t = {}
|
||||||
|
Details:GetFramework().table.copy(t, Details.mythic_plus.last_mythicrun_chart)
|
||||||
|
mythicDungeonCharts.ChartTable = t
|
||||||
|
mythicDungeonCharts:Debug("no valid data, saved data loaded")
|
||||||
|
|
||||||
|
else
|
||||||
|
mythicDungeonCharts:Debug("no valid data and no saved data, canceling")
|
||||||
|
mythicDungeonCharts.Frame:Hide()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
mythicDungeonCharts.Frame:Hide()
|
||||||
|
mythicDungeonCharts:Debug("no data found, canceling")
|
||||||
|
|
||||||
|
if (verbosemode) then
|
||||||
|
mythicDungeonCharts:Debug("mythicDungeonCharts.ShowChart() failed: no chart table")
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local charts = mythicDungeonCharts.ChartTable.Players
|
||||||
|
local classDuplicated = {}
|
||||||
|
|
||||||
|
mythicDungeonCharts.PlayerGraphIndex = {}
|
||||||
|
|
||||||
|
for playerName, playerTable in pairs(charts) do
|
||||||
|
local chartData = playerTable.ChartData
|
||||||
|
local lineName = playerTable.Name
|
||||||
|
|
||||||
|
classDuplicated[playerTable.Class] = (classDuplicated[playerTable.Class] or 0) + 1
|
||||||
|
|
||||||
|
local lineColor
|
||||||
|
if (playerTable.Class) then
|
||||||
|
local classColor = mythicDungeonCharts.ClassColors[playerTable.Class .. classDuplicated[playerTable.Class]]
|
||||||
|
if (classColor) then
|
||||||
|
lineColor = {classColor.r, classColor.g, classColor.b}
|
||||||
|
else
|
||||||
|
lineColor = {1, 1, 1}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
lineColor = {1, 1, 1}
|
||||||
|
end
|
||||||
|
|
||||||
|
local combatTime = mythicDungeonCharts.ChartTable.ElapsedTime
|
||||||
|
local texture = "line"
|
||||||
|
|
||||||
|
--lowess smooth
|
||||||
|
--chartData = mythicDungeonCharts.LowessSmoothing (chartData, 75)
|
||||||
|
chartData = mythicDungeonCharts.Frame.ChartFrame:CalcLowessSmoothing(chartData, 75)
|
||||||
|
|
||||||
|
local maxValue = 0
|
||||||
|
for i = 1, #chartData do
|
||||||
|
if (chartData [i] > maxValue) then
|
||||||
|
maxValue = chartData[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
chartData.max_value = maxValue
|
||||||
|
|
||||||
|
mythicDungeonCharts.Frame.ChartFrame:AddLine(chartData, lineColor, lineName, combatTime, texture, "SMA")
|
||||||
|
table.insert(mythicDungeonCharts.PlayerGraphIndex, playerName)
|
||||||
|
end
|
||||||
|
|
||||||
|
mythicDungeonCharts.Frame.ChartFrame:RefreshBossTimeline(mythicDungeonCharts.ChartTable.BossDefeated, mythicDungeonCharts.ChartTable.ElapsedTime)
|
||||||
|
|
||||||
|
--generate boss time table
|
||||||
|
local bossTimeTable = {}
|
||||||
|
for i, bossTable in ipairs(mythicDungeonCharts.ChartTable.BossDefeated) do
|
||||||
|
local combatTime = bossTable [3] or math.random(10, 30)
|
||||||
|
|
||||||
|
table.insert(bossTimeTable, bossTable[1])
|
||||||
|
table.insert(bossTimeTable, bossTable[1] - combatTime)
|
||||||
|
end
|
||||||
|
|
||||||
|
mythicDungeonCharts.Frame.ChartFrame:AddOverlay(bossTimeTable, {1, 1, 1, 0.05}, "Show Boss", "")
|
||||||
|
|
||||||
|
--local phrase = " Average Dps (under development)\npress Escape to hide, Details! Alpha Build." .. _detalhes.build_counter .. "." .. _detalhes.realversion
|
||||||
|
local phrase = "Details!: Average Dps for "
|
||||||
|
|
||||||
|
mythicDungeonCharts.Frame.ChartFrame:SetTitle("")
|
||||||
|
Details:GetFramework():SetFontSize(mythicDungeonCharts.Frame.ChartFrame.chart_title, 14)
|
||||||
|
|
||||||
|
mythicDungeonCharts.Frame.TitleText:SetText(mythicDungeonCharts.ChartTable.DungeonName and phrase .. mythicDungeonCharts.ChartTable.DungeonName or phrase)
|
||||||
|
|
||||||
|
mythicDungeonCharts.Frame.ShowChartFrame()
|
||||||
|
|
||||||
|
if (verbosemode) then
|
||||||
|
mythicDungeonCharts:Debug("mythicDungeonCharts.ShowChart() success")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local showID = 0
|
||||||
|
local HideTooltip = function(ticker)
|
||||||
|
if (showID == ticker.ShowID) then
|
||||||
|
GameCooltip2:Hide()
|
||||||
|
mythicDungeonCharts.Frame.BossWidgetsFrame.GraphPin:Hide()
|
||||||
|
mythicDungeonCharts.Frame.BossWidgetsFrame.GraphPinGlow:Hide()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local PixelFrameOnEnter = function(self)
|
||||||
|
local playerName = self.PlayerName
|
||||||
|
--get the percent from the pixel height relative to the chart window
|
||||||
|
local dps = self.Height / mythicDungeonCharts.Frame.ChartFrame:GetHeight()
|
||||||
|
--multiply the max dps with the percent
|
||||||
|
dps = mythicDungeonCharts.Frame.ChartFrame.Graphic.max_value * dps
|
||||||
|
|
||||||
|
mythicDungeonCharts.Frame.BossWidgetsFrame.GraphPin:SetPoint("center", self, "center", 0, 0)
|
||||||
|
mythicDungeonCharts.Frame.BossWidgetsFrame.GraphPin:Show()
|
||||||
|
mythicDungeonCharts.Frame.BossWidgetsFrame.GraphPinGlow:Show()
|
||||||
|
|
||||||
|
GameCooltip2:Preset(2)
|
||||||
|
GameCooltip2:SetOption("FixedWidth", 100)
|
||||||
|
GameCooltip2:SetOption("TextSize", 10)
|
||||||
|
local onlyName = Details:GetOnlyName(playerName)
|
||||||
|
GameCooltip2:AddLine(onlyName)
|
||||||
|
|
||||||
|
local classIcon, L, R, B, T = Details:GetClassIcon(mythicDungeonCharts.ChartTable.Players [playerName] and mythicDungeonCharts.ChartTable.Players [playerName].Class)
|
||||||
|
GameCooltip2:AddIcon (classIcon, 1, 1, 16, 16, L, R, B, T)
|
||||||
|
|
||||||
|
GameCooltip2:AddLine(Details:GetCurrentToKFunction()(nil, floor(dps)))
|
||||||
|
|
||||||
|
GameCooltip2:SetOwner(self)
|
||||||
|
GameCooltip2:Show()
|
||||||
|
showID = showID + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local PixelFrameOnLeave = function(self)
|
||||||
|
local timer = C_Timer.NewTimer(1, HideTooltip)
|
||||||
|
timer.ShowID = showID
|
||||||
|
end
|
||||||
|
|
||||||
|
local TAXIROUTE_LINEFACTOR = 128 / 126 -- Multiplying factor for texture coordinates
|
||||||
|
local TAXIROUTE_LINEFACTOR_2 = TAXIROUTE_LINEFACTOR / 2 -- Half of that
|
||||||
|
|
||||||
|
function mythicDungeonCharts:CustomDrawLine (C, sx, sy, ex, ey, w, color, layer, linetexture, graphIndex)
|
||||||
|
local relPoint = "BOTTOMLEFT"
|
||||||
|
|
||||||
|
if sx == ex then
|
||||||
|
if sy == ey then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
return self:DrawVLine(C, sx, sy, ey, w, color, layer)
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif sy == ey then
|
||||||
|
return self:DrawHLine(C, sx, ex, sy, w, color, layer)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not C.GraphLib_Lines then
|
||||||
|
C.GraphLib_Lines = {}
|
||||||
|
C.GraphLib_Lines_Used = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
local T = tremove(C.GraphLib_Lines) or C:CreateTexture(nil, "ARTWORK")
|
||||||
|
|
||||||
|
if linetexture then --this data series texture
|
||||||
|
T:SetTexture(linetexture)
|
||||||
|
|
||||||
|
elseif C.CustomLine then --overall chart texture
|
||||||
|
T:SetTexture(C.CustomLine)
|
||||||
|
|
||||||
|
else --no texture assigned, use default
|
||||||
|
T:SetTexture(TextureDirectory.."line")
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(C.GraphLib_Lines_Used, T)
|
||||||
|
|
||||||
|
T:SetDrawLayer(layer or "ARTWORK")
|
||||||
|
|
||||||
|
T:SetVertexColor(color[1], color[2], color[3], color[4])
|
||||||
|
-- Determine dimensions and center point of line
|
||||||
|
local dx, dy = ex - sx, ey - sy
|
||||||
|
local cx, cy = (sx + ex) / 2, (sy + ey) / 2
|
||||||
|
|
||||||
|
-- Normalize direction if necessary
|
||||||
|
if (dx < 0) then
|
||||||
|
dx, dy = -dx, -dy
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Calculate actual length of line
|
||||||
|
local l = sqrt((dx * dx) + (dy * dy))
|
||||||
|
|
||||||
|
-- Sin and Cosine of rotation, and combination (for later)
|
||||||
|
local s, c = -dy / l, dx / l
|
||||||
|
local sc = s * c
|
||||||
|
|
||||||
|
-- Calculate bounding box size and texture coordinates
|
||||||
|
local Bwid, Bhgt, BLx, BLy, TLx, TLy, TRx, TRy, BRx, BRy
|
||||||
|
if (dy >= 0) then
|
||||||
|
Bwid = ((l * c) - (w * s)) * TAXIROUTE_LINEFACTOR_2
|
||||||
|
Bhgt = ((w * c) - (l * s)) * TAXIROUTE_LINEFACTOR_2
|
||||||
|
BLx, BLy, BRy = (w / l) * sc, s * s, (l / w) * sc
|
||||||
|
BRx, TLx, TLy, TRx = 1 - BLy, BLy, 1 - BRy, 1 - BLx
|
||||||
|
TRy = BRx
|
||||||
|
else
|
||||||
|
Bwid = ((l * c) + (w * s)) * TAXIROUTE_LINEFACTOR_2
|
||||||
|
Bhgt = ((w * c) + (l * s)) * TAXIROUTE_LINEFACTOR_2
|
||||||
|
BLx, BLy, BRx = s * s, -(l / w) * sc, 1 + (w / l) * sc
|
||||||
|
BRy, TLx, TLy, TRy = BLx, 1 - BRx, 1 - BLx, 1 - BLy
|
||||||
|
TRx = TLy
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Thanks Blizzard for adding (-)10000 as a hard-cap and throwing errors!
|
||||||
|
-- The cap was added in 3.1.0 and I think it was upped in 3.1.1
|
||||||
|
-- (way less chance to get the error)
|
||||||
|
if TLx > 10000 then TLx = 10000 elseif TLx < -10000 then TLx = -10000 end
|
||||||
|
if TLy > 10000 then TLy = 10000 elseif TLy < -10000 then TLy = -10000 end
|
||||||
|
if BLx > 10000 then BLx = 10000 elseif BLx < -10000 then BLx = -10000 end
|
||||||
|
if BLy > 10000 then BLy = 10000 elseif BLy < -10000 then BLy = -10000 end
|
||||||
|
if TRx > 10000 then TRx = 10000 elseif TRx < -10000 then TRx = -10000 end
|
||||||
|
if TRy > 10000 then TRy = 10000 elseif TRy < -10000 then TRy = -10000 end
|
||||||
|
if BRx > 10000 then BRx = 10000 elseif BRx < -10000 then BRx = -10000 end
|
||||||
|
if BRy > 10000 then BRy = 10000 elseif BRy < -10000 then BRy = -10000 end
|
||||||
|
|
||||||
|
-- Set texture coordinates and anchors
|
||||||
|
T:ClearAllPoints()
|
||||||
|
T:SetTexCoord(TLx, TLy, BLx, BLy, TRx, TRy, BRx, BRy)
|
||||||
|
T:SetPoint("BOTTOMLEFT", C, relPoint, cx - Bwid, cy - Bhgt)
|
||||||
|
T:SetPoint("TOPRIGHT", C, relPoint, cx + Bwid, cy + Bhgt)
|
||||||
|
T:Show()
|
||||||
|
|
||||||
|
local playerName = mythicDungeonCharts.PlayerGraphIndex [graphIndex]
|
||||||
|
if (mythicDungeonCharts.Frame.ChartFrame.TextureID % 3 == 0 and playerName) then
|
||||||
|
|
||||||
|
local pixelFrame = tremove(mythicDungeonCharts.Frame.ChartFrame.FrameFree)
|
||||||
|
if (not pixelFrame) then
|
||||||
|
local newFrame = CreateFrame("frame", nil, mythicDungeonCharts.Frame.ChartFrame, "BackdropTemplate")
|
||||||
|
newFrame:SetSize(1, 1)
|
||||||
|
|
||||||
|
--newFrame:SetBackdrop({edgeFile = [[Interface\Buttons\WHITE8X8]], edgeSize = 1, bgFile = [[Interface\Tooltips\UI-Tooltip-Background]], tileSize = 2, tile = true})
|
||||||
|
--newFrame:SetBackdropColor(0, 0, 0, 1)
|
||||||
|
newFrame:SetScript("OnEnter", PixelFrameOnEnter)
|
||||||
|
newFrame:SetScript("OnLeave", PixelFrameOnLeave)
|
||||||
|
|
||||||
|
pixelFrame = newFrame
|
||||||
|
end
|
||||||
|
|
||||||
|
pixelFrame:SetPoint("BOTTOMLEFT", C, relPoint, cx - Bwid, cy - Bhgt)
|
||||||
|
pixelFrame:SetPoint("TOPRIGHT", C, relPoint, cx + Bwid, cy + Bhgt)
|
||||||
|
|
||||||
|
table.insert(mythicDungeonCharts.Frame.ChartFrame.FrameInUse, pixelFrame)
|
||||||
|
pixelFrame.PlayerName = playerName
|
||||||
|
pixelFrame.Height = ey
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
mythicDungeonCharts.Frame.ChartFrame.TextureID = mythicDungeonCharts.Frame.ChartFrame.TextureID + 1
|
||||||
|
return T
|
||||||
|
end
|
||||||
|
|
||||||
|
mythicDungeonCharts.ClassColors = {
|
||||||
|
["HUNTER1"] = { r = 0.67, g = 0.83, b = 0.45, colorStr = "ffabd473" },
|
||||||
|
["HUNTER2"] = { r = 0.47, g = 0.63, b = 0.25, colorStr = "ffabd473" },
|
||||||
|
["HUNTER3"] = { r = 0.27, g = 0.43, b = 0.05, colorStr = "ffabd473" },
|
||||||
|
|
||||||
|
["WARLOCK1"] = { r = 0.53, g = 0.53, b = 0.93, colorStr = "ff8788ee" },
|
||||||
|
["WARLOCK2"] = { r = 0.33, g = 0.33, b = 0.73, colorStr = "ff8788ee" },
|
||||||
|
["WARLOCK3"] = { r = 0.13, g = 0.13, b = 0.53, colorStr = "ff8788ee" },
|
||||||
|
|
||||||
|
["PRIEST1"] = { r = 1.0, g = 1.0, b = 1.0, colorStr = "ffffffff" },
|
||||||
|
["PRIEST2"] = { r = 0.8, g = 0.8, b = 0.8, colorStr = "ffffffff" },
|
||||||
|
["PRIEST3"] = { r = 0.6, g = 0.6, b = 0.6, colorStr = "ffffffff" },
|
||||||
|
|
||||||
|
["PALADIN1"] = { r = 0.96, g = 0.55, b = 0.73, colorStr = "fff58cba" },
|
||||||
|
["PALADIN2"] = { r = 0.76, g = 0.35, b = 0.53, colorStr = "fff58cba" },
|
||||||
|
["PALADIN3"] = { r = 0.56, g = 0.15, b = 0.33, colorStr = "fff58cba" },
|
||||||
|
|
||||||
|
["MAGE1"] = { r = 0.25, g = 0.78, b = 0.92, colorStr = "ff3fc7eb" },
|
||||||
|
["MAGE2"] = { r = 0.05, g = 0.58, b = 0.72, colorStr = "ff3fc7eb" },
|
||||||
|
["MAGE3"] = { r = 0.0, g = 0.38, b = 0.52, colorStr = "ff3fc7eb" },
|
||||||
|
|
||||||
|
["ROGUE1"] = { r = 1.0, g = 0.96, b = 0.41, colorStr = "fffff569" },
|
||||||
|
["ROGUE2"] = { r = 0.8, g = 0.76, b = 0.21, colorStr = "fffff569" },
|
||||||
|
["ROGUE3"] = { r = 0.6, g = 0.56, b = 0.01, colorStr = "fffff569" },
|
||||||
|
|
||||||
|
["DRUID1"] = { r = 1.0, g = 0.49, b = 0.04, colorStr = "ffff7d0a" },
|
||||||
|
["DRUID2"] = { r = 0.8, g = 0.29, b = 0.04, colorStr = "ffff7d0a" },
|
||||||
|
["DRUID3"] = { r = 0.6, g = 0.09, b = 0.04, colorStr = "ffff7d0a" },
|
||||||
|
|
||||||
|
["SHAMAN1"] = { r = 0.0, g = 0.44, b = 0.87, colorStr = "ff0070de" },
|
||||||
|
["SHAMAN2"] = { r = 0.0, g = 0.24, b = 0.67, colorStr = "ff0070de" },
|
||||||
|
["SHAMAN3"] = { r = 0.0, g = 0.04, b = 0.47, colorStr = "ff0070de" },
|
||||||
|
|
||||||
|
["WARRIOR1"] = { r = 0.78, g = 0.61, b = 0.43, colorStr = "ffc79c6e" },
|
||||||
|
["WARRIOR2"] = { r = 0.58, g = 0.41, b = 0.23, colorStr = "ffc79c6e" },
|
||||||
|
["WARRIOR3"] = { r = 0.38, g = 0.21, b = 0.03, colorStr = "ffc79c6e" },
|
||||||
|
|
||||||
|
["DEATHKNIGHT1"] = { r = 0.77, g = 0.12 , b = 0.23, colorStr = "ffc41f3b" },
|
||||||
|
["DEATHKNIGHT2"] = { r = 0.57, g = 0.02 , b = 0.03, colorStr = "ffc41f3b" },
|
||||||
|
["DEATHKNIGHT3"] = { r = 0.37, g = 0.02 , b = 0.03, colorStr = "ffc41f3b" },
|
||||||
|
|
||||||
|
["MONK1"] = { r = 0.0, g = 1.00 , b = 0.59, colorStr = "ff00ff96" },
|
||||||
|
["MONK2"] = { r = 0.0, g = 0.8 , b = 0.39, colorStr = "ff00ff96" },
|
||||||
|
["MONK3"] = { r = 0.0, g = 0.6 , b = 0.19, colorStr = "ff00ff96" },
|
||||||
|
|
||||||
|
["DEMONHUNTER1"] = { r = 0.64, g = 0.19, b = 0.79, colorStr = "ffa330c9" },
|
||||||
|
["DEMONHUNTER2"] = { r = 0.44, g = 0.09, b = 0.59, colorStr = "ffa330c9" },
|
||||||
|
["DEMONHUNTER3"] = { r = 0.24, g = 0.09, b = 0.39, colorStr = "ffa330c9" },
|
||||||
|
|
||||||
|
["EVOKER1"] = { r = 0.0, g = 1.00 , b = 0.59, colorStr = "FF205F45" },
|
||||||
|
["EVOKER2"] = { r = 0.0, g = 0.8 , b = 0.39, colorStr = "FF126442" },
|
||||||
|
["EVOKER3"] = { r = 0.0, g = 0.6 , b = 0.19, colorStr = "FF274B3C" },
|
||||||
|
};
|
||||||
|
|
||||||
|
if (debugmode) then
|
||||||
|
--C_Timer.After(1, mythicDungeonCharts.ShowChart)
|
||||||
|
end
|
||||||
@@ -0,0 +1,719 @@
|
|||||||
|
|
||||||
|
local Details = _G.Details
|
||||||
|
local debugmode = false --print debug lines
|
||||||
|
local verbosemode = false --auto open the chart panel
|
||||||
|
local addonName, Details222 = ...
|
||||||
|
local mPlus = Details222.MythicPlusBreakdown
|
||||||
|
local detailsFramework = DetailsFramework
|
||||||
|
local _
|
||||||
|
|
||||||
|
local CreateFrame = CreateFrame
|
||||||
|
local UnitExists = UnitExists
|
||||||
|
local UnitGroupRolesAssigned = UnitGroupRolesAssigned
|
||||||
|
local UIParent = UIParent
|
||||||
|
local PixelUtil = PixelUtil
|
||||||
|
local C_Timer = C_Timer
|
||||||
|
|
||||||
|
local Loc = _G.LibStub("AceLocale-3.0"):GetLocale("Details")
|
||||||
|
|
||||||
|
local mythicDungeonCharts = Details222.MythicPlus.Charts.Listener
|
||||||
|
local mythicDungeonFrames = Details222.MythicPlus.Frames
|
||||||
|
|
||||||
|
--debug
|
||||||
|
--_G.DetailsMythicDungeonChartHandler = mythicDungeonCharts
|
||||||
|
|
||||||
|
|
||||||
|
local createPlayerBanner = function(parent, name)
|
||||||
|
local template = "ChallengeModeBannerPartyMemberTemplate"
|
||||||
|
local playerFrame = CreateFrame("frame", name, parent, template)
|
||||||
|
playerFrame:SetAlpha(1)
|
||||||
|
playerFrame:EnableMouse(true)
|
||||||
|
playerFrame:SetFrameLevel(parent:GetFrameLevel()+2)
|
||||||
|
|
||||||
|
local playerNameFontString = playerFrame:CreateFontString("$parentPlayerNameText", "overlay", "GameFontNormal")
|
||||||
|
playerNameFontString:SetTextColor(1, 1, 1)
|
||||||
|
playerNameFontString:SetPoint("top", playerFrame, "bottom", -1, -7)
|
||||||
|
DetailsFramework:SetFontSize(playerNameFontString, 12)
|
||||||
|
playerFrame.PlayerNameFontString = playerNameFontString
|
||||||
|
|
||||||
|
local playerNameBackgroundTexture = playerFrame:CreateTexture("$parentPlayerNameBackgroundTexture", "overlay", nil, 6)
|
||||||
|
playerNameBackgroundTexture:SetTexture([[Interface\Cooldown\LoC-ShadowBG]])
|
||||||
|
playerNameBackgroundTexture:SetSize(68, 12)
|
||||||
|
playerNameBackgroundTexture:SetPoint("center", playerNameFontString, "center", 0, 0)
|
||||||
|
|
||||||
|
local backgroundBannerTexture = playerFrame:CreateTexture("$parentBannerTexture", "background", nil, 0)
|
||||||
|
backgroundBannerTexture:SetTexture([[Interface\ACHIEVEMENTFRAME\GuildTabard]])
|
||||||
|
backgroundBannerTexture:SetDrawLayer("background", 0)
|
||||||
|
backgroundBannerTexture:SetSize(63, 129)
|
||||||
|
backgroundBannerTexture:SetTexCoord(5/128, 68/128, 123/256, 252/256)
|
||||||
|
backgroundBannerTexture:SetPoint("topleft", playerFrame, "bottomleft", -5, playerFrame:GetHeight()/2)
|
||||||
|
backgroundBannerTexture:SetPoint("topright", playerFrame, "bottomright", 4, playerFrame:GetHeight()/2)
|
||||||
|
backgroundBannerTexture:SetVertexColor(.1, .1, .1)
|
||||||
|
playerFrame.BackgroundBannerTexture = backgroundBannerTexture
|
||||||
|
|
||||||
|
local backgroundBannerBorderTexture = playerFrame:CreateTexture("$parentBannerBorderTexture", "highlight", nil, -1)
|
||||||
|
backgroundBannerBorderTexture:SetAtlas("UI-Achievement-Guild-Flag-Outline")
|
||||||
|
backgroundBannerBorderTexture:SetSize(63, 129)
|
||||||
|
backgroundBannerBorderTexture:SetPoint("topleft", playerFrame, "bottomleft", -5, playerFrame:GetHeight()/2)
|
||||||
|
backgroundBannerBorderTexture:SetPoint("topright", playerFrame, "bottomright", 4, playerFrame:GetHeight()/2)
|
||||||
|
|
||||||
|
local dungeonTexture = playerFrame:CreateTexture("$parentDungeonTexture", "artwork")
|
||||||
|
dungeonTexture:SetTexCoord(25/512, 360/512, 50/512, 290/512)
|
||||||
|
dungeonTexture:SetSize(50, 39)
|
||||||
|
dungeonTexture:SetPoint("top", playerFrame,"bottom", 0, -16)
|
||||||
|
dungeonTexture:SetAlpha(0.9934)
|
||||||
|
playerFrame.DungeonTexture = dungeonTexture
|
||||||
|
|
||||||
|
local dungeonBorderTexture = playerFrame:CreateTexture("$parentDungeonBorder", "border")
|
||||||
|
dungeonBorderTexture:SetTexture([[Interface\BUTTONS\UI-EmptySlot]])
|
||||||
|
dungeonBorderTexture:SetDrawLayer("border", 0)
|
||||||
|
dungeonBorderTexture:ClearAllPoints()
|
||||||
|
dungeonBorderTexture:SetPoint("topleft", dungeonTexture,"topleft", -17, 15)
|
||||||
|
dungeonBorderTexture:SetPoint("bottomright", dungeonTexture,"bottomright", 18, -15)
|
||||||
|
dungeonBorderTexture:SetAlpha(1)
|
||||||
|
playerFrame.DungeonBorderTexture = dungeonBorderTexture
|
||||||
|
|
||||||
|
--load this addon, required to have access to the garrison templates
|
||||||
|
if (not C_AddOns.IsAddOnLoaded("Blizzard_GarrisonTemplates")) then
|
||||||
|
C_AddOns.LoadAddOn("Blizzard_GarrisonTemplates")
|
||||||
|
end
|
||||||
|
|
||||||
|
--animation for the key leveling up
|
||||||
|
local levelUpFrame = CreateFrame("frame", "$LevelUpFrame", playerFrame, "GarrisonFollowerLevelUpTemplate")
|
||||||
|
levelUpFrame:SetPoint("top", dungeonTexture, "bottom", 0, 44)
|
||||||
|
levelUpFrame:SetScale(0.9)
|
||||||
|
levelUpFrame.Text:SetText("")
|
||||||
|
playerFrame.LevelUpFrame = levelUpFrame
|
||||||
|
levelUpFrame:SetFrameLevel(playerFrame:GetFrameLevel()+1)
|
||||||
|
|
||||||
|
local levelUpTextFrame = CreateFrame("frame", "$LevelUpTextFrame", playerFrame)
|
||||||
|
levelUpTextFrame:SetPoint("top", dungeonTexture, "bottom", -1, -14)
|
||||||
|
levelUpTextFrame:SetFrameLevel(playerFrame:GetFrameLevel()+2)
|
||||||
|
levelUpTextFrame:SetSize(1, 1)
|
||||||
|
playerFrame.LevelUpTextFrame = levelUpTextFrame
|
||||||
|
--scaleX, scaleY, fadeInTime, fadeOutTime
|
||||||
|
local shakeAnimation = detailsFramework:CreateFrameShake(levelUpTextFrame, 0.8, 2, 200, false, false, 0, 1, 0.5, 0.15)
|
||||||
|
local shakeAnimation2 = detailsFramework:CreateFrameShake(levelUpTextFrame, 0.5, 1, 200, false, false, 0, 1, 0, 0)
|
||||||
|
|
||||||
|
local levelFontString = levelUpTextFrame:CreateFontString("$parentLVLText", "artwork", "GameFontNormal")
|
||||||
|
levelFontString:SetTextColor(1, 1, 1)
|
||||||
|
levelFontString:SetPoint("center", levelUpTextFrame, "center", 0, 0)
|
||||||
|
DetailsFramework:SetFontSize(levelFontString, 20)
|
||||||
|
levelFontString:SetText("")
|
||||||
|
playerFrame.LevelFontString = levelFontString
|
||||||
|
|
||||||
|
--> animations for levelFontString
|
||||||
|
local animationGroup = levelFontString:CreateAnimationGroup("DetailsMythicLevelTextAnimationGroup")
|
||||||
|
animationGroup:SetLooping("NONE")
|
||||||
|
levelFontString.AnimationGroup = animationGroup
|
||||||
|
|
||||||
|
do
|
||||||
|
levelFontString.translation = animationGroup:CreateAnimation("TRANSLATION")
|
||||||
|
levelFontString.translation:SetTarget(levelFontString)
|
||||||
|
levelFontString.translation:SetOrder(1)
|
||||||
|
levelFontString.translation:SetDuration(0.096000000834465)
|
||||||
|
levelFontString.translation:SetOffset(0, -4)
|
||||||
|
levelFontString.translation = animationGroup:CreateAnimation("TRANSLATION")
|
||||||
|
levelFontString.translation:SetTarget(levelFontString)
|
||||||
|
levelFontString.translation:SetOrder(2)
|
||||||
|
levelFontString.translation:SetDuration(0.11599999666214)
|
||||||
|
levelFontString.translation:SetOffset(0, 16)
|
||||||
|
levelFontString.rotation = animationGroup:CreateAnimation("ROTATION")
|
||||||
|
levelFontString.rotation:SetTarget(levelFontString)
|
||||||
|
levelFontString.rotation:SetOrder(3)
|
||||||
|
levelFontString.rotation:SetDuration(0.096000000834465)
|
||||||
|
levelFontString.rotation:SetDegrees(20)
|
||||||
|
levelFontString.rotation:SetOrigin("center", 0, 0)
|
||||||
|
levelFontString.rotation = animationGroup:CreateAnimation("ROTATION")
|
||||||
|
levelFontString.rotation:SetTarget(levelFontString)
|
||||||
|
levelFontString.rotation:SetOrder(4)
|
||||||
|
levelFontString.rotation:SetDuration(0.096000000834465)
|
||||||
|
levelFontString.rotation:SetDegrees(-20)
|
||||||
|
levelFontString.rotation:SetOrigin("center", 0, 0)
|
||||||
|
levelFontString.rotation = animationGroup:CreateAnimation("ROTATION")
|
||||||
|
levelFontString.rotation:SetTarget(levelFontString)
|
||||||
|
levelFontString.rotation:SetOrder(5)
|
||||||
|
levelFontString.rotation:SetDuration(0.195999994874)
|
||||||
|
levelFontString.rotation:SetDegrees(360)
|
||||||
|
levelFontString.rotation:SetOrigin("center", 0, 0)
|
||||||
|
levelFontString.translation = animationGroup:CreateAnimation("TRANSLATION")
|
||||||
|
levelFontString.translation:SetTarget(levelFontString)
|
||||||
|
levelFontString.translation:SetOrder(6)
|
||||||
|
levelFontString.translation:SetDuration(0.21599999070168)
|
||||||
|
levelFontString.translation:SetOffset(0, 9)
|
||||||
|
levelFontString.translation = animationGroup:CreateAnimation("TRANSLATION")
|
||||||
|
levelFontString.translation:SetTarget(levelFontString)
|
||||||
|
levelFontString.translation:SetOrder(7)
|
||||||
|
levelFontString.translation:SetDuration(0.046000000089407)
|
||||||
|
levelFontString.translation:SetOffset(0, -24)
|
||||||
|
end
|
||||||
|
|
||||||
|
function levelUpTextFrame.PlayAnimations(newLevel)
|
||||||
|
levelUpTextFrame:PlayFrameShake(shakeAnimation)
|
||||||
|
|
||||||
|
C_Timer.After(0.7, function()
|
||||||
|
playerFrame.LevelUpFrame:Show()
|
||||||
|
playerFrame.LevelUpFrame:SetAlpha(1)
|
||||||
|
playerFrame.LevelUpFrame.Anim:Play()
|
||||||
|
animationGroup:Play()
|
||||||
|
end)
|
||||||
|
|
||||||
|
C_Timer.After(0.7 + 0.5, function()
|
||||||
|
levelFontString:SetText(newLevel or "")
|
||||||
|
end)
|
||||||
|
|
||||||
|
C_Timer.After(1.65, function()
|
||||||
|
levelUpTextFrame:PlayFrameShake(shakeAnimation2)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local flashTexture = playerFrame:CreateTexture("$parentFlashTexture", "overlay", nil, 6)
|
||||||
|
flashTexture:SetAtlas("UI-Achievement-Guild-Flag-Outline")
|
||||||
|
flashTexture:SetSize(63, 129)
|
||||||
|
flashTexture:SetPoint("topleft", playerFrame, "bottomleft", -5, playerFrame:GetHeight()/2)
|
||||||
|
flashTexture:SetPoint("topright", playerFrame, "bottomright", 4, playerFrame:GetHeight()/2)
|
||||||
|
flashTexture:Hide()
|
||||||
|
playerFrame.flashTexture = flashTexture
|
||||||
|
|
||||||
|
detailsFramework:CreateFlashAnimation(flashTexture)
|
||||||
|
--flashTexture:Flash(0.1, 0.5, 0.01)
|
||||||
|
|
||||||
|
local lootSquare = CreateFrame("frame", name, parent)
|
||||||
|
lootSquare:SetSize(46, 46)
|
||||||
|
lootSquare:SetPoint("top", playerFrame, "bottom", 0, -90)
|
||||||
|
lootSquare:SetFrameLevel(parent:GetFrameLevel()+1)
|
||||||
|
playerFrame.LootSquare = lootSquare
|
||||||
|
lootSquare:Hide()
|
||||||
|
|
||||||
|
lootSquare:SetScript("OnEnter", function(self)
|
||||||
|
if (self.itemLink) then
|
||||||
|
GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT")
|
||||||
|
GameTooltip:SetHyperlink(lootSquare.itemLink)
|
||||||
|
GameTooltip:Show()
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
lootSquare:SetScript("OnLeave", function(self)
|
||||||
|
GameTooltip:Hide()
|
||||||
|
end)
|
||||||
|
|
||||||
|
local lootIcon = lootSquare:CreateTexture("$parentLootIcon", "artwork")
|
||||||
|
lootIcon:SetSize(46, 46)
|
||||||
|
lootIcon:SetPoint("center", lootSquare, "center", 0, 0)
|
||||||
|
lootIcon:SetTexture([[Interface\ICONS\INV_Misc_QuestionMark]])
|
||||||
|
lootSquare.LootIcon = lootIcon
|
||||||
|
|
||||||
|
local lootIconBorder = lootSquare:CreateTexture("$parentLootSquareBorder", "overlay")
|
||||||
|
lootIconBorder:SetTexture([[Interface\COMMON\WhiteIconFrame]])
|
||||||
|
lootIconBorder:SetTexCoord(0, 1, 0, 1)
|
||||||
|
lootIconBorder:SetSize(46, 46)
|
||||||
|
lootIconBorder:SetPoint("center", lootIcon, "center", 0, 0)
|
||||||
|
lootSquare.LootIconBorder = lootIconBorder
|
||||||
|
|
||||||
|
local lootItemLevel = lootSquare:CreateFontString("$parentLootItemLevel", "overlay", "GameFontNormal")
|
||||||
|
lootItemLevel:SetPoint("top", lootSquare, "bottom", 0, -2)
|
||||||
|
lootItemLevel:SetTextColor(1, 1, 1)
|
||||||
|
DetailsFramework:SetFontSize(lootItemLevel, 12)
|
||||||
|
lootSquare.LootItemLevel = lootItemLevel
|
||||||
|
|
||||||
|
return playerFrame
|
||||||
|
end
|
||||||
|
|
||||||
|
local updatPlayerBanner = function(unitId, bannerIndex)
|
||||||
|
if (UnitExists(unitId)) then
|
||||||
|
local readyFrame = DetailsMythicDungeonReadyFrame
|
||||||
|
local unitName = Details:GetFullName(unitId)
|
||||||
|
local libOpenRaid = LibStub("LibOpenRaid-1.0", true)
|
||||||
|
|
||||||
|
local playerBanner = readyFrame.PlayerBanners[bannerIndex]
|
||||||
|
readyFrame.playerCacheByName[unitName] = playerBanner
|
||||||
|
playerBanner.unitId = unitId
|
||||||
|
playerBanner.unitName = unitName
|
||||||
|
playerBanner:Show()
|
||||||
|
|
||||||
|
SetPortraitTexture(playerBanner.Portrait, unitId)
|
||||||
|
|
||||||
|
unitName = detailsFramework:RemoveRealmName(unitName)
|
||||||
|
playerBanner.PlayerNameFontString:SetText(unitName)
|
||||||
|
detailsFramework:TruncateText(playerBanner.PlayerNameFontString, 60)
|
||||||
|
|
||||||
|
local role = UnitGroupRolesAssigned(unitId)
|
||||||
|
if (role == "TANK" or role == "HEALER" or role == "DAMAGER") then
|
||||||
|
playerBanner.RoleIcon:SetAtlas(GetMicroIconForRole(role), TextureKitConstants.IgnoreAtlasSize)
|
||||||
|
playerBanner.RoleIcon:Show()
|
||||||
|
else
|
||||||
|
playerBanner.RoleIcon:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
local playerKeystoneInfo = libOpenRaid.GetKeystoneInfo(unitId)
|
||||||
|
if (playerKeystoneInfo) then
|
||||||
|
---@type details_instanceinfo
|
||||||
|
local instanceInfo = Details:GetInstanceInfo(playerKeystoneInfo.mapID)
|
||||||
|
|
||||||
|
playerBanner.LevelFontString:SetText(playerKeystoneInfo.level or "")
|
||||||
|
|
||||||
|
if (instanceInfo) then
|
||||||
|
playerBanner.DungeonTexture:SetTexture(instanceInfo.iconLore)
|
||||||
|
else
|
||||||
|
playerBanner.DungeonTexture:SetTexture([[Interface\ICONS\INV_Misc_QuestionMark]])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
playerBanner.DungeonTexture:SetTexture([[Interface\ICONS\INV_Misc_QuestionMark]])
|
||||||
|
playerBanner.LevelFontString:SetText("")
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local updateKeysStoneLevel = function()
|
||||||
|
--update the player banners
|
||||||
|
local libOpenRaid = LibStub("LibOpenRaid-1.0", true)
|
||||||
|
local readyFrame = DetailsMythicDungeonReadyFrame
|
||||||
|
|
||||||
|
for bannerIndex = 1, #readyFrame.PlayerBanners do
|
||||||
|
local unitBanner = readyFrame.PlayerBanners[bannerIndex]
|
||||||
|
if (unitBanner) then
|
||||||
|
local unitId = unitBanner.unitId
|
||||||
|
if (UnitExists(unitId)) then
|
||||||
|
local unitKeystoneInfo = libOpenRaid.GetKeystoneInfo(unitId)
|
||||||
|
--print("Unit Exists:", unitBanner.unitName, unitId, "updating keystone level", unitKeystoneInfo)
|
||||||
|
if (unitKeystoneInfo) then
|
||||||
|
--if (instanceInfo) then
|
||||||
|
-- ---@type details_instanceinfo
|
||||||
|
-- local thisInstanceInfo = Details:GetInstanceInfo(unitKeystoneInfo.mapID)
|
||||||
|
-- unitBanner.DungeonTexture:SetTexture(thisInstanceInfo.iconLore)
|
||||||
|
--end
|
||||||
|
|
||||||
|
--unitBanner.LevelFontString:SetText(unitKeystoneInfo.level)
|
||||||
|
--print("setting player", unitBanner.unitName, "keystone level to", unitKeystoneInfo.level)
|
||||||
|
|
||||||
|
local oldKeystoneLevel = Details.KeystoneLevels[Details:GetFullName(unitId)]
|
||||||
|
|
||||||
|
if (oldKeystoneLevel and oldKeystoneLevel >= 2) then
|
||||||
|
if (unitKeystoneInfo.level > oldKeystoneLevel) then
|
||||||
|
C_Timer.After(0.5, function()
|
||||||
|
unitBanner.LevelUpTextFrame.PlayAnimations(unitKeystoneInfo.level)
|
||||||
|
end)
|
||||||
|
|
||||||
|
---@type details_instanceinfo
|
||||||
|
local instanceInfo = Details:GetInstanceInfo(unitKeystoneInfo.mapID)
|
||||||
|
|
||||||
|
if (instanceInfo) then
|
||||||
|
unitBanner.DungeonTexture:SetTexture(instanceInfo.iconLore)
|
||||||
|
else
|
||||||
|
unitBanner.DungeonTexture:SetTexture([[Interface\ICONS\INV_Misc_QuestionMark]])
|
||||||
|
end
|
||||||
|
|
||||||
|
--this character had its keystone upgraded
|
||||||
|
--unitBanner.flashTexture:Flash()
|
||||||
|
--print("keystone upgraded for", Details:GetFullName(unitId), unitKeystoneInfo.level, "old was:", oldKeystoneLevel)
|
||||||
|
--C_Timer.After(0.1, function() unitBanner.flashTexture:Stop() end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--print("keystone level updated for", Details:GetFullName(unitId), unitKeystoneInfo.level)
|
||||||
|
else
|
||||||
|
unitBanner.DungeonTexture:SetTexture([[Interface\ICONS\INV_Misc_QuestionMark]])
|
||||||
|
unitBanner.LevelFontString:SetText("")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--SetPortraitTexture(texture, unitId)
|
||||||
|
-- /run _G.DetailsMythicDungeonChartHandler.ShowChart(); DetailsMythicDungeonChartFrame.ShowChartFrame()
|
||||||
|
-- /run _G.DetailsMythicDungeonChartHandler.ShowEndOfMythicPlusPanel()
|
||||||
|
|
||||||
|
--show a small panel telling the chart is ready to show
|
||||||
|
function mythicDungeonFrames.ShowEndOfMythicPlusPanel(bIsDebug)
|
||||||
|
--check if is enabled
|
||||||
|
if (not Details.mythic_plus.show_damage_graphic) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if (bIsDebug) then
|
||||||
|
Details222.MythicPlus.Level = Details222.MythicPlus.Level or 2
|
||||||
|
end
|
||||||
|
|
||||||
|
--feature under development
|
||||||
|
if (Details222.MythicPlus.Level and Details222.MythicPlus.Level < 28 and not Details.user_is_patreon_supporter) then
|
||||||
|
--create the panel
|
||||||
|
if (not mythicDungeonFrames.ReadyFrame) then
|
||||||
|
mythicDungeonFrames.ReadyFrame = CreateFrame("frame", "DetailsMythicDungeonReadyFrame", UIParent, "BackdropTemplate")
|
||||||
|
local readyFrame = mythicDungeonFrames.ReadyFrame
|
||||||
|
|
||||||
|
local textColor = {1, 0.8196, 0, 1}
|
||||||
|
local textSize = 11
|
||||||
|
|
||||||
|
local roundedCornerTemplate = {
|
||||||
|
roundness = 6,
|
||||||
|
color = {.1, .1, .1, 0.98},
|
||||||
|
border_color = {.05, .05, .05, 0.834},
|
||||||
|
}
|
||||||
|
|
||||||
|
detailsFramework:AddRoundedCornersToFrame(readyFrame, roundedCornerTemplate)
|
||||||
|
|
||||||
|
local titleLabel = DetailsFramework:CreateLabel(readyFrame, "Details! Mythic Run Completed!", 12, "yellow")
|
||||||
|
titleLabel:SetPoint("top", readyFrame, "top", 0, -7)
|
||||||
|
titleLabel.textcolor = textColor
|
||||||
|
|
||||||
|
local closeButton = detailsFramework:CreateCloseButton(readyFrame, "$parentCloseButton")
|
||||||
|
closeButton:SetPoint("topright", readyFrame, "topright", -2, -2)
|
||||||
|
closeButton:SetScale(1.4)
|
||||||
|
closeButton:SetAlpha(0.823)
|
||||||
|
|
||||||
|
readyFrame:SetSize(255, 120)
|
||||||
|
readyFrame:SetPoint("center", UIParent, "center", 300, 0)
|
||||||
|
readyFrame:SetFrameStrata("LOW")
|
||||||
|
readyFrame:EnableMouse(true)
|
||||||
|
readyFrame:SetMovable(true)
|
||||||
|
--DetailsFramework:ApplyStandardBackdrop(readyFrame)
|
||||||
|
--DetailsFramework:CreateTitleBar (readyFrame, "Details! Mythic Run Completed!")
|
||||||
|
|
||||||
|
readyFrame:Hide()
|
||||||
|
|
||||||
|
--register to libwindow
|
||||||
|
local LibWindow = LibStub("LibWindow-1.1")
|
||||||
|
LibWindow.RegisterConfig(readyFrame, Details.mythic_plus.mythicrun_chart_frame_ready)
|
||||||
|
LibWindow.RestorePosition(readyFrame)
|
||||||
|
LibWindow.MakeDraggable(readyFrame)
|
||||||
|
LibWindow.SavePosition(readyFrame)
|
||||||
|
|
||||||
|
--show button
|
||||||
|
---@type df_button
|
||||||
|
readyFrame.ShowChartButton = DetailsFramework:CreateButton(readyFrame, function() mythicDungeonCharts.ShowChart(); readyFrame:Hide() end, 80, 20, "Show Damage Graphic")
|
||||||
|
readyFrame.ShowChartButton:SetTemplate(DetailsFramework:GetTemplate("button", "DETAILS_PLUGIN_BUTTON_TEMPLATE"))
|
||||||
|
readyFrame.ShowChartButton:SetPoint("topleft", readyFrame, "topleft", 5, -30)
|
||||||
|
readyFrame.ShowChartButton:SetIcon([[Interface\AddOns\Details\images\icons2.png]], 16, 16, "overlay", {42/512, 75/512, 153/512, 187/512}, {.7, .7, .7, 1}, nil, 0, 0)
|
||||||
|
readyFrame.ShowChartButton.textcolor = textColor
|
||||||
|
|
||||||
|
--disable feature check box (dont show this again)
|
||||||
|
local on_switch_enable = function(self, _, value)
|
||||||
|
Details.mythic_plus.show_damage_graphic = not value
|
||||||
|
end
|
||||||
|
|
||||||
|
local notAgainSwitch, notAgainLabel = DetailsFramework:CreateSwitch(readyFrame, on_switch_enable, not Details.mythic_plus.show_damage_graphic, _, _, _, _, _, _, _, _, _, Loc ["STRING_MINITUTORIAL_BOOKMARK4"], DetailsFramework:GetTemplate("switch", "OPTIONS_CHECKBOX_BRIGHT_TEMPLATE"), "GameFontHighlightLeft")
|
||||||
|
notAgainSwitch:ClearAllPoints()
|
||||||
|
notAgainLabel:SetPoint("left", notAgainSwitch, "right", 2, 0)
|
||||||
|
notAgainSwitch:SetPoint("bottomleft", readyFrame, "bottomleft", 5, 5)
|
||||||
|
notAgainSwitch:SetAsCheckBox()
|
||||||
|
notAgainLabel.textSize = textSize
|
||||||
|
|
||||||
|
local timeNotInCombatLabel = DetailsFramework:CreateLabel(readyFrame, "Time not in combat:", textSize, "orangered")
|
||||||
|
timeNotInCombatLabel:SetPoint("bottomleft", notAgainSwitch, "topleft", 0, 7)
|
||||||
|
local timeNotInCombatAmount = DetailsFramework:CreateLabel(readyFrame, "00:00", textSize, "orangered")
|
||||||
|
timeNotInCombatAmount:SetPoint("left", timeNotInCombatLabel, "left", 130, 0)
|
||||||
|
|
||||||
|
local elapsedTimeLabel = DetailsFramework:CreateLabel(readyFrame, "Run Time:", textSize, textColor)
|
||||||
|
elapsedTimeLabel:SetPoint("bottomleft", timeNotInCombatLabel, "topleft", 0, 5)
|
||||||
|
local elapsedTimeAmount = DetailsFramework:CreateLabel(readyFrame, "00:00", textSize, textColor)
|
||||||
|
elapsedTimeAmount:SetPoint("left", elapsedTimeLabel, "left", 130, 0)
|
||||||
|
|
||||||
|
readyFrame.TimeNotInCombatAmountLabel = timeNotInCombatAmount
|
||||||
|
readyFrame.ElapsedTimeAmountLabel = elapsedTimeAmount
|
||||||
|
end
|
||||||
|
|
||||||
|
mythicDungeonCharts.ReadyFrame:Show()
|
||||||
|
|
||||||
|
--update the run time and time not in combat
|
||||||
|
local elapsedTime = Details222.MythicPlus.time or 1507
|
||||||
|
mythicDungeonCharts.ReadyFrame.ElapsedTimeAmountLabel.text = DetailsFramework:IntegerToTimer(elapsedTime)
|
||||||
|
|
||||||
|
local overallMythicDungeonCombat = Details:GetCurrentCombat()
|
||||||
|
if (overallMythicDungeonCombat:GetCombatType() == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL) then
|
||||||
|
local combatTime = overallMythicDungeonCombat:GetCombatTime()
|
||||||
|
local notInCombat = elapsedTime - combatTime
|
||||||
|
mythicDungeonCharts.ReadyFrame.TimeNotInCombatAmountLabel.text = DetailsFramework:IntegerToTimer(notInCombat) .. " (" .. math.floor(notInCombat / elapsedTime * 100) .. "%)"
|
||||||
|
end
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
--create the panel
|
||||||
|
if (not mythicDungeonCharts.ReadyFrame) then
|
||||||
|
mythicDungeonCharts.ReadyFrame = CreateFrame("frame", "DetailsMythicDungeonReadyFrame", UIParent, "BackdropTemplate")
|
||||||
|
local readyFrame = mythicDungeonCharts.ReadyFrame
|
||||||
|
readyFrame.playerCacheByName = {}
|
||||||
|
|
||||||
|
local textColor = {1, 0.8196, 0, 1}
|
||||||
|
local textSize = 11
|
||||||
|
|
||||||
|
local roundedCornerTemplate = {
|
||||||
|
roundness = 6,
|
||||||
|
color = {.1, .1, .1, 0.98},
|
||||||
|
border_color = {.05, .05, .05, 0.834},
|
||||||
|
}
|
||||||
|
|
||||||
|
detailsFramework:AddRoundedCornersToFrame(readyFrame, roundedCornerTemplate)
|
||||||
|
|
||||||
|
local titleLabel = DetailsFramework:CreateLabel(readyFrame, "Details! Mythic Run Completed!", 12, "yellow")
|
||||||
|
titleLabel:SetPoint("top", readyFrame, "top", 0, -7)
|
||||||
|
titleLabel.textcolor = textColor
|
||||||
|
|
||||||
|
local closeButton = detailsFramework:CreateCloseButton(readyFrame, "$parentCloseButton")
|
||||||
|
closeButton:SetPoint("topright", readyFrame, "topright", -2, -2)
|
||||||
|
closeButton:SetScale(1.4)
|
||||||
|
closeButton:SetAlpha(0.823)
|
||||||
|
|
||||||
|
readyFrame:SetSize(355, 390)
|
||||||
|
readyFrame:SetPoint("center", UIParent, "center", 300, 0)
|
||||||
|
readyFrame:SetFrameStrata("LOW")
|
||||||
|
readyFrame:EnableMouse(true)
|
||||||
|
readyFrame:SetMovable(true)
|
||||||
|
readyFrame:Hide()
|
||||||
|
|
||||||
|
--register to libwindow
|
||||||
|
local LibWindow = LibStub("LibWindow-1.1")
|
||||||
|
LibWindow.RegisterConfig(readyFrame, Details.mythic_plus.mythicrun_chart_frame_ready)
|
||||||
|
LibWindow.RestorePosition(readyFrame)
|
||||||
|
LibWindow.MakeDraggable(readyFrame)
|
||||||
|
LibWindow.SavePosition(readyFrame)
|
||||||
|
|
||||||
|
--warning footer
|
||||||
|
local warningFooter = DetailsFramework:CreateLabel(readyFrame, "You are seeing this because it's a 28 or above. Under development.", 9, "yellow")
|
||||||
|
warningFooter:SetPoint("bottom", readyFrame, "bottom", 0, 20)
|
||||||
|
|
||||||
|
local roundedCornerPreset = {
|
||||||
|
color = {.075, .075, .075, 1},
|
||||||
|
border_color = {.2, .2, .2, 1},
|
||||||
|
roundness = 8,
|
||||||
|
}
|
||||||
|
|
||||||
|
local leftAnchor
|
||||||
|
|
||||||
|
--show m+ run breakdown
|
||||||
|
local showBreakdownFunc = function()
|
||||||
|
mPlus.ShowSummary()
|
||||||
|
end
|
||||||
|
---@type df_button
|
||||||
|
readyFrame.ShowBreakdownButton = DetailsFramework:CreateButton(readyFrame, showBreakdownFunc, 145, 30, "Show Breakdown")
|
||||||
|
PixelUtil.SetPoint(readyFrame.ShowBreakdownButton, "topleft", readyFrame, "topleft", 5, -30)
|
||||||
|
PixelUtil.SetSize(readyFrame.ShowBreakdownButton, 145, 32)
|
||||||
|
readyFrame.ShowBreakdownButton:SetBackdrop(nil)
|
||||||
|
readyFrame.ShowBreakdownButton:SetIcon([[Interface\AddOns\Details\images\icons2.png]], 16, 16, "overlay", {84/512, 120/512, 153/512, 187/512}, {.7, .7, .7, 1}, nil, 0, 0)
|
||||||
|
readyFrame.ShowBreakdownButton.textcolor = textColor
|
||||||
|
detailsFramework:AddRoundedCornersToFrame(readyFrame.ShowBreakdownButton.widget, roundedCornerPreset)
|
||||||
|
leftAnchor = readyFrame.ShowBreakdownButton
|
||||||
|
readyFrame.ShowBreakdownButton:Disable()
|
||||||
|
|
||||||
|
--show graphic button
|
||||||
|
local showChartFunc = function(self)
|
||||||
|
mythicDungeonCharts.ShowChart()
|
||||||
|
readyFrame:Hide()
|
||||||
|
end
|
||||||
|
---@type df_button
|
||||||
|
readyFrame.ShowChartButton = DetailsFramework:CreateButton(readyFrame, showChartFunc, 145, 30, "Show Damage Graphic")
|
||||||
|
PixelUtil.SetPoint(readyFrame.ShowChartButton, "left", readyFrame.ShowBreakdownButton, "right", 5, 0)
|
||||||
|
PixelUtil.SetSize(readyFrame.ShowChartButton, 145, 32)
|
||||||
|
readyFrame.ShowChartButton:SetBackdrop(nil)
|
||||||
|
readyFrame.ShowChartButton:SetIcon([[Interface\AddOns\Details\images\icons2.png]], 16, 16, "overlay", {42/512, 75/512, 153/512, 187/512}, {.7, .7, .7, 1}, nil, 0, 0)
|
||||||
|
readyFrame.ShowChartButton.textcolor = textColor
|
||||||
|
detailsFramework:AddRoundedCornersToFrame(readyFrame.ShowChartButton.widget, roundedCornerPreset)
|
||||||
|
|
||||||
|
|
||||||
|
--disable feature check box (dont show this again)
|
||||||
|
local on_switch_enable = function(self, _, value)
|
||||||
|
Details.mythic_plus.show_damage_graphic = not value
|
||||||
|
end
|
||||||
|
|
||||||
|
local elapsedTimeLabel = DetailsFramework:CreateLabel(readyFrame, "Run Time:", textSize, textColor)
|
||||||
|
elapsedTimeLabel:SetPoint("topleft", leftAnchor, "bottomleft", 0, -8)
|
||||||
|
local elapsedTimeAmount = DetailsFramework:CreateLabel(readyFrame, "00:00", textSize, textColor)
|
||||||
|
elapsedTimeAmount:SetPoint("left", elapsedTimeLabel, "left", 130, 0)
|
||||||
|
|
||||||
|
local timeNotInCombatLabel = DetailsFramework:CreateLabel(readyFrame, "Time not in combat:", textSize, "orangered")
|
||||||
|
timeNotInCombatLabel:SetPoint("topleft", elapsedTimeLabel, "bottomleft", 0, -5)
|
||||||
|
local timeNotInCombatAmount = DetailsFramework:CreateLabel(readyFrame, "00:00", textSize, "orangered")
|
||||||
|
timeNotInCombatAmount:SetPoint("left", timeNotInCombatLabel, "left", 130, 0)
|
||||||
|
|
||||||
|
local youBeatTheTimerLabel = DetailsFramework:CreateLabel(readyFrame, "", textSize, "white")
|
||||||
|
youBeatTheTimerLabel:SetPoint("topleft", timeNotInCombatLabel, "bottomleft", 0, -5)
|
||||||
|
|
||||||
|
--local keystoneUpgradeLabel = DetailsFramework:CreateLabel(readyFrame, "Keystone Upgrade:", textSize, "white")
|
||||||
|
--keystoneUpgradeLabel:SetPoint("topleft", youBeatTheTimerLabel, "bottomleft", 0, -5)
|
||||||
|
|
||||||
|
local rantingLabel = DetailsFramework:CreateLabel(readyFrame, "", textSize, textColor)
|
||||||
|
--rantingLabel:SetPoint("topleft", keystoneUpgradeLabel, "bottomleft", 0, -5)
|
||||||
|
rantingLabel:SetPoint("topleft", youBeatTheTimerLabel, "bottomleft", 0, -5)
|
||||||
|
|
||||||
|
readyFrame.PlayerBanners = {}
|
||||||
|
for i = 1, 5 do
|
||||||
|
local playerBanner = createPlayerBanner(readyFrame, "$parentPlayerBanner" .. i)
|
||||||
|
readyFrame.PlayerBanners[#readyFrame.PlayerBanners+1] = playerBanner
|
||||||
|
if (i == 1) then
|
||||||
|
playerBanner:SetPoint("topleft", rantingLabel.widget, "bottomleft", 0, -22)
|
||||||
|
else
|
||||||
|
playerBanner:SetPoint("topleft", readyFrame.PlayerBanners[i-1], "topright", 10, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--frame to handle loot events
|
||||||
|
local lootFrame = CreateFrame("frame", "$parentLootFrame", readyFrame)
|
||||||
|
lootFrame:RegisterEvent("BOSS_KILL");
|
||||||
|
lootFrame:RegisterEvent("ENCOUNTER_LOOT_RECEIVED")
|
||||||
|
|
||||||
|
local bossKillEncounterId
|
||||||
|
|
||||||
|
lootFrame:SetScript("OnEvent", function(self, event, ...)
|
||||||
|
if (event == "BOSS_KILL") then
|
||||||
|
local encounterID, name = ...;
|
||||||
|
bossKillEncounterId = encounterID
|
||||||
|
--print("BOSS_KILL", GetTime(), bossKillEncounterId)
|
||||||
|
|
||||||
|
elseif (event == "ENCOUNTER_LOOT_RECEIVED") then
|
||||||
|
local lootEncounterId, itemID, itemLink, quantity, playerName, className = ...
|
||||||
|
--print("ENCOUNTER_LOOT_RECEIVED", GetTime(), lootEncounterId, bossKillEncounterId)
|
||||||
|
|
||||||
|
--print("no ambig:", playerName, "with ambig:", Ambiguate(playerName, "none")) --debug
|
||||||
|
playerName = Ambiguate(playerName, "none")
|
||||||
|
local unitBanner = readyFrame.playerCacheByName[playerName]
|
||||||
|
|
||||||
|
if (not unitBanner) then
|
||||||
|
--print("no unitBanner for player", playerName, "aborting.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local _, instanceType = GetInstanceInfo()
|
||||||
|
--print("Is encounter the same:", lootEncounterId == bossKillEncounterId)
|
||||||
|
if (instanceType == "party") then -- or instanceType == "raid" --lootEncounterId == bossKillEncounterId and
|
||||||
|
--print("all good showing loot for player", playerName)
|
||||||
|
local lootSquare = unitBanner.LootSquare
|
||||||
|
lootSquare.itemLink = itemLink
|
||||||
|
|
||||||
|
local effectiveILvl = GetDetailedItemLevelInfo(itemLink)
|
||||||
|
|
||||||
|
local itemName, itemLink, itemQuality, itemLevel, itemMinLevel, itemType, itemSubType,
|
||||||
|
itemStackCount, itemEquipLoc, itemTexture, sellPrice, classID, subclassID, bindType,
|
||||||
|
expacID, setID, isCraftingReagent = GetItemInfo(itemLink)
|
||||||
|
|
||||||
|
--print("equip loc:", itemEquipLoc)
|
||||||
|
|
||||||
|
if (effectiveILvl > 300) then --avoid showing loot that isn't items
|
||||||
|
|
||||||
|
local rarityColor = ITEM_QUALITY_COLORS[itemQuality]
|
||||||
|
lootSquare.LootIconBorder:SetVertexColor(rarityColor.r, rarityColor.g, rarityColor.b, 1)
|
||||||
|
|
||||||
|
lootSquare.LootIcon:SetTexture(GetItemIcon(itemID))
|
||||||
|
lootSquare.LootItemLevel:SetText(effectiveILvl or "0")
|
||||||
|
|
||||||
|
--print("loot info:", itemLink, effectiveILvl, itemQuality)
|
||||||
|
lootSquare:Show()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
Details222.MythicPlus.MapID = mapID
|
||||||
|
Details222.MythicPlus.Level = level --level of the key just finished
|
||||||
|
Details222.MythicPlus.OnTime = onTime
|
||||||
|
Details222.MythicPlus.KeystoneUpgradeLevels = keystoneUpgradeLevels
|
||||||
|
Details222.MythicPlus.PracticeRun = practiceRun
|
||||||
|
Details222.MythicPlus.OldDungeonScore = oldDungeonScore
|
||||||
|
Details222.MythicPlus.NewDungeonScore = newDungeonScore
|
||||||
|
Details222.MythicPlus.IsAffixRecord = isAffixRecord
|
||||||
|
Details222.MythicPlus.IsMapRecord = isMapRecord
|
||||||
|
Details222.MythicPlus.PrimaryAffix = primaryAffix
|
||||||
|
Details222.MythicPlus.IsEligibleForScore = isEligibleForScore
|
||||||
|
Details222.MythicPlus.UpgradeMembers = upgradeMembers
|
||||||
|
Details222.MythicPlus.DungeonName = dungeonName
|
||||||
|
Details222.MythicPlus.DungeonID = id
|
||||||
|
Details222.MythicPlus.TimeLimit = timeLimit
|
||||||
|
Details222.MythicPlus.Texture = texture
|
||||||
|
Details222.MythicPlus.BackgroundTexture = backgroundTexture
|
||||||
|
--]=]
|
||||||
|
|
||||||
|
local notAgainSwitch, notAgainLabel = DetailsFramework:CreateSwitch(readyFrame, on_switch_enable, not Details.mythic_plus.show_damage_graphic, _, _, _, _, _, _, _, _, _, Loc ["STRING_MINITUTORIAL_BOOKMARK4"], DetailsFramework:GetTemplate("switch", "OPTIONS_CHECKBOX_BRIGHT_TEMPLATE"), "GameFontHighlightLeft")
|
||||||
|
notAgainSwitch:ClearAllPoints()
|
||||||
|
notAgainLabel:SetPoint("left", notAgainSwitch, "right", 2, 0)
|
||||||
|
notAgainSwitch:SetPoint("bottomleft", readyFrame, "bottomleft", 5, 5)
|
||||||
|
notAgainSwitch:SetAsCheckBox()
|
||||||
|
notAgainSwitch:SetSize(12, 12)
|
||||||
|
notAgainLabel.textsize = 9
|
||||||
|
|
||||||
|
readyFrame.TimeNotInCombatAmountLabel = timeNotInCombatAmount
|
||||||
|
readyFrame.ElapsedTimeAmountLabel = elapsedTimeAmount
|
||||||
|
readyFrame.YouBeatTheTimerLabel = youBeatTheTimerLabel
|
||||||
|
readyFrame.KeystoneUpgradeLabel = keystoneUpgradeLabel
|
||||||
|
readyFrame.RantingLabel = rantingLabel
|
||||||
|
end
|
||||||
|
|
||||||
|
local readyFrame = mythicDungeonCharts.ReadyFrame
|
||||||
|
readyFrame:Show()
|
||||||
|
|
||||||
|
for i = 1, #readyFrame.PlayerBanners do
|
||||||
|
--hide the lootSquare
|
||||||
|
readyFrame.PlayerBanners[i].LootSquare:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
wipe(readyFrame.playerCacheByName)
|
||||||
|
|
||||||
|
--update the run time and time not in combat
|
||||||
|
local elapsedTime = Details222.MythicPlus.time or 1507
|
||||||
|
readyFrame.ElapsedTimeAmountLabel.text = DetailsFramework:IntegerToTimer(elapsedTime)
|
||||||
|
|
||||||
|
C_Timer.After(1.5, function()
|
||||||
|
local overallMythicDungeonCombat = Details:GetCurrentCombat()
|
||||||
|
--print("overall combat type:", overallMythicDungeonCombat:GetCombatType(), overallMythicDungeonCombat:GetCombatType() == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL)
|
||||||
|
if (overallMythicDungeonCombat:GetCombatType() == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL) then
|
||||||
|
local combatTime = overallMythicDungeonCombat:GetCombatTime()
|
||||||
|
local notInCombat = elapsedTime - combatTime
|
||||||
|
readyFrame.TimeNotInCombatAmountLabel.text = DetailsFramework:IntegerToTimer(notInCombat) .. " (" .. math.floor(notInCombat / elapsedTime * 100) .. "%)"
|
||||||
|
else
|
||||||
|
readyFrame.TimeNotInCombatAmountLabel.text = "Unknown for this run"
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
if (Details222.MythicPlus.OnTime) then
|
||||||
|
readyFrame.YouBeatTheTimerLabel:SetFormattedText(CHALLENGE_MODE_COMPLETE_BEAT_TIMER .. " | " .. CHALLENGE_MODE_COMPLETE_KEYSTONE_UPGRADED, Details222.MythicPlus.KeystoneUpgradeLevels) --"You beat the timer!"
|
||||||
|
readyFrame.YouBeatTheTimerLabel.textcolor = "limegreen"
|
||||||
|
--readyFrame.KeystoneUpgradeLabel:SetFormattedText(CHALLENGE_MODE_COMPLETE_KEYSTONE_UPGRADED, Details222.MythicPlus.KeystoneUpgradeLevels)
|
||||||
|
else
|
||||||
|
readyFrame.YouBeatTheTimerLabel.textcolor = "white"
|
||||||
|
readyFrame.YouBeatTheTimerLabel.text = CHALLENGE_MODE_COMPLETE_TIME_EXPIRED --"Time expired!"
|
||||||
|
--readyFrame.KeystoneUpgradeLabel.text = CHALLENGE_MODE_COMPLETE_TRY_AGAIN --"Try again! Beat the timer to upgrade your keystone!"
|
||||||
|
end
|
||||||
|
|
||||||
|
if (Details222.MythicPlus.NewDungeonScore and Details222.MythicPlus.OldDungeonScore) then
|
||||||
|
local gainedScore = Details222.MythicPlus.NewDungeonScore - Details222.MythicPlus.OldDungeonScore
|
||||||
|
local color = C_ChallengeMode.GetDungeonScoreRarityColor(Details222.MythicPlus.NewDungeonScore)
|
||||||
|
if (not color) then
|
||||||
|
color = HIGHLIGHT_FONT_COLOR
|
||||||
|
end
|
||||||
|
readyFrame.RantingLabel.text = CHALLENGE_COMPLETE_DUNGEON_SCORE:format(color:WrapTextInColorCode(CHALLENGE_COMPLETE_DUNGEON_SCORE_FORMAT_TEXT:format(Details222.MythicPlus.NewDungeonScore, gainedScore)))
|
||||||
|
readyFrame.RantingLabel.textcolor = "limegreen"
|
||||||
|
else
|
||||||
|
readyFrame.RantingLabel.text = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, #readyFrame.PlayerBanners do
|
||||||
|
readyFrame.PlayerBanners[i]:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
local playersFound = 0
|
||||||
|
local playerBannerIndex = 1
|
||||||
|
do --update the player banner
|
||||||
|
if (updatPlayerBanner("player", playerBannerIndex)) then
|
||||||
|
playersFound = playersFound + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local unitCount = 1
|
||||||
|
for bannerIndex = 2, #readyFrame.PlayerBanners do
|
||||||
|
if (updatPlayerBanner("party"..unitCount, bannerIndex)) then
|
||||||
|
playersFound = playersFound + 1
|
||||||
|
end
|
||||||
|
unitCount = unitCount + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = playersFound+1, #readyFrame.PlayerBanners do
|
||||||
|
readyFrame.PlayerBanners[i]:Hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
C_Timer.After(2.5, updateKeysStoneLevel)
|
||||||
|
end
|
||||||
|
|
||||||
|
Details222.MythicPlus.IsMythicPlus = function()
|
||||||
|
return C_ChallengeMode and C_ChallengeMode.GetActiveKeystoneInfo() and true or false
|
||||||
|
end
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,915 +0,0 @@
|
|||||||
local Details = _G.Details
|
|
||||||
local DF = _G.DetailsFramework
|
|
||||||
local C_Timer = _G.C_Timer
|
|
||||||
local unpack = _G.unpack
|
|
||||||
local GetTime = _G.GetTime
|
|
||||||
local tremove = _G.tremove
|
|
||||||
local GetInstanceInfo = _G.GetInstanceInfo
|
|
||||||
local addonName, Details222 = ...
|
|
||||||
|
|
||||||
local Loc = _G.LibStub("AceLocale-3.0"):GetLocale("Details")
|
|
||||||
|
|
||||||
--data for the current mythic + dungeon
|
|
||||||
Details.MythicPlus = {
|
|
||||||
RunID = 0,
|
|
||||||
}
|
|
||||||
|
|
||||||
-- ~mythic ~dungeon
|
|
||||||
local DetailsMythicPlusFrame = _G.CreateFrame("frame", "DetailsMythicPlusFrame", UIParent)
|
|
||||||
DetailsMythicPlusFrame.DevelopmentDebug = false
|
|
||||||
|
|
||||||
--disabling the mythic+ feature if the user is playing in wow classic
|
|
||||||
if (not DF.IsTimewalkWoW()) then
|
|
||||||
DetailsMythicPlusFrame:RegisterEvent("CHALLENGE_MODE_START")
|
|
||||||
DetailsMythicPlusFrame:RegisterEvent("CHALLENGE_MODE_COMPLETED")
|
|
||||||
DetailsMythicPlusFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
|
|
||||||
DetailsMythicPlusFrame:RegisterEvent("ENCOUNTER_END")
|
|
||||||
DetailsMythicPlusFrame:RegisterEvent("START_TIMER")
|
|
||||||
end
|
|
||||||
|
|
||||||
function Details222.MythicPlus.LogStep(log)
|
|
||||||
local today = date("%d/%m/%y %H:%M:%S")
|
|
||||||
table.insert(Details.mythic_plus_log, 1, today .. "|" .. log)
|
|
||||||
tremove(Details.mythic_plus_log, 50)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--[[
|
|
||||||
all mythic segments have:
|
|
||||||
.is_mythic_dungeon_segment = true
|
|
||||||
.is_mythic_dungeon_run_id = run id from details.profile.mythic_dungeon_id
|
|
||||||
boss, 'trash overall' and 'dungeon overall' segments have:
|
|
||||||
.is_mythic_dungeon
|
|
||||||
boss segments have:
|
|
||||||
.is_boss
|
|
||||||
'trash overall' segments have:
|
|
||||||
.is_mythic_dungeon with .SegmentID = "trashoverall"
|
|
||||||
'dungeon overall' segment have:
|
|
||||||
.is_mythic_dungeon with .SegmentID = "overall"
|
|
||||||
|
|
||||||
--]]
|
|
||||||
|
|
||||||
function DetailsMythicPlusFrame.MergeSegmentsOnEnd() --~merge
|
|
||||||
--at the end of a mythic run, if enable on settings, merge all the segments from the mythic run into only one
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MergeSegmentsOnEnd() > starting to merge mythic segments.", "InCombatLockdown():", InCombatLockdown())
|
|
||||||
end
|
|
||||||
|
|
||||||
Details222.MythicPlus.LogStep("MergeSegmentsOnEnd started | creating the overall segment at the end of the run.")
|
|
||||||
|
|
||||||
--create a new combat to be the overall for the mythic run
|
|
||||||
Details:StartCombat()
|
|
||||||
|
|
||||||
--get the current combat just created and the table with all past segments
|
|
||||||
local newCombat = Details:GetCurrentCombat()
|
|
||||||
local segmentsTable = Details:GetCombatSegments()
|
|
||||||
|
|
||||||
newCombat.is_challenge = true
|
|
||||||
|
|
||||||
local timeInCombat = 0
|
|
||||||
local startDate, endDate = "", ""
|
|
||||||
local lastSegment
|
|
||||||
local totalSegments = 0
|
|
||||||
|
|
||||||
--copy deaths occured on all segments to the new segment, also sum the activity combat time
|
|
||||||
if (Details.mythic_plus.reverse_death_log) then
|
|
||||||
for i = 1, 40 do --copy the deaths from the first segment to the last one
|
|
||||||
local thisCombat = segmentsTable[i]
|
|
||||||
if (thisCombat and thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
|
|
||||||
newCombat:CopyDeathsFrom(thisCombat, true)
|
|
||||||
timeInCombat = timeInCombat + thisCombat:GetCombatTime()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
for i = 40, 1, -1 do --copy the deaths from the last segment to the new segment
|
|
||||||
local thisCombat = segmentsTable[i]
|
|
||||||
if (thisCombat) then
|
|
||||||
if (thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
|
|
||||||
newCombat:CopyDeathsFrom(thisCombat, true)
|
|
||||||
timeInCombat = timeInCombat + thisCombat:GetCombatTime()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
|
|
||||||
|
|
||||||
--tag the segment as mythic overall segment
|
|
||||||
newCombat.is_mythic_dungeon = {
|
|
||||||
StartedAt = Details.MythicPlus.StartedAt, --the start of the run
|
|
||||||
EndedAt = Details.MythicPlus.EndedAt, --the end of the run
|
|
||||||
WorldStateTimerStart = Details222.MythicPlus.WorldStateTimerStartAt,
|
|
||||||
WorldStateTimerEnd = Details222.MythicPlus.WorldStateTimerEndAt,
|
|
||||||
RunTime = Details222.MythicPlus.time,
|
|
||||||
TimeInCombat = timeInCombat,
|
|
||||||
SegmentID = "overall", --segment number within the dungeon
|
|
||||||
RunID = Details.mythic_dungeon_id,
|
|
||||||
OverallSegment = true,
|
|
||||||
ZoneName = Details.MythicPlus.DungeonName,
|
|
||||||
EJID = Details.MythicPlus.ejID,
|
|
||||||
MapID = Details222.MythicPlus.MapID,
|
|
||||||
Level = Details222.MythicPlus.Level,
|
|
||||||
OnTime = Details222.MythicPlus.OnTime,
|
|
||||||
KeystoneUpgradeLevels = Details222.MythicPlus.KeystoneUpgradeLevels,
|
|
||||||
PracticeRun = Details222.MythicPlus.PracticeRun,
|
|
||||||
OldDungeonScore = Details222.MythicPlus.OldDungeonScore,
|
|
||||||
NewDungeonScore = Details222.MythicPlus.NewDungeonScore,
|
|
||||||
IsAffixRecord = Details222.MythicPlus.IsAffixRecord,
|
|
||||||
IsMapRecord = Details222.MythicPlus.IsMapRecord,
|
|
||||||
PrimaryAffix = Details222.MythicPlus.PrimaryAffix,
|
|
||||||
IsEligibleForScore = Details222.MythicPlus.IsEligibleForScore,
|
|
||||||
UpgradeMembers = Details222.MythicPlus.UpgradeMembers,
|
|
||||||
TimeLimit = Details222.MythicPlus.TimeLimit,
|
|
||||||
DungeonName = Details222.MythicPlus.DungeonName,
|
|
||||||
DungeonID = Details222.MythicPlus.DungeonID,
|
|
||||||
DungeonTexture = Details222.MythicPlus.Texture,
|
|
||||||
DungeonBackgroundTexture = Details222.MythicPlus.BackgroundTexture,
|
|
||||||
}
|
|
||||||
|
|
||||||
--add all boss segments from this run to this new segment
|
|
||||||
for i = 1, 40 do --from the newer combat to the oldest
|
|
||||||
local thisCombat = segmentsTable[i]
|
|
||||||
if (thisCombat and thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
|
|
||||||
local canAddThisSegment = true
|
|
||||||
if (Details.mythic_plus.make_overall_boss_only) then
|
|
||||||
if (not thisCombat.is_boss) then
|
|
||||||
--canAddThisSegment = false --disabled
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (canAddThisSegment) then
|
|
||||||
newCombat = newCombat + thisCombat
|
|
||||||
totalSegments = totalSegments + 1
|
|
||||||
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("MergeSegmentsOnEnd() > adding time:", thisCombat:GetCombatTime(), thisCombat.is_boss and thisCombat.is_boss.name)
|
|
||||||
end
|
|
||||||
|
|
||||||
if (endDate == "") then
|
|
||||||
local _, whenEnded = thisCombat:GetDate()
|
|
||||||
endDate = whenEnded
|
|
||||||
end
|
|
||||||
lastSegment = thisCombat
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--get the date where the first segment started
|
|
||||||
if (lastSegment) then
|
|
||||||
startDate = lastSegment:GetDate()
|
|
||||||
end
|
|
||||||
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MergeSegmentsOnEnd() > totalTime:", timeInCombat, "startDate:", startDate)
|
|
||||||
end
|
|
||||||
|
|
||||||
newCombat.total_segments_added = totalSegments
|
|
||||||
newCombat.is_mythic_dungeon_segment = true
|
|
||||||
newCombat.is_mythic_dungeon_run_id = Details.mythic_dungeon_id
|
|
||||||
|
|
||||||
--check if both values are valid, this can get invalid if the player leaves the dungeon before the timer ends or the game crashes
|
|
||||||
if (type(Details222.MythicPlus.time) == "number") then
|
|
||||||
newCombat.run_time = Details222.MythicPlus.time
|
|
||||||
Details222.MythicPlus.LogStep("GetCompletionInfo() Found, Time: " .. Details222.MythicPlus.time)
|
|
||||||
|
|
||||||
elseif (newCombat.is_mythic_dungeon.WorldStateTimerEnd and newCombat.is_mythic_dungeon.WorldStateTimerStart) then
|
|
||||||
local runTime = newCombat.is_mythic_dungeon.WorldStateTimerEnd - newCombat.is_mythic_dungeon.WorldStateTimerStart
|
|
||||||
newCombat.run_time = Details222.MythicPlus.time
|
|
||||||
Details222.MythicPlus.LogStep("World State Timers is Available, Run Time: " .. runTime .. "| start:" .. newCombat.is_mythic_dungeon.WorldStateTimerStart .. "| end:" .. newCombat.is_mythic_dungeon.WorldStateTimerEnd)
|
|
||||||
else
|
|
||||||
newCombat.run_time = timeInCombat
|
|
||||||
Details222.MythicPlus.LogStep("GetCompletionInfo() and World State Timers not Found, Activity Time: " .. timeInCombat)
|
|
||||||
end
|
|
||||||
|
|
||||||
newCombat:SetStartTime(GetTime() - timeInCombat)
|
|
||||||
newCombat:SetEndTime(GetTime())
|
|
||||||
Details222.MythicPlus.LogStep("Activity Time: " .. timeInCombat)
|
|
||||||
|
|
||||||
--set the segment time and date
|
|
||||||
newCombat:SetDate(startDate, endDate)
|
|
||||||
|
|
||||||
--immediatly finishes the segment just started
|
|
||||||
Details:SairDoCombate()
|
|
||||||
|
|
||||||
--update all windows
|
|
||||||
Details:InstanceCallDetailsFunc(Details.FadeHandler.Fader, "IN", nil, "barras")
|
|
||||||
Details:InstanceCallDetailsFunc(Details.UpdateCombatObjectInUse)
|
|
||||||
Details:InstanceCallDetailsFunc(Details.AtualizaSoloMode_AfertReset)
|
|
||||||
Details:InstanceCallDetailsFunc(Details.ResetaGump)
|
|
||||||
Details:RefreshMainWindow(-1, true)
|
|
||||||
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MergeSegmentsOnEnd() > finished merging segments.")
|
|
||||||
print("Details!", "MergeSegmentsOnEnd() > all done, check in the segments list if everything is correct, if something is weird: '/details feedback' thanks in advance!")
|
|
||||||
end
|
|
||||||
|
|
||||||
local lower_instance = Details:GetLowerInstanceNumber()
|
|
||||||
if (lower_instance) then
|
|
||||||
local instance = Details:GetInstance(lower_instance)
|
|
||||||
if (instance) then
|
|
||||||
local func = {function() end}
|
|
||||||
instance:InstanceAlert ("Showing Mythic+ Run Segment", {[[Interface\AddOns\Details\images\icons]], 16, 16, false, 434/512, 466/512, 243/512, 273/512}, 6, func, true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
Details:SendEvent("COMBAT_MYTHICPLUS_OVERALL_READY")
|
|
||||||
end
|
|
||||||
|
|
||||||
--after each boss fight, if enalbed on settings, create an extra segment with all trash segments from the boss just killed
|
|
||||||
function DetailsMythicPlusFrame.MergeTrashCleanup (isFromSchedule)
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MergeTrashCleanup() > running", DetailsMythicPlusFrame.TrashMergeScheduled and #DetailsMythicPlusFrame.TrashMergeScheduled)
|
|
||||||
end
|
|
||||||
|
|
||||||
local segmentsToMerge = DetailsMythicPlusFrame.TrashMergeScheduled
|
|
||||||
|
|
||||||
--table exists and there's at least one segment
|
|
||||||
if (segmentsToMerge and segmentsToMerge[1]) then
|
|
||||||
Details222.MythicPlus.LogStep("MergeTrashCleanup started.")
|
|
||||||
|
|
||||||
--the first segment is the segment where all other trash segments will be added
|
|
||||||
local masterSegment = segmentsToMerge[1]
|
|
||||||
masterSegment.is_mythic_dungeon_trash = nil
|
|
||||||
|
|
||||||
--get the current combat just created and the table with all past segments
|
|
||||||
local newCombat = masterSegment
|
|
||||||
local totalTime = newCombat:GetCombatTime()
|
|
||||||
local startDate, endDate = "", ""
|
|
||||||
local lastSegment
|
|
||||||
|
|
||||||
--add segments
|
|
||||||
for i = 2, #segmentsToMerge do --segment #1 is the host
|
|
||||||
local pastCombat = segmentsToMerge[i]
|
|
||||||
newCombat = newCombat + pastCombat
|
|
||||||
totalTime = totalTime + pastCombat:GetCombatTime()
|
|
||||||
|
|
||||||
newCombat:CopyDeathsFrom(pastCombat, true)
|
|
||||||
|
|
||||||
--tag this combat as already added to a boss trash overall
|
|
||||||
pastCombat._trashoverallalreadyadded = true
|
|
||||||
|
|
||||||
if (endDate == "") then
|
|
||||||
local _, whenEnded = pastCombat:GetDate()
|
|
||||||
endDate = whenEnded
|
|
||||||
end
|
|
||||||
lastSegment = pastCombat
|
|
||||||
end
|
|
||||||
|
|
||||||
--get the date where the first segment started
|
|
||||||
if (lastSegment) then
|
|
||||||
startDate = lastSegment:GetDate()
|
|
||||||
end
|
|
||||||
|
|
||||||
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
|
|
||||||
|
|
||||||
--tag the segment as mythic overall segment
|
|
||||||
newCombat.is_mythic_dungeon = {
|
|
||||||
StartedAt = segmentsToMerge.PreviousBossKilledAt, --start of the mythic run or when the previous boss got killed
|
|
||||||
EndedAt = segmentsToMerge.LastBossKilledAt, --the time() when encounter_end got triggered
|
|
||||||
SegmentID = "trashoverall",
|
|
||||||
RunID = Details.mythic_dungeon_id,
|
|
||||||
TrashOverallSegment = true,
|
|
||||||
ZoneName = Details.MythicPlus.DungeonName,
|
|
||||||
MapID = instanceMapID,
|
|
||||||
Level = Details.MythicPlus.Level,
|
|
||||||
EJID = Details.MythicPlus.ejID,
|
|
||||||
EncounterID = segmentsToMerge.EncounterID,
|
|
||||||
EncounterName = segmentsToMerge.EncounterName or Loc ["STRING_UNKNOW"],
|
|
||||||
}
|
|
||||||
|
|
||||||
newCombat.is_mythic_dungeon_segment = true
|
|
||||||
newCombat.is_mythic_dungeon_run_id = Details.mythic_dungeon_id
|
|
||||||
|
|
||||||
--set the segment time / using a sum of combat times, this combat time is reliable
|
|
||||||
newCombat:SetStartTime (GetTime() - totalTime)
|
|
||||||
newCombat:SetEndTime (GetTime())
|
|
||||||
--set the segment date
|
|
||||||
newCombat:SetDate (startDate, endDate)
|
|
||||||
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MergeTrashCleanup() > finished merging trash segments.", Details.tabela_vigente, Details.tabela_vigente.is_boss)
|
|
||||||
end
|
|
||||||
|
|
||||||
--delete all segments that were merged
|
|
||||||
local segmentsTable = Details:GetCombatSegments()
|
|
||||||
for segmentId = #segmentsTable, 1, -1 do
|
|
||||||
local segment = segmentsTable[segmentId]
|
|
||||||
if (segment and segment._trashoverallalreadyadded) then
|
|
||||||
tremove(segmentsTable, segmentId)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = #segmentsToMerge, 1, -1 do
|
|
||||||
tremove(segmentsToMerge, i)
|
|
||||||
end
|
|
||||||
|
|
||||||
--call the segment removed event to notify third party addons
|
|
||||||
Details:SendEvent("DETAILS_DATA_SEGMENTREMOVED")
|
|
||||||
|
|
||||||
--update all windows
|
|
||||||
Details:InstanceCallDetailsFunc(Details.FadeHandler.Fader, "IN", nil, "barras")
|
|
||||||
Details:InstanceCallDetailsFunc(Details.UpdateCombatObjectInUse)
|
|
||||||
Details:InstanceCallDetailsFunc(Details.AtualizaSoloMode_AfertReset)
|
|
||||||
Details:InstanceCallDetailsFunc(Details.ResetaGump)
|
|
||||||
Details:RefreshMainWindow(-1, true)
|
|
||||||
else
|
|
||||||
Details222.MythicPlus.LogStep("MergeTrashCleanup | no segments to merge.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--this function merges trash segments after all bosses of the mythic dungeon are defeated
|
|
||||||
--happens when the group finishes all bosses but don't complete the trash requirement
|
|
||||||
function DetailsMythicPlusFrame.MergeRemainingTrashAfterAllBossesDone()
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MergeRemainingTrashAfterAllBossesDone() > running, #segments: ", #DetailsMythicPlusFrame.TrashMergeScheduled2, "trash overall table:", DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat)
|
|
||||||
end
|
|
||||||
|
|
||||||
Details222.MythicPlus.LogStep("running MergeRemainingTrashAfterAllBossesDone.")
|
|
||||||
|
|
||||||
local segmentsToMerge = DetailsMythicPlusFrame.TrashMergeScheduled2
|
|
||||||
local overallCombat = DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat
|
|
||||||
|
|
||||||
--needs to merge, add the total combat time, set the date end to the date of the first segment
|
|
||||||
local totalTime = 0
|
|
||||||
local startDate, endDate = "", ""
|
|
||||||
local lastSegment
|
|
||||||
|
|
||||||
--add segments
|
|
||||||
for i, pastCombat in ipairs(segmentsToMerge) do
|
|
||||||
overallCombat = overallCombat + pastCombat
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("MergeRemainingTrashAfterAllBossesDone() > segment added")
|
|
||||||
end
|
|
||||||
totalTime = totalTime + pastCombat:GetCombatTime()
|
|
||||||
|
|
||||||
--tag this combat as already added to a boss trash overall
|
|
||||||
pastCombat._trashoverallalreadyadded = true
|
|
||||||
|
|
||||||
if (endDate == "") then --get the end date of the first index only
|
|
||||||
local _, whenEnded = pastCombat:GetDate()
|
|
||||||
endDate = whenEnded
|
|
||||||
end
|
|
||||||
lastSegment = pastCombat
|
|
||||||
end
|
|
||||||
|
|
||||||
--set the segment time / using a sum of combat times, this combat time is reliable
|
|
||||||
local startTime = overallCombat:GetStartTime()
|
|
||||||
overallCombat:SetStartTime (startTime - totalTime)
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("MergeRemainingTrashAfterAllBossesDone() > total combat time:", totalTime)
|
|
||||||
end
|
|
||||||
|
|
||||||
--set the segment date
|
|
||||||
local startDate = overallCombat:GetDate()
|
|
||||||
overallCombat:SetDate (startDate, endDate)
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("MergeRemainingTrashAfterAllBossesDone() > new end date:", endDate)
|
|
||||||
end
|
|
||||||
|
|
||||||
local mythicDungeonInfo = overallCombat:GetMythicDungeonInfo()
|
|
||||||
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("MergeRemainingTrashAfterAllBossesDone() > elapsed time before:", mythicDungeonInfo.EndedAt - mythicDungeonInfo.StartedAt)
|
|
||||||
end
|
|
||||||
mythicDungeonInfo.StartedAt = mythicDungeonInfo.StartedAt - (Details.MythicPlus.EndedAt - Details.MythicPlus.PreviousBossKilledAt)
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("MergeRemainingTrashAfterAllBossesDone() > elapsed time after:", mythicDungeonInfo.EndedAt - mythicDungeonInfo.StartedAt)
|
|
||||||
end
|
|
||||||
|
|
||||||
--remove trash segments from the segment history after the merge
|
|
||||||
local removedCurrentSegment = false
|
|
||||||
local segmentsTable = Details:GetCombatSegments()
|
|
||||||
for _, pastCombat in ipairs(segmentsToMerge) do
|
|
||||||
for i = #segmentsTable, 1, -1 do
|
|
||||||
local segment = segmentsTable [i]
|
|
||||||
if (segment == pastCombat) then
|
|
||||||
--remove the segment
|
|
||||||
if (Details.tabela_vigente == segment) then
|
|
||||||
removedCurrentSegment = true
|
|
||||||
end
|
|
||||||
tremove(segmentsTable, i)
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for i = #segmentsToMerge, 1, -1 do
|
|
||||||
tremove(segmentsToMerge, i)
|
|
||||||
end
|
|
||||||
|
|
||||||
if (removedCurrentSegment) then
|
|
||||||
--find another current segment
|
|
||||||
local segmentsTable = Details:GetCombatSegments()
|
|
||||||
Details.tabela_vigente = segmentsTable [1]
|
|
||||||
|
|
||||||
if (not Details.tabela_vigente) then
|
|
||||||
--assuming there's no segment from the dungeon run
|
|
||||||
Details:EntrarEmCombate()
|
|
||||||
Details:SairDoCombate()
|
|
||||||
end
|
|
||||||
|
|
||||||
--update all windows
|
|
||||||
Details:InstanceCallDetailsFunc(Details.FadeHandler.Fader, "IN", nil, "barras")
|
|
||||||
Details:InstanceCallDetailsFunc(Details.UpdateCombatObjectInUse)
|
|
||||||
Details:InstanceCallDetailsFunc(Details.AtualizaSoloMode_AfertReset)
|
|
||||||
Details:InstanceCallDetailsFunc(Details.ResetaGump)
|
|
||||||
Details:RefreshMainWindow(-1, true)
|
|
||||||
end
|
|
||||||
|
|
||||||
Details222.MythicPlus.LogStep("delete_trash_after_merge | concluded")
|
|
||||||
Details:SendEvent("DETAILS_DATA_SEGMENTREMOVED")
|
|
||||||
|
|
||||||
DetailsMythicPlusFrame.TrashMergeScheduled2 = nil
|
|
||||||
DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat = nil
|
|
||||||
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MergeRemainingTrashAfterAllBossesDone() > done merging")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DetailsMythicPlusFrame.BossDefeated(this_is_end_end, encounterID, encounterName, difficultyID, raidSize, endStatus) --hold your breath and count to ten
|
|
||||||
--this function is called right after defeat a boss inside a mythic dungeon
|
|
||||||
--it comes from details! control leave combat
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "BossDefeated() > boss defeated | SegmentID:", Details.MythicPlus.SegmentID, " | mapID:", Details.MythicPlus.DungeonID)
|
|
||||||
end
|
|
||||||
|
|
||||||
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
|
|
||||||
|
|
||||||
--add the mythic dungeon info to the combat
|
|
||||||
Details.tabela_vigente.is_mythic_dungeon = {
|
|
||||||
StartedAt = Details.MythicPlus.StartedAt, --the start of the run
|
|
||||||
EndedAt = time(), --when the boss got killed
|
|
||||||
SegmentID = Details.MythicPlus.SegmentID, --segment number within the dungeon
|
|
||||||
EncounterID = encounterID,
|
|
||||||
EncounterName = encounterName or Loc ["STRING_UNKNOW"],
|
|
||||||
RunID = Details.mythic_dungeon_id,
|
|
||||||
ZoneName = Details.MythicPlus.DungeonName,
|
|
||||||
MapID = Details.MythicPlus.DungeonID,
|
|
||||||
OverallSegment = false,
|
|
||||||
Level = Details.MythicPlus.Level,
|
|
||||||
EJID = Details.MythicPlus.ejID,
|
|
||||||
}
|
|
||||||
|
|
||||||
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
|
|
||||||
local mPlusTable = Details.tabela_vigente.is_mythic_dungeon
|
|
||||||
Details222.MythicPlus.LogStep("BossDefeated | key level: | " .. mythicLevel .. " | " .. (mPlusTable.EncounterName or "") .. " | " .. (mPlusTable.ZoneName or ""))
|
|
||||||
|
|
||||||
--check if need to merge the trash for this boss
|
|
||||||
if (Details.mythic_plus.merge_boss_trash and not Details.MythicPlus.IsRestoredState) then
|
|
||||||
--store on an table all segments which should be merged
|
|
||||||
local segmentsToMerge = DetailsMythicPlusFrame.TrashMergeScheduled or {}
|
|
||||||
|
|
||||||
--table with all past semgnets
|
|
||||||
local segmentsTable = Details:GetCombatSegments()
|
|
||||||
|
|
||||||
--iterate among segments
|
|
||||||
for i = 1, 25 do --from the newer combat to the oldest
|
|
||||||
local pastCombat = segmentsTable [i]
|
|
||||||
--does the combat exists
|
|
||||||
if (pastCombat and not pastCombat._trashoverallalreadyadded and pastCombat.is_mythic_dungeon_trash) then
|
|
||||||
--is the combat a mythic segment from this run?
|
|
||||||
local isMythicSegment, SegmentID = pastCombat:IsMythicDungeon()
|
|
||||||
if (isMythicSegment and SegmentID == Details.mythic_dungeon_id and not pastCombat.is_boss) then
|
|
||||||
|
|
||||||
local mythicDungeonInfo = pastCombat:GetMythicDungeonInfo() -- .is_mythic_dungeon only boss, trash overall and run overall have it
|
|
||||||
if (not mythicDungeonInfo or not mythicDungeonInfo.TrashOverallSegment) then
|
|
||||||
--trash segment found, schedule to merge
|
|
||||||
table.insert(segmentsToMerge, pastCombat)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--add encounter information
|
|
||||||
segmentsToMerge.EncounterID = encounterID
|
|
||||||
segmentsToMerge.EncounterName = encounterName
|
|
||||||
segmentsToMerge.PreviousBossKilledAt = Details.MythicPlus.PreviousBossKilledAt
|
|
||||||
|
|
||||||
--reduce this boss encounter time from the trash lenght time, since the boss doesn't count towards the time spent cleaning trash
|
|
||||||
segmentsToMerge.LastBossKilledAt = time() - Details.tabela_vigente:GetCombatTime()
|
|
||||||
|
|
||||||
DetailsMythicPlusFrame.TrashMergeScheduled = segmentsToMerge
|
|
||||||
|
|
||||||
--there's no more script run too long
|
|
||||||
--if (not InCombatLockdown() and not UnitAffectingCombat("player")) then
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "BossDefeated() > not in combat, merging trash now")
|
|
||||||
end
|
|
||||||
--merge the trash clean up
|
|
||||||
DetailsMythicPlusFrame.MergeTrashCleanup()
|
|
||||||
--else
|
|
||||||
-- if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
-- print("Details!", "BossDefeated() > player in combatlockdown, scheduling trash merge")
|
|
||||||
-- end
|
|
||||||
-- _detalhes.schedule_mythicdungeon_trash_merge = true
|
|
||||||
--end
|
|
||||||
end
|
|
||||||
|
|
||||||
--close the combat
|
|
||||||
if (this_is_end_end) then
|
|
||||||
--player left the dungeon
|
|
||||||
--had some deprecated code removed about alweays in combat
|
|
||||||
else
|
|
||||||
--increase the segment number for the mythic run
|
|
||||||
Details.MythicPlus.SegmentID = Details.MythicPlus.SegmentID + 1
|
|
||||||
|
|
||||||
--register the time when the last boss has been killed (started a clean up for the next trash)
|
|
||||||
Details.MythicPlus.PreviousBossKilledAt = time()
|
|
||||||
|
|
||||||
--update the saved table inside the profile
|
|
||||||
Details:UpdateState_CurrentMythicDungeonRun (true, Details.MythicPlus.SegmentID, Details.MythicPlus.PreviousBossKilledAt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DetailsMythicPlusFrame.MythicDungeonFinished (fromZoneLeft)
|
|
||||||
if (DetailsMythicPlusFrame.IsDoingMythicDungeon) then
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MythicDungeonFinished() > the dungeon was a Mythic+ and just ended.")
|
|
||||||
end
|
|
||||||
|
|
||||||
DetailsMythicPlusFrame.IsDoingMythicDungeon = false
|
|
||||||
Details.MythicPlus.Started = false
|
|
||||||
Details.MythicPlus.EndedAt = time()-1.9
|
|
||||||
|
|
||||||
Details:UpdateState_CurrentMythicDungeonRun()
|
|
||||||
|
|
||||||
--at this point, details! should not be in combat, but if something triggered a combat start, just close the combat right away
|
|
||||||
if (Details.in_combat) then
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MythicDungeonFinished() > was in combat, calling SairDoCombate():", InCombatLockdown())
|
|
||||||
end
|
|
||||||
Details:SairDoCombate()
|
|
||||||
Details222.MythicPlus.LogStep("MythicDungeonFinished() | Details was in combat.")
|
|
||||||
end
|
|
||||||
|
|
||||||
local segmentsToMerge = {}
|
|
||||||
|
|
||||||
--check if there is trash segments after the last boss. need to merge these segments with the trash segment of the last boss
|
|
||||||
local bCanMergeBossTrash = Details.mythic_plus.merge_boss_trash
|
|
||||||
Details222.MythicPlus.LogStep("MythicDungeonFinished() | merge_boss_trash = " .. (bCanMergeBossTrash and "true" or "false"))
|
|
||||||
|
|
||||||
if (bCanMergeBossTrash and not Details.MythicPlus.IsRestoredState and not fromZoneLeft) then
|
|
||||||
--is the current combat not a boss fight?
|
|
||||||
--this mean a combat was opened after the last boss of the dungeon was killed
|
|
||||||
if (not Details.tabela_vigente.is_boss and Details.tabela_vigente:GetCombatTime() > 5) then
|
|
||||||
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MythicDungeonFinished() > the last combat isn't a boss fight, might have trash after bosses done.")
|
|
||||||
end
|
|
||||||
|
|
||||||
--table with all past semgnets
|
|
||||||
local segmentsTable = Details:GetCombatSegments()
|
|
||||||
|
|
||||||
for i = 1, #segmentsTable do
|
|
||||||
local pastCombat = segmentsTable [i]
|
|
||||||
--does the combat exists
|
|
||||||
|
|
||||||
if (pastCombat and not pastCombat._trashoverallalreadyadded and pastCombat:GetCombatTime() > 5) then
|
|
||||||
--is the last boss?
|
|
||||||
if (pastCombat.is_boss) then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
--is the combat a mythic segment from this run?
|
|
||||||
local isMythicSegment, SegmentID = pastCombat:IsMythicDungeon()
|
|
||||||
if (isMythicSegment and SegmentID == Details.mythic_dungeon_id and pastCombat.is_mythic_dungeon_trash) then
|
|
||||||
|
|
||||||
--if have mythic dungeon info, cancel the loop
|
|
||||||
local mythicDungeonInfo = pastCombat:GetMythicDungeonInfo()
|
|
||||||
if (mythicDungeonInfo) then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
--merge this segment
|
|
||||||
table.insert(segmentsToMerge, pastCombat)
|
|
||||||
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("MythicDungeonFinished() > found after last boss combat")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (#segmentsToMerge > 0) then
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MythicDungeonFinished() > found ", #segmentsToMerge, "segments after the last boss")
|
|
||||||
end
|
|
||||||
|
|
||||||
--find the latest trash overall
|
|
||||||
local segmentsTable = Details:GetCombatSegments()
|
|
||||||
local latestTrashOverall
|
|
||||||
for i = 1, #segmentsTable do
|
|
||||||
local pastCombat = segmentsTable [i]
|
|
||||||
if (pastCombat and pastCombat.is_mythic_dungeon and pastCombat.is_mythic_dungeon.SegmentID == "trashoverall") then
|
|
||||||
latestTrashOverall = pastCombat
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (latestTrashOverall) then
|
|
||||||
--stores the segment table and the trash overall segment to use on the merge
|
|
||||||
DetailsMythicPlusFrame.TrashMergeScheduled2 = segmentsToMerge
|
|
||||||
DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat = latestTrashOverall
|
|
||||||
|
|
||||||
--there's no more script ran too long
|
|
||||||
--if (not InCombatLockdown() and not UnitAffectingCombat("player")) then
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MythicDungeonFinished() > not in combat, merging last pack of trash now")
|
|
||||||
end
|
|
||||||
|
|
||||||
DetailsMythicPlusFrame.MergeRemainingTrashAfterAllBossesDone()
|
|
||||||
--else
|
|
||||||
-- if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
-- print("Details!", "MythicDungeonFinished() > player in combatlockdown, scheduling the merge for last trash packs")
|
|
||||||
-- end
|
|
||||||
-- _detalhes.schedule_mythicdungeon_endtrash_merge = true
|
|
||||||
--end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--merge segments
|
|
||||||
if (Details.mythic_plus.make_overall_when_done and not Details.MythicPlus.IsRestoredState and not fromZoneLeft) then
|
|
||||||
--if (not InCombatLockdown() and not UnitAffectingCombat("player")) then
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MythicDungeonFinished() > not in combat, creating overall segment now")
|
|
||||||
end
|
|
||||||
DetailsMythicPlusFrame.MergeSegmentsOnEnd()
|
|
||||||
--else
|
|
||||||
-- if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
-- print("Details!", "MythicDungeonFinished() > player in combatlockdown, scheduling the creation of the overall segment")
|
|
||||||
-- end
|
|
||||||
-- _detalhes.schedule_mythicdungeon_overallrun_merge = true
|
|
||||||
--end
|
|
||||||
end
|
|
||||||
|
|
||||||
Details.MythicPlus.IsRestoredState = nil
|
|
||||||
|
|
||||||
--shutdown parser for a few seconds to avoid opening new segments after the run ends
|
|
||||||
if (not fromZoneLeft) then
|
|
||||||
Details:CaptureSet (false, "damage", false, 15)
|
|
||||||
Details:CaptureSet (false, "energy", false, 15)
|
|
||||||
Details:CaptureSet (false, "aura", false, 15)
|
|
||||||
Details:CaptureSet (false, "energy", false, 15)
|
|
||||||
Details:CaptureSet (false, "spellcast", false, 15)
|
|
||||||
end
|
|
||||||
|
|
||||||
--store data
|
|
||||||
--[=[
|
|
||||||
local expansion = tostring(select(4, GetBuildInfo())):match ("%d%d")
|
|
||||||
if (expansion and type(expansion) == "string" and string.len(expansion) == 2) then
|
|
||||||
local expansionDungeonData = _detalhes.dungeon_data [expansion]
|
|
||||||
if (not expansionDungeonData) then
|
|
||||||
expansionDungeonData = {}
|
|
||||||
_detalhes.dungeon_data [expansion] = expansionDungeonData
|
|
||||||
end
|
|
||||||
|
|
||||||
--store information about the dungeon run
|
|
||||||
--the the dungeon ID, can't be localized
|
|
||||||
--players in the group
|
|
||||||
--difficulty level
|
|
||||||
--
|
|
||||||
|
|
||||||
end
|
|
||||||
--]=]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DetailsMythicPlusFrame.MythicDungeonStarted()
|
|
||||||
--flag as a mythic dungeon
|
|
||||||
DetailsMythicPlusFrame.IsDoingMythicDungeon = true
|
|
||||||
|
|
||||||
--this counter is individual for each character
|
|
||||||
Details.mythic_dungeon_id = Details.mythic_dungeon_id + 1
|
|
||||||
|
|
||||||
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
|
|
||||||
local zoneName, _, _, _, _, _, _, currentZoneID = GetInstanceInfo()
|
|
||||||
|
|
||||||
local mapID = C_Map.GetBestMapForUnit("player")
|
|
||||||
|
|
||||||
if (not mapID) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local ejID = Details:GetInstanceEJID(mapID)
|
|
||||||
|
|
||||||
--setup the mythic run info
|
|
||||||
Details.MythicPlus.Started = true
|
|
||||||
Details.MythicPlus.DungeonName = zoneName
|
|
||||||
Details.MythicPlus.DungeonID = currentZoneID
|
|
||||||
Details:Msg("(debug) mythic dungeon start time: ", time()+9.7, "time now:", time(), "diff:", time()+9.7-time())
|
|
||||||
Details.MythicPlus.StartedAt = time()+9.7 --there's the countdown timer of 10 seconds
|
|
||||||
Details.MythicPlus.EndedAt = nil --reset
|
|
||||||
Details.MythicPlus.SegmentID = 1
|
|
||||||
Details.MythicPlus.Level = mythicLevel
|
|
||||||
Details.MythicPlus.ejID = ejID
|
|
||||||
Details.MythicPlus.PreviousBossKilledAt = time()
|
|
||||||
|
|
||||||
Details:SaveState_CurrentMythicDungeonRun(Details.mythic_dungeon_id, zoneName, currentZoneID, time()+9.7, 1, mythicLevel, ejID, time())
|
|
||||||
|
|
||||||
local name, groupType, difficultyID, difficult = GetInstanceInfo()
|
|
||||||
if (groupType == "party" and Details.overall_clear_newchallenge) then
|
|
||||||
Details.historico:ResetOverallData()
|
|
||||||
Details:Msg("the overall data has been reset.") --localize-me
|
|
||||||
|
|
||||||
if (Details.debug) then
|
|
||||||
Details:Msg("(debug) timer is for a mythic+ dungeon, overall has been reseted.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", "MythicDungeonStarted() > State set to Mythic Dungeon, new combat starting in 10 seconds.")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DetailsMythicPlusFrame.OnChallengeModeStart()
|
|
||||||
--is this a mythic dungeon?
|
|
||||||
local _, _, difficultyID, _, _, _, _, currentZoneID = GetInstanceInfo()
|
|
||||||
|
|
||||||
if (difficultyID == 8) then
|
|
||||||
--start the dungeon on Details!
|
|
||||||
DetailsMythicPlusFrame.MythicDungeonStarted()
|
|
||||||
Details222.MythicPlus.LogStep("OnChallengeModeStart()")
|
|
||||||
else
|
|
||||||
--print("D! mythic dungeon was already started!")
|
|
||||||
--from zone changed
|
|
||||||
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
|
|
||||||
local zoneName, _, _, _, _, _, _, currentZoneID = GetInstanceInfo()
|
|
||||||
|
|
||||||
--print("Details.MythicPlus.Started", Details.MythicPlus.Started)
|
|
||||||
--print("Details.MythicPlus.DungeonID", Details.MythicPlus.DungeonID)
|
|
||||||
--print("currentZoneID", currentZoneID)
|
|
||||||
--print("Details.MythicPlus.Level", Details.MythicPlus.Level)
|
|
||||||
--print("mythicLevel", mythicLevel)
|
|
||||||
|
|
||||||
if (not Details.MythicPlus.Started and Details.MythicPlus.DungeonID == currentZoneID and Details.MythicPlus.Level == mythicLevel) then
|
|
||||||
Details.MythicPlus.Started = true
|
|
||||||
Details.MythicPlus.EndedAt = nil
|
|
||||||
Details.mythic_dungeon_currentsaved.started = true
|
|
||||||
DetailsMythicPlusFrame.IsDoingMythicDungeon = true
|
|
||||||
|
|
||||||
--print("D! mythic dungeon was NOT already started! debug 2")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--make an event listener to sync combat data
|
|
||||||
DetailsMythicPlusFrame.EventListener = Details:CreateEventListener()
|
|
||||||
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_ENCOUNTER_START")
|
|
||||||
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_ENCOUNTER_END")
|
|
||||||
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_PLAYER_ENTER")
|
|
||||||
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_PLAYER_LEAVE")
|
|
||||||
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_MYTHICDUNGEON_START")
|
|
||||||
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_MYTHICDUNGEON_END")
|
|
||||||
|
|
||||||
function DetailsMythicPlusFrame.EventListener.OnDetailsEvent(contextObject, event, ...)
|
|
||||||
--these events triggers within Details control functions, they run exactly after details! creates or close a segment
|
|
||||||
if (event == "COMBAT_PLAYER_ENTER") then
|
|
||||||
|
|
||||||
|
|
||||||
elseif (event == "COMBAT_PLAYER_LEAVE") then
|
|
||||||
--ignore the event if ignoring mythic dungeon special treatment
|
|
||||||
if (Details.streamer_config.disable_mythic_dungeon) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if (DetailsMythicPlusFrame.IsDoingMythicDungeon) then
|
|
||||||
local combatObject = ...
|
|
||||||
|
|
||||||
if (combatObject.is_boss) then
|
|
||||||
if (not combatObject.is_boss.killed) then
|
|
||||||
local encounterName = combatObject.is_boss.encounter
|
|
||||||
local zoneName = combatObject.is_boss.zone
|
|
||||||
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
|
|
||||||
|
|
||||||
--just in case the combat get tagged as boss fight
|
|
||||||
Details.tabela_vigente.is_boss = nil
|
|
||||||
|
|
||||||
--tag the combat as mythic dungeon trash
|
|
||||||
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
|
|
||||||
Details.tabela_vigente.is_mythic_dungeon_trash = {
|
|
||||||
ZoneName = zoneName,
|
|
||||||
MapID = instanceMapID,
|
|
||||||
Level = Details.MythicPlus.Level,
|
|
||||||
EJID = Details.MythicPlus.ejID,
|
|
||||||
}
|
|
||||||
|
|
||||||
Details222.MythicPlus.LogStep("COMBAT_PLAYER_LEAVE | wiped on boss | key level: | " .. mythicLevel .. " | " .. (encounterName or "") .. " " .. zoneName)
|
|
||||||
else
|
|
||||||
DetailsMythicPlusFrame.BossDefeated(false, combatObject.is_boss.id, combatObject.is_boss.name, combatObject.is_boss.diff, 5, 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif (event == "COMBAT_ENCOUNTER_START") then
|
|
||||||
--ignore the event if ignoring mythic dungeon special treatment
|
|
||||||
if (Details.streamer_config.disable_mythic_dungeon) then
|
|
||||||
Details222.MythicPlus.LogStep("COMBAT_ENCOUNTER_START | streamer_config.disable_mythic_dungeon is true and the code cannot continue.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local encounterID, encounterName, difficultyID, raidSize, endStatus = ...
|
|
||||||
--nothing
|
|
||||||
|
|
||||||
elseif (event == "COMBAT_ENCOUNTER_END") then
|
|
||||||
--ignore the event if ignoring mythic dungeon special treatment
|
|
||||||
if (Details.streamer_config.disable_mythic_dungeon) then
|
|
||||||
Details222.MythicPlus.LogStep("COMBAT_ENCOUNTER_END | streamer_config.disable_mythic_dungeon is true and the code cannot continue.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local encounterID, encounterName, difficultyID, raidSize, endStatus = ...
|
|
||||||
--nothing
|
|
||||||
|
|
||||||
elseif (event == "COMBAT_MYTHICDUNGEON_START") then
|
|
||||||
local lowerInstance = Details:GetLowerInstanceNumber()
|
|
||||||
if (lowerInstance) then
|
|
||||||
lowerInstance = Details:GetInstance(lowerInstance)
|
|
||||||
if (lowerInstance) then
|
|
||||||
C_Timer.After(3, function()
|
|
||||||
--if (lowerInstance:IsEnabled()) then
|
|
||||||
--todo, need localization
|
|
||||||
--lowerInstance:InstanceAlert("Details!" .. " " .. "Damage" .. " " .. "Meter", {[[Interface\AddOns\Details\images\minimap]], 16, 16, false}, 3, {function() end}, false, true)
|
|
||||||
--end
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--ignore the event if ignoring mythic dungeon special treatment
|
|
||||||
if (Details.streamer_config.disable_mythic_dungeon) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
--reset spec cache if broadcaster requested
|
|
||||||
if (Details.streamer_config.reset_spec_cache) then
|
|
||||||
Details:Destroy(Details.cached_specs)
|
|
||||||
end
|
|
||||||
|
|
||||||
C_Timer.After(0.25, DetailsMythicPlusFrame.OnChallengeModeStart)
|
|
||||||
|
|
||||||
--debugging
|
|
||||||
local mPlusSettings = Details.mythic_plus
|
|
||||||
local result = ""
|
|
||||||
for key, value in pairs(Details.mythic_plus) do
|
|
||||||
if (type(value) ~= "table") then
|
|
||||||
result = result .. key .. " = " .. tostring(value) .. " | "
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
|
|
||||||
local zoneName, _, _, _, _, _, _, currentZoneID = GetInstanceInfo()
|
|
||||||
Details222.MythicPlus.LogStep("COMBAT_MYTHICDUNGEON_START | settings: " .. result .. " | level: " .. mythicLevel .. " | zone: " .. zoneName .. " | zoneId: " .. currentZoneID)
|
|
||||||
|
|
||||||
elseif (event == "COMBAT_MYTHICDUNGEON_END") then
|
|
||||||
--ignore the event if ignoring mythic dungeon special treatment
|
|
||||||
if (Details.streamer_config.disable_mythic_dungeon) then
|
|
||||||
Details222.MythicPlus.LogStep("COMBAT_MYTHICDUNGEON_END | streamer_config.disable_mythic_dungeon is true and the code cannot continue.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
--delay to wait the encounter_end trigger first
|
|
||||||
--assuming here the party cleaned the mobs kill objective before going to kill the last boss
|
|
||||||
C_Timer.After(2, DetailsMythicPlusFrame.MythicDungeonFinished)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
DetailsMythicPlusFrame:SetScript("OnEvent", function(_, event, ...)
|
|
||||||
if (event == "START_TIMER") then
|
|
||||||
--DetailsMythicPlusFrame.LastTimer = GetTime()
|
|
||||||
|
|
||||||
elseif (event == "ZONE_CHANGED_NEW_AREA") then
|
|
||||||
if (DetailsMythicPlusFrame.IsDoingMythicDungeon) then
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Details!", event, ...)
|
|
||||||
print("Zone changed and is Doing Mythic Dungeon")
|
|
||||||
end
|
|
||||||
|
|
||||||
--ignore the event if ignoring mythic dungeon special treatment
|
|
||||||
if (Details.streamer_config.disable_mythic_dungeon) then
|
|
||||||
Details222.MythicPlus.LogStep("ZONE_CHANGED_NEW_AREA | streamer_config.disable_mythic_dungeon is true and the code cannot continue.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local _, _, difficulty, _, _, _, _, currentZoneID = GetInstanceInfo()
|
|
||||||
if (currentZoneID ~= Details.MythicPlus.DungeonID) then
|
|
||||||
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
|
||||||
print("Zone changed and the zone is different than the dungeon")
|
|
||||||
end
|
|
||||||
|
|
||||||
Details222.MythicPlus.LogStep("ZONE_CHANGED_NEW_AREA | player has left the dungeon and Details! finished the dungeon because of that.")
|
|
||||||
|
|
||||||
--send mythic dungeon end event
|
|
||||||
Details:SendEvent("COMBAT_MYTHICDUNGEON_END")
|
|
||||||
|
|
||||||
--finish the segment
|
|
||||||
DetailsMythicPlusFrame.BossDefeated(true)
|
|
||||||
|
|
||||||
--finish the mythic run
|
|
||||||
DetailsMythicPlusFrame.MythicDungeonFinished(true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
@@ -0,0 +1,290 @@
|
|||||||
|
|
||||||
|
local Details = _G.Details
|
||||||
|
local addonName, Details222 = ...
|
||||||
|
local detailsFramework = DetailsFramework
|
||||||
|
local _
|
||||||
|
|
||||||
|
local debugmode = false --print debug lines
|
||||||
|
local verbosemode = false --auto open the chart panel
|
||||||
|
local UnitClass = UnitClass
|
||||||
|
local IsInInstance = IsInInstance
|
||||||
|
local GetNumGroupMembers = GetNumGroupMembers
|
||||||
|
local GetInstanceInfo = GetInstanceInfo
|
||||||
|
local time = time
|
||||||
|
local floor = math.floor
|
||||||
|
local C_Timer = C_Timer
|
||||||
|
local C_ChallengeMode = C_ChallengeMode
|
||||||
|
|
||||||
|
--constants
|
||||||
|
local CONST_USE_PLAYER_EDPS = false
|
||||||
|
|
||||||
|
|
||||||
|
--Generate damage chart for mythic dungeon runs
|
||||||
|
|
||||||
|
--[=[
|
||||||
|
The chart table needs to be stored saparated from the combat
|
||||||
|
Should the chart data be volatile?
|
||||||
|
|
||||||
|
--]=]
|
||||||
|
|
||||||
|
local mythicDungeonFrames = Details222.MythicPlus.Frames
|
||||||
|
local mythicDungeonCharts = Details222.MythicPlus.Charts.Listener
|
||||||
|
|
||||||
|
--debug
|
||||||
|
_G.DetailsMythicDungeonChartHandler = mythicDungeonCharts
|
||||||
|
--DetailsMythicDungeonChartHandler.ChartTable.Players["playername"].ChartData = {max_value = 0}
|
||||||
|
|
||||||
|
function mythicDungeonCharts:Debug(...)
|
||||||
|
if (debugmode or verbosemode) then
|
||||||
|
print("Details! DungeonCharts: ", ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local addPlayerDamage = function(unitCleuName)
|
||||||
|
--get the player data
|
||||||
|
local playerData = mythicDungeonCharts.ChartTable.Players[unitCleuName]
|
||||||
|
|
||||||
|
--if this is the first tick for the player, ignore the damage done on this tick
|
||||||
|
--this is done to prevent a tick tick with all the damage the player did on the previous segment
|
||||||
|
local bIsFirstTick = false
|
||||||
|
|
||||||
|
--check if the player data doesn't exists
|
||||||
|
if (not playerData) then
|
||||||
|
playerData = {
|
||||||
|
Name = detailsFramework:RemoveRealmName(unitCleuName),
|
||||||
|
ChartData = {max_value = 0},
|
||||||
|
Class = select(2, UnitClass(Details:Ambiguate(unitCleuName))),
|
||||||
|
|
||||||
|
--spec zero for now, need to retrive later during combat
|
||||||
|
Spec = 0,
|
||||||
|
|
||||||
|
--last damage to calc difference
|
||||||
|
LastDamage = 0,
|
||||||
|
|
||||||
|
--if started a new combat, need to reset the lastdamage
|
||||||
|
LastCombatID = -1,
|
||||||
|
}
|
||||||
|
|
||||||
|
mythicDungeonCharts.ChartTable.Players[unitCleuName] = playerData
|
||||||
|
bIsFirstTick = true
|
||||||
|
end
|
||||||
|
|
||||||
|
--get the current combat
|
||||||
|
local currentCombat = Details:GetCombat(DETAILS_SEGMENTID_CURRENT)
|
||||||
|
if (currentCombat) then
|
||||||
|
local isOverallSegment = false
|
||||||
|
|
||||||
|
local mythicDungeonInfo = currentCombat.is_mythic_dungeon
|
||||||
|
if (mythicDungeonInfo) then
|
||||||
|
if (mythicDungeonInfo.TrashOverallSegment or mythicDungeonInfo.OverallSegment) then
|
||||||
|
isOverallSegment = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (not isOverallSegment) then
|
||||||
|
--check if the combat has changed
|
||||||
|
local segmentId = currentCombat.combat_id
|
||||||
|
if (segmentId ~= playerData.LastCombatID) then
|
||||||
|
playerData.LastDamage = 0
|
||||||
|
playerData.LastCombatID = segmentId
|
||||||
|
--mythicDungeonCharts:Debug("Combat changed for player", unitCleuName)
|
||||||
|
end
|
||||||
|
|
||||||
|
local actorTable = currentCombat:GetActor(DETAILS_ATTRIBUTE_DAMAGE, unitCleuName)
|
||||||
|
if (actorTable) then
|
||||||
|
--update the player spec
|
||||||
|
playerData.Spec = actorTable.spec
|
||||||
|
|
||||||
|
if (bIsFirstTick) then
|
||||||
|
--ignore previous damage
|
||||||
|
playerData.LastDamage = actorTable.total
|
||||||
|
end
|
||||||
|
|
||||||
|
--get the damage done
|
||||||
|
local damageDone = actorTable.total
|
||||||
|
|
||||||
|
--check which data is used, dps or damage done
|
||||||
|
if (CONST_USE_PLAYER_EDPS) then
|
||||||
|
local eDps = damageDone / currentCombat:GetCombatTime()
|
||||||
|
|
||||||
|
--add the damage to the chart table
|
||||||
|
table.insert(playerData.ChartData, eDps)
|
||||||
|
--mythicDungeonCharts:Debug("Added dps for " , unitCleuName, ":", eDps)
|
||||||
|
|
||||||
|
if (eDps > playerData.ChartData.max_value) then
|
||||||
|
playerData.ChartData.max_value = eDps
|
||||||
|
end
|
||||||
|
else
|
||||||
|
--calc the difference and add to the table
|
||||||
|
local damageDiff = floor(damageDone - playerData.LastDamage)
|
||||||
|
playerData.LastDamage = damageDone
|
||||||
|
|
||||||
|
--add the damage to the chart table
|
||||||
|
table.insert(playerData.ChartData, damageDiff)
|
||||||
|
--mythicDungeonCharts:Debug("Added damage for " , unitCleuName, ":", damageDiff)
|
||||||
|
|
||||||
|
if (damageDiff > playerData.ChartData.max_value) then
|
||||||
|
playerData.ChartData.max_value = damageDiff
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
--player still didn't made anything on this combat, so just add zero
|
||||||
|
table.insert(playerData.ChartData, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local tickerCallback = function(tickerObject)
|
||||||
|
--check if is inside the dungeon
|
||||||
|
local inInstance = IsInInstance()
|
||||||
|
if (not inInstance) then
|
||||||
|
mythicDungeonCharts:OnEndMythicDungeon()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
--check if still running the dungeon
|
||||||
|
if (not mythicDungeonCharts.ChartTable or not mythicDungeonCharts.ChartTable.Running) then
|
||||||
|
tickerObject:Cancel()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
--tick damage
|
||||||
|
local totalPlayers = GetNumGroupMembers()
|
||||||
|
for i = 1, totalPlayers-1 do
|
||||||
|
---@type cleuname
|
||||||
|
local cleuName = Details:GetFullName("party" .. i)
|
||||||
|
if (cleuName) then
|
||||||
|
addPlayerDamage(cleuName)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
addPlayerDamage(Details:GetFullName("player"))
|
||||||
|
end
|
||||||
|
|
||||||
|
function mythicDungeonCharts:OnBossDefeated()
|
||||||
|
local currentCombat = Details:GetCurrentCombat()
|
||||||
|
local segmentType = currentCombat:GetCombatType()
|
||||||
|
local bossInfo = currentCombat:GetBossInfo()
|
||||||
|
local mythicLevel = C_ChallengeMode and C_ChallengeMode.GetActiveKeystoneInfo()
|
||||||
|
|
||||||
|
if (mythicLevel and mythicLevel > 0) then
|
||||||
|
if (mythicDungeonCharts.ChartTable and mythicDungeonCharts.ChartTable.Running and bossInfo) then
|
||||||
|
|
||||||
|
local copiedBossInfo = Details:GetFramework().table.copy({}, bossInfo)
|
||||||
|
table.insert(mythicDungeonCharts.ChartTable.BossDefeated, {time() - mythicDungeonCharts.ChartTable.StartTime, copiedBossInfo, currentCombat:GetCombatTime()})
|
||||||
|
mythicDungeonCharts:Debug("Boss defeated, time saved", currentCombat:GetCombatTime())
|
||||||
|
else
|
||||||
|
if (mythicDungeonCharts.ChartTable and mythicDungeonCharts.ChartTable.EndTime ~= -1) then
|
||||||
|
local now = time()
|
||||||
|
--check if the dungeon just ended
|
||||||
|
if (mythicDungeonCharts.ChartTable.EndTime + 2 >= now) then
|
||||||
|
|
||||||
|
if (bossInfo) then
|
||||||
|
local copiedBossInfo = Details:GetFramework().table.copy({}, bossInfo)
|
||||||
|
table.insert(mythicDungeonCharts.ChartTable.BossDefeated, {time() - mythicDungeonCharts.ChartTable.StartTime, copiedBossInfo, currentCombat:GetCombatTime()})
|
||||||
|
mythicDungeonCharts:Debug("Boss defeated, time saved, but used time aproximation:", mythicDungeonCharts.ChartTable.EndTime + 2, now, currentCombat:GetCombatTime())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
mythicDungeonCharts:Debug("Boss defeated, but no chart capture is running")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
mythicDungeonCharts:Debug("Boss defeated, but isn't a mythic dungeon boss fight")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mythicDungeonCharts:OnStartMythicDungeon()
|
||||||
|
if (not Details.mythic_plus.show_damage_graphic) then
|
||||||
|
mythicDungeonCharts:Debug("Dungeon started, no capturing mythic dungeon chart data, disabled on profile")
|
||||||
|
if (verbosemode) then
|
||||||
|
mythicDungeonCharts:Debug("OnStartMythicDungeon() not allowed")
|
||||||
|
end
|
||||||
|
return
|
||||||
|
else
|
||||||
|
mythicDungeonCharts:Debug("Dungeon started, new capture started")
|
||||||
|
end
|
||||||
|
|
||||||
|
mythicDungeonCharts.ChartTable = {
|
||||||
|
Running = true,
|
||||||
|
Players = {},
|
||||||
|
ElapsedTime = 0,
|
||||||
|
StartTime = time(),
|
||||||
|
EndTime = -1,
|
||||||
|
DungeonName = "",
|
||||||
|
|
||||||
|
--store when each boss got defeated in comparison with the StartTime
|
||||||
|
BossDefeated = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
mythicDungeonCharts.ChartTable.Ticker = C_Timer.NewTicker(1, tickerCallback)
|
||||||
|
|
||||||
|
--save the chart for development
|
||||||
|
if (debugmode) then
|
||||||
|
Details.mythic_plus.last_mythicrun_chart = mythicDungeonCharts.ChartTable
|
||||||
|
end
|
||||||
|
|
||||||
|
if (verbosemode) then
|
||||||
|
mythicDungeonCharts:Debug("OnStartMythicDungeon() success")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mythicDungeonCharts:OnEndMythicDungeon()
|
||||||
|
if (mythicDungeonCharts.ChartTable and mythicDungeonCharts.ChartTable.Running) then
|
||||||
|
|
||||||
|
--stop capturinfg
|
||||||
|
mythicDungeonCharts.ChartTable.Running = false
|
||||||
|
mythicDungeonCharts.ChartTable.ElapsedTime = time() - mythicDungeonCharts.ChartTable.StartTime
|
||||||
|
mythicDungeonCharts.ChartTable.EndTime = time()
|
||||||
|
mythicDungeonCharts.ChartTable.Ticker:Cancel()
|
||||||
|
|
||||||
|
local name, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
|
||||||
|
mythicDungeonCharts.ChartTable.DungeonName = name
|
||||||
|
|
||||||
|
--check if is inside the dungeon
|
||||||
|
--many players just leave the dungeon in order the re-enter and start the run again, the chart window is showing in these cases data to an imcomplete run.
|
||||||
|
local isInsideDungeon = IsInInstance()
|
||||||
|
if (not isInsideDungeon) then
|
||||||
|
mythicDungeonCharts:Debug("OnEndMythicDungeon() player wasn't inside the dungeon.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
mythicDungeonCharts:Debug("Dungeon ended successfully, chart data capture stopped, scheduling to open the window.")
|
||||||
|
|
||||||
|
C_Timer.After(0.1, function()
|
||||||
|
|
||||||
|
end)
|
||||||
|
|
||||||
|
--the run is valid, schedule to open the chart window
|
||||||
|
Details.mythic_plus.delay_to_show_graphic = 1
|
||||||
|
C_Timer.After(Details.mythic_plus.delay_to_show_graphic, mythicDungeonFrames.ShowEndOfMythicPlusPanel)
|
||||||
|
|
||||||
|
if (verbosemode) then
|
||||||
|
mythicDungeonCharts:Debug("OnEndMythicDungeon() success!")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
mythicDungeonCharts:Debug("Dungeon ended, no chart data was running")
|
||||||
|
if (verbosemode) then
|
||||||
|
mythicDungeonCharts:Debug("OnEndMythicDungeon() fail")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
mythicDungeonCharts:RegisterEvent("COMBAT_MYTHICDUNGEON_START", "OnStartMythicDungeon")
|
||||||
|
mythicDungeonCharts:RegisterEvent("COMBAT_MYTHICDUNGEON_END", "OnEndMythicDungeon")
|
||||||
|
mythicDungeonCharts:RegisterEvent("COMBAT_BOSS_DEFEATED", "OnBossDefeated")
|
||||||
|
|
||||||
|
|
||||||
|
--SetPortraitTexture(texture, unitId)
|
||||||
|
-- /run _G.DetailsMythicDungeonChartHandler.ShowChart(); DetailsMythicDungeonChartFrame.ShowChartFrame()
|
||||||
|
-- /run mythicDungeonFrames.ShowEndOfMythicPlusPanel()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,349 @@
|
|||||||
|
|
||||||
|
local Details = _G.Details
|
||||||
|
local DF = _G.DetailsFramework
|
||||||
|
local addonName, Details222 = ...
|
||||||
|
local _
|
||||||
|
|
||||||
|
local time = time
|
||||||
|
local C_Timer = _G.C_Timer
|
||||||
|
local unpack = _G.unpack
|
||||||
|
local GetTime = _G.GetTime
|
||||||
|
local tremove = _G.tremove
|
||||||
|
local GetInstanceInfo = _G.GetInstanceInfo
|
||||||
|
|
||||||
|
local Loc = _G.LibStub("AceLocale-3.0"):GetLocale("Details")
|
||||||
|
|
||||||
|
--data for the current mythic + dungeon
|
||||||
|
Details.MythicPlus = {
|
||||||
|
RunID = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
local mythicDungeonCharts = Details:CreateEventListener()
|
||||||
|
Details222.MythicPlus.Charts.Listener = mythicDungeonCharts
|
||||||
|
|
||||||
|
-- ~mythic ~dungeon
|
||||||
|
local DetailsMythicPlusFrame = _G.CreateFrame("frame", "DetailsMythicPlusFrame", UIParent)
|
||||||
|
DetailsMythicPlusFrame.DevelopmentDebug = false
|
||||||
|
|
||||||
|
--disabling the mythic+ feature if the user is playing in wow classic
|
||||||
|
if (not DF.IsTimewalkWoW()) then
|
||||||
|
DetailsMythicPlusFrame:RegisterEvent("CHALLENGE_MODE_START")
|
||||||
|
DetailsMythicPlusFrame:RegisterEvent("CHALLENGE_MODE_COMPLETED")
|
||||||
|
DetailsMythicPlusFrame:RegisterEvent("ZONE_CHANGED_NEW_AREA")
|
||||||
|
DetailsMythicPlusFrame:RegisterEvent("ENCOUNTER_END")
|
||||||
|
DetailsMythicPlusFrame:RegisterEvent("START_TIMER")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Details222.MythicPlus.LogStep(log)
|
||||||
|
local today = date("%d/%m/%y %H:%M:%S")
|
||||||
|
table.insert(Details.mythic_plus_log, 1, today .. "|" .. log)
|
||||||
|
tremove(Details.mythic_plus_log, 50)
|
||||||
|
end
|
||||||
|
|
||||||
|
function DetailsMythicPlusFrame.BossDefeated(this_is_end_end, encounterID, encounterName, difficultyID, raidSize, endStatus) --hold your breath and count to ten
|
||||||
|
--this function is called right after defeat a boss inside a mythic dungeon
|
||||||
|
--it comes from details! control leave combat
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "BossDefeated() > boss defeated | SegmentID:", Details.MythicPlus.SegmentID, " | mapID:", Details.MythicPlus.DungeonID)
|
||||||
|
end
|
||||||
|
|
||||||
|
--local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
|
||||||
|
Details222.MythicPlus.OnBossDefeated(encounterID, encounterName)
|
||||||
|
|
||||||
|
--increase the segment number for the mythic run
|
||||||
|
Details.MythicPlus.SegmentID = Details.MythicPlus.SegmentID + 1
|
||||||
|
|
||||||
|
--register the time when the last boss has been killed (started a clean up for the next trash)
|
||||||
|
Details.MythicPlus.PreviousBossKilledAt = time()
|
||||||
|
|
||||||
|
--update the saved table inside the profile
|
||||||
|
Details:UpdateState_CurrentMythicDungeonRun(true, Details.MythicPlus.SegmentID, Details.MythicPlus.PreviousBossKilledAt)
|
||||||
|
end
|
||||||
|
|
||||||
|
function DetailsMythicPlusFrame.MythicDungeonFinished(fromZoneLeft)
|
||||||
|
if (DetailsMythicPlusFrame.IsDoingMythicDungeon) then
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MythicDungeonFinished() > the dungeon was a Mythic+ and just ended.")
|
||||||
|
end
|
||||||
|
|
||||||
|
DetailsMythicPlusFrame.IsDoingMythicDungeon = false
|
||||||
|
Details.MythicPlus.Started = false
|
||||||
|
Details.MythicPlus.EndedAt = time()-1.9
|
||||||
|
|
||||||
|
Details:UpdateState_CurrentMythicDungeonRun()
|
||||||
|
|
||||||
|
--at this point, details! should not be in combat, but if something triggered a combat start, just close the combat right away
|
||||||
|
if (Details.in_combat) then
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MythicDungeonFinished() > was in combat, calling SairDoCombate():", InCombatLockdown())
|
||||||
|
end
|
||||||
|
Details:SairDoCombate()
|
||||||
|
Details222.MythicPlus.LogStep("MythicDungeonFinished() | Details was in combat.")
|
||||||
|
end
|
||||||
|
|
||||||
|
--check if there is trash segments after the last boss. need to merge these segments with the trash segment of the last boss
|
||||||
|
local bCanMergeBossTrash = Details.mythic_plus.merge_boss_trash
|
||||||
|
Details222.MythicPlus.LogStep("MythicDungeonFinished() | merge_boss_trash = " .. (bCanMergeBossTrash and "true" or "false"))
|
||||||
|
|
||||||
|
--check if there's trash after the last boss, if does, merge it with the trash of the last boss defeated
|
||||||
|
if (bCanMergeBossTrash and not Details.MythicPlus.IsRestoredState and not fromZoneLeft) then
|
||||||
|
--is the current combat not a boss fight?
|
||||||
|
--this mean a combat was opened after the last boss of the dungeon was killed
|
||||||
|
if (not Details.tabela_vigente.is_boss and Details.tabela_vigente:GetCombatTime() > 5) then
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MythicDungeonFinished() > the last combat isn't a boss fight, might have trash after bosses done.")
|
||||||
|
end
|
||||||
|
Details222.MythicPlus.MergeTrashAfterLastBoss()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--merge segments
|
||||||
|
if (Details.mythic_plus.make_overall_when_done and not Details.MythicPlus.IsRestoredState and not fromZoneLeft) then
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MythicDungeonFinished() > not in combat, creating overall segment now")
|
||||||
|
end
|
||||||
|
DetailsMythicPlusFrame.MergeSegmentsOnEnd()
|
||||||
|
end
|
||||||
|
|
||||||
|
Details.MythicPlus.IsRestoredState = nil
|
||||||
|
|
||||||
|
--shutdown parser for a few seconds to avoid opening new segments after the run ends
|
||||||
|
if (not fromZoneLeft) then
|
||||||
|
Details:CaptureSet(false, "damage", false, 15)
|
||||||
|
Details:CaptureSet(false, "energy", false, 15)
|
||||||
|
Details:CaptureSet(false, "aura", false, 15)
|
||||||
|
Details:CaptureSet(false, "energy", false, 15)
|
||||||
|
Details:CaptureSet(false, "spellcast", false, 15)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function DetailsMythicPlusFrame.MythicDungeonStarted()
|
||||||
|
--flag as a mythic dungeon
|
||||||
|
DetailsMythicPlusFrame.IsDoingMythicDungeon = true
|
||||||
|
|
||||||
|
--this counter is individual for each character
|
||||||
|
Details.mythic_dungeon_id = Details.mythic_dungeon_id + 1
|
||||||
|
|
||||||
|
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
|
||||||
|
local zoneName, _, _, _, _, _, _, currentZoneID = GetInstanceInfo()
|
||||||
|
|
||||||
|
local mapID = C_Map.GetBestMapForUnit("player")
|
||||||
|
|
||||||
|
if (not mapID) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local ejID = Details:GetInstanceEJID(mapID)
|
||||||
|
|
||||||
|
--setup the mythic run info
|
||||||
|
Details.MythicPlus.Started = true
|
||||||
|
Details.MythicPlus.DungeonName = zoneName
|
||||||
|
Details.MythicPlus.DungeonID = currentZoneID
|
||||||
|
Details:Msg("(debug) mythic dungeon start time: ", time()+9.7, "time now:", time(), "diff:", time()+9.7-time())
|
||||||
|
Details.MythicPlus.StartedAt = time()+9.7 --there's the countdown timer of 10 seconds
|
||||||
|
Details.MythicPlus.EndedAt = nil --reset
|
||||||
|
Details.MythicPlus.SegmentID = 1
|
||||||
|
Details.MythicPlus.Level = mythicLevel
|
||||||
|
Details.MythicPlus.ejID = ejID
|
||||||
|
Details.MythicPlus.PreviousBossKilledAt = time()
|
||||||
|
|
||||||
|
Details:SaveState_CurrentMythicDungeonRun(Details.mythic_dungeon_id, zoneName, currentZoneID, time()+9.7, 1, mythicLevel, ejID, time())
|
||||||
|
|
||||||
|
local name, groupType, difficultyID, difficult = GetInstanceInfo()
|
||||||
|
if (groupType == "party" and Details.overall_clear_newchallenge) then
|
||||||
|
Details.historico:ResetOverallData()
|
||||||
|
Details:Msg("the overall data has been reset.") --localize-me
|
||||||
|
|
||||||
|
if (Details.debug) then
|
||||||
|
Details:Msg("(debug) timer is for a mythic+ dungeon, overall has been reseted.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MythicDungeonStarted() > State set to Mythic Dungeon, new combat starting in 10 seconds.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function DetailsMythicPlusFrame.OnChallengeModeStart()
|
||||||
|
--is this a mythic dungeon?
|
||||||
|
local _, _, difficultyID, _, _, _, _, currentZoneID = GetInstanceInfo()
|
||||||
|
|
||||||
|
if (difficultyID == 8) then
|
||||||
|
--start the dungeon on Details!
|
||||||
|
DetailsMythicPlusFrame.MythicDungeonStarted()
|
||||||
|
Details222.MythicPlus.LogStep("OnChallengeModeStart()")
|
||||||
|
else
|
||||||
|
--print("D! mythic dungeon was already started!")
|
||||||
|
--from zone changed
|
||||||
|
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
|
||||||
|
local zoneName, _, _, _, _, _, _, currentZoneID = GetInstanceInfo()
|
||||||
|
|
||||||
|
if (not Details.MythicPlus.Started and Details.MythicPlus.DungeonID == currentZoneID and Details.MythicPlus.Level == mythicLevel) then
|
||||||
|
Details.MythicPlus.Started = true
|
||||||
|
Details.MythicPlus.EndedAt = nil
|
||||||
|
Details.mythic_dungeon_currentsaved.started = true
|
||||||
|
DetailsMythicPlusFrame.IsDoingMythicDungeon = true
|
||||||
|
--print("D! mythic dungeon was NOT already started! debug 2")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--make an event listener to sync combat data
|
||||||
|
DetailsMythicPlusFrame.EventListener = Details:CreateEventListener()
|
||||||
|
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_ENCOUNTER_START")
|
||||||
|
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_ENCOUNTER_END")
|
||||||
|
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_PLAYER_ENTER")
|
||||||
|
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_PLAYER_LEAVE")
|
||||||
|
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_MYTHICDUNGEON_START")
|
||||||
|
DetailsMythicPlusFrame.EventListener:RegisterEvent("COMBAT_MYTHICDUNGEON_END")
|
||||||
|
|
||||||
|
function DetailsMythicPlusFrame.EventListener.OnDetailsEvent(contextObject, event, ...)
|
||||||
|
--these events triggers within Details control functions, they run exactly after details! creates or close a segment
|
||||||
|
if (event == "COMBAT_PLAYER_ENTER") then
|
||||||
|
|
||||||
|
|
||||||
|
elseif (event == "COMBAT_PLAYER_LEAVE") then
|
||||||
|
--ignore the event if ignoring mythic dungeon special treatment
|
||||||
|
if (Details.streamer_config.disable_mythic_dungeon) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.IsDoingMythicDungeon) then
|
||||||
|
local combatObject = ...
|
||||||
|
|
||||||
|
if (combatObject.is_boss) then
|
||||||
|
if (not combatObject.is_boss.killed) then
|
||||||
|
local encounterName = combatObject.is_boss.encounter
|
||||||
|
local zoneName = combatObject.is_boss.zone
|
||||||
|
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
|
||||||
|
|
||||||
|
--just in case the combat get tagged as boss fight
|
||||||
|
Details.tabela_vigente.is_boss = nil
|
||||||
|
|
||||||
|
--tag the combat as mythic dungeon trash
|
||||||
|
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
|
||||||
|
Details.tabela_vigente.is_mythic_dungeon_trash = {
|
||||||
|
ZoneName = zoneName,
|
||||||
|
MapID = instanceMapID,
|
||||||
|
Level = Details.MythicPlus.Level,
|
||||||
|
EJID = Details.MythicPlus.ejID,
|
||||||
|
}
|
||||||
|
|
||||||
|
Details222.MythicPlus.LogStep("COMBAT_PLAYER_LEAVE | wiped on boss | key level: | " .. mythicLevel .. " | " .. (encounterName or "") .. " " .. zoneName)
|
||||||
|
else
|
||||||
|
DetailsMythicPlusFrame.BossDefeated(false, combatObject.is_boss.id, combatObject.is_boss.name, combatObject.is_boss.diff, 5, 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif (event == "COMBAT_ENCOUNTER_START") then
|
||||||
|
--ignore the event if ignoring mythic dungeon special treatment
|
||||||
|
if (Details.streamer_config.disable_mythic_dungeon) then
|
||||||
|
Details222.MythicPlus.LogStep("COMBAT_ENCOUNTER_START | streamer_config.disable_mythic_dungeon is true and the code cannot continue.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local encounterID, encounterName, difficultyID, raidSize, endStatus = ...
|
||||||
|
--nothing
|
||||||
|
|
||||||
|
elseif (event == "COMBAT_ENCOUNTER_END") then
|
||||||
|
--ignore the event if ignoring mythic dungeon special treatment
|
||||||
|
if (Details.streamer_config.disable_mythic_dungeon) then
|
||||||
|
Details222.MythicPlus.LogStep("COMBAT_ENCOUNTER_END | streamer_config.disable_mythic_dungeon is true and the code cannot continue.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local encounterID, encounterName, difficultyID, raidSize, endStatus = ...
|
||||||
|
--nothing
|
||||||
|
|
||||||
|
elseif (event == "COMBAT_MYTHICDUNGEON_START") then
|
||||||
|
local lowerInstance = Details:GetLowerInstanceNumber()
|
||||||
|
if (lowerInstance) then
|
||||||
|
lowerInstance = Details:GetInstance(lowerInstance)
|
||||||
|
if (lowerInstance) then
|
||||||
|
C_Timer.After(3, function()
|
||||||
|
--if (lowerInstance:IsEnabled()) then
|
||||||
|
--todo, need localization
|
||||||
|
--lowerInstance:InstanceAlert("Details!" .. " " .. "Damage" .. " " .. "Meter", {[[Interface\AddOns\Details\images\minimap]], 16, 16, false}, 3, {function() end}, false, true)
|
||||||
|
--end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--ignore the event if ignoring mythic dungeon special treatment
|
||||||
|
if (Details.streamer_config.disable_mythic_dungeon) then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
--reset spec cache if broadcaster requested
|
||||||
|
if (Details.streamer_config.reset_spec_cache) then
|
||||||
|
Details:Destroy(Details.cached_specs)
|
||||||
|
end
|
||||||
|
|
||||||
|
C_Timer.After(0.25, DetailsMythicPlusFrame.OnChallengeModeStart)
|
||||||
|
|
||||||
|
--debugging
|
||||||
|
local mPlusSettings = Details.mythic_plus
|
||||||
|
local result = ""
|
||||||
|
for key, value in pairs(Details.mythic_plus) do
|
||||||
|
if (type(value) ~= "table") then
|
||||||
|
result = result .. key .. " = " .. tostring(value) .. " | "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
|
||||||
|
local zoneName, _, _, _, _, _, _, currentZoneID = GetInstanceInfo()
|
||||||
|
Details222.MythicPlus.LogStep("COMBAT_MYTHICDUNGEON_START | settings: " .. result .. " | level: " .. mythicLevel .. " | zone: " .. zoneName .. " | zoneId: " .. currentZoneID)
|
||||||
|
|
||||||
|
elseif (event == "COMBAT_MYTHICDUNGEON_END") then
|
||||||
|
--ignore the event if ignoring mythic dungeon special treatment
|
||||||
|
if (Details.streamer_config.disable_mythic_dungeon) then
|
||||||
|
Details222.MythicPlus.LogStep("COMBAT_MYTHICDUNGEON_END | streamer_config.disable_mythic_dungeon is true and the code cannot continue.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
--delay to wait the encounter_end trigger first
|
||||||
|
--assuming here the party cleaned the mobs kill objective before going to kill the last boss
|
||||||
|
C_Timer.After(2, DetailsMythicPlusFrame.MythicDungeonFinished)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
DetailsMythicPlusFrame:SetScript("OnEvent", function(_, event, ...)
|
||||||
|
if (event == "START_TIMER") then
|
||||||
|
--DetailsMythicPlusFrame.LastTimer = GetTime()
|
||||||
|
|
||||||
|
elseif (event == "ZONE_CHANGED_NEW_AREA") then
|
||||||
|
if (DetailsMythicPlusFrame.IsDoingMythicDungeon) then
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", event, ...)
|
||||||
|
print("Zone changed and is Doing Mythic Dungeon")
|
||||||
|
end
|
||||||
|
|
||||||
|
--ignore the event if ignoring mythic dungeon special treatment
|
||||||
|
if (Details.streamer_config.disable_mythic_dungeon) then
|
||||||
|
Details222.MythicPlus.LogStep("ZONE_CHANGED_NEW_AREA | streamer_config.disable_mythic_dungeon is true and the code cannot continue.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local _, _, difficulty, _, _, _, _, currentZoneID = GetInstanceInfo()
|
||||||
|
if (currentZoneID ~= Details.MythicPlus.DungeonID) then
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Zone changed and the zone is different than the dungeon")
|
||||||
|
end
|
||||||
|
|
||||||
|
Details222.MythicPlus.LogStep("ZONE_CHANGED_NEW_AREA | player has left the dungeon and Details! finished the dungeon because of that.")
|
||||||
|
|
||||||
|
--send mythic dungeon end event
|
||||||
|
Details:SendEvent("COMBAT_MYTHICDUNGEON_END")
|
||||||
|
|
||||||
|
--finish the segment
|
||||||
|
DetailsMythicPlusFrame.BossDefeated(true)
|
||||||
|
|
||||||
|
--finish the mythic run
|
||||||
|
DetailsMythicPlusFrame.MythicDungeonFinished(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
@@ -0,0 +1,545 @@
|
|||||||
|
|
||||||
|
local Details = _G.Details
|
||||||
|
local addonName, Details222 = ...
|
||||||
|
local detailsFramework = DetailsFramework
|
||||||
|
local _
|
||||||
|
|
||||||
|
local GetTime = GetTime
|
||||||
|
local GetInstanceInfo = GetInstanceInfo
|
||||||
|
local time = time
|
||||||
|
local C_ChallengeMode = C_ChallengeMode
|
||||||
|
local InCombatLockdown = InCombatLockdown
|
||||||
|
|
||||||
|
local Loc = _G.LibStub("AceLocale-3.0"):GetLocale("Details")
|
||||||
|
--[[
|
||||||
|
all mythic segments have:
|
||||||
|
.is_mythic_dungeon_segment = true
|
||||||
|
.is_mythic_dungeon_run_id = run id from details.profile.mythic_dungeon_id
|
||||||
|
boss, 'trash overall' and 'dungeon overall' segments have:
|
||||||
|
.is_mythic_dungeon
|
||||||
|
boss segments have:
|
||||||
|
.is_boss
|
||||||
|
'trash overall' segments have:
|
||||||
|
.is_mythic_dungeon with .SegmentID = "trashoverall"
|
||||||
|
'dungeon overall' segment have:
|
||||||
|
.is_mythic_dungeon with .SegmentID = "overall"
|
||||||
|
|
||||||
|
--]]
|
||||||
|
|
||||||
|
local DetailsMythicPlusFrame = _G["DetailsMythicPlusFrame"]
|
||||||
|
|
||||||
|
function Details222.MythicPlus.OnMythicDungeonFinished(encounterID, encounterName)
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function Details222.MythicPlus.MergeTrashAfterLastBoss()
|
||||||
|
local segmentsToMerge = {}
|
||||||
|
--table with all past segments
|
||||||
|
local segmentsTable = Details:GetCombatSegments()
|
||||||
|
|
||||||
|
for i = 1, #segmentsTable do
|
||||||
|
local pastCombat = segmentsTable [i]
|
||||||
|
--does the combat exists
|
||||||
|
|
||||||
|
if (pastCombat and not pastCombat._trashoverallalreadyadded and pastCombat:GetCombatTime() > 5) then
|
||||||
|
--is the last boss?
|
||||||
|
if (pastCombat.is_boss) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
--is the combat a mythic segment from this run?
|
||||||
|
local isMythicSegment, SegmentID = pastCombat:IsMythicDungeon()
|
||||||
|
if (isMythicSegment and SegmentID == Details.mythic_dungeon_id and pastCombat.is_mythic_dungeon_trash) then
|
||||||
|
|
||||||
|
--if have mythic dungeon info, cancel the loop
|
||||||
|
local mythicDungeonInfo = pastCombat:GetMythicDungeonInfo()
|
||||||
|
if (mythicDungeonInfo) then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
--merge this segment
|
||||||
|
table.insert(segmentsToMerge, pastCombat)
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("MythicDungeonFinished() > found after last boss combat")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (#segmentsToMerge > 0) then
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MythicDungeonFinished() > found ", #segmentsToMerge, "segments after the last boss")
|
||||||
|
end
|
||||||
|
|
||||||
|
--find the latest trash overall
|
||||||
|
segmentsTable = Details:GetCombatSegments()
|
||||||
|
local latestTrashOverall
|
||||||
|
for i = 1, #segmentsTable do
|
||||||
|
local pastCombat = segmentsTable [i]
|
||||||
|
if (pastCombat and pastCombat.is_mythic_dungeon and pastCombat.is_mythic_dungeon.SegmentID == "trashoverall") then
|
||||||
|
latestTrashOverall = pastCombat
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (latestTrashOverall) then
|
||||||
|
--stores the segment table and the trash overall segment to use on the merge
|
||||||
|
DetailsMythicPlusFrame.TrashMergeScheduled2 = segmentsToMerge
|
||||||
|
DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat = latestTrashOverall
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MythicDungeonFinished() > not in combat, merging last pack of trash now")
|
||||||
|
end
|
||||||
|
|
||||||
|
DetailsMythicPlusFrame.MergeRemainingTrashAfterAllBossesDone()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Details222.MythicPlus.OnBossDefeated(encounterID, encounterName)
|
||||||
|
local currentCombat = Details:GetCurrentCombat()
|
||||||
|
|
||||||
|
--add the mythic dungeon info to the combat
|
||||||
|
currentCombat.is_mythic_dungeon = {
|
||||||
|
StartedAt = Details.MythicPlus.StartedAt, --the start of the run
|
||||||
|
EndedAt = time(), --when the boss got killed
|
||||||
|
SegmentID = Details.MythicPlus.SegmentID, --segment number within the dungeon
|
||||||
|
EncounterID = encounterID,
|
||||||
|
EncounterName = encounterName or Loc["STRING_UNKNOW"],
|
||||||
|
RunID = Details.mythic_dungeon_id,
|
||||||
|
ZoneName = Details.MythicPlus.DungeonName,
|
||||||
|
MapID = Details.MythicPlus.DungeonID,
|
||||||
|
OverallSegment = false,
|
||||||
|
Level = Details.MythicPlus.Level,
|
||||||
|
EJID = Details.MythicPlus.ejID,
|
||||||
|
}
|
||||||
|
|
||||||
|
local mythicLevel = C_ChallengeMode.GetActiveKeystoneInfo()
|
||||||
|
local mPlusTable = currentCombat.is_mythic_dungeon
|
||||||
|
|
||||||
|
--logs
|
||||||
|
Details222.MythicPlus.LogStep("BossDefeated | key level: | " .. mythicLevel .. " | " .. (mPlusTable.EncounterName or "") .. " | " .. (mPlusTable.ZoneName or ""))
|
||||||
|
|
||||||
|
--check if need to merge the trash for this boss
|
||||||
|
if (Details.mythic_plus.merge_boss_trash and not Details.MythicPlus.IsRestoredState) then
|
||||||
|
--store on an table all segments which should be merged
|
||||||
|
local segmentsToMerge = DetailsMythicPlusFrame.TrashMergeScheduled or {}
|
||||||
|
|
||||||
|
--table with all past semgnets
|
||||||
|
local segmentsTable = Details:GetCombatSegments()
|
||||||
|
|
||||||
|
--iterate among segments
|
||||||
|
for i = 1, 25 do --from the newer combat to the oldest
|
||||||
|
local pastCombat = segmentsTable [i]
|
||||||
|
--does the combat exists
|
||||||
|
if (pastCombat and not pastCombat._trashoverallalreadyadded and pastCombat.is_mythic_dungeon_trash) then
|
||||||
|
--is the combat a mythic segment from this run?
|
||||||
|
local isMythicSegment, SegmentID = pastCombat:IsMythicDungeon()
|
||||||
|
if (isMythicSegment and SegmentID == Details.mythic_dungeon_id and not pastCombat.is_boss) then
|
||||||
|
|
||||||
|
local mythicDungeonInfo = pastCombat:GetMythicDungeonInfo() -- .is_mythic_dungeon only boss, trash overall and run overall have it
|
||||||
|
if (not mythicDungeonInfo or not mythicDungeonInfo.TrashOverallSegment) then
|
||||||
|
--trash segment found, schedule to merge
|
||||||
|
table.insert(segmentsToMerge, pastCombat)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--add encounter information
|
||||||
|
segmentsToMerge.EncounterID = encounterID
|
||||||
|
segmentsToMerge.EncounterName = encounterName
|
||||||
|
segmentsToMerge.PreviousBossKilledAt = Details.MythicPlus.PreviousBossKilledAt
|
||||||
|
|
||||||
|
--reduce this boss encounter time from the trash lenght time, since the boss doesn't count towards the time spent cleaning trash
|
||||||
|
segmentsToMerge.LastBossKilledAt = time() - currentCombat:GetCombatTime()
|
||||||
|
|
||||||
|
DetailsMythicPlusFrame.TrashMergeScheduled = segmentsToMerge
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "BossDefeated() > not in combat, merging trash now")
|
||||||
|
end
|
||||||
|
--merge the trash clean up
|
||||||
|
DetailsMythicPlusFrame.MergeTrashCleanup()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function DetailsMythicPlusFrame.MergeSegmentsOnEnd() --~merge
|
||||||
|
--at the end of a mythic run, if enable on settings, merge all the segments from the mythic run into only one
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MergeSegmentsOnEnd() > starting to merge mythic segments.", "InCombatLockdown():", InCombatLockdown())
|
||||||
|
end
|
||||||
|
|
||||||
|
Details222.MythicPlus.LogStep("MergeSegmentsOnEnd started | creating the overall segment at the end of the run.")
|
||||||
|
|
||||||
|
--create a new combat to be the overall for the mythic run
|
||||||
|
Details:StartCombat()
|
||||||
|
|
||||||
|
--get the current combat just created and the table with all past segments
|
||||||
|
local newCombat = Details:GetCurrentCombat()
|
||||||
|
local segmentsTable = Details:GetCombatSegments()
|
||||||
|
|
||||||
|
newCombat.is_challenge = true
|
||||||
|
|
||||||
|
local timeInCombat = 0
|
||||||
|
local startDate, endDate = "", ""
|
||||||
|
local lastSegment
|
||||||
|
local totalSegments = 0
|
||||||
|
|
||||||
|
--copy deaths occured on all segments to the new segment, also sum the activity combat time
|
||||||
|
if (Details.mythic_plus.reverse_death_log) then
|
||||||
|
for i = 1, 40 do --copy the deaths from the first segment to the last one
|
||||||
|
local thisCombat = segmentsTable[i]
|
||||||
|
if (thisCombat and thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
|
||||||
|
newCombat:CopyDeathsFrom(thisCombat, true)
|
||||||
|
timeInCombat = timeInCombat + thisCombat:GetCombatTime()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i = 40, 1, -1 do --copy the deaths from the last segment to the new segment
|
||||||
|
local thisCombat = segmentsTable[i]
|
||||||
|
if (thisCombat) then
|
||||||
|
if (thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
|
||||||
|
newCombat:CopyDeathsFrom(thisCombat, true)
|
||||||
|
timeInCombat = timeInCombat + thisCombat:GetCombatTime()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
|
||||||
|
|
||||||
|
--tag the segment as mythic overall segment
|
||||||
|
newCombat.is_mythic_dungeon = {
|
||||||
|
StartedAt = Details.MythicPlus.StartedAt, --the start of the run
|
||||||
|
EndedAt = Details.MythicPlus.EndedAt, --the end of the run
|
||||||
|
WorldStateTimerStart = Details222.MythicPlus.WorldStateTimerStartAt,
|
||||||
|
WorldStateTimerEnd = Details222.MythicPlus.WorldStateTimerEndAt,
|
||||||
|
RunTime = Details222.MythicPlus.time,
|
||||||
|
TimeInCombat = timeInCombat,
|
||||||
|
SegmentID = "overall", --segment number within the dungeon
|
||||||
|
RunID = Details.mythic_dungeon_id,
|
||||||
|
OverallSegment = true,
|
||||||
|
ZoneName = Details.MythicPlus.DungeonName,
|
||||||
|
EJID = Details.MythicPlus.ejID,
|
||||||
|
MapID = Details222.MythicPlus.MapID,
|
||||||
|
Level = Details222.MythicPlus.Level,
|
||||||
|
OnTime = Details222.MythicPlus.OnTime,
|
||||||
|
KeystoneUpgradeLevels = Details222.MythicPlus.KeystoneUpgradeLevels,
|
||||||
|
PracticeRun = Details222.MythicPlus.PracticeRun,
|
||||||
|
OldDungeonScore = Details222.MythicPlus.OldDungeonScore,
|
||||||
|
NewDungeonScore = Details222.MythicPlus.NewDungeonScore,
|
||||||
|
IsAffixRecord = Details222.MythicPlus.IsAffixRecord,
|
||||||
|
IsMapRecord = Details222.MythicPlus.IsMapRecord,
|
||||||
|
PrimaryAffix = Details222.MythicPlus.PrimaryAffix,
|
||||||
|
IsEligibleForScore = Details222.MythicPlus.IsEligibleForScore,
|
||||||
|
UpgradeMembers = Details222.MythicPlus.UpgradeMembers,
|
||||||
|
TimeLimit = Details222.MythicPlus.TimeLimit,
|
||||||
|
DungeonName = Details222.MythicPlus.DungeonName,
|
||||||
|
DungeonID = Details222.MythicPlus.DungeonID,
|
||||||
|
DungeonTexture = Details222.MythicPlus.Texture,
|
||||||
|
DungeonBackgroundTexture = Details222.MythicPlus.BackgroundTexture,
|
||||||
|
}
|
||||||
|
|
||||||
|
--add all boss segments from this run to this new segment
|
||||||
|
for i = 1, 40 do --from the newer combat to the oldest
|
||||||
|
local thisCombat = segmentsTable[i]
|
||||||
|
if (thisCombat and thisCombat.is_mythic_dungeon_run_id == Details.mythic_dungeon_id) then
|
||||||
|
local canAddThisSegment = true
|
||||||
|
if (Details.mythic_plus.make_overall_boss_only) then
|
||||||
|
if (not thisCombat.is_boss) then
|
||||||
|
--canAddThisSegment = false --disabled
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if (canAddThisSegment) then
|
||||||
|
newCombat = newCombat + thisCombat
|
||||||
|
totalSegments = totalSegments + 1
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("MergeSegmentsOnEnd() > adding time:", thisCombat:GetCombatTime(), thisCombat.is_boss and thisCombat.is_boss.name)
|
||||||
|
end
|
||||||
|
|
||||||
|
if (endDate == "") then
|
||||||
|
local _, whenEnded = thisCombat:GetDate()
|
||||||
|
endDate = whenEnded
|
||||||
|
end
|
||||||
|
lastSegment = thisCombat
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--get the date where the first segment started
|
||||||
|
if (lastSegment) then
|
||||||
|
startDate = lastSegment:GetDate()
|
||||||
|
end
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MergeSegmentsOnEnd() > totalTime:", timeInCombat, "startDate:", startDate)
|
||||||
|
end
|
||||||
|
|
||||||
|
newCombat.total_segments_added = totalSegments
|
||||||
|
newCombat.is_mythic_dungeon_segment = true
|
||||||
|
newCombat.is_mythic_dungeon_run_id = Details.mythic_dungeon_id
|
||||||
|
|
||||||
|
--check if both values are valid, this can get invalid if the player leaves the dungeon before the timer ends or the game crashes
|
||||||
|
if (type(Details222.MythicPlus.time) == "number") then
|
||||||
|
newCombat.run_time = Details222.MythicPlus.time
|
||||||
|
Details222.MythicPlus.LogStep("GetCompletionInfo() Found, Time: " .. Details222.MythicPlus.time)
|
||||||
|
|
||||||
|
elseif (newCombat.is_mythic_dungeon.WorldStateTimerEnd and newCombat.is_mythic_dungeon.WorldStateTimerStart) then
|
||||||
|
local runTime = newCombat.is_mythic_dungeon.WorldStateTimerEnd - newCombat.is_mythic_dungeon.WorldStateTimerStart
|
||||||
|
newCombat.run_time = Details222.MythicPlus.time
|
||||||
|
Details222.MythicPlus.LogStep("World State Timers is Available, Run Time: " .. runTime .. "| start:" .. newCombat.is_mythic_dungeon.WorldStateTimerStart .. "| end:" .. newCombat.is_mythic_dungeon.WorldStateTimerEnd)
|
||||||
|
else
|
||||||
|
newCombat.run_time = timeInCombat
|
||||||
|
Details222.MythicPlus.LogStep("GetCompletionInfo() and World State Timers not Found, Activity Time: " .. timeInCombat)
|
||||||
|
end
|
||||||
|
|
||||||
|
newCombat:SetStartTime(GetTime() - timeInCombat)
|
||||||
|
newCombat:SetEndTime(GetTime())
|
||||||
|
Details222.MythicPlus.LogStep("Activity Time: " .. timeInCombat)
|
||||||
|
|
||||||
|
--set the segment time and date
|
||||||
|
newCombat:SetDate(startDate, endDate)
|
||||||
|
|
||||||
|
--immediatly finishes the segment just started
|
||||||
|
Details:SairDoCombate()
|
||||||
|
|
||||||
|
--update all windows
|
||||||
|
Details:InstanceCallDetailsFunc(Details.FadeHandler.Fader, "IN", nil, "barras")
|
||||||
|
Details:InstanceCallDetailsFunc(Details.UpdateCombatObjectInUse)
|
||||||
|
Details:InstanceCallDetailsFunc(Details.AtualizaSoloMode_AfertReset)
|
||||||
|
Details:InstanceCallDetailsFunc(Details.ResetaGump)
|
||||||
|
Details:RefreshMainWindow(-1, true)
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MergeSegmentsOnEnd() > finished merging segments.")
|
||||||
|
print("Details!", "MergeSegmentsOnEnd() > all done, check in the segments list if everything is correct, if something is weird: '/details feedback' thanks in advance!")
|
||||||
|
end
|
||||||
|
|
||||||
|
local lower_instance = Details:GetLowerInstanceNumber()
|
||||||
|
if (lower_instance) then
|
||||||
|
local instance = Details:GetInstance(lower_instance)
|
||||||
|
if (instance) then
|
||||||
|
local func = {function() end}
|
||||||
|
instance:InstanceAlert ("Showing Mythic+ Run Segment", {[[Interface\AddOns\Details\images\icons]], 16, 16, false, 434/512, 466/512, 243/512, 273/512}, 6, func, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Details:SendEvent("COMBAT_MYTHICPLUS_OVERALL_READY")
|
||||||
|
end
|
||||||
|
|
||||||
|
--after each boss fight, if enalbed on settings, create an extra segment with all trash segments from the boss just killed
|
||||||
|
function DetailsMythicPlusFrame.MergeTrashCleanup (isFromSchedule)
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MergeTrashCleanup() > running", DetailsMythicPlusFrame.TrashMergeScheduled and #DetailsMythicPlusFrame.TrashMergeScheduled)
|
||||||
|
end
|
||||||
|
|
||||||
|
local segmentsToMerge = DetailsMythicPlusFrame.TrashMergeScheduled
|
||||||
|
|
||||||
|
--table exists and there's at least one segment
|
||||||
|
if (segmentsToMerge and segmentsToMerge[1]) then
|
||||||
|
Details222.MythicPlus.LogStep("MergeTrashCleanup started.")
|
||||||
|
|
||||||
|
--the first segment is the segment where all other trash segments will be added
|
||||||
|
local masterSegment = segmentsToMerge[1]
|
||||||
|
masterSegment.is_mythic_dungeon_trash = nil
|
||||||
|
|
||||||
|
--get the current combat just created and the table with all past segments
|
||||||
|
local newCombat = masterSegment
|
||||||
|
local totalTime = newCombat:GetCombatTime()
|
||||||
|
local startDate, endDate = "", ""
|
||||||
|
local lastSegment
|
||||||
|
|
||||||
|
--add segments
|
||||||
|
for i = 2, #segmentsToMerge do --segment #1 is the host
|
||||||
|
local pastCombat = segmentsToMerge[i]
|
||||||
|
newCombat = newCombat + pastCombat
|
||||||
|
totalTime = totalTime + pastCombat:GetCombatTime()
|
||||||
|
|
||||||
|
newCombat:CopyDeathsFrom(pastCombat, true)
|
||||||
|
|
||||||
|
--tag this combat as already added to a boss trash overall
|
||||||
|
pastCombat._trashoverallalreadyadded = true
|
||||||
|
|
||||||
|
if (endDate == "") then
|
||||||
|
local _, whenEnded = pastCombat:GetDate()
|
||||||
|
endDate = whenEnded
|
||||||
|
end
|
||||||
|
lastSegment = pastCombat
|
||||||
|
end
|
||||||
|
|
||||||
|
--get the date where the first segment started
|
||||||
|
if (lastSegment) then
|
||||||
|
startDate = lastSegment:GetDate()
|
||||||
|
end
|
||||||
|
|
||||||
|
local zoneName, instanceType, difficultyID, difficultyName, maxPlayers, dynamicDifficulty, isDynamic, instanceMapID, instanceGroupSize = GetInstanceInfo()
|
||||||
|
|
||||||
|
--tag the segment as mythic overall segment
|
||||||
|
newCombat.is_mythic_dungeon = {
|
||||||
|
StartedAt = segmentsToMerge.PreviousBossKilledAt, --start of the mythic run or when the previous boss got killed
|
||||||
|
EndedAt = segmentsToMerge.LastBossKilledAt, --the time() when encounter_end got triggered
|
||||||
|
SegmentID = "trashoverall",
|
||||||
|
RunID = Details.mythic_dungeon_id,
|
||||||
|
TrashOverallSegment = true,
|
||||||
|
ZoneName = Details.MythicPlus.DungeonName,
|
||||||
|
MapID = instanceMapID,
|
||||||
|
Level = Details.MythicPlus.Level,
|
||||||
|
EJID = Details.MythicPlus.ejID,
|
||||||
|
EncounterID = segmentsToMerge.EncounterID,
|
||||||
|
EncounterName = segmentsToMerge.EncounterName or Loc ["STRING_UNKNOW"],
|
||||||
|
}
|
||||||
|
|
||||||
|
newCombat.is_mythic_dungeon_segment = true
|
||||||
|
newCombat.is_mythic_dungeon_run_id = Details.mythic_dungeon_id
|
||||||
|
|
||||||
|
--set the segment time / using a sum of combat times, this combat time is reliable
|
||||||
|
newCombat:SetStartTime (GetTime() - totalTime)
|
||||||
|
newCombat:SetEndTime (GetTime())
|
||||||
|
--set the segment date
|
||||||
|
newCombat:SetDate (startDate, endDate)
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MergeTrashCleanup() > finished merging trash segments.", Details.tabela_vigente, Details.tabela_vigente.is_boss)
|
||||||
|
end
|
||||||
|
|
||||||
|
--delete all segments that were merged
|
||||||
|
local segmentsTable = Details:GetCombatSegments()
|
||||||
|
for segmentId = #segmentsTable, 1, -1 do
|
||||||
|
local segment = segmentsTable[segmentId]
|
||||||
|
if (segment and segment._trashoverallalreadyadded) then
|
||||||
|
table.remove(segmentsTable, segmentId)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = #segmentsToMerge, 1, -1 do
|
||||||
|
table.remove(segmentsToMerge, i)
|
||||||
|
end
|
||||||
|
|
||||||
|
--call the segment removed event to notify third party addons
|
||||||
|
Details:SendEvent("DETAILS_DATA_SEGMENTREMOVED")
|
||||||
|
|
||||||
|
--update all windows
|
||||||
|
Details:InstanceCallDetailsFunc(Details.FadeHandler.Fader, "IN", nil, "barras")
|
||||||
|
Details:InstanceCallDetailsFunc(Details.UpdateCombatObjectInUse)
|
||||||
|
Details:InstanceCallDetailsFunc(Details.AtualizaSoloMode_AfertReset)
|
||||||
|
Details:InstanceCallDetailsFunc(Details.ResetaGump)
|
||||||
|
Details:RefreshMainWindow(-1, true)
|
||||||
|
else
|
||||||
|
Details222.MythicPlus.LogStep("MergeTrashCleanup | no segments to merge.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--this function merges trash segments after all bosses of the mythic dungeon are defeated
|
||||||
|
--happens when the group finishes all bosses but don't complete the trash requirement
|
||||||
|
function DetailsMythicPlusFrame.MergeRemainingTrashAfterAllBossesDone()
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MergeRemainingTrashAfterAllBossesDone() > running, #segments: ", #DetailsMythicPlusFrame.TrashMergeScheduled2, "trash overall table:", DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat)
|
||||||
|
end
|
||||||
|
|
||||||
|
Details222.MythicPlus.LogStep("running MergeRemainingTrashAfterAllBossesDone.")
|
||||||
|
|
||||||
|
local segmentsToMerge = DetailsMythicPlusFrame.TrashMergeScheduled2
|
||||||
|
local overallCombat = DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat
|
||||||
|
|
||||||
|
--needs to merge, add the total combat time, set the date end to the date of the first segment
|
||||||
|
local totalTime = 0
|
||||||
|
local startDate, endDate = "", ""
|
||||||
|
local lastSegment
|
||||||
|
|
||||||
|
--add segments
|
||||||
|
for i, pastCombat in ipairs(segmentsToMerge) do
|
||||||
|
overallCombat = overallCombat + pastCombat
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("MergeRemainingTrashAfterAllBossesDone() > segment added")
|
||||||
|
end
|
||||||
|
totalTime = totalTime + pastCombat:GetCombatTime()
|
||||||
|
|
||||||
|
--tag this combat as already added to a boss trash overall
|
||||||
|
pastCombat._trashoverallalreadyadded = true
|
||||||
|
|
||||||
|
if (endDate == "") then --get the end date of the first index only
|
||||||
|
local _, whenEnded = pastCombat:GetDate()
|
||||||
|
endDate = whenEnded
|
||||||
|
end
|
||||||
|
lastSegment = pastCombat
|
||||||
|
end
|
||||||
|
|
||||||
|
--set the segment time / using a sum of combat times, this combat time is reliable
|
||||||
|
local startTime = overallCombat:GetStartTime()
|
||||||
|
overallCombat:SetStartTime (startTime - totalTime)
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("MergeRemainingTrashAfterAllBossesDone() > total combat time:", totalTime)
|
||||||
|
end
|
||||||
|
|
||||||
|
--set the segment date
|
||||||
|
local startDate = overallCombat:GetDate()
|
||||||
|
overallCombat:SetDate (startDate, endDate)
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("MergeRemainingTrashAfterAllBossesDone() > new end date:", endDate)
|
||||||
|
end
|
||||||
|
|
||||||
|
local mythicDungeonInfo = overallCombat:GetMythicDungeonInfo()
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("MergeRemainingTrashAfterAllBossesDone() > elapsed time before:", mythicDungeonInfo.EndedAt - mythicDungeonInfo.StartedAt)
|
||||||
|
end
|
||||||
|
mythicDungeonInfo.StartedAt = mythicDungeonInfo.StartedAt - (Details.MythicPlus.EndedAt - Details.MythicPlus.PreviousBossKilledAt)
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("MergeRemainingTrashAfterAllBossesDone() > elapsed time after:", mythicDungeonInfo.EndedAt - mythicDungeonInfo.StartedAt)
|
||||||
|
end
|
||||||
|
|
||||||
|
--remove trash segments from the segment history after the merge
|
||||||
|
local removedCurrentSegment = false
|
||||||
|
local segmentsTable = Details:GetCombatSegments()
|
||||||
|
for _, pastCombat in ipairs(segmentsToMerge) do
|
||||||
|
for i = #segmentsTable, 1, -1 do
|
||||||
|
local segment = segmentsTable [i]
|
||||||
|
if (segment == pastCombat) then
|
||||||
|
--remove the segment
|
||||||
|
if (Details.tabela_vigente == segment) then
|
||||||
|
removedCurrentSegment = true
|
||||||
|
end
|
||||||
|
table.remove(segmentsTable, i)
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = #segmentsToMerge, 1, -1 do
|
||||||
|
table.remove(segmentsToMerge, i)
|
||||||
|
end
|
||||||
|
|
||||||
|
if (removedCurrentSegment) then
|
||||||
|
--find another current segment
|
||||||
|
local segmentsTable = Details:GetCombatSegments()
|
||||||
|
Details.tabela_vigente = segmentsTable [1]
|
||||||
|
|
||||||
|
if (not Details.tabela_vigente) then
|
||||||
|
--assuming there's no segment from the dungeon run
|
||||||
|
Details:EntrarEmCombate()
|
||||||
|
Details:SairDoCombate()
|
||||||
|
end
|
||||||
|
|
||||||
|
--update all windows
|
||||||
|
Details:InstanceCallDetailsFunc(Details.FadeHandler.Fader, "IN", nil, "barras")
|
||||||
|
Details:InstanceCallDetailsFunc(Details.UpdateCombatObjectInUse)
|
||||||
|
Details:InstanceCallDetailsFunc(Details.AtualizaSoloMode_AfertReset)
|
||||||
|
Details:InstanceCallDetailsFunc(Details.ResetaGump)
|
||||||
|
Details:RefreshMainWindow(-1, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
Details222.MythicPlus.LogStep("delete_trash_after_merge | concluded")
|
||||||
|
Details:SendEvent("DETAILS_DATA_SEGMENTREMOVED")
|
||||||
|
|
||||||
|
DetailsMythicPlusFrame.TrashMergeScheduled2 = nil
|
||||||
|
DetailsMythicPlusFrame.TrashMergeScheduled2_OverallCombat = nil
|
||||||
|
|
||||||
|
if (DetailsMythicPlusFrame.DevelopmentDebug) then
|
||||||
|
print("Details!", "MergeRemainingTrashAfterAllBossesDone() > done merging")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1201,6 +1201,7 @@ local default_player_data = {
|
|||||||
ocd_tracker = {
|
ocd_tracker = {
|
||||||
enabled = false,
|
enabled = false,
|
||||||
cooldowns = {},
|
cooldowns = {},
|
||||||
|
ignored_cooldowns = {},
|
||||||
frames = {
|
frames = {
|
||||||
["defensive-raid"] = {},
|
["defensive-raid"] = {},
|
||||||
["defensive-target"] = {},
|
["defensive-target"] = {},
|
||||||
|
|||||||
Reference in New Issue
Block a user