diff --git a/.gitignore b/.gitignore index bdffba39..1f49f5a0 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ photoshop/ten_years_skin.tga plugins/Details_EncounterDetails/Libs/LibLuaServer/LuaServerDefinitions.lua plugins/Details_EncounterDetails/Definitions.lua *.afphoto~lock~ +annotations.txt diff --git a/Details.toc b/Details.toc index e668f7e7..851d5876 100644 --- a/Details.toc +++ b/Details.toc @@ -57,9 +57,10 @@ functions\currentdps.lua functions\report.lua functions\rowanimation.lua functions\raidinfo.lua -functions\dungeon.lua +functions\mythicdungeon\mythicdungeon.lua +functions\mythicdungeon\data_capture.lua +functions\mythicdungeon\segments.lua functions\pack.lua -functions\mythicdungeon.lua functions\immersion.lua functions\schedules.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_phaseframes.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_main.lua frames\window_custom.lua diff --git a/Details_Classic.toc b/Details_Classic.toc index e836309f..45a6981a 100644 --- a/Details_Classic.toc +++ b/Details_Classic.toc @@ -54,9 +54,10 @@ functions\currentdps.lua functions\report.lua functions\rowanimation.lua functions\raidinfo.lua -functions\dungeon.lua +functions\mythicdungeon\segments.lua +functions\mythicdungeon\mythicdungeon.lua +functions\mythicdungeon\data_capture.lua functions\pack.lua -functions\mythicdungeon.lua functions\immersion.lua functions\schedules.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_phaseframes.lua frames\window_mythicplus\window_mythic_breakdown.lua +frames\window_mythicplus\window_end_of_run.lua frames\window_report.lua frames\window_main.lua frames\window_custom.lua diff --git a/Details_Wrath.toc b/Details_Wrath.toc index f9b3bc1b..dd75d739 100644 --- a/Details_Wrath.toc +++ b/Details_Wrath.toc @@ -54,9 +54,10 @@ functions\currentdps.lua functions\report.lua functions\rowanimation.lua functions\raidinfo.lua -functions\dungeon.lua +functions\mythicdungeon\segments.lua +functions\mythicdungeon\mythicdungeon.lua +functions\mythicdungeon\data_capture.lua functions\pack.lua -functions\mythicdungeon.lua functions\immersion.lua functions\schedules.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_phaseframes.lua frames\window_mythicplus\window_mythic_breakdown.lua +frames\window_mythicplus\window_end_of_run.lua frames\window_report.lua frames\window_main.lua frames\window_custom.lua diff --git a/Libs/DF/definitions.lua b/Libs/DF/definitions.lua index 5cbe27fa..b9184df8 100644 --- a/Libs/DF/definitions.lua +++ b/Libs/DF/definitions.lua @@ -48,6 +48,7 @@ ---@field internalFunctions table ---@field OptionsFunctions df_optionsmixin ---@field GlobalWidgetControlNames table +---@field DefaultRoundedCornerPreset table ---@field RoundedCornerPanelMixin df_roundedcornermixin ---@field Schedules df_schedule ---@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 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 +---@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 diff --git a/Libs/DF/dropdown.lua b/Libs/DF/dropdown.lua index cff92a67..c09c479d 100644 --- a/Libs/DF/dropdown.lua +++ b/Libs/DF/dropdown.lua @@ -397,7 +397,7 @@ function DropDownMetaFunctions:Select(optionName, byOptionNumber, bOnlyShown, ru return false end - local optionsTable = DF:Dispatch(self.func, self) --399 + local runOkay, optionsTable = xpcall(self.func, geterrorhandler(), self) if (#optionsTable == 0) then self:NoOption(true) @@ -563,6 +563,11 @@ function DropDownMetaFunctions:Selected(thisOption) self.statusbar:SetTexture([[Interface\Tooltips\CHATBUBBLE-BACKGROUND]]) 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 local r, g, b, a = DF:ParseColors(thisOption.color) self.label:SetTextColor(r, g, b, a) diff --git a/Libs/DF/editor.lua b/Libs/DF/editor.lua index e8bf7265..ce7d11ad 100644 --- a/Libs/DF/editor.lua +++ b/Libs/DF/editor.lua @@ -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 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 +---@field editingObject uiobject +---@field editingProfileTable table +---@field editingProfileMap table +---@field editingOptions df_editobjectoptions +---@field editingExtraOptions table +---@field moverGuideLines table +---@field onEditCallback function +---@field optionsFrame frame +---@field overTheTopFrame frame +---@field objectSelector df_scrollbox +---@field moverFrame frame +---@field canvasScrollBox df_canvasscrollbox + ---@class df_editor_attribute ----@field name string? +---@field key string? ---@field label string? ---@field widget string ---@field default any? @@ -32,19 +49,31 @@ local _ ---@field usedecimals boolean? ---@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 local attributes = { ---@type df_editor_attribute[] FontString = { { - name = "text", + key = "text", label = "Text", widget = "textentry", default = "font string text", setter = function(widget, value) widget:SetText(value) end, }, { - name = "size", + key = "size", label = "Size", widget = "range", minvalue = 5, @@ -52,7 +81,7 @@ local attributes = { setter = function(widget, value) widget:SetFont(widget:GetFont(), value, select(3, widget:GetFont())) end }, { - name = "font", + key = "font", label = "Font", widget = "fontdropdown", setter = function(widget, value) @@ -61,32 +90,32 @@ local attributes = { end }, { - name = "color", + key = "color", label = "Color", widget = "color", setter = function(widget, value) widget:SetTextColor(unpack(value)) end }, { - name = "alpha", + key = "alpha", label = "Alpha", widget = "range", setter = function(widget, value) widget:SetAlpha(value) end }, {widget = "blank"}, { - name = "shadow", + key = "shadow", label = "Draw Shadow", 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 }, { - name = "shadowcolor", + key = "shadowcolor", label = "Shadow Color", widget = "color", setter = function(widget, value) widget:SetShadowColor(unpack(value)) end }, { - name = "shadowoffsetx", + key = "shadowoffsetx", label = "Shadow X Offset", widget = "range", minvalue = -10, @@ -94,7 +123,7 @@ local attributes = { setter = function(widget, value) widget:SetShadowOffset(value, select(2, widget:GetShadowOffset())) end }, { - name = "shadowoffsety", + key = "shadowoffsety", label = "Shadow Y Offset", widget = "range", minvalue = -10, @@ -102,20 +131,20 @@ local attributes = { setter = function(widget, value) widget:SetShadowOffset(widget:GetShadowOffset(), value) end }, { - name = "outline", + key = "outline", label = "Outline", widget = "outlinedropdown", setter = function(widget, value) widget:SetFont(widget:GetFont(), select(2, widget:GetFont()), value) end }, {widget = "blank"}, { - name = "anchor", + key = "anchor", label = "Anchor", widget = "anchordropdown", setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end }, { - name = "anchoroffsetx", + key = "anchoroffsetx", label = "Anchor X Offset", widget = "range", minvalue = -100, @@ -123,7 +152,7 @@ local attributes = { setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end }, { - name = "anchoroffsety", + key = "anchoroffsety", label = "Anchor Y Offset", widget = "range", minvalue = -100, @@ -131,7 +160,7 @@ local attributes = { setter = function(widget, value) detailsFramework:SetAnchor(widget, value, widget:GetParent()) end }, { - name = "rotation", + key = "rotation", label = "Rotation", widget = "range", usedecimals = true, @@ -140,7 +169,7 @@ local attributes = { setter = function(widget, value) widget:SetRotation(value) end }, { - name = "scale", + key = "scale", label = "Scale", widget = "range", usedecimals = true, @@ -161,24 +190,38 @@ local attributes = { ---@field GetOptionsFrame fun(self:df_editor):frame ---@field GetCanvasScrollBox fun(self:df_editor):df_canvasscrollbox ---@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 CreateMoverGuideLines fun(self:df_editor) ---@field GetOverTheTopFrame fun(self:df_editor):frame ---@field GetMoverFrame fun(self:df_editor):frame ---@field StartObjectMovement fun(self:df_editor, anchorSettings:df_anchor) ---@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 ---@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 use_guide_lines boolean if true guide lines are shown when the object is being moved +---@field text_template table ---@type df_editobjectoptions local editObjectDefaultOptions = { - use_colon = true, + use_colon = false, can_move = true, use_guide_lines = true, + text_template = detailsFramework:GetTemplate("font", "OPTIONS_FONT_TEMPLATE"), } local getParentTable = function(profileTable, profileKey) @@ -269,12 +312,14 @@ detailsFramework.EditorMixin = { self.onEditCallback = nil local object = registeredObject.object - local profileTable = registeredObject.profiletable local profileKeyMap = registeredObject.profilekeymap local extraOptions = registeredObject.extraoptions local callback = registeredObject.callback 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 self.editingObject = object self.editingProfileMap = profileKeyMap @@ -338,7 +383,7 @@ detailsFramework.EditorMixin = { end end, - PrepareObjectForEditing = function(self) + PrepareObjectForEditing = function(self) --~edit --get the object and its profile table with the current values local object = self:GetEditingObject() local profileTable, profileMap = self:GetEditingProfile() @@ -390,7 +435,7 @@ detailsFramework.EditorMixin = { menuOptions[#menuOptions+1] = {type = "blank"} else --get the key to be used on profile table - local profileKey = profileMap[option.name] + local profileKey = profileMap[option.key] local value --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 maxValue = option.maxvalue - if (option.name == "anchoroffsetx") then + if (option.key == "anchoroffsetx") then minValue = -object:GetParent():GetWidth()/2 maxValue = object:GetParent():GetWidth()/2 - elseif (option.name == "anchoroffsety") then + elseif (option.key == "anchoroffsety") then minValue = -object:GetParent():GetHeight()/2 maxValue = object:GetParent():GetHeight()/2 end @@ -421,7 +466,7 @@ detailsFramework.EditorMixin = { if (bHasValue) then 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 end @@ -446,20 +491,20 @@ detailsFramework.EditorMixin = { parentTable[4] = alpha newValue = parentTable - else - detailsFramework.table.setfrompath(profileTable, profileKey, newValue) end + detailsFramework.table.setfrompath(profileTable, profileKey, newValue) + if (self:GetOnEditCallback()) then - self:GetOnEditCallback()(object, option.name, newValue, profileTable, profileKey) + self:GetOnEditCallback()(object, option.key, newValue, profileTable, profileKey) end --update the widget visual --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 - if (option.name == "anchor") then + if (option.key == "anchor") then anchorSettings.x = 0 anchorSettings.y = 0 end @@ -479,7 +524,7 @@ detailsFramework.EditorMixin = { max = maxValue, step = option.step, usedecimals = option.usedecimals, - id = option.name, + id = option.key, } end end @@ -504,13 +549,14 @@ detailsFramework.EditorMixin = { optionsFrame:SetHeight(optionsFrameHeight) --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_switch_template = detailsFramework:GetTemplate("switch", "OPTIONS_CHECKBOX_TEMPLATE") local options_slider_template = detailsFramework:GetTemplate("slider", "OPTIONS_SLIDER_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 self:StartObjectMovement(anchorSettings) @@ -539,8 +585,14 @@ detailsFramework.EditorMixin = { 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() - moverFrame:SetSize(objectWidth, objectHeight) + moverFrame:SetSize(moverWidth, moverHeight) detailsFramework:SetAnchor(moverFrame, anchorSettings, object:GetParent()) local currentPosX, currentPosY @@ -557,6 +609,10 @@ detailsFramework.EditorMixin = { moverFrame:StopMovingOrSizing() moverFrame.bIsMoving = false + --0.64 UIParent + --0.96 object + --local scale = object:GetEffectiveScale() / UIParent:GetEffectiveScale() --1.5 + local originX = anchorSettings.x local originY = anchorSettings.y @@ -565,8 +621,11 @@ detailsFramework.EditorMixin = { local xOffset = newPosX - currentPosX local yOffset = newPosY - currentPosY - anchorSettings.x = originX + xOffset - anchorSettings.y = originY + yOffset + xOffset = xOffset + yOffset = yOffset + + anchorSettings.x = (originX + xOffset) + anchorSettings.y = (originY + yOffset) local anchorXSlider = optionsFrame:GetWidgetById("anchoroffsetx") anchorXSlider:SetValueNoCallback(anchorSettings.x) @@ -576,12 +635,24 @@ detailsFramework.EditorMixin = { object:ClearAllPoints() 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) --detailsFramework:SetAnchor(moverFrame, anchorSettings) --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 (false and moverFrame.bIsMoving) then --object:ClearAllPoints() @@ -607,19 +678,6 @@ detailsFramework.EditorMixin = { currentPosX, currentPosY = newPosX, newPosY 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, @@ -638,7 +696,36 @@ detailsFramework.EditorMixin = { moverFrame:Hide() 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(object.GetObjectType, "RegisterObjectToEdit() expects an UIObject on #1 parameter.") assert(type(profileTable) == "table", "RegisterObjectToEdit() expects a table on #4 parameter.") @@ -671,6 +758,7 @@ detailsFramework.EditorMixin = { label = localizedLabel, id = id, profiletable = profileTable, + subtablepath = subTablePath, profilekeymap = profileKeyMap, extraoptions = extraOptions or {}, callback = callback, @@ -741,6 +829,10 @@ detailsFramework.EditorMixin = { local editorFrame = self local refreshFunc = function(self, data, offset, totalLines) --~refresh + self.SelectionTexture:Hide() + self.SelectionTexture:ClearAllPoints() + local objectCurrentBeingEdited = editorFrame:GetEditingObject() + for i = 1, totalLines do local index = i + offset ---@type df_editor_objectinfo @@ -749,16 +841,20 @@ detailsFramework.EditorMixin = { if (objectRegistered) then local line = self:GetLine(i) 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 - line.Icon:SetTexture([[Interface\AnimCreate\AnimCreateIcons]]) - line.Icon:SetTexCoord(2/4, 3/4, 0, 1/4) + if (objectRegistered.object:GetObjectType() == "Texture") then + line.Icon:SetAtlas("AnimCreate_Icon_Texture") + + elseif (objectRegistered.object:GetObjectType() == "FontString") then + line.Icon:SetAtlas("AnimCreate_Icon_Text") end line.Label:SetText(objectRegistered.label) + + if (objectRegistered.object == objectCurrentBeingEdited) then + self.SelectionTexture:SetAllPoints(line) + self.SelectionTexture:Show() + end end end end @@ -775,14 +871,13 @@ detailsFramework.EditorMixin = { line:SetBackdropColor(.1, .1, .1, .4) end - detailsFramework:Mixin(line, detailsFramework.HeaderFunctions) - - --line:SetScript("OnEnter", lineOnEnter) - --line:SetScript("OnLeave", lineOnLeave) + detailsFramework:CreateHighlightTexture(line, "HighlightTexture") + detailsFramework:Mixin(line, detailsFramework.HeaderFunctions) line:SetScript("OnClick", function(self) local objectRegistered = editorFrame:GetObjectByIndex(self.index) editorFrame:EditObject(objectRegistered) + editorFrame.objectSelector:RefreshMe() end) --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) detailsFramework:ReskinSlider(selectObjectScrollBox) + local selectionTexture = selectObjectScrollBox:CreateTexture(nil, "overlay") + selectionTexture:SetColorTexture(1, 1, 0, 0.2) + selectObjectScrollBox.SelectionTexture = selectionTexture + function selectObjectScrollBox:RefreshMe() selectObjectScrollBox:SetData(editorFrame:GetAllRegisteredObjects()) selectObjectScrollBox:Refresh() @@ -831,8 +930,11 @@ detailsFramework.EditorMixin = { ---@field object_list_height number ---@field object_list_lines 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 = { width = 400, height = 548, @@ -842,36 +944,9 @@ local editorDefaultOptions = { object_list_height = 420, object_list_lines = 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 ----@field editingObject uiobject ----@field editingProfileTable table ----@field editingProfileMap table ----@field editingOptions df_editobjectoptions ----@field editingExtraOptions table ----@field moverGuideLines table ----@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) name = name or ("DetailsFrameworkEditor" .. math.random(100000, 10000000)) local editorFrame = CreateFrame("frame", name, parent, "BackdropTemplate") diff --git a/Libs/DF/fw.lua b/Libs/DF/fw.lua index d6dd11eb..5b3a9a20 100644 --- a/Libs/DF/fw.lua +++ b/Libs/DF/fw.lua @@ -1,6 +1,6 @@ -local dversion = 507 +local dversion = 510 local major, minor = "DetailsFramework-1.0", dversion 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, ...) end +DF.DefaultRoundedCornerPreset = { + roundness = 6, + color = {.1, .1, .1, 0.98}, + border_color = {.05, .05, .05, 0.834}, +} + DF.internalFunctions = DF.internalFunctions or {} local PixelUtil = PixelUtil or DFPixelUtil @@ -506,6 +512,16 @@ function DF:FadeFrame(frame, t) 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 @@ -804,6 +820,7 @@ function DF.table.deploy(t1, t2) return t1 end +--/run print (DetailsFramework.table.dump({{1, 2}, {2, 3}, {4, 5}})) local function tableToString(t, resultString, deep, seenTables) resultString = resultString or "" deep = deep or 0 @@ -853,7 +870,11 @@ local function tableToString(t, resultString, deep, seenTables) resultString = resultString .. space .. "[\"" .. key .. "\"] = \"|cFFfff1c1" .. value .. "|r\",\n" 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 resultString = resultString .. space .. "[\"" .. key .. "\"] = |cFFC586C0function|r,\n" diff --git a/Libs/DF/loadconditions.lua b/Libs/DF/loadconditions.lua index a4bbd50d..c9fe9380 100644 --- a/Libs/DF/loadconditions.lua +++ b/Libs/DF/loadconditions.lua @@ -100,7 +100,7 @@ local default_load_conditions_frame_options = { function detailsFramework:CreateLoadFilterParser(callback) local filterFrame = CreateFrame("frame") - + if IS_WOW_PROJECT_MAINLINE then filterFrame:RegisterEvent("PLAYER_SPECIALIZATION_CHANGED") filterFrame:RegisterEvent("TRAIT_CONFIG_LIST_UPDATED") @@ -117,11 +117,47 @@ function detailsFramework:CreateLoadFilterParser(callback) filterFrame:RegisterEvent("PLAYER_REGEN_ENABLED") filterFrame:RegisterEvent("PLAYER_REGEN_DISABLED") + filterFrame:RegisterEvent("CHAT_MSG_LOOT") + filterFrame:SetScript("OnEvent", function(self, event, ...) if (event == "ENCOUNTER_START") then --triggers before regen_disabled local 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 == "ENCOUNTER_END") then @@ -157,7 +193,8 @@ function detailsFramework:CreateLoadFilterParser(callback) detailsFramework.CurrentPlayerRole = assignedRole 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 diff --git a/Libs/DF/panel.lua b/Libs/DF/panel.lua index 225e57e3..b877aa32 100644 --- a/Libs/DF/panel.lua +++ b/Libs/DF/panel.lua @@ -2085,7 +2085,7 @@ local no_options = {} ---NoCloseButton = false, --if true, won't show the close button ---NoTitleBar = false, --if true, don't create the title bar ---RoundedCorners = false, --use rounded corners if true ----@class simplepanel +---@class simplepanel : frame ---@field TitleBar frame ---@field Title fontstring ---@field Close button diff --git a/Libs/DF/picture.lua b/Libs/DF/picture.lua index 9e2936c6..24915a3a 100644 --- a/Libs/DF/picture.lua +++ b/Libs/DF/picture.lua @@ -367,3 +367,22 @@ detailsFramework:Mixin(ImageMetaFunctions, detailsFramework.ScriptHookMixin) return ImageObject 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 \ No newline at end of file diff --git a/Libs/DF/rounded_panel.lua b/Libs/DF/rounded_panel.lua index e997b5a2..d7e3d998 100644 --- a/Libs/DF/rounded_panel.lua +++ b/Libs/DF/rounded_panel.lua @@ -411,6 +411,11 @@ detailsFramework.RoundedCornerPanelMixin = { alignment = alignment:lower() 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 elseif (alignment == "horizontal") then @@ -678,6 +683,68 @@ function detailsFramework:AddRoundedCornersToFrame(frame, preset) applyPreset(frame, preset) else 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 diff --git a/Libs/DF/savedvars.lua b/Libs/DF/savedvars.lua index 52ab0f23..3309016f 100644 --- a/Libs/DF/savedvars.lua +++ b/Libs/DF/savedvars.lua @@ -15,6 +15,16 @@ local UnitGUID = UnitGUID --create namespace 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 ---@param addonObject df_addon the addon object created by detailsFramework:CreateNewAddOn() ---@return table @@ -83,7 +93,7 @@ end ---@param addonObject df_addon the addon object created by detailsFramework:CreateNewAddOn() ---@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) assert(type(addonObject) == "table", "SetProfile: addonObject must be a table.") assert(type(profileName) == "string", "SetProfile: profileName must be a string.") @@ -137,4 +147,147 @@ function detailsFramework.SavedVars.SaveProfile(addonObject) savedVariables.profiles[playerProfileId] = profileTable end end -end \ No newline at end of file +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 diff --git a/Libs/DF/schedules.lua b/Libs/DF/schedules.lua index 6141da18..07252fe8 100644 --- a/Libs/DF/schedules.lua +++ b/Libs/DF/schedules.lua @@ -8,6 +8,8 @@ local C_Timer = _G.C_Timer local unpack = table.unpack or _G.unpack local GetTime = GetTime +local CONST_DEBUG_ENABLED = false + --make a namespace for schedules detailsFramework.Schedules = detailsFramework.Schedules or {} @@ -67,10 +69,11 @@ local triggerScheduledLoop = function(tickerObject) local payload = tickerObject.payload local callback = tickerObject.callback - local result, errortext = pcall(callback, unpack(payload)) - if (not result) then - detailsFramework:Msg("error on scheduler: ",tickerObject.path , tickerObject.name, errortext) - end + --local result, errortext = pcall(callback, unpack(payload)) + local runOkay, result = xpcall(callback, geterrorhandler(), unpack(payload)) + --if (not result) then + -- detailsFramework:Msg("error on scheduler: ",tickerObject.path , tickerObject.name, errortext) + --end local checkPointCallback = tickerObject.checkPointCallback if (checkPointCallback) then @@ -127,10 +130,11 @@ local triggerScheduledTick = function(tickerObject) local payload = tickerObject.payload local callback = tickerObject.callback - local result, errortext = pcall(callback, unpack(payload)) - if (not result) then - detailsFramework:Msg("error on scheduler: ",tickerObject.path , tickerObject.name, errortext) - end + local runOkay, result = xpcall(callback, geterrorhandler(), unpack(payload)) + --local result, errortext = pcall(callback, unpack(payload)) + --if (not result) then + -- detailsFramework:Msg("error on scheduler: ",tickerObject.path , tickerObject.name, errortext) + --end return result end @@ -142,8 +146,8 @@ function detailsFramework.Schedules.NewTicker(time, callback, ...) newTicker.callback = callback --debug - newTicker.path = debugstack() - -- + newTicker.path = CONST_DEBUG_ENABLED and debugstack() or "" + return newTicker end @@ -156,8 +160,7 @@ function detailsFramework.Schedules.NewTimer(time, callback, ...) newTimer.expireAt = GetTime() + time --debug - newTimer.path = debugstack() - -- + newTimer.path = CONST_DEBUG_ENABLED and debugstack() or "" return newTimer end diff --git a/Libs/DF/scrollbox.lua b/Libs/DF/scrollbox.lua index f315daa2..8065d542 100644 --- a/Libs/DF/scrollbox.lua +++ b/Libs/DF/scrollbox.lua @@ -26,10 +26,12 @@ detailsFramework.ScrollBoxFunctions = { Refresh = function(self) --hide all frames and tag as not in use self._LinesInUse = 0 + --self.Frames has a list of frames used by the scrollbox for index, frame in ipairs(self.Frames) do if (not self.DontHideChildrenOnPreRefresh) then frame:Hide() end + --set the frame as not in use frame._InUse = nil end @@ -39,6 +41,7 @@ detailsFramework.ScrollBoxFunctions = { offset = self:GetOffsetFaux() end + --before starting the refresh, check if there's a pre refresh function and call it if (self.pre_refresh_func) then detailsFramework:Dispatch(self.pre_refresh_func, self, self.data, offset, self.LineAmount) end @@ -428,6 +431,24 @@ function detailsFramework:CreateGridScrollBox(parent, name, refreshFunc, data, c return scrollBox 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 --also need to make sure this can work with any data (global, class, spec) and aura type (buff, debuff) diff --git a/Libs/DF/textentry.lua b/Libs/DF/textentry.lua index feec402f..81b81720 100644 --- a/Libs/DF/textentry.lua +++ b/Libs/DF/textentry.lua @@ -148,6 +148,10 @@ detailsFramework.TextEntryCounter = detailsFramework.TextEntryCounter or 1 end end + local smember_fontsize = function(object, value) + return detailsFramework:SetFontSize(object.editbox, value) + end + --text horizontal pos local smember_horizontalpos = function(object, 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["multiline"] = smember_multiline TextEntryMetaFunctions.SetMembers["align"] = smember_horizontalpos + TextEntryMetaFunctions.SetMembers["fontsize"] = smember_fontsize + TextEntryMetaFunctions.SetMembers["textsize"] = smember_fontsize TextEntryMetaFunctions.__newindex = function(object, key, value) local func = TextEntryMetaFunctions.SetMembers[key] @@ -544,6 +550,7 @@ end ---@field text any ---@field multiline any ---@field align any +---@field fontsize any ---@field ShouldOptimizeAutoComplete boolean? ---@field SetTemplate fun(self:df_textentry, template:table) ---@field Disable fun(self:df_textentry) diff --git a/Libs/LibLuaServer/LibLuaServer.lua b/Libs/LibLuaServer/LibLuaServer.lua index 335599b4..8f666006 100644 --- a/Libs/LibLuaServer/LibLuaServer.lua +++ b/Libs/LibLuaServer/LibLuaServer.lua @@ -616,3 +616,1273 @@ ---@field SetFocus fun(self:editbox, focus:boolean) ---@field HasFocus fun(self:editbox) : boolean return true if the editbox has focus ---@field HighlightText fun(self:editbox, start:number?, finish:number?) select a portion of the text, passing zero will select the entire text + + +--functions +C_ChatInfo = true +unpack = true +abs = true +IsInGroup = true +Ambiguate = true +IsInRaid = true +LE_PARTY_CATEGORY_INSTANCE = true +C_Timer = true +ceil = true +strsplit = true +INVSLOT_FIRST_EQUIPPED = true +INVSLOT_LAST_EQUIPPED = true +floor = true +tremove = true +GetSpellCharges = function(spellId) end +AddTrackedAchievement = true +CanShowAchievementUI = true +ClearAchievementComparisonUnit = true +GetAchievementCategory = true +GetAchievementComparisonInfo = true +GetAchievementCriteriaInfo = true +GetAchievementInfo = true +GetAchievementInfoFromCriteria = true +GetAchievementLink = true +GetAchievementNumCriteria = true +GetSpecializationInfo = true +GetAchievementNumRewards = true +GetCategoryInfo = true +GetCategoryList = true +GetSpecialization = true +GetCategoryNumAchievements = true +GetComparisonAchievementPoints = true +GetComparisonCategoryNumAchievements = true +GetComparisonStatistic = true +GetLatestCompletedAchievements = true +GetLatestCompletedComparisonAchievements = true +GetLatestUpdatedComparisonStatsGetLatestUpdatedStats = true +GetNextAchievement = true +GetNumComparisonCompletedAchievements = true +GetNumCompletedAchievements = true +GetPreviousAchievement = true +GetStatistic = true +GetStatisticsCategoryList = true +GetTotalAchievementPoints = true +GetTrackedAchievements = true +GetNumTrackedAchievements = true +RemoveTrackedAchievement = true +SetAchievementComparisonUnit = true +ActionButtonDown = true +ActionButtonUp = true +ActionHasRange = true +CameraOrSelectOrMoveStart = true +CameraOrSelectOrMoveStop = true +ChangeActionBarPage = true +GetActionBarPage = true +GetActionBarToggles = true +GetActionCooldown = true +GetActionCount = true +GetActionInfo = true +GetActionText = true +GetActionTexture = true +GetBonusBarOffset = true +GetMouseButtonClicked = true +GetMultiCastBarOffset = true +GetPossessInfo = true +HasAction = true +IsActionInRange = true +IsAttackAction = true +IsAutoRepeatAction = true +IsCurrentAction = true +IsConsumableAction = true +IsEquippedAction = true +IsUsableAction = true +PetHasActionBar = true +PickupAction = true +PickupPetAction = true +PlaceAction = true +SetActionBarToggles = true +StopAttack = true +TurnOrActionStart = true +TurnOrActionStop = true +UseAction = true +AcceptDuel = true +AttackTarget = true +CancelDuel = true +CancelLogout = true +ClearTutorials = true +CancelSummon = true +ConfirmSummon = true +DescendStop = true +Dismount = true +FlagTutorial = true +ForceQuit = true +GetPVPTimer = true +GetSummonConfirmAreaName = true +GetSummonConfirmSummoner = true +GetSummonConfirmTimeLeft = true +RandomRoll = true +SetPVP = true +StartDuel = true +TogglePVP = true +ToggleSheath = true +UseSoulstone = true +CanSolveArtifact = true +UIParent = true +GetArtifactInfoByRace = true +GetArtifactProgress = true +GetNumArtifactsByRace = true +GetSelectedArtifactInfo = true +IsArtifactCompletionHistoryAvailable = true +ItemAddedToArtifact = true +RemoveItemFromArtifact = true +RequestArtifactCompletionHistory = true +SocketItemToArtifact = true +AcceptArenaTeam = true +ArenaTeamInviteByName = true +ArenaTeamSetLeaderByName = true +ArenaTeamLeave = true +ArenaTeamRoster = true +ArenaTeamUninviteByName = true +ArenaTeamDisband = true +DeclineArenaTeam = true +GetArenaTeam = true +GetArenaTeamGdfInf = true +oGetArenaTeamRosterInfo = true +GetBattlefieldTeamInfo = true +GetCurrentArenaSeason = true +GetInspectArenaTeamData = true +GetNumArenaTeamMembers = true +GetPreviousArenaSeason = true +IsActiveBattlefieldArena = true +IsArenaTeamCaptain = true +IsInArenaTeam = true +CalculateAuctionDeposit = true +CanCancelAuction = true +CancelSell = true +CanSendAuctionQuery = true +CancelAuction = true +ClickAuctionSellItemButton = true +CloseAuctionHouse = true +GetAuctionHouseDepositRate = true +GetAuctionInvTypes = true +GetAuctionItemClasses = true +GetAuctionItemInfo = true +GetAuctionItemLink = true +GetAuctionItemSubClasses = true +GetAuctionItemTimeLeft = true +GetAuctionSellItemInfo = true +GetBidderAuctionItems = true +GetNumAuctionItems = true +GetOwnerAuctionItems = true +GetSelectedAuctionItem = true +IsAuctionSortReversed = true +PlaceAuctionBid = true +QueryAuctionItems = true +SetAuctionsTabShowing = true +SetSelectedAuctionItem = true +SortAuctionItems = true +StartAuction = true +BankButtonIDToInvSlotID = true +CloseBankFrame = true +GetBankSlotCost = true +GetNumBankSlots = true +PurchaseSlot = true +AcceptAreaSpiritHeal = true +AcceptBattlefieldPort = true +CancelAreaSpiritHeal = true +CanJoinBattlefieldAsGroup = true +CheckSpiritHealerDist = true +GetAreaSpiritHealerTime = true +GetBattlefieldEstimatedWaitTime = true +GetBattlefieldFlagPosition = true +GetBattlefieldInstanceExpiration = true +GetBattlefieldInstanceRunTime = true +GetBattlefieldMapIconScale = true +GetBattlefieldPortExpiration = true +GetBattlefieldPosition = true +GetBattlefieldScore = true +GetBattlefieldStatData = true +GetBattlefieldStatInfo = true +GetBattlefieldStatus = true +GetBattlefieldTimeWaited = true +GetBattlefieldWinner = true +GetBattlegroundInfo = true +GetNumBattlefieldFlagPositions = true +GetNumBattlefieldPositions = true +GetNumBattlefieldScores = true +GetNumBattlefieldStats = true +GetNumWorldStateUI = true +GetWintergraspWaitTime = true +GetWorldStateUIInfo = true +IsPVPTimerRunning = true +JoinBattlefield = true +LeaveBattlefield = true +ReportPlayerIsPVPAFK = true +RequestBattlefieldPositions = true +RequestBattlefieldScoreData = true +RequestBattlegroundInstanceInfo = true +SetBattlefieldScoreFaction = true +GetBinding = true +GetBindingAction = true +GetBindingKey = true +GetBindingText = true +GetCurrentBindingSet = true +GetNumBindings = true +LoadBindings = true +RunBinding = true +SaveBindings = true +SetBinding = true +SetBindingSpell = true +SetBindingClick = true +SetBindingItem = true +SetBindingMacro = true +SetConsoleKey = true +SetOverrideBinding = true +SetOverrideBindingSpell = true +SetOverrideBindingClick = true +SetOverrideBindingItem = true +SetOverrideBindingMacro = true +ClearOverrideBindings = true +SetMouselookOverrideBinding = true +IsModifierKeyDown = true +IsModifiedClick = true +IsMouseButtonDown = true +CancelUnitBuff = true +CancelShapeshiftForm = true +CancelItemTempEnchantment = true +GetWeaponEnchantInfo = true +UnitAura = true +UnitBuff = true +UnitDebuff = true +AddChatWindowChannel = true +ChannelBan = true +ChannelInvite = true +ChannelKick = true +ChannelModerator = true +ChannelMute = true +ChannelToggleAnnouncements = true +ChannelUnban = true +ChannelUnmoderator = true +ChannelUnmute = true +DisplayChannelOwner = true +DeclineInvite = true +EnumerateServerChannels = true +GetChannelList = true +GetChannelName = true +GetChatWindowChannels = true +JoinChannelByName = true +LeaveChannelByName = true +ListChannelByName = true +ListChannels = true +RemoveChatWindowChannel = true +SendChatMessage = true +SetChannelOwner = true +SetChannelPassword = true +AcceptResurrect = true +AcceptXPLoss = true +CheckBinderDist = true +ConfirmBinder = true +DeclineResurrect = true +DestroyTotem = true +GetBindLocation = true +GetComboPoints = true +GetCorpseRecoveryDelay = true +GetCurrentTitle = true +GetMirrorTimerInfo = true +GetMirrorTimerProgress = true +GetMoney = true +GetNumTitles = true +GetPlayerFacing = true +GetPVPDesired = true +GetReleaseTimeRemaining = true +GetResSicknessDuration = true +GetRestState = true +GetRuneCooldown = true +GetRuneCount = true +GetRuneType = true +GetTimeToWellRested = true +GetTitleName = true +GetUnitPitch = true +GetXPExhaustion = true +HasFullControl = true +HasSoulstone = true +IsFalling = true +IsFlying = true +IsFlyableArea = true +IsIndoors = true +IsMounted = true +IsOutdoors = true +IsOutOfBounds = true +IsResting = true +IsStealthed = true +IsSwimming = true +IsTitleKnown = true +IsXPUserDisabled = true +NotWhileDeadError = true +ResurrectHasSickness = true +ResurrectHasTimer = true +ResurrectGetOfferer = true +RetrieveCorpse = true +SetCurrentTitle = true +TargetTotem = true +GetArmorPenetration = true +GetAttackPowerForStat = true +GetAverageItemLevel = true +GetBlockChance = true +GetCombatRating = true +GetCombatRatingBonus = true +GetCritChance = true +GetCritChanceFromAgility = true +GetDodgeChance = true +GetExpertise = true +GetExpertisePercent = true +GetManaRegen = true +GetMaxCombatRatingBonus = true +GetParryChance = true +GetPetSpellBonusDamage = true +GetPowerRegen = true +GetSpellBonusDamage = true +GetRangedCritChance = true +GetSpellBonusHealing = true +GetSpellCritChance = true +GetShieldBlock = true +GetSpellCritChanceFromIntellect = true +GetSpellPenetration = true +AddChatWindowChannel = true +ChangeChatColor = true +ChatFrame_AddChannel = true +ChatFrame_AddMessageEventFilter = true +ChatFrame_GetMessageEventFilters = true +ChatFrame_OnHyperlinkShow = true +ChatFrame_RemoveMessageEventFilter = true +GetAutoCompleteResults = true +GetChatTypeIndex = true +GetChatWindowChannels = true +GetChatWindowInfo = true +GetChatWindowMessages = true +JoinChannelByName = true +LoggingChat = true +LoggingCombat = true +RemoveChatWindowChannel = true +RemoveChatWindowMessages = true +SetChatWindowAlpha = true +SetChatWindowColor = true +SetChatWindowDocked = true +SetChatWindowLocked = true +SetChatWindowName = true +SetChatWindowShown = true +SetChatWindowSize = true +SetChatWindowUninteractable = true +DoEmote = true +GetDefaultLanguage = true +GetLanguageByIndex = true +GetNumLanguages = true +GetRegisteredAddonMessagePrefixes = true +IsAddonMessagePrefixRegistered = true +RegisterAddonMessagePrefix = true +SendAddonMessage = true +SendChatMessage = true +CallCompanion = true +DismissCompanion = true +GetCompanionInfo = true +GetNumCompanions = true +GetCompanionCooldown = true +PickupCompanion = true +SummonRandomCritter = true +ContainerIDToInventoryID = true +GetBagName = true +GetContainerItemCooldown = true +GetContainerItemDurability = true +GetContainerItemGems = true +GetContainerItemID = true +GetContainerItemInfo = true +GetContainerItemLink = true +GetContainerNumSlots = true +GetContainerItemQuestInfo = true +GetContainerNumFreeSlots = true +OpenAllBags = true +CloseAllBags = true +PickupBagFromSlot = true +PickupContainerItem = true +PutItemInBackpack = true +PutItemInBag = true +PutKeyInKeyRing = true +SplitContainerItem = true +ToggleBackpack = true +ToggleBag = true +GetCoinText = true +GetCoinTextureString = true +GetCurrencyInfo = true +GetCurrencyListSize = true +GetCurrencyListInfo = true +ExpandCurrencyList = true +SetCurrencyUnused = true +GetNumWatchedTokens = true +GetBackpackCurrencyInfo = true +SetCurrencyBackpack = true +AutoEquipCursorItem = true +ClearCursor = true +CursorCanGoInSlot = true +CursorHasItem = true +CursorHasMoney = true +CursorHasSpell = true +DeleteCursorItem = true +DropCursorMoney = true +DropItemOnUnit = true +EquipCursorItem = true +GetCursorInfo = true +GetCursorPosition = true +HideRepairCursor = true +InRepairMode = true +PickupAction = true +PickupBagFromSlot = true +PickupContainerItem = true +PickupInventoryItem = true +PickupItem = true +PickupMacro = true +PickupMerchantItem = true +PickupPetAction = true +PickupSpell = true +PickupStablePet = true +PickupTradeMoney = true +PlaceAction = true +PutItemInBackpack = true +PutItemInBag = true +ResetCursor = true +SetCursor = true +ShowContainerSellCursor = true +ShowInspectCursor = true +ShowInventorySellCursor = true +ShowMerchantSellCursor = true +ShowRepairCursor = true +SplitContainerItem = true +GetWeaponEnchantInfo = true +ReplaceEnchant = true +ReplaceTradeEnchant = true +BindEnchant = true +CollapseFactionHeader = true +CollapseAllFactionHeaders = true +ExpandFactionHeader = true +ExpandAllFactionHeaders = true +FactionToggleAtWar = true +GetFactionInfo = true +GetNumFactions = true +GetSelectedFaction = true +GetWatchedFactionInfo = true +IsFactionInactive = true +SetFactionActive = true +SetFactionInactive = true +SetSelectedFaction = true +SetWatchedFactionIndex = true +UnitFactionGroup = true +CreateFrame = true +CreateFont = true +GetFramesRegisteredForEvent = true +GetNumFrames = true +EnumerateFrames = true +GetMouseFocus = true +ToggleDropDownMenu = true +UIFrameFadeIn = true +UIFrameFadeOut = true +UIFrameFlash = true +EasyMenu = true +AddFriend = true +AddOrRemoveFriend = true +GetFriendInfo = true +SetFriendNotes = true +GetNumFriends = true +GetSelectedFriend = true +RemoveFriend = true +SetSelectedFriend = true +ShowFriends = true +ToggleFriendsFrame = true +GetNumGlyphSockets = true +GetGlyphSocketInfo = true +GetGlyphLink = true +GlyphMatchesSocket = true +PlaceGlyphInSocket = true +RemoveGlyphFromSocket = true +SpellCanTargetGlyph = true +CanComplainChat = true +CanComplainInboxItem = true +ComplainChat = true +ComplainInboxItem = true +CloseGossip = true +ForceGossip = true +GetGossipActiveQuests = true +GetGossipAvailableQuests = true +GetGossipOptions = true +GetGossipText = true +GetNumGossipActiveQuests = true +GetNumGossipAvailableQuests = true +GetNumGossipOptions = true +SelectGossipActiveQuest = true +SelectGossipAvailableQuest = true +SelectGossipOption = true +AcceptGroup = true +ConfirmReadyCheck = true +ConvertToRaid = true +DeclineGroup = true +DoReadyCheck = true +GetLootMethod = true +GetLootThreshold = true +GetMasterLootCandidate = true +GetNumPartyMembers = true +GetRealNumPartyMembers = true +GetPartyLeaderIndex = true +GetPartyMember = true +InviteUnit = true +IsPartyLeader = true +LeaveParty = true +PromoteToLeader = true +SetLootMethod = true +SetLootThreshold = true +UninviteUnit = true +UnitInParty = true +UnitIsPartyLeader = true +AcceptGuild = true +BuyGuildCharter = true +CanEditGuildEvent = true +CanEditGuildInfo = true +CanEditMOTD = true +CanEditOfficerNote = true +CanEditPublicNote = true +CanGuildDemote = true +CanGuildInvite = true +CanGuildPromote = true +CanGuildRemove = true +CanViewOfficerNote = true +CloseGuildRegistrar = true +CloseGuildRoster = true +CloseTabardCreation = true +DeclineGuild = true +GetGuildCharterCost = true +GetGuildEventInfo = true +GetGuildInfo = true +GetGuildInfoText = true +GetGuildRosterInfo = true +GetGuildRosterLastOnline = true +GetGuildRosterMOTD = true +GetGuildRosterSelection = true +GetGuildRosterShowOffline = true +GetNumGuildEvents = true +GetNumGuildMembers = true +GetTabardCreationCost = true +GetTabardInfo = true +GuildControlAddRank = true +GuildControlDelRank = true +GuildControlGetNumRanks = true +GuildControlGetRankFlags = true +GuildControlGetRankName = true +GuildControlSaveRank = true +GuildControlSetRank = true +GuildControlSetRankFlag = true +GuildDemote = true +GuildDisband = true +GuildInfo = true +GuildInvite = true +GuildLeave = true +GuildPromote = true +GuildRoster = true +GuildRosterSetOfficerNote = true +GuildRosterSetPublicNote = true +GuildSetMOTD = true +GuildSetLeader = true +GuildUninvite = true +IsGuildLeader = true +IsInGuild = true +QueryGuildEventLog = true +SetGuildInfoText = true +SetGuildRosterSelection = true +SetGuildRosterShowOffline = true +SortGuildRoster = true +UnitGetGuildXP = true +AutoStoreGuildBankItem = true +BuyGuildBankTab = true +CanGuildBankRepair = true +CanWithdrawGuildBankMoney = true +CloseGuildBankFrame = true +DepositGuildBankMoney = true +GetCurrentGuildBankTab = true +GetGuildBankItemInfo = true +GetGuildBankItemLink = true +GetGuildBankMoney = true +GetGuildBankMoneyTransaction = true +GetGuildBankTabCost = true +GetGuildBankTabInfo = true +GetGuildBankTabPermissions = true +GetGuildBankText = true +GetGuildBankTransaction = true +GetGuildTabardFileNames = true +GetNumGuildBankMoneyTransactions = true +GetNumGuildBankTabs = true +GetNumGuildBankTransactions = true +PickupGuildBankItem = true +PickupGuildBankMoney = true +QueryGuildBankLog = true +QueryGuildBankTab = true +SetCurrentGuildBankTab = true +SetGuildBankTabInfo = true +SetGuildBankTabPermissions = true +SplitGuildBankItem = true +WithdrawGuildBankMoney = true +GetHolidayBGHonorCurrencyBonuses = true +GetInspectHonorData = true +GetPVPLifetimeStats = true +GetPVPRankInfo = true +GetPVPRankProgress = true +GetPVPSessionStats = true +GetPVPYesterdayStats = true +GetRandomBGHonorCurrencyBonuses = true +HasInspectHonorData = true +RequestInspectHonorData = true +UnitPVPName = true +UnitPVPRank = true +AddIgnore = true +AddOrDelIgnore = true +DelIgnore = true +GetIgnoreName = true +GetNumIgnores = true +GetSelectedIgnore = true +SetSelectedIgnore = true +CanInspect = true +CheckInteractDistance = true +ClearInspectPlayer = true +GetInspectArenaTeamData = true +HasInspectHonorData = true +RequestInspectHonorData = true +GetInspectHonorData = true +NotifyInspect = true +InspectUnit = true +CanShowResetInstances = true +GetBattlefieldInstanceExpiration = true +GetBattlefieldInstanceInfo = true +GetBattlefieldInstanceRunTime = true +GetInstanceBootTimeRemaining = true +GetInstanceInfo = true +GetNumSavedInstances = true +GetSavedInstanceInfo = true +IsInInstance = true +ResetInstances = true +GetDungeonDifficulty = true +SetDungeonDifficulty = true +GetInstanceDifficulty = true +GetInstanceLockTimeRemaining = true +GetInstanceLockTimeRemainingEncounter = true +AutoEquipCursorItem = true +BankButtonIDToInvSlotID = true +CancelPendingEquip = true +ConfirmBindOnUse = true +ContainerIDToInventoryID = true +CursorCanGoInSlot = true +EquipCursorItem = true +EquipPendingItem = true +GetInventoryAlertStatus = true +GetInventoryItemBroken = true +GetInventoryItemCooldown = true +GetInventoryItemCount = true +GetInventoryItemDurability = true +GetInventoryItemGems = true +GetInventoryItemID = true +GetInventoryItemLink = true +GetInventoryItemQuality = true +GetInventoryItemTexture = true +GetInventorySlotInfo = true +GetWeaponEnchantInfo = true +HasWandEquipped = true +IsInventoryItemLocked = true +KeyRingButtonIDToInvSlotID = true +PickupBagFromSlot = true +PickupInventoryItem = true +UpdateInventoryAlertStatus = true +UseInventoryItem = true +EquipItemByName = true +GetAuctionItemLink = true +GetContainerItemLink = true +GetItemCooldown = true +GetItemCount = true +GetItemFamily = true +GetItemIcon = true +GetItemInfo = true +GetItemQualityColor = true +GetItemSpell = true +GetItemStats = true +GetMerchantItemLink = true +GetQuestItemLink = true +GetQuestLogItemLink = true +GetTradePlayerItemLink = true +GetTradeSkillItemLink = true +GetTradeSkillReagentItemLink = true +GetTradeTargetItemLink = true +IsUsableItem = true +IsConsumableItem = true +IsCurrentItem = true +IsEquippedItem = true +IsEquippableItem = true +IsEquippedItemType = true +IsItemInRange = true +ItemHasRange = true +OffhandHasWeapon = true +SplitContainerItem = true +SetItemRef = true +AcceptSockets = true +ClickSocketButton = true +CloseSocketInfo = true +GetSocketItemInfo = true +GetSocketItemRefundable = true +GetSocketItemBoundTradeable = true +GetNumSockets = true +GetSocketTypes = true +GetExistingSocketInfo = true +GetExistingSocketLink = true +GetNewSocketInfo = true +GetNewSocketLink = true +SocketInventoryItem = true +SocketContainerItem = true +CloseItemText = true +ItemTextGetCreator = true +ItemTextGetItem = true +ItemTextGetMaterial = true +ItemTextGetPage = true +ItemTextGetText = true +ItemTextHasNextPage = true +ItemTextNextPage = true +ItemTextPrevPage = true +GetMinimapZoneText = true +GetRealZoneText = true +GetSubZoneText = true +GetZonePVPInfo = true +GetZoneText = true +CompleteLFGRoleCheck = true +GetLFGDeserterExpiration = true +GetLFGRandomCooldownExpiration = true +GetLFGBootProposal = true +GetLFGMode = true +GetLFGQueueStats = true +GetLFGRoles = true +GetLFGRoleUpdate = true +GetLFGRoleUpdateSlot = true +SetLFGBootVote = true +SetLFGComment = true +SetLFGRoles = true +UninviteUnit = true +UnitGroupRolesAssigned = true +UnitHasLFGDeserter = true +UnitHasLFGRandomCooldown = true +CloseLoot = true +ConfirmBindOnUse = true +ConfirmLootRoll = true +ConfirmLootSlot = true +GetLootMethod = true +GetLootRollItemInfo = true +GetLootRollItemLink = true +GetLootRollTimeLeft = true +GetLootSlotInfo = true +GetLootSlotLink = true +GetLootThreshold = true +GetMasterLootCandidate = true +GetNumLootItems = true +GetOptOutOfLoot = true +GiveMasterLoot = true +IsFishingLoot = true +LootSlot = true +LootSlotIsCoin = true +LootSlotIsCurrency = true +LootSlotIsItem = true +RollOnLoot = true +SetLootMethod = true +SetLootPortrait = true +SetLootThreshold = true +SetOptOutOfLoot = true +CursorHasMacro = true +DeleteMacro = true +GetMacroBody = true +GetMacroIconInfo = true +GetMacroItemIconInfo = true +GetMacroIndexByName = true +GetMacroInfo = true +GetNumMacroIcons = true +GetNumMacroItemIcons = true +GetNumMacros = true +PickupMacro = true +RunMacro = true +RunMacroText = true +SecureCmdOptionParse = true +StopMacro = true +AutoLootMailItem = true +CheckInbox = true +ClearSendMail = true +ClickSendMailItemButton = true +CloseMail = true +DeleteInboxItem = true +GetCoinIcon = true +GetInboxHeaderInfo = true +GetInboxItem = true +GetInboxItemLink = true +GetInboxNumItems = true +GetInboxText = true +GetInboxInvoiceInfo = true +GetNumPackages = true +GetNumStationeries = true +GetPackageInfo = true +GetSelectedStationeryTexture = true +GetSendMailCOD = true +GetSendMailItem = true +GetSendMailItemLink = true +GetSendMailMoney = true +GetSendMailPrice = true +GetStationeryInfo = true +HasNewMail = true +InboxItemCanDelete = true +ReturnInboxItem = true +SelectPackage = true +SelectStationery = true +SendMail = true +SetSendMailCOD = true +SetSendMailMoney = true +TakeInboxItem = true +TakeInboxMoney = true +TakeInboxTextItem = true +ClickLandmark = true +GetCorpseMapPosition = true +GetCurrentMapContinent = true +GetCurrentMapDungeonLevel = true +GetNumDungeonMapLevels = true +GetCurrentMapAreaID = true +GetCurrentMapZone = true +GetMapContinents = true +GetMapDebugObjectInfo = true +GetMapInfo = true +GetMapLandmarkInfo = true +GetMapOverlayInfo = true +GetMapZones = true +GetNumMapDebugObjects = true +GetNumMapLandmarks = true +GetNumMapOverlays = true +GetPlayerMapPosition = true +ProcessMapClick = true +RequestBattlefieldPositions = true +SetDungeonMapLevel = true +SetMapByID = true +SetMapToCurrentZone = true +SetMapZoom = true +SetupFullscreenScale = true +UpdateMapHighlight = true +CreateWorldMapArrowFrame = true +UpdateWorldMapArrowFrames = true +ShowWorldMapArrowFrame = true +PositionWorldMapArrowFrame = true +ZoomOut = true +BuyMerchantItem = true +BuybackItem = true +CanMerchantRepair = true +CloseMerchant = true +GetBuybackItemInfo = true +GetBuybackItemLink = true +GetMerchantItemCostInfo = true +GetMerchantItemCostItem = true +GetMerchantItemInfo = true +GetMerchantItemLink = true +GetMerchantItemMaxStack = true +GetMerchantNumItems = true +GetRepairAllCost = true +HideRepairCursor = true +InRepairMode = true +PickupMerchantItem = true +RepairAllItems = true +ShowMerchantSellCursor = true +ShowRepairCursor = true +GetNumBuybackItems = true +CastPetAction = true +ClosePetStables = true +DropItemOnUnit = true +GetPetActionCooldown = true +GetPetActionInfo = true +GetPetActionSlotUsable = true +GetPetActionsUsable = true +GetPetExperience = true +GetPetFoodTypes = true +GetPetHappiness = true +GetPetIcon = true +GetPetTimeRemaining = true +GetStablePetFoodTypes = true +GetStablePetInfo = true +HasPetSpells = true +HasPetUI = true +PetAbandon = true +PetAggressiveMode = true +PetAttack = true +IsPetAttackActive = true +PetStopAttack = true +PetCanBeAbandoned = true +PetCanBeDismissed = true +PetCanBeRenamed = true +PetDefensiveMode = true +PetDismiss = true +PetFollow = true +PetHasActionBar = true +PetPassiveMode = true +PetRename = true +PetWait = true +PickupPetAction = true +PickupStablePet = true +SetPetStablePaperdoll = true +TogglePetAutocast = true +ToggleSpellAutocast = true +GetSpellAutocast = true +AddQuestWatch = true +GetActiveLevel = true +GetActiveTitle = true +GetAvailableLevel = true +GetAvailableTitle = true +GetAvailableQuestInfo = true +GetGreetingText = true +GetNumQuestLeaderBoards = true +GetNumQuestWatches = true +GetObjectiveText = true +GetProgressText = true +GetQuestGreenRange = true +GetQuestIndexForWatch = true +GetQuestLink = true +GetQuestLogGroupNum = true +GetQuestLogLeaderBoard = true +GetQuestLogTitle = true +GetQuestReward = true +GetRewardArenaPoints = true +GetRewardHonor = true +GetRewardMoney = true +GetRewardSpell = true +GetRewardTalents = true +GetRewardText = true +GetRewardTitle = true +GetRewardXP = true +IsQuestWatched = true +IsUnitOnQuest = true +QuestFlagsPVP = true +QuestGetAutoAccept = true +RemoveQuestWatch = true +ShiftQuestWatches = true +SortQuestWatches = true +QueryQuestsCompleted = true +GetQuestsCompleted = true +QuestIsDaily = true +QuestIsWeekly = true +ClearRaidMarker = true +ConvertToRaid = true +ConvertToParty = true +DemoteAssistant = true +GetAllowLowLevelRaid = true +GetNumRaidMembers = true +GetRealNumRaidMembers = true +GetPartyAssignment = true +GetPartyAssignment = true +GetRaidRosterInfo = true +GetRaidTargetIndex = true +GetReadyCheckStatus = true +InitiateRolePoll = true +IsRaidLeader = true +IsRaidOfficer = true +PlaceRaidMarker = true +PromoteToAssistant = true +RequestRaidInfo = true +SetPartyAssignment = true +SetAllowLowLevelRaid = true +SetRaidRosterSelection = true +SetRaidSubgroup = true +SwapRaidSubgroup = true +SetRaidTarget = true +UnitInRaid = true +LFGGetDungeonInfoByID = true +GetInstanceLockTimeRemainingEncounter = true +RefreshLFGList = true +SearchLFGGetEncounterResults = true +SearchLFGGetJoinedID = true +SearchLFGGetNumResults = true +SearchLFGGetPartyResults = true +SearchLFGGetResults = true +SearchLFGJoin = true +SearchLFGLeave = true +SearchLFGSort = true +SetLFGComment = true +ClearAllLFGDungeons = true +JoinLFG = true +LeaveLFG = true +RequestLFDPartyLockInfo = true +RequestLFDPlayerLockInfo = true +SetLFGDungeon = true +SetLFGDungeonEnabled = true +SetLFGHeaderCollapsed = true +GetAddOnCPUUsage = true +GetAddOnMemoryUsage = true +GetEventCPUUsage = true +GetFrameCPUUsage = true +GetFunctionCPUUsage = true +GetScriptCPUUsage = true +ResetCPUUsage = true +UpdateAddOnCPUUsage = true +UpdateAddOnMemoryUsage = true +issecure = true +forceinsecure = true +issecurevariable = true +securecall = true +hooksecurefunc = true +InCombatLockdown = true +CombatTextSetActiveUnit = true +DownloadSettings = true +GetCVar = true +GetCVarDefault = true +GetCVarBool = true +GetCVarInfo = true +GetCurrentMultisampleFormat = true +GetCurrentResolution = true +GetGamma = true +GetMultisampleFormats = true +GetRefreshRates = true +GetScreenResolutions = true +GetVideoCaps = true +IsThreatWarningEnabled = true +RegisterCVar = true +ResetPerformanceValues = true +ResetTutorials = true +SetCVar = true +SetEuropeanNumbers = true +SetGamma = true +SetLayoutMode = true +SetMultisampleFormat = true +SetScreenResolution = true +ShowCloak = true +ShowHelm = true +ShowNumericThreat = true +ShowingCloak = true +ShowingHelm = true +UploadSettings = true +AbandonSkill = true +CastShapeshiftForm = true +CastSpell = true +CastSpellByName = true +GetMultiCastTotemSpells = true +GetNumShapeshiftForms = true +GetNumSpellTabs = true +GetShapeshiftForm = true +GetShapeshiftFormCooldown = true +GetShapeshiftFormInfo = true +GetSpellAutocast = true +GetSpellBookItemInfo = true +GetSpellBookItemName = true +GetSpellCooldown = true +GetSpellDescription = true +GetSpellInfo = true +GetSpellLink = true +GetSpellTabInfo = true +GetSpellTexture = true +GetTotemInfo = true +IsAttackSpell = true +IsAutoRepeatSpell = true +IsPassiveSpell = true +IsSpellInRange = true +IsUsableSpell = true +PickupSpell = true +QueryCastSequence = true +SetMultiCastSpell = true +SpellCanTargetUnit = true +SpellHasRange = true +SpellIsTargeting = true +SpellStopCasting = true +SpellStopTargeting = true +SpellTargetUnit = true +ToggleSpellAutocast = true +UnitCastingInfo = true +UnitChannelInfo = true +ConsoleExec = true +DetectWowMouse = true +GetBuildInfo = true +geterrorhandler = true +GetCurrentKeyBoardFocus = true +GetExistingLocales = true +GetFramerate = true +GetGameTime = true +GetLocale = true +GetCursorPosition = true +GetNetStats = true +GetRealmName = true +GetScreenHeight = true +GetScreenWidth = true +GetText = true +GetTime = true +IsAltKeyDown = true +InCinematic = true +IsControlKeyDown = true +IsDebugBuild = true +IsDesaturateSupported = true +IsLeftAltKeyDown = true +IsLeftControlKeyDown = true +IsLeftShiftKeyDown = true +IsLinuxClient = true +IsLoggedIn = true +IsMacClient = true +IsRightAltKeyDown = true +IsRightControlKeyDown = true +IsRightShiftKeyDown = true +IsShiftKeyDown = true +IsStereoVideoAvailable = true +IsWindowsClient = true +OpeningCinematic = true +PlayMusic = true +PlaySound = true +PlaySoundFile = true +ReloadUI = true +RepopMe = true +RequestTimePlayed = true +RestartGx = true +RunScript = true +Screenshot = true +SetAutoDeclineGuildInvites = true +seterrorhandler = true +StopCinematic = true +StopMusic = true +UIParentLoadAddOn = true +TakeScreenshot = true +BuyTrainerService = true +CheckTalentMasterDist = true +ConfirmTalentWipe = true +GetActiveTalentGroup = true +GetNumTalentTabs = true +GetNumTalents = true +GetTalentInfo = true +GetTalentLink = true +GetTalentPrereqs = true +GetTalentTabInfo = true +LearnTalent = true +SetActiveTalentGroup = true +GetNumTalentGroups = true +GetActiveTalentGroup = true +AddPreviewTalentPoints = true +GetGroupPreviewTalentPointsSpent = true +GetPreviewTalentPointsSpent = true +GetUnspentTalentPoints = true +LearnPreviewTalents = true +ResetGroupPreviewTalentPoints = true +ResetPreviewTalentPoints = true +AssistUnit = true +AttackTarget = true +ClearTarget = true +ClickTargetTradeButton = true +TargetLastEnemy = true +TargetLastTarget = true +TargetNearestEnemy = true +TargetNearestEnemyPlayer = true +TargetNearestFriend = true +TargetNearestFriendPlayer = true +TargetNearestPartyMember = true +TargetNearestRaidMember = true +TargetUnit = true +ToggleBackpack = true +ToggleBag = true +ToggleCharacter = true +ToggleFriendsFrame = true +ToggleSpellBook = true +TradeSkill = true +CloseTradeSkill = true +CollapseTradeSkillSubClass = true +PickupPlayerMoney = true +PickupTradeMoney = true +SetTradeMoney = true +ReplaceTradeEnchant = true +AssistUnit = true +CheckInteractDistance = true +DropItemOnUnit = true +FollowUnit = true +FocusUnit = true +ClearFocus = true +GetUnitName = true +GetUnitPitch = true +GetUnitSpeed = true +InviteUnit = true +IsUnitOnQuest = true +SpellCanTargetUnit = true +SpellTargetUnit = true +TargetUnit = true +UnitAffectingCombat = true +UnitArmor = true +UnitAttackBothHands = true +UnitAttackPower = true +UnitAttackSpeed = true +UnitAura = true +UnitBuff = true +UnitCanAssist = true +UnitCanAttack = true +UnitCanCooperate = true +UnitClass = true +UnitClassification = true +UnitCreatureFamily = true +UnitCreatureType = true +UnitDamage = true +UnitDebuff = true +UnitDefense = true +UnitDetailedThreatSituation = true +UnitExists = true +UnitFactionGroup = true +UnitGroupRolesAssigned = true +UnitGUID = true +GetPlayerInfoByGUID = true +UnitHasLFGDeserter = true +UnitHasLFGRandomCooldown = true +UnitHasRelicSlot = true +UnitHealth = true +UnitHealthMax = true +UnitInParty = true +UnitInRaid = true +UnitInBattleground = true +UnitIsInMyGuild = true +UnitInRange = true +UnitIsAFK = true +UnitIsCharmed = true +UnitIsConnected = true +UnitIsCorpse = true +UnitIsDead = true +UnitIsDeadOrGhost = true +UnitIsDND = true +UnitIsEnemy = true +UnitIsFeignDeath = true +UnitIsFriend = true +UnitIsGhost = true +UnitIsPVP = true +UnitIsPVPFreeForAll = true +UnitIsPVPSanctuary = true +UnitIsPartyLeader = true +UnitIsPlayer = true +UnitIsPossessed = true +UnitIsRaidOfficer = true +UnitIsSameServer = true +UnitIsTapped = true +UnitIsTappedByPlayer = true +UnitIsTappedByAllThreatList = true +UnitIsTrivial = true +UnitIsUnit = true +UnitIsVisible = true +UnitLevel = true +UnitMana = true +UnitManaMax = true +UnitName = true +UnitOnTaxi = true +UnitPlayerControlled = true +UnitPlayerOrPetInParty = true +UnitPlayerOrPetInRaid = true +UnitPVPName = true +UnitPVPRank = true +UnitPower = true +UnitPowerMax = true +UnitPowerType = true +UnitRace = true +UnitRangedAttack = true +UnitRangedAttackPower = true +UnitRangedDamage = true +UnitReaction = true +UnitResistance = true +UnitSelectionColor = true +UnitSex = true +UnitStat = true +UnitThreatSituation = true +UnitUsingVehicle = true +GetThreatStatusColor = true +UnitXP = true +UnitXPMax = true +SetPortraitTexture = true +SetPortraitToTexture = true +tinsert = true \ No newline at end of file diff --git a/Libs/LibOpenRaid/GetPlayerInformation.lua b/Libs/LibOpenRaid/GetPlayerInformation.lua index b55de1a9..ac4349a6 100644 --- a/Libs/LibOpenRaid/GetPlayerInformation.lua +++ b/Libs/LibOpenRaid/GetPlayerInformation.lua @@ -374,21 +374,24 @@ function openRaidLib.GearManager.GetPlayerGemsAndEnchantInfo() end --gems - local itemStatsTable = {} + --local itemStatsTable = {} --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 - if (itemStatsTable.EMPTY_SOCKET_PRISMATIC) then - --check if the socket is empty - for i = 1, itemStatsTable.EMPTY_SOCKET_PRISMATIC do - local gemId = tonumber(gemsIds[i]) - if (not gemId or gemId == 0) then - slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId + if (itemStatsTable) then + if (itemStatsTable.EMPTY_SOCKET_PRISMATIC) then + --check if the socket is empty + for i = 1, itemStatsTable.EMPTY_SOCKET_PRISMATIC do + local gemId = tonumber(gemsIds[i]) + if (not gemId or gemId == 0) then + slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId - --check if the gem is not a valid gem (deprecated gem) - elseif (gemId < 180000) then - slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId + --check if the gem is not a valid gem (deprecated gem) + elseif (gemId < 180000) then + slotsWithoutGems[#slotsWithoutGems+1] = equipmentSlotId + end end end end @@ -404,7 +407,7 @@ function openRaidLib.GearManager.BuildPlayerEquipmentList() for equipmentSlotId = 1, 17 do local itemLink = GetInventoryItemLink("player", equipmentSlotId) if (itemLink) then - local itemStatsTable = {} + --local itemStatsTable = {} local itemID, enchantID, gemID1, gemID2, gemID3, gemID4, suffixID, uniqueID, linkLevel, specializationID, modifiersMask, itemContext = select(2, strsplit(":", itemLink)) 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") end - GetItemStats(itemLink, itemStatsTable) + local itemStatsTable = C_Item.GetItemStats(itemLink) + --GetItemStats(itemLink, itemStatsTable) local gemSlotsAvailable = itemStatsTable and itemStatsTable.EMPTY_SOCKET_PRISMATIC or 0 local noPrefixItemLink = itemLink : gsub("^|c%x%x%x%x%x%x%x%x|Hitem", "") diff --git a/Libs/LibOpenRaid/ThingsToMantain_Dragonflight.lua b/Libs/LibOpenRaid/ThingsToMantain_Dragonflight.lua index bc54544d..a3c733d9 100644 --- a/Libs/LibOpenRaid/ThingsToMantain_Dragonflight.lua +++ b/Libs/LibOpenRaid/ThingsToMantain_Dragonflight.lua @@ -376,6 +376,7 @@ do [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 [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 [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 diff --git a/boot.lua b/boot.lua index 4090d932..ca98d5f5 100644 --- a/boot.lua +++ b/boot.lua @@ -97,7 +97,11 @@ Details222.OptionsPanel = {} Details222.Instances = {} Details222.Combat = {} - Details222.MythicPlus = {} + Details222.MythicPlus = { + Charts = {}, + Frames = {}, + } + Details222.MythicPlusBreakdown = {} Details222.EJCache = {} Details222.Segments = {} diff --git a/classes/container_actors.lua b/classes/container_actors.lua index 60c5a2e7..093bbecb 100644 --- a/classes/container_actors.lua +++ b/classes/container_actors.lua @@ -527,14 +527,12 @@ end return nickname end + local dungeonFollowersNpcs = {} + --read the actor flag local readActorFlag = function(actorObject, ownerActorObject, actorSerial, actorFlags, actorName) if (actorFlags) then - local _, zoneType = GetInstanceInfo() - - --UnitIsInMyGuild - - --on retail post 100200 patch, actorName is formatted as "name-realm" + local _, zoneType, difficultyId = GetInstanceInfo() --this is player actor 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 if ((bitBand(actorFlags, IS_GROUP_OBJECT) ~= 0 and actorObject.classe ~= "UNKNOW" and actorObject.classe ~= "UNGROUPPLAYER") or Details:IsInCache(actorSerial)) then 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) if (Details:IsATank(actorSerial)) then actorObject.isTank = true @@ -690,6 +694,12 @@ end end end end + + if (difficultyId == 205) then + if (dungeonFollowersNpcs[actorName]) then + actorObject.grupo = true + end + end end end diff --git a/core/plugins_statusbar.lua b/core/plugins_statusbar.lua index 7853ff6c..b91ae0d5 100644 --- a/core/plugins_statusbar.lua +++ b/core/plugins_statusbar.lua @@ -1430,13 +1430,16 @@ end end end - local textStyle = { - {value = 1, label = Loc ["STRING_PLUGINOPTIONS_ABBREVIATE"] .. "(105.5K)", onclick = onSelectTextStyle}, - {value = 2, label = Loc ["STRING_PLUGINOPTIONS_COMMA"] .. "(105.500)", onclick = onSelectTextStyle}, - {value = 3, label = Loc ["STRING_PLUGINOPTIONS_NOFORMAT"] .. "(105500)", onclick = onSelectTextStyle} - } + local textStyleDropdownFunc = function() + local textStyle = { + {value = 1, label = Loc ["STRING_PLUGINOPTIONS_ABBREVIATE"] .. "(105.5K)", 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) --text color diff --git a/frames/window_breakdown/window_playerbreakdown.lua b/frames/window_breakdown/window_playerbreakdown.lua index e169774f..fabbddee 100644 --- a/frames/window_breakdown/window_playerbreakdown.lua +++ b/frames/window_breakdown/window_playerbreakdown.lua @@ -799,7 +799,7 @@ function Details:CreateBreakdownWindow() function breakdownWindowFrame:SetStatusbarText(text, fontSize, fontColor) 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 end statusBar.Text.text = text diff --git a/frames/window_cdtracker.lua b/frames/window_cdtracker.lua index 76f64152..95e11166 100644 --- a/frames/window_cdtracker.lua +++ b/frames/window_cdtracker.lua @@ -17,6 +17,10 @@ Details222.CooldownTracking = { cooldownPanels = {}, } +function Details222.CooldownTracking.IsCooldownIgnored(spellId) + return Details.ocd_tracker.ignored_cooldowns[spellId] +end + --return a hash table with all cooldown panels created function Details222.CooldownTracking.GetAllCooldownFrames() return Details222.CooldownTracking.cooldownPanels @@ -131,6 +135,10 @@ end --need to get the filter name which that spell belong --and then check if that filter is enabled + if (Details222.CooldownTracking.IsCooldownIgnored(spellId)) then + return + end + 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 @@ -292,27 +300,29 @@ end local allCooldownFrames = Details222.CooldownTracking.GetAllCooldownFrames() for spellId, cooldownInfo in pairs(unitCooldowns) do - --get a cooldownLine - local cooldownLine = Details222.CooldownTracking.GetOrCreateNewCooldownLine(cooldownFrame, cooldownFrame.nextLineId) - cooldownLine.cooldownInfo = cooldownInfo - --local isReady, normalizedPercent, timeLeft, charges, minValue, maxValue, currentValue = openRaidLib.GetCooldownStatusFromCooldownInfo(cooldownInfo) + if (not Details222.CooldownTracking.IsCooldownIgnored(spellId)) then + --get a cooldownLine + local cooldownLine = Details222.CooldownTracking.GetOrCreateNewCooldownLine(cooldownFrame, cooldownFrame.nextLineId) + cooldownLine.cooldownInfo = cooldownInfo + --local isReady, normalizedPercent, timeLeft, charges, minValue, maxValue, currentValue = openRaidLib.GetCooldownStatusFromCooldownInfo(cooldownInfo) - cooldownLine.spellId = spellId - cooldownLine.class = unitInfo.class - cooldownLine.unitName = unitInfo.nameFull + cooldownLine.spellId = spellId + cooldownLine.class = unitInfo.class + cooldownLine.unitName = unitInfo.nameFull - --setup the cooldown in the line - Details222.CooldownTracking.SetupCooldownLine(cooldownLine) + --setup the cooldown in the line + Details222.CooldownTracking.SetupCooldownLine(cooldownLine) - --add the cooldown into the organized by class table - table.insert(cooldownsOrganized[classId], cooldownLine) + --add the cooldown into the organized by class table + table.insert(cooldownsOrganized[classId], cooldownLine) - --iterate to the next cooldown line - cooldownFrame.nextLineId = cooldownFrame.nextLineId + 1 + --iterate to the next cooldown line + cooldownFrame.nextLineId = cooldownFrame.nextLineId + 1 - --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][spellId] = cooldownLine + --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][spellId] = cooldownLine + end end end end @@ -775,24 +785,113 @@ end cooldownSelectionFrame:SetPoint("bottomright", f, "bottomright", 0, 10) DF:ApplyStandardBackdrop(cooldownSelectionFrame) - --lib test test warning texts - local warning1 = cooldownSelectionFrame:CreateFontString(nil, "overlay", "GameFontNormal", 5) - warning1:SetPoint("center", f, "center", 0, 0) - warning1:SetText("A cooldown tracker on Details!?\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) warning2:SetJustifyH("left") warning2:SetPoint("topleft", f, "topleft", 5, -160) DF:SetFontColor(warning2, "lime") - warning2:SetText("This is a concept of a cooldown tracker using the new library 'Open Raid' which uses comms to update cooldown timers.\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 _G.DetailsPluginContainerWindow.OpenPlugin(_G.DetailsCDTrackerWindow) diff --git a/frames/window_mythicplus/window_chart.lua b/frames/window_mythicplus/window_chart.lua new file mode 100644 index 00000000..87c85f05 --- /dev/null +++ b/frames/window_mythicplus/window_chart.lua @@ -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 \ No newline at end of file diff --git a/frames/window_mythicplus/window_end_of_run.lua b/frames/window_mythicplus/window_end_of_run.lua new file mode 100644 index 00000000..80225dc0 --- /dev/null +++ b/frames/window_mythicplus/window_end_of_run.lua @@ -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 diff --git a/functions/dungeon.lua b/functions/dungeon.lua deleted file mode 100644 index 12154b23..00000000 --- a/functions/dungeon.lua +++ /dev/null @@ -1,1550 +0,0 @@ - ---local pointer to details object -local Details = _G.Details -local debugmode = false --print debug lines -local verbosemode = false --auto open the chart panel -local _ -local addonName, Details222 = ... -local mPlus = Details222.MythicPlusBreakdown -local detailsFramework = DetailsFramework - -local Loc = _G.LibStub("AceLocale-3.0"):GetLocale( "Details" ) - ---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 mythicDungeonCharts = Details:CreateEventListener() -_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, mythicDungeonCharts.ShowReadyPanel) - - 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") - -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.ShowReadyPanel() - ---show a small panel telling the chart is ready to show -function mythicDungeonCharts.ShowReadyPanel(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 mythicDungeonCharts.ReadyFrame) then - mythicDungeonCharts.ReadyFrame = CreateFrame("frame", "DetailsMythicDungeonReadyFrame", UIParent, "BackdropTemplate") - local readyFrame = mythicDungeonCharts.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 - - --discart button - --readyFrame.DiscartButton = DetailsFramework:CreateButton(readyFrame, function() readyFrame:Hide() end, 80, 20, Loc ["STRING_DISCARD"]) - --readyFrame.DiscartButton:SetTemplate(DetailsFramework:GetTemplate("button", "DETAILS_PLUGIN_BUTTON_TEMPLATE")) - --readyFrame.DiscartButton:SetPoint("right", readyFrame.ShowChartButton, "left", -5, 0) - - --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 - --- /run _G.DetailsMythicDungeonChartHandler.ShowReadyPanel() - -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 - -Details222.MythicPlus = { - IsMythicPlus = function() - return C_ChallengeMode and C_ChallengeMode.GetActiveKeystoneInfo() and true or false - end, -} \ No newline at end of file diff --git a/functions/mythicdungeon.lua b/functions/mythicdungeon.lua deleted file mode 100644 index 31a82397..00000000 --- a/functions/mythicdungeon.lua +++ /dev/null @@ -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) diff --git a/functions/mythicdungeon/data_capture.lua b/functions/mythicdungeon/data_capture.lua new file mode 100644 index 00000000..d4abdae6 --- /dev/null +++ b/functions/mythicdungeon/data_capture.lua @@ -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() + + + + + + + + + diff --git a/functions/mythicdungeon/mythicdungeon.lua b/functions/mythicdungeon/mythicdungeon.lua new file mode 100644 index 00000000..d5d0f651 --- /dev/null +++ b/functions/mythicdungeon/mythicdungeon.lua @@ -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) diff --git a/functions/mythicdungeon/segments.lua b/functions/mythicdungeon/segments.lua new file mode 100644 index 00000000..e2445121 --- /dev/null +++ b/functions/mythicdungeon/segments.lua @@ -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 \ No newline at end of file diff --git a/functions/profiles.lua b/functions/profiles.lua index bc23482e..28153444 100644 --- a/functions/profiles.lua +++ b/functions/profiles.lua @@ -1201,6 +1201,7 @@ local default_player_data = { ocd_tracker = { enabled = false, cooldowns = {}, + ignored_cooldowns = {}, frames = { ["defensive-raid"] = {}, ["defensive-target"] = {},