diff --git a/Definitions.lua b/Definitions.lua index 7ebdc7008..2a122a860 100644 --- a/Definitions.lua +++ b/Definitions.lua @@ -216,7 +216,7 @@ ---@field contra string the name of the player enemy in a 1v1 pvp combat ---@field bossTimers table[] stored timers for bigwigs and dbm ---@field last_events_tables table[] where the death log of each player is stored ----@field +---@field boss_hp number percentage of the health points of the boss ---@field ---@field ---@field @@ -251,7 +251,7 @@ ---@field is_world_trash_combat boolean when true this combat is a regular combat done in the world, not in a dungeon, raid, battleground, arena, ... ---@field player_last_events table record the latest events of each player, latter used to build the death log ---@field ----@field +---@field FindEnemyName fun(combat: combat) : string attempt to get the name of the enemy in the combat by getting the top most damaged unit by the player ---@field GetTryNumber fun(combat: combat) : number? ---@field GetFormattedCombatTime fun(combat: combat) : string ---@field GetMSTime fun(combat: combat) : number, number @@ -421,7 +421,7 @@ ---@field friendlyfire_total number ---@field friendlyfire table ---@field damage_taken number amount of damage the actor took during the segment ----@field damage_from table store the name of the actors which damaged the actor, format: [actorName] = true +---@field damage_from table store the name of the actors which damaged the actor, format: [actorName] = true ---@field totalabsorbed number amount of damage dealt by the actor by got absorbed by the target, this is a "ABSORB" type of miss but still counts as damage done ---@field augmentedSpellsContainer spellcontainer diff --git a/Libs/DF/cooltip.lua b/Libs/DF/cooltip.lua index 17e4815b8..82cd5d658 100644 --- a/Libs/DF/cooltip.lua +++ b/Libs/DF/cooltip.lua @@ -17,7 +17,7 @@ local max = math.max --api locals local PixelUtil = PixelUtil or DFPixelUtil -local version = 21 +local version = 22 local CONST_MENU_TYPE_MAINMENU = "main" local CONST_MENU_TYPE_SUBMENU = "sub" @@ -36,6 +36,7 @@ function DF:CreateCoolTip() tile = true, tileSize = 16, insets = {left = 0, right = 0, top = 0, bottom = 0}} local defaultBackdropColor = {0.1215, 0.1176, 0.1294, 0.8000} local defaultBackdropBorderColor = {0.05, 0.05, 0.05, 1} + local defaultTexCoord = {0, 1, 0, 1} --initialize local gameCooltip = { @@ -1498,6 +1499,9 @@ function DF:CreateCoolTip() wallpaper:SetDesaturated(true) else wallpaper:SetDesaturated(false) + if (wallpaperTable[8]) then + wallpaper:SetDesaturation(wallpaperTable[8]) + end end wallpaper:Show() @@ -3003,7 +3007,16 @@ function DF:CreateCoolTip() frame1.frameWallpaper:Hide() frame2.frameWallpaper:Hide() - function gameCooltip:SetWallpaper(menuType, texture, texcoord, color, desaturate) + + ---set an image as wallpaper for the cooltip frame + ---@param menuType any + ---@param texture any + ---@param texcoord table + ---@param color any + ---@param bDesaturated boolean? + ---@param desaturation number? + ---@return nil + function gameCooltip:SetWallpaper(menuType, texture, texcoord, color, bDesaturated, desaturation) if (gameCooltip.Indexes == 0) then return gameCooltip:PrintDebug("SetWallpaper() requires an already added line (Cooltip:AddLine()).") end @@ -3026,20 +3039,18 @@ function DF:CreateCoolTip() wallpaperTable = subMenuContainerWallpapers end - wallpaperTable[1] = texture - if (texcoord) then - wallpaperTable[2] = texcoord[1] - wallpaperTable[3] = texcoord[2] - wallpaperTable[4] = texcoord[3] - wallpaperTable[5] = texcoord[4] - else - wallpaperTable[2] = 0 - wallpaperTable[3] = 1 - wallpaperTable[4] = 0 - wallpaperTable[5] = 1 - end - wallpaperTable[6] = color - wallpaperTable[7] = desaturate + texcoord = texcoord or defaultTexCoord + + --parse the texure + local iconTexture, iconWidth, iconHeight, leftCoord, rightCoord, topCoord, bottomCoord, red, green, blue, alpha = detailsFramework:ParseTexture(texture, 1, 1, texcoord[1], texcoord[2], texcoord[3], texcoord[4], color) + wallpaperTable[1] = iconTexture + wallpaperTable[2] = leftCoord + wallpaperTable[3] = rightCoord + wallpaperTable[4] = topCoord + wallpaperTable[5] = bottomCoord + wallpaperTable[6] = {red, green, blue, alpha} + wallpaperTable[7] = bDesaturated or false + wallpaperTable[8] = desaturation end function gameCooltip:SetBannerText(menuType, index, text, anchor, color, fontSize, fontFace, fontFlag) diff --git a/Libs/DF/definitions.lua b/Libs/DF/definitions.lua index e2819ed26..ee2314931 100644 --- a/Libs/DF/definitions.lua +++ b/Libs/DF/definitions.lua @@ -44,6 +44,8 @@ ---@field colorName string? ---@field nativeWidth number? ---@field nativeHeight number? +---@field desaturated boolean? +---@field desaturation number? ---@alias templatetype ---| "font" @@ -186,8 +188,8 @@ ---@field GetSpellBookSpells fun(self:table) : table, spellid[] return a list of spells from the player spellbook ---@field PreviewTexture fun(self:table, texture:atlasname|texturepath|textureid, left:number?, right:number?, top:number?, bottom:number?) : nil ---@field SetAtlas fun(self:table, textureObject:texture, atlas:atlasinfo|atlasname, useAtlasSize:boolean?, filterMode:texturefilter?, resetTexCoords:boolean?) : nil ----@field CreateAtlas fun(self:table, file:texturepath|textureid, width:number?, height:number?, leftTexCoord:number?, rightTexCoord:number?, topTexCoord:number?, bottomTexCoord:number?, tilesHorizontally:boolean?, tilesVertically:boolean?, vertexRed:any, vertexGreen:number?, vertexBlue:number?, vertexAlpha:number?) : atlasinfo ----@field ParseTexture fun(self:table, texture:texturepath|textureid|atlasname|atlasinfo, width: number?, height: number?, leftTexCoord: number?, rightTexCoord: number?, topTexCoord: number?, bottomTexCoord: number?, vertexRed:number|string?, vertexGreenvertexRed:number?, vertexBluevertexRed:number?, vertexAlphavertexRed:number?) : any, number?, number?, number?, number?, number?, number?, number?, number?, number?, number?, number? +---@field CreateAtlas fun(self:table, file:texturepath|textureid, width:number?, height:number?, leftTexCoord:number?, rightTexCoord:number?, topTexCoord:number?, bottomTexCoord:number?, tilesHorizontally:boolean?, tilesVertically:boolean?, vertexRed:any, vertexGreen:number?, vertexBlue:number?, vertexAlpha:number?, desaturated:boolean?, desaturation:number?, alpha:number) : atlasinfo +---@field ParseTexture fun(self:table, texture:texturepath|textureid|atlasname|atlasinfo, width: number?, height: number?, leftTexCoord: number?, rightTexCoord: number?, topTexCoord: number?, bottomTexCoord: number?, vertexRed:number|string?, vertexGreenvertexRed:number?, vertexBluevertexRed:number?, vertexAlphavertexRed:number?) : any, number?, number?, number?, number?, number?, number?, number?, number?, number?, number?, number?, number? ---@field IsTexture fun(self:table, texture:any, bCheckTextureObject: boolean?) : boolean ---@field CreateAtlasString fun(self:table, atlas:atlasinfo|atlasname, textureHeight:number?, textureWidth:number?) : string ---@field diff --git a/Libs/DF/fw.lua b/Libs/DF/fw.lua index 8d13e9869..3114f177e 100644 --- a/Libs/DF/fw.lua +++ b/Libs/DF/fw.lua @@ -1,6 +1,6 @@ -local dversion = 516 +local dversion = 517 local major, minor = "DetailsFramework-1.0", dversion local DF, oldminor = LibStub:NewLibrary(major, minor) @@ -1528,6 +1528,67 @@ function DF:TruncateText(fontString, maxWidth) fontString:SetText(text) end +---truncate removing text through a binary search with a max of 10 iterations +---@param fontString table +---@param maxWidth number +function DF:TruncateTextSafeBinarySearch(fontString, maxWidth) + local text = fontString:GetText() + if text == nil or text == '' then return end + + if fontString:GetUnboundedStringWidth() > maxWidth then + local left = 1 + local right = #text + local numIterations = 10 + + while left <= right and numIterations > 0 do + local middle = math.floor((left + right) * 0.5) + local substring = strsub(text, 1, middle) + fontString:SetText(substring) + + if fontString:GetUnboundedStringWidth() <= maxWidth then + left = middle + 1 + else + right = middle - 1 + end + + numIterations = numIterations - 1 + end + + text = strsub(text, 1, right) + end + + fontString:SetText(DF:CleanTruncateUTF8String(text)) +end + +---truncate removing characters from the string until the maxWidth is reach +---@param fontString table +---@param maxWidth number +function DF:TruncateTextBinarySearch(fontString, maxWidth) + local text = fontString:GetText() + if text == nil or text == '' then return end + + if fontString:GetUnboundedStringWidth() > maxWidth then + local left = 1 + local right = #text + + while left <= right do + local middle = math.floor((left + right) * 0.5) + local substring = strsub(text, 1, middle) + fontString:SetText(substring) + + if fontString:GetUnboundedStringWidth() <= maxWidth then + left = middle + 1 + else + right = middle - 1 + end + end + + text = strsub(text, 1, right) + end + + fontString:SetText(DF:CleanTruncateUTF8String(text)) +end + ---@param text string ---@return string function DF:CleanTruncateUTF8String(text) @@ -2082,8 +2143,8 @@ end ---* b (number|nil): The blue component of the color. This is optional if r is a string. ---* a (number|nil): The alpha component of the color. This is optional and defaults to 1 if not provided. ---* decimalsAmount (number|nil): The number of decimal places to round the color components to. This is optional and defaults to 4 if not provided. - ---* The function returns the color in the new format. The return type depends on the newFormat parameter. It can be a string, a table, or four separate number values (for the "numbers" format). - ---* For the "hex" format, it returns a string representing the color in hexadecimal format. + ---* The function returns the color in the new format. The return type depends on the newFormat parameter. It can be a string, a table, or four separate number values (for the "numbers" format). + ---* For the "hex" format, it returns a string representing the color in hexadecimal format. ---@param newFormat string ---@param r number|string ---@param g number|nil @@ -5085,16 +5146,28 @@ function _G.__benchmark(bNotPrintResult) end function DF:PreviewTexture(texture, left, right, top, bottom) + if (texture and type(texture) == "table" and texture.GetObjectType and texture:GetObjectType() == "Texture") then + DF:Msg("PreviewTexture: you have passed a texture object (uiobject) instead of the texture atlas, filename or id.") + end + local preview = DetailsFrameworkTexturePreview or CreateFrame("frame", "DetailsFrameworkTexturePreview", UIParent) preview:SetSize(200, 200) preview:SetPoint("center") preview.texture = DetailsFrameworkTexturePreviewTexture or preview:CreateTexture("DetailsFrameworkTexturePreviewTexture", "artwork") preview.texture:SetAllPoints() + preview.fontString = DetailsFrameworkTexturePreviewFontString or preview:CreateFontString("DetailsFrameworkTexturePreviewFontString", "artwork", "GameFontNormal") + preview.fontString:SetPoint("center", preview, "center", 0, 0) + + preview.texture:SetTexture("") + preview.fontString:SetText("") --check if the texture passed is an atlas if (type(texture) == "string" and C_Texture.GetAtlasInfo(texture)) then preview.texture:SetAtlas(texture) + elseif (type(texture) == "string" and texture:find("|T")) then + preview.fontString:SetText(texture) + elseif (type(texture) == "table") then preview.texture:SetTexture(texture.file or texture.filename) preview.texture:SetTexCoord(texture.leftTexCoord, texture.rightTexCoord, texture.topTexCoord, texture.bottomTexCoord) diff --git a/Libs/DF/picture.lua b/Libs/DF/picture.lua index fed130366..c95f099ac 100644 --- a/Libs/DF/picture.lua +++ b/Libs/DF/picture.lua @@ -477,6 +477,15 @@ function detailsFramework:SetAtlas(textureObject, atlas, useAtlasSize, filterMod textureObject:SetTexture(atlasInfo.file, atlasInfo.tilesHorizontally and "REPEAT" or "CLAMP", atlasInfo.tilesVertically and "REPEAT" or "CLAMP", filterMode or "LINEAR") textureObject:SetTexCoord(atlasInfo.leftTexCoord or 0, atlasInfo.rightTexCoord or 1, atlasInfo.topTexCoord or 0, atlasInfo.bottomTexCoord or 1) + if (atlasInfo.desaturated) then + textureObject:SetDesaturated(true) + else + textureObject:SetDesaturated(false) + if (atlasInfo.desaturation) then + textureObject:SetDesaturation(atlasInfo.desaturation) + end + end + if (atlasInfo.colorName) then textureObject:SetVertexColor(detailsFramework:ParseColors(atlasInfo.colorName)) else @@ -496,7 +505,10 @@ end ---@param textureWidth number? ---@return string function detailsFramework:CreateAtlasString(atlas, textureHeight, textureWidth) - local file, width, height, leftTexCoord, rightTexCoord, topTexCoord, bottomTexCoord, r, g, b, nativeWidth, nativeHeight = detailsFramework:ParseTexture(atlas) + local file, width, height, leftTexCoord, rightTexCoord, topTexCoord, bottomTexCoord, r, g, b, a, nativeWidth, nativeHeight = detailsFramework:ParseTexture(atlas) + + nativeWidth = nativeWidth or width or textureWidth + nativeHeight = nativeHeight or height or textureHeight if (not height) then return "|T" .. file .. "|t" @@ -507,9 +519,10 @@ function detailsFramework:CreateAtlasString(atlas, textureHeight, textureWidth) elseif (not r) then --the two zeros are the x and y offset --texCoords are multiplied by the heigh and width to get the actual pixel position - return "|T" .. file .. ":" .. (textureHeight or height) .. ":" .. (textureWidth or width) .. ":0:0:" .. (nativeWidth or width) .. ":" .. (nativeHeight or height) .. ":" .. leftTexCoord*(nativeWidth or width) .. ":" .. rightTexCoord*(nativeWidth or width) .. ":" .. topTexCoord*(nativeHeight or height) .. ":" .. bottomTexCoord*(nativeHeight or height) .. "|t" + local str = "|T" .. file .. ":" .. (textureHeight or height) .. ":" .. (textureWidth or width) .. ":0:0:" .. nativeWidth .. ":" .. nativeHeight .. ":" .. math.floor(leftTexCoord*nativeWidth) .. ":" .. math.floor(rightTexCoord*nativeWidth) .. ":" .. math.floor(topTexCoord*nativeHeight) .. ":" .. math.floor(bottomTexCoord*nativeHeight) .. "|t" + return str else - return "|T" .. file .. ":" .. (textureHeight or height) .. ":" .. (textureWidth or width) .. ":0:0:" .. (nativeWidth or width) .. ":" .. (nativeHeight or height) .. ":" .. leftTexCoord*(nativeWidth or width) .. ":" .. rightTexCoord*(nativeWidth or width) .. ":" .. topTexCoord*(nativeHeight or height) .. ":" .. bottomTexCoord*(nativeHeight or height) .. ":" .. r .. ":" .. g .. ":" .. b .. "|t" + return "|T" .. file .. ":" .. (textureHeight or height) .. ":" .. (textureWidth or width) .. ":0:0:" .. nativeWidth .. ":" .. nativeHeight .. ":" .. math.floor(leftTexCoord*nativeWidth) .. ":" .. math.floor(rightTexCoord*nativeWidth) .. ":" .. math.floor(topTexCoord*nativeHeight) .. ":" .. math.floor(bottomTexCoord*nativeHeight) .. ":" .. r .. ":" .. g .. ":" .. b .. "|t" end end @@ -548,6 +561,7 @@ function detailsFramework:ParseTexture(texture, width, height, leftTexCoord, rig end if (isAtlas) then + --ui atlasinfo ---@type atlasinfo local atlasInfo = isAtlas local textureId = atlasInfo.file @@ -567,7 +581,7 @@ function detailsFramework:ParseTexture(texture, width, height, leftTexCoord, rig end local nativeWidth, nativeHeight = atlasInfo.nativeWidth, atlasInfo.nativeHeight - return atlasInfo.file or atlasInfo.filename, width or atlasInfo.width, height or atlasInfo.height, atlasInfo.leftTexCoord, atlasInfo.rightTexCoord, atlasInfo.topTexCoord, atlasInfo.bottomTexCoord, r, g, b, a, nativeWidth, nativeHeight + return atlasInfo.file or atlasInfo.filename, width or atlasInfo.width, height or atlasInfo.height, atlasInfo.leftTexCoord or 0, atlasInfo.rightTexCoord or 1, atlasInfo.topTexCoord or 0, atlasInfo.bottomTexCoord or 1, r, g, b, a, nativeWidth, nativeHeight end if (type(vertexRed) == "string" or type(vertexRed) == "table") then @@ -593,8 +607,11 @@ end ---@param vertexGreen number? green color to use with SetVertexColor ---@param vertexBlue number? blue color to use with SetVertexColor ---@param vertexAlpha number? alpha color to use with SetVertexColor +---@param desaturated boolean? if the texture should be desaturated +---@param desaturation number? the amount of desaturation to use with SetDesaturation +---@param alpha number? the alpha to use with SetAlpha ---@return df_atlasinfo -function detailsFramework:CreateAtlas(file, width, height, leftTexCoord, rightTexCoord, topTexCoord, bottomTexCoord, tilesHorizontally, tilesVertically, vertexRed, vertexGreen, vertexBlue, vertexAlpha) +function detailsFramework:CreateAtlas(file, width, height, leftTexCoord, rightTexCoord, topTexCoord, bottomTexCoord, tilesHorizontally, tilesVertically, vertexRed, vertexGreen, vertexBlue, vertexAlpha, desaturated, desaturation, alpha) ---@type df_atlasinfo local atlasInfo = { file = file, @@ -606,6 +623,9 @@ function detailsFramework:CreateAtlas(file, width, height, leftTexCoord, rightTe bottomTexCoord = bottomTexCoord or 1, tilesHorizontally = tilesHorizontally or false, tilesVertically = tilesVertically or false, + desaturated = desaturated, + desaturation = desaturation, + alpha = alpha, } --parse the colors passed diff --git a/boot.lua b/boot.lua index 2f4d34730..c01787d27 100644 --- a/boot.lua +++ b/boot.lua @@ -71,6 +71,8 @@ DamageSpellsCache = {} } + Details222.Unknown = _G["UNKNOWN"] + --namespace color Details222.ColorScheme = { ["gradient-background"] = {0.1215, 0.1176, 0.1294, 0.8}, diff --git a/classes/class_combat.lua b/classes/class_combat.lua index 2b66cdf10..31bdbc24b 100644 --- a/classes/class_combat.lua +++ b/classes/class_combat.lua @@ -46,13 +46,16 @@ local segmentTypeToString = { [DETAILS_SEGMENTTYPE_RAID_TRASH] = "RaidTrash", [DETAILS_SEGMENTTYPE_RAID_BOSS] = "RaidBoss", [DETAILS_SEGMENTTYPE_MYTHICDUNGEON] = "Category MythicDungeon", - [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_GENERIC] = "MythicDungeonGeneric", - [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH] = "MythicDungeonTrash", + [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_GENERIC] = "MythicDungeonGeneric _GENERIC", + [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH] = "MythicDungeonTrash _TRASH", [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL] = "MythicDungeonOverall", - [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASHOVERALL] = "MythicDungeonTrashOverall", - [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS] = "MythicDungeonBoss", + [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASHOVERALL] = "MythicDungeonTrashOverall TRASHOVERALL", + [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS] = "MythicDungeonBoss _BOSS", [DETAILS_SEGMENTTYPE_PVP_ARENA] = "PvPArena", [DETAILS_SEGMENTTYPE_PVP_BATTLEGROUND] = "PvPBattleground", + [DETAILS_SEGMENTTYPE_EVENT_VALENTINEDAY] = "EventValentineDay", + [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSTRASH] = "MythicDungeonBossTrash _BOSSTRASH", + [DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSWIPE] = "MythicDungeonBossWipe _BOSSWIPE", } ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -529,7 +532,7 @@ local segmentTypeToString = { end if (bTryFind) then - local newName = Details:FindEnemy() + local newName = self:FindEnemyName() if (newName) then self.enemy = newName return newName @@ -540,17 +543,110 @@ local segmentTypeToString = { return Loc["STRING_FIGHTNUMBER"] .. segmentId end + ---debug function to print the combat name + ---@param self combat + ---@return string + function classCombat:GetCombatTypeName() + local combatType = self:GetCombatType() + return segmentTypeToString[combatType] or ("no type found: " .. combatType) + end + + ---@param self combat + ---@return string + function classCombat:FindEnemyName() + local zoneName, instanceType = GetInstanceInfo() + local bIsInInstance = IsInInstance() --garrison returns party as instance type + if ((instanceType == "party" or instanceType == "raid") and bIsInInstance) then + if (instanceType == "party") then + if (Details:GetBossNames(Details.zone_id)) then + return Loc ["STRING_SEGMENT_TRASH"] + end + else + return Loc ["STRING_SEGMENT_TRASH"] + end + end + + local playerActorObject = self:GetActor(DETAILS_ATTRIBUTE_DAMAGE, Details.playername) + ---@cast playerActorObject actordamage + + --search for an enemy name in the player targets + if (playerActorObject) then + local targets = playerActorObject.targets + --check if the player has at least 1 target, this can happen when the player got hit by enemies but didn't hit back + if (next(targets)) then + --add the targets to an array, this allow to get the enemy with most damage taken by the player + ---@type table[] + local targetsArray = {} + for targetName, amount in pairs(targets) do + table.insert(targetsArray, {targetName, amount}) + end + + table.sort(targetsArray, Details.Sort2) + + local targetName = targetsArray[1][1] + if (targetName) then + return targetName + end + end + + --search for an enemy name in the player damage taken + local damageTakenFrom = playerActorObject.damage_from + if (next(damageTakenFrom)) then + ---@type table[] + local damageTakenArray = {} + for damagerName in pairs(damageTakenFrom) do + --get the actor object for the damager to know how much damage was done to the player + ---@type actordamage + local damagerActor = self:GetActor(DETAILS_ATTRIBUTE_DAMAGE, damagerName) + if (damagerActor) then + table.insert(damageTakenArray, {damagerName, damagerActor.targets[playerActorObject:Name()] or 0}) + end + end + + table.sort(damageTakenArray, Details.Sort2) + + local targetName = damageTakenArray[1][1] + if (targetName) then + return targetName + end + end + end + + --search for an enemy name in the group members targets + ---@type actorcontainer + local actorContainer = self:GetContainer(DETAILS_ATTRIBUTE_DAMAGE) + local actorTable = actorContainer:GetActorTable() + for i = 1, #actorTable do + local actorObject = actorTable[i] + --check if this actor was a group member during the combat + if (actorObject:IsGroupPlayer()) then + local targets = actorObject.targets + if (next(targets)) then + ---@type table[] + local targetsArray = {} + for targetName, amount in pairs(targets) do + table.insert(targetsArray, {targetName, amount}) + end + + table.sort(targetsArray, Details.Sort2) + + local targetName = targetsArray[1][1] + if (targetName) then + return targetName + end + end + end + end + + return Details222.Unknown + end + function classCombat:GetCombatType() --mythic dungeon local bIsMythicDungeon = self:IsMythicDungeon() if (bIsMythicDungeon) then local mythicDungeonInfo = self:GetMythicDungeonInfo() - if (not mythicDungeonInfo) then - print("sem mythicDungeonInfo") - return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH, DETAILS_SEGMENTTYPE_MYTHICDUNGEON - end - if (mythicDungeonInfo.SegmentType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH) then return DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH, DETAILS_SEGMENTTYPE_MYTHICDUNGEON @@ -944,6 +1040,8 @@ function classCombat:NovaTabela(bTimeStarted, overallCombatObject, combatId, ... combatObject.data_inicio = 0 combatObject.tempo_start = _tempo + combatObject.boss_hp = 1 + combatObject.bossTimers = {} ---store trinket procs diff --git a/core/control.lua b/core/control.lua index 48c1c1366..a950bb59d 100644 --- a/core/control.lua +++ b/core/control.lua @@ -63,6 +63,25 @@ end local currentCombat = Details:GetCurrentCombat() + local playerActorObject = currentCombat:GetActor(DETAILS_ATTRIBUTE_DAMAGE, Details.playername) + if (playerActorObject) then + local targets = playerActorObject.targets + + --make an array of targets {{targetName, amount}} + local targetsArray = {} + for targetName, amount in pairs(targets) do + table.insert(targetsArray, {targetName, amount}) + end + + --sort the array by amount + table.sort(targetsArray, Details.Sort2) + + local targetName = targetsArray[1][1] + + if (targetName) then + return targetName + end + end for _, actor in ipairs(currentCombat[attributeDamage]._ActorTable) do if (not actor.grupo and not actor.owner and not actor.nome:find("[*]") and bitBand(actor.flag_original, 0x00000060) ~= 0) then --0x20+0x40 neutral + enemy reaction @@ -526,17 +545,12 @@ end end - Details:OnCombatPhaseChanged() - - if (currentCombat.bossFunction) then - Details:CancelTimer(currentCombat.bossFunction) - currentCombat.bossFunction = nil - end - if (currentCombat.is_challenge or Details.debug) then --Details222.AuraScan.Stop() --combat ended (m+ active) end + Details:OnCombatPhaseChanged() + --stop combat ticker Details:StopCombatTicker() @@ -548,7 +562,6 @@ Details:CloseShields(currentCombat) end - --salva hora, minuto, segundo do fim da luta local bSetStartTime = false local bSetEndTime = true currentCombat:SetDateToNow(bSetStartTime, bSetEndTime) @@ -632,7 +645,7 @@ currentCombat.enemy = "[" .. ARENA .. "] " .. currentCombat.is_arena.name end - --check if the player is in a instance + --check if the player is in an instance local bInInstance = IsInInstance() --garrison returns party as instance type. if ((instanceType == "party" or instanceType == "raid") and bInInstance) then --if is not boss and inside a instance of type party or raid: mark the combat as trash @@ -647,12 +660,12 @@ end end - if (not currentCombat.enemy) then - local enemy = Details:FindEnemy() - currentCombat.enemy = enemy + if (not currentCombat.enemy or currentCombat.enemy == Details222.Unknown) then + local enemyName = currentCombat:FindEnemyName() + currentCombat.enemy = enemyName end - Details:FlagActorsOnCommonFight() --fight_component + Details:FlagActorsOnCommonFight() else --combat is boss encounter --calling here without checking for combat since the does not ran too long for scripts diff --git a/core/plugins_statusbar.lua b/core/plugins_statusbar.lua index b239c5aca..ab0694fd3 100644 --- a/core/plugins_statusbar.lua +++ b/core/plugins_statusbar.lua @@ -1,4 +1,5 @@ + ---@type details local Details = _G.Details local Loc = LibStub("AceLocale-3.0"):GetLocale( "Details" ) local SharedMedia = LibStub:GetLibrary("LibSharedMedia-3.0") @@ -625,15 +626,15 @@ do --still a little buggy, working on function Details:PluginDpsUpdate(child) --showing is the combat table which is current shown on instance - if (child.instance.showing and not child.instance.showing.__destroyed) then + if (child.instance:GetCombat() and not child.instance:GetCombat().__destroyed) then --GetCombatTime() return the time length of combat - local combatTime = child.instance.showing:GetCombatTime() + local combatTime = child.instance:GetCombat():GetCombatTime() if (combatTime < 1) then return child.text:SetText("0") end --GetTotal(attribute, sub attribute, onlyGroup) return the total of requested attribute - local total = child.instance.showing:GetTotal(child.instance.atributo, child.instance.sub_atributo, true) + local total = child.instance:GetCombat():GetTotal(child.instance.atributo, child.instance.sub_atributo, true) local dps = math.floor(total / combatTime) @@ -711,7 +712,7 @@ do if (child.enabled and child.instance:IsEnabled()) then child.options.segmentType = child.options.segmentType or 2 - if (not child.instance.showing) then + if (not child.instance:GetCombat()) then return child.text:SetText(Loc ["STRING_EMPTY_SEGMENT"]) end @@ -722,7 +723,7 @@ do if (child.options.segmentType == 1) then child.text:SetText(Loc ["STRING_CURRENT"]) else - local combatName = Details.tabela_vigente:GetCombatName(false, true) + local combatName = Details:GetCurrentCombat():GetCombatName(false, true) if (combatName and combatName ~= Loc ["STRING_UNKNOW"]) then if (child.options.segmentType == 2) then @@ -746,7 +747,7 @@ do child.text:SetText(Loc ["STRING_FIGHTNUMBER"] .. child.instance:GetSegmentId()) else - local combatName = child.instance.showing:GetCombatName(false, true) + local combatName = child.instance:GetCombat():GetCombatName(false, true) if (combatName ~= Loc ["STRING_UNKNOW"]) then if (child.options.segmentType == 2) then child.text:SetText(combatName) diff --git a/core/util.lua b/core/util.lua index 26b152b5b..269a2e951 100644 --- a/core/util.lua +++ b/core/util.lua @@ -1251,6 +1251,13 @@ end Details:BrokerTick() Details:HealthTick() + local currentCombat = Details:GetCurrentCombat() + if (Details.encounter_table.start and not Details.encounter_table["end"] and currentCombat.is_boss) then + local encounterHealth = UnitHealth("boss1") or 0 + local encounterMaxHealth = UnitHealthMax("boss1") or 1 + currentCombat.boss_hp = encounterHealth / encounterMaxHealth + end + local zoneName, zoneType = GetInstanceInfo() if (Details.Coach.Server.IsEnabled()) then diff --git a/frames/window_main.lua b/frames/window_main.lua index c204e40a6..13c7251d8 100644 --- a/frames/window_main.lua +++ b/frames/window_main.lua @@ -6312,6 +6312,10 @@ end local segmentsUsed = 0 local segmentsFilled = 0 +---texture coords for the encounter journal "icon lore" image of the instance +local iconLoreCoords = {30/512, 355/512, 45/512, 290/512} +--overlay color for the encounter journal "icon lore" image of the instance +local wallpaperColor = {1, 1, 1, 0.5} -- search key: ~segments local buildSegmentTooltip = function(self, deltaTime) @@ -6364,6 +6368,8 @@ local buildSegmentTooltip = function(self, deltaTime) local mythicDungeonRunId local statusBarTexture = "Skyline" + local combatTimeColor = "silver" + local combatTimeColorGeneric = "gray" for i = Details.segments_amount, 1, -1 do if (i <= fill) then @@ -6379,12 +6385,16 @@ local buildSegmentTooltip = function(self, deltaTime) ---@type details_encounterinfo local encounterInfo = Details:GetEncounterInfo(thisCombat:GetEncounterName()) + ---@type string, string local dateStart, dateEnd = thisCombat:GetDate() ---@type combattime local elapsedCombatTime = thisCombat:GetCombatTime() + local formattedElapsedTime = detailsFramework:IntegerToTimer(elapsedCombatTime) + + ---@type string + local enemyName = bossInfo and bossInfo.name or "" - local enemyName = bossInfo and bossInfo.name local segmentInfoAdded = false segmentsUsed = segmentsUsed + 1 @@ -6408,15 +6418,31 @@ local buildSegmentTooltip = function(self, deltaTime) --if is bIsMythicDungeon but no mythicDungeonInfo, it will show as M+ 'Trash Cleanup' --is a boss, trash overall or run overall segment if (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_TRASH or combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSTRASH) then - gameCooltip:AddLine(thisCombat:GetCombatName(), detailsFramework:IntegerToTimer(thisCombat:GetCombatTime()), 1, dungeonColorTrash, "gray") + local combatName, r, g, b = thisCombat:GetCombatName() + local broomStick = detailsFramework:CreateAtlasString(Details:GetTextureAtlas("segment-icon-broom")) + + --dumpt(mythicDungeonInfo) + + gameCooltip:AddLine(broomStick .. " " .. combatName, detailsFramework:IntegerToTimer(thisCombat:GetCombatTime()), 1, dungeonColor, combatTimeColor) gameCooltip:AddIcon(thisCombat:GetCombatIcon(), "main", "left", nil, nil, nil, nil, nil, nil, nil, nil, true) --submenu gameCooltip:AddLine(Loc["STRING_SEGMENT_TRASH"], nil, 2, "white", "white") + gameCooltip:AddIcon(Details:GetTextureAtlas("small-pin-yellow"), 2, 1) + gameCooltip:AddStatusBar(100, 2, 0, 0, 0, 0.25, false, false, statusBarTexture) + gameCooltip:AddLine(Loc["STRING_SEGMENTS_LIST_COMBATTIME"] .. ":", detailsFramework:IntegerToTimer(thisCombat:GetCombatTime()), 2, "white", "white") - gameCooltip:AddLine("", "", 2, "white", "white") + gameCooltip:AddIcon(Details:GetTextureAtlas("small-pin-yellow"), 2, 1) + gameCooltip:AddStatusBar(100, 2, 0, 0, 0, 0.25, false, false, statusBarTexture) + + --gameCooltip:AddLine("", "", 2, "white", "white") gameCooltip:AddLine(Loc["STRING_SEGMENT_START"] .. ":", thisCombat:GetDate(), 2, "white", "white") + gameCooltip:AddIcon(Details:GetTextureAtlas("small-pin-yellow"), 2, 1) + gameCooltip:AddStatusBar(100, 2, 0, 0, 0, 0.25, false, false, statusBarTexture) + gameCooltip:AddLine(Loc["STRING_SEGMENT_END"] .. ":", dateEnd or "in progress", 2, "white", "white") + gameCooltip:AddIcon(Details:GetTextureAtlas("small-pin-yellow"), 2, 1) + gameCooltip:AddStatusBar(100, 2, 0, 0, 0, 0.25, false, false, statusBarTexture) local backgroundImage = Details:GetRaidIcon(mapID, EJID, "party") if (backgroundImage and bCanUseBackgroundImage) then @@ -6427,23 +6453,46 @@ local buildSegmentTooltip = function(self, deltaTime) gameCooltip:AddLine(thisCombat:GetCombatName(), detailsFramework:IntegerToTimer(endedAt - startedAt), 1, dungeonColor) gameCooltip:AddIcon(thisCombat:GetCombatIcon(), "main", "left") gameCooltip:AddStatusBar(100, 1, .5, .1, 0, 0.55, false, false, statusBarTexture) + local timeInCombat = thisCombat:GetCombatTime() + --submenu gameCooltip:AddLine(zoneName .. " +" .. mythicLevel .. " (" .. Loc["STRING_SEGMENTS_LIST_OVERALL"] .. ")", nil, 2, "white", "white") - gameCooltip:AddStatusBar(100, 2, 0, 0, 0, 0.85, false, false, statusBarTexture) + gameCooltip:AddIcon(Details:GetTextureAtlas("small-pin-yellow"), 2, 1) + gameCooltip:AddStatusBar(100, 2, 0, 0, 0, 0.25, false, false, statusBarTexture) + + local totalRealTime = thisCombat:GetRunTimeNoDefault() or (endedAt - startedAt) + local notInCombatTime = totalRealTime - timeInCombat + + gameCooltip:AddLine(Loc["STRING_SEGMENTS_LIST_TOTALTIME"] .. ":", detailsFramework:IntegerToTimer(totalRealTime), 2, "white", "white") + gameCooltip:AddIcon(Details:GetTextureAtlas("small-pin-yellow"), 2, 1) + gameCooltip:AddStatusBar(100, 2, 0, 0, 0, 0.25, false, false, statusBarTexture) + + gameCooltip:AddLine(Loc["STRING_SEGMENTS_LIST_TIMEINCOMBAT"] .. ":", detailsFramework:IntegerToTimer(timeInCombat), 2, "white", "white") + gameCooltip:AddIcon(Details:GetTextureAtlas("small-pin-yellow"), 2, 1) + gameCooltip:AddStatusBar(100, 2, 0, 0, 0, 0.25, false, false, statusBarTexture) + + --wasted time + gameCooltip:AddLine(Loc["STRING_SEGMENTS_LIST_WASTED_TIME"] .. ":", "|cFFFF3300" .. detailsFramework:IntegerToTimer(notInCombatTime) .. " (" .. floor(notInCombatTime / totalRealTime * 100) .. "%)|r", 2, "white", "white") + gameCooltip:AddIcon(Details:GetTextureAtlas("small-pin-yellow"), 2, 1) + gameCooltip:AddStatusBar(100, 2, 0, 0, 0, 0.25, false, false, statusBarTexture) elseif (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSS or combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_BOSSWIPE) then local addIconAndStatusBar = function(redTint) - gameCooltip:AddIcon(Details:GetTextureAtlas("segment-icon-empty"), 2, 1) - gameCooltip:AddStatusBar(100, 2, redTint or 0, 0, 0, 0.85, false, false, statusBarTexture) + gameCooltip:AddIcon(Details:GetTextureAtlas("small-pin-yellow"), 2, 1) + gameCooltip:AddStatusBar(100, 2, 0, 0, 0, 0.25, false, false, statusBarTexture) end local skull = "|TInterface\\AddOns\\Details\\images\\icons:16:16:0:0:512:512:496:512:0:16|t" + local skullIcon = detailsFramework:CreateAtlasString(Details:GetTextureAtlas("segment-icon-boss")) + --main cooltip frame local combatName, combatColor = thisCombat:GetCombatName() - gameCooltip:AddLine(skull .. "" .. combatName, detailsFramework:IntegerToTimer(elapsedCombatTime), 1, combatColor, "gray") + local r, g, b, a = detailsFramework:ParseColors(combatColor) + gameCooltip:AddLine(skullIcon .. " " .. combatName, detailsFramework:IntegerToTimer(elapsedCombatTime), 1, dungeonColor, combatTimeColor) gameCooltip:AddIcon(thisCombat:GetCombatIcon(), "main", "left") addIconAndStatusBar() + --sub cooltip frame gameCooltip:AddLine(thisCombat:GetCombatName(), nil, 2, "white", "white") addIconAndStatusBar() @@ -6496,29 +6545,12 @@ local buildSegmentTooltip = function(self, deltaTime) addIconAndStatusBar() elseif (isMythicOverallSegment) then - gameCooltip:AddLine(Loc["STRING_SEGMENTS_LIST_TIMEINCOMBAT"] .. ":", detailsFramework:IntegerToTimer(timeInCombat), 2, "white", "white") - addIconAndStatusBar() - - local totalRealTime = thisCombat:GetRunTimeNoDefault() or (endedAt - startedAt) - local notInCombatTime = totalRealTime - timeInCombat - - gameCooltip:AddLine(Loc["STRING_SEGMENTS_LIST_TOTALTIME"] .. ":", detailsFramework:IntegerToTimer(totalRealTime), 2, "white", "white") - addIconAndStatusBar() - - --wasted time - gameCooltip:AddLine(Loc["STRING_SEGMENTS_LIST_WASTED_TIME"] .. ":", "|cFFFF3300" .. detailsFramework:IntegerToTimer(notInCombatTime) .. " (" .. floor(notInCombatTime / totalRealTime * 100) .. "%)|r", 2, "white", "white") - addIconAndStatusBar(0.15) else gameCooltip:AddLine(Loc["STRING_SEGMENTS_LIST_COMBATTIME"] .. ":", detailsFramework:IntegerToTimer(timeInCombat), 2, "white", "white") addIconAndStatusBar() end - if (thisCombat.is_boss) then - gameCooltip:AddLine("", "", 2, "white", "white") - addIconAndStatusBar() - end - gameCooltip:AddLine(Loc["STRING_SEGMENT_START"] .. ":", thisCombat:GetDate(), 2, "white", "white") addIconAndStatusBar() gameCooltip:AddLine(Loc["STRING_SEGMENT_END"] .. ":", dateEnd or "in progress", 2, "white", "white") @@ -6526,7 +6558,18 @@ local buildSegmentTooltip = function(self, deltaTime) end segmentInfoAdded = true - --end of DETAILS_SEGMENTTYPE_MYTHICDUNGEON + + if (instanceInfo) then + local bgImage = instanceInfo.iconLore + local bIsDesaturated = false + local desaturation = 0.7 + if (combatType == DETAILS_SEGMENTTYPE_MYTHICDUNGEON_OVERALL) then + desaturation = 0.4 + end + gameCooltip:SetWallpaper(2, bgImage, iconLoreCoords, wallpaperColor, bIsDesaturated, desaturation) + end + + --end of mythic+ segments elseif (combatType == DETAILS_SEGMENTTYPE_DUNGEON_BOSS or combatType == DETAILS_SEGMENTTYPE_RAID_BOSS) then --if this is a boss encounter --isn't anymore a sequence of mythic+ segments @@ -6535,15 +6578,15 @@ local buildSegmentTooltip = function(self, deltaTime) local tryNumber = thisCombat:GetTryNumber() local combatTime = thisCombat:GetCombatTime() local combatInstanceType = thisCombat:GetInstanceType() + local combatName, r, g, b = thisCombat:GetCombatName() if (combatInstanceType == "party") then - local combatName, r, g, b = thisCombat:GetCombatName() - gameCooltip:AddLine(combatName, _, 1, dungeonColor) + gameCooltip:AddLine(combatName, formattedElapsedTime, 1, dungeonColor, combatTimeColor) elseif (bossInfo.killed) then - gameCooltip:AddLine(thisCombat:GetCombatName(), _, 1, "lime") + gameCooltip:AddLine(combatName, formattedElapsedTime, 1, "lime", combatTimeColor) else - gameCooltip:AddLine(thisCombat:GetCombatName(), _, 1, "red") + gameCooltip:AddLine(combatName, formattedElapsedTime, 1, "red", combatTimeColor) end local portrait = thisCombat:GetBossImage() @@ -6555,7 +6598,6 @@ local buildSegmentTooltip = function(self, deltaTime) if (Details.tooltip.submenu_wallpaper) then local background = Details:GetRaidIcon(bossInfo.mapid) - if (background and bCanUseBackgroundImage) then gameCooltip:SetWallpaper(2, background, nil, segments_wallpaper_color, true) else @@ -6577,13 +6619,13 @@ local buildSegmentTooltip = function(self, deltaTime) mythicDungeonRunId = false --dungeon local combatName, r, g, b = thisCombat:GetCombatName() - gameCooltip:AddLine(combatName, _, 1, "hotpink") + gameCooltip:AddLine(combatName, formattedElapsedTime, 1, "hotpink", "hotpink") gameCooltip:AddIcon(thisCombat:GetCombatIcon(), "main", "left") elseif (combatType == DETAILS_SEGMENTTYPE_PVP_BATTLEGROUND) then mythicDungeonRunId = false enemyName = thisCombat:GetCombatName() - gameCooltip:AddLine(enemyName, _, 1, battleground_color) + gameCooltip:AddLine(enemyName, formattedElapsedTime, 1, battleground_color, combatTimeColor) enemyName = enemyName gameCooltip:AddIcon(thisCombat:GetCombatIcon(), "main", "left") @@ -6608,9 +6650,8 @@ local buildSegmentTooltip = function(self, deltaTime) end else mythicDungeonRunId = false - local bFindEnemyName = true - gameCooltip:AddLine(thisCombat:GetCombatName(false, bFindEnemyName), _, 1, "yellow") + gameCooltip:AddLine(thisCombat:GetCombatName(false, bFindEnemyName), formattedElapsedTime, 1, "yellow", combatTimeColorGeneric) gameCooltip:AddIcon(thisCombat:GetCombatIcon(), "main", "left") --print("passing here...") diff --git a/textures.lua b/textures.lua index fef823f64..d1c20020c 100644 --- a/textures.lua +++ b/textures.lua @@ -57,6 +57,20 @@ Details.TextureAtlas = { nativeHeight = 512, }, + ["small-pin-yellow"] = { + file = [[Interface\BUTTONS\UI-RadioButton]], + width = 12, + height = 12, + leftTexCoord = 0.25, + rightTexCoord = 0.5, + topTexCoord = 0, + bottomTexCoord = 1, + tilesHorizontally = false, + tilesVertically = false, + nativeWidth = 64, + nativeHeight = 16, + }, + ["segment-icon-skull"] = { file = [[Interface\AddOns\Details\images\icons]], width = 16, @@ -91,8 +105,8 @@ Details.TextureAtlas = { height = 16, leftTexCoord = 0.96875, rightTexCoord = 1, - topTexCoord = 0.0625, - bottomTexCoord = 0.09375, + topTexCoord = 0, + bottomTexCoord = 0.03125, tilesHorizontally = false, tilesVertically = false, nativeWidth = 512,