local Details = _G.Details local textAlpha = 0.9 local AceLocale = LibStub("AceLocale-3.0") local L = AceLocale:GetLocale ( "Details" ) local on_deathrecap_line_enter = function(self) if (self.spellid) then GameTooltip:SetOwner(self, "ANCHOR_RIGHT") Details:GameTooltipSetSpellByID (self.spellid) self:SetBackdropColor(.3, .3, .3, .2) GameTooltip:Show() self.backgroundTextureOverlay:Show() self.timeAt:SetAlpha(1) self.sourceName:SetAlpha(1) self.amount:SetAlpha(1) self.lifePercent:SetAlpha(1) end end local on_deathrecap_line_leave = function(self) GameTooltip:Hide() self:SetBackdropColor(.3, .3, .3, 0) self.backgroundTextureOverlay:Hide() self.timeAt:SetAlpha(textAlpha) self.sourceName:SetAlpha(textAlpha) self.amount:SetAlpha(textAlpha) self.lifePercent:SetAlpha(textAlpha) end local create_deathrecap_line = function(parent, n) local line = CreateFrame("frame", "DetailsDeathRecapLine" .. n, parent, "BackdropTemplate") line:SetPoint("topleft", parent, "topleft", 10, (-24 * n) - 17) line:SetPoint("topright", parent, "topright", -10, (-24 * n) - 17) line:SetScript("OnEnter", on_deathrecap_line_enter) line:SetScript("OnLeave", on_deathrecap_line_leave) line:SetSize(300, 21) local timeAt = line:CreateFontString(nil, "overlay", "GameFontNormal") local backgroundTexture = line:CreateTexture(nil, "border") local backgroundTextureOverlay = line:CreateTexture(nil, "artwork") local spellIcon = line:CreateTexture(nil, "overlay") local spellIconBorder = line:CreateTexture(nil, "overlay") spellIcon:SetDrawLayer("overlay", 1) spellIconBorder:SetDrawLayer("overlay", 2) local sourceName = line:CreateFontString(nil, "overlay", "GameFontNormal") local amount = line:CreateFontString(nil, "overlay", "GameFontNormal") local lifePercent = line:CreateFontString(nil, "overlay", "GameFontNormal") local lifeStatusBar = line:CreateTexture(nil, "border", nil, -3) --grave icon local graveIcon = line:CreateTexture(nil, "overlay") graveIcon:SetTexture([[Interface\MINIMAP\POIIcons]]) graveIcon:SetTexCoord(146/256, 160/256, 0/512, 18/512) graveIcon:SetPoint("left", line, "left", 11, 0) graveIcon:SetSize(14, 18) --spell icon spellIcon:SetSize(19, 19) spellIconBorder:SetTexture([[Interface\ENCOUNTERJOURNAL\LootTab]]) spellIconBorder:SetTexCoord(6/256, 38/256, 49/128, 81/128) spellIconBorder:SetSize(20, 20) spellIconBorder:SetPoint("topleft", spellIcon, "topleft", 0, 0) --locations timeAt:SetPoint("left", line, "left", 2, 0) spellIcon:SetPoint("left", line, "left", 50, 0) sourceName:SetPoint("left", line, "left", 82, 0) amount:SetPoint("left", line, "left", 240, 0) lifePercent:SetPoint("left", line, "left", 320, 0) --text colors Details.gump:SetFontColor(amount, "red") Details.gump:SetFontColor(timeAt, "gray") Details.gump:SetFontColor(sourceName, "yellow") Details.gump:SetFontSize(sourceName, 10) --text alpha timeAt:SetAlpha(textAlpha) sourceName:SetAlpha(textAlpha) amount:SetAlpha(textAlpha) lifePercent:SetAlpha(textAlpha) --text setup amount:SetWidth(85) amount:SetJustifyH("right") lifePercent:SetWidth(42) lifePercent:SetJustifyH("right") --life statusbar lifeStatusBar:SetPoint("topleft", line, "topleft") lifeStatusBar:SetPoint("bottomleft", line, "bottomleft") lifeStatusBar:SetColorTexture(0.5, 0.5, 0.5, 0.4) backgroundTexture:SetTexture([[Interface\AddOns\Details\images\deathrecap_background]]) backgroundTexture:SetTexCoord(0, 1, 0, 1) backgroundTexture:SetVertexColor(.1, .1, .1, .3) --top border local TopFader = line:CreateTexture(nil, "border") TopFader:SetTexture([[Interface\AddOns\Details\images\deathrecap_background_top]]) TopFader:SetTexCoord(0, 1, 0, 1) TopFader:SetVertexColor(.1, .1, .1, .3) TopFader:SetPoint("bottomleft", backgroundTexture, "topleft", 0, -0) TopFader:SetPoint("bottomright", backgroundTexture, "topright", 0, -0) TopFader:SetHeight(32) TopFader:Hide() line.TopFader = TopFader if (n == 10) then --bottom fader local backgroundTexture2 = line:CreateTexture(nil, "border") backgroundTexture2:SetTexture([[Interface\AddOns\Details\images\deathrecap_background_bottom]]) backgroundTexture2:SetTexCoord(0, 1, 0, 1) backgroundTexture2:SetVertexColor(.1, .1, .1, .3) backgroundTexture2:SetPoint("topleft", backgroundTexture, "bottomleft", 0, 0) backgroundTexture2:SetPoint("topright", backgroundTexture, "bottomright", 0, 0) backgroundTexture2:SetHeight(32) Details.gump:SetFontSize(amount, 14) Details.gump:SetFontSize(lifePercent, 14) backgroundTexture:SetVertexColor(.2, .1, .1, .3) end backgroundTexture:SetPoint("topleft", 0, 1) backgroundTexture:SetPoint("bottomright", 0, -1) backgroundTexture:SetDesaturated(true) backgroundTextureOverlay:SetTexture([[Interface\AdventureMap\AdventureMap]]) backgroundTextureOverlay:SetTexCoord(460/1024, 659/1024, 330/1024, 350/1024) backgroundTextureOverlay:SetAllPoints() backgroundTextureOverlay:SetDesaturated(true) backgroundTextureOverlay:SetAlpha(0.5) backgroundTextureOverlay:Hide() line.timeAt = timeAt line.spellIcon = spellIcon line.sourceName = sourceName line.amount = amount line.lifePercent = lifePercent line.backgroundTexture = backgroundTexture line.backgroundTextureOverlay = backgroundTextureOverlay line.graveIcon = graveIcon line.lifeStatusBar = lifeStatusBar if (n == 10) then graveIcon:Show() line.timeAt:Hide() else graveIcon:Hide() end return line end local OpenDetailsDeathRecapAtSegment = function(segment) Details.OpenDetailsDeathRecap (segment, RecapID) end function Details.BuildDeathTableFromRecap (recapID) local events = DeathRecap_GetEvents (recapID) --check if it is a valid recap if (not events or #events <= 0) then DeathRecapFrame.Unavailable:Show() return end --build an death log using details format ArtificialDeathLog = { {}, --deathlog events (events [1] and events [1].timestamp) or (DeathRecapFrame and DeathRecapFrame.DeathTimeStamp) or 0, --time of death UnitName ("player"), select(2, UnitClass("player")), UnitHealthMax ("player"), "0m 0s", --formated fight time ["dead"] = true, ["last_cooldown"] = false, ["dead_at"] = 0, n = 1 } for i = 1, #events do local evtData = events [i] local spellId, spellName, texture = DeathRecapFrame_GetEventInfo ( evtData ) local ev = { true, spellId or 0, evtData.amount or 0, evtData.timestamp or 0, --? evtData.currentHP or 0, evtData.sourceName or "--x--x--", evtData.absorbed or 0, evtData.school or 0, false, evtData.overkill, not spellId and {spellId, spellName, texture}, } tinsert(ArtificialDeathLog[1], ev) ArtificialDeathLog.n = ArtificialDeathLog.n + 1 end return ArtificialDeathLog end function Details.GetDeathRecapFromChat() local chat1 = ChatFrame1 local recapIDFromChat if (chat1) then local numLines = chat1:GetNumMessages() for i = numLines, 1, -1 do local text = chat1:GetMessageInfo (i) if (text) then if (text:find("Hdeath:%d")) then local recapID = text:match ("|Hdeath:(%d+)|h") if (recapID) then recapIDFromChat = tonumber(recapID) end break end end end end if (recapIDFromChat) then Details.OpenDetailsDeathRecap (nil, recapIDFromChat, true) return end end function Details.OpenDetailsDeathRecap (segment, RecapID, fromChat) if (not Details.death_recap.enabled) then if (Details.DeathRecap and Details.DeathRecap.Lines) then for i = 1, 10 do Details.DeathRecap.Lines [i]:Hide() end for i, button in ipairs(Details.DeathRecap.Segments) do button:Hide() end end return end --hide blizzard death recap DeathRecapFrame.Recap1:Hide() DeathRecapFrame.Recap2:Hide() DeathRecapFrame.Recap3:Hide() DeathRecapFrame.Recap4:Hide() DeathRecapFrame.Recap5:Hide() --create details death recap if not existant if (not Details.DeathRecap) then Details.DeathRecap = CreateFrame("frame", "DetailsDeathRecap", DeathRecapFrame, "BackdropTemplate") Details.DeathRecap:SetAllPoints() DeathRecapFrame.Title:SetText(DeathRecapFrame.Title:GetText() .. " (by Details!)") --lines Details.DeathRecap.Lines = {} for i = 1, 10 do Details.DeathRecap.Lines [i] = create_deathrecap_line (Details.DeathRecap, i) end --segments Details.DeathRecap.Segments = {} for i = 5, 1, -1 do local segmentButton = CreateFrame("button", "DetailsDeathRecapSegmentButton" .. i, Details.DeathRecap, "BackdropTemplate") segmentButton:SetSize(16, 20) segmentButton:SetPoint("topright", DeathRecapFrame, "topright", (-abs(i-6) * 22) - 10, -5) local text = segmentButton:CreateFontString(nil, "overlay", "GameFontNormal") segmentButton.text = text text:SetText("#" .. i) text:SetPoint("center") Details.gump:SetFontColor(text, "silver") segmentButton:SetScript("OnClick", function() OpenDetailsDeathRecapAtSegment (i) end) tinsert(Details.DeathRecap.Segments, i, segmentButton) end end for i = 1, 10 do Details.DeathRecap.Lines[i]:Hide() end --segment to use local death = Details.tabela_vigente.last_events_tables --see if this segment has a death for the player local foundPlayer = false for index = #death, 1, -1 do if (death [index] [3] == Details.playername) then foundPlayer = true break end end --in case a combat has been created after the player death, the death won't be at the current segment if (not foundPlayer) then local segmentHistory = Details:GetCombatSegments() for i = 1, 2 do local segment = segmentHistory [1] if (segment and segment ~= Details.tabela_vigente) then if (Details.tabela_vigente.start_time - 3 < segment.end_time) then death = segment.last_events_tables end end end end --segments if (Details.death_recap.show_segments) then local last_index = 0 local buttonsInUse = {} for i, button in ipairs(Details.DeathRecap.Segments) do if (Details.tabela_historico.tabelas [i]) then button:Show() tinsert(buttonsInUse, button) Details.gump:SetFontColor(button.text, "silver") last_index = i else button:Hide() end end local buttonsInUse2 = {} for i = #buttonsInUse, 1, -1 do tinsert(buttonsInUse2, buttonsInUse[i]) end for i = 1, #buttonsInUse2 do local button = buttonsInUse2 [i] button:ClearAllPoints() button:SetPoint("topright", DeathRecapFrame, "topright", (-i * 22) - 10, -5) end if (not segment) then Details.gump:SetFontColor(Details.DeathRecap.Segments [1].text, "orange") else Details.gump:SetFontColor(Details.DeathRecap.Segments [segment].text, "orange") death = Details.tabela_historico.tabelas [segment] and Details.tabela_historico.tabelas [segment].last_events_tables end else for i, button in ipairs(Details.DeathRecap.Segments) do button:Hide() end end --if couldn't find the requested log from details!, so, import the log from the blizzard death recap --or if the player cliced on the chat link for the recap local ArtificialDeathLog if (not death or RecapID) then if (segment) then --nop, the player requested a death log from details it self but the log does not exists DeathRecapFrame.Unavailable:Show() return end --get the death events from the blizzard's recap ArtificialDeathLog = Details.BuildDeathTableFromRecap (RecapID) end DeathRecapFrame.Unavailable:Hide() --get the relevance config local relevanceTime = Details.death_recap.relevance_time local t if (ArtificialDeathLog) then t = ArtificialDeathLog else for index = #death, 1, -1 do if (death [index] [3] == Details.playername) then t = death [index] break end end end if (t) then local events = t [1] local timeOfDeath = t [2] local BiggestDamageHits = {} for i = #events, 1, -1 do tinsert(BiggestDamageHits, events [i]) end table.sort (BiggestDamageHits, function(t1, t2) return t1[3] > t2[3] end) for i = #BiggestDamageHits, 1, -1 do if (BiggestDamageHits [i][4] + relevanceTime < timeOfDeath) then tremove(BiggestDamageHits, i) end end --check if the event which killed the player is in the list, or addit to BiggestDamageHits local hitKill for i = #events, 1, -1 do local event = events [i] local evType = event [1] if (type(evType) == "boolean" and evType) then hitKill = event break end end if (hitKill) then local haveHitKill = false for index, t in ipairs(BiggestDamageHits) do if (t == hitKill) then haveHitKill = true break end end if (not haveHitKill) then tinsert(BiggestDamageHits, 1, hitKill) end end --check if there's at least 10 big events, if not fill with smaller events if (#BiggestDamageHits < 10) then for i = #events, 1, -1 do local event = events [i] local evType = event [1] if (type(evType) == "boolean" and evType) then local alreadyHave = false for index, t in ipairs(BiggestDamageHits) do if (t == event) then alreadyHave = true break end end if (not alreadyHave) then tinsert(BiggestDamageHits, event) if (#BiggestDamageHits == 10) then break end end end end else --cut table to show only 10 events while (#BiggestDamageHits > 10) do tremove(BiggestDamageHits, 11) end end if (#BiggestDamageHits == 0) then if (not fromChat) then Details.GetDeathRecapFromChat() return end end table.sort (BiggestDamageHits, function(t1, t2) return t1[4] > t2[4] end) local events = BiggestDamageHits local maxHP = t [5] local lineIndex = 10 --for i = #events, 1, -1 do for i, event in ipairs(events) do local event = events [i] local evType = event [1] local hp = min (floor(event [5] / maxHP * 100), 100) local spellName, _, spellIcon = Details.GetSpellInfo(event [2]) local amount = event [3] local eventTime = event [4] local source = event [6] local overkill = event [10] or 0 local customSpellInfo = event [11] if (type(evType) == "boolean" and evType) then local line = Details.DeathRecap.Lines [lineIndex] if (line) then line.timeAt:SetText(format("%.1f", eventTime - timeOfDeath) .. "s") line.spellIcon:SetTexture(spellIcon or customSpellInfo and customSpellInfo [3] or "") line.TopFader:Hide() --line.spellIcon:SetTexCoord(.1, .9, .1, .9) --line.sourceName:SetText("|cFFC6B0D9" .. source .. "|r") --parse source and cut the length of the string after setting the spellname and source local sourceClass = Details:GetClass(source) local sourceSpec = Details:GetSpec(source) if (not sourceClass) then local combat = Details:GetCurrentCombat() if (combat) then local sourceActor = combat:GetActor(1, source) if (sourceActor) then sourceClass = sourceActor.classe end end end if (not sourceSpec) then local combat = Details:GetCurrentCombat() if (combat) then local sourceActor = combat:GetActor(1, source) if (sourceActor) then sourceSpec = sourceActor.spec end end end --remove real name or owner name source = Details:GetOnlyName(source) --remove owner name source = source:gsub((" <.*"), "") --if a player? if (Details.player_class [sourceClass]) then source = Details:AddClassOrSpecIcon (source, sourceClass, sourceSpec, 16, true) elseif (sourceClass == "PET") then source = Details:AddClassOrSpecIcon (source, sourceClass) end --remove the dot signal from the spell name if (not spellName) then spellName = customSpellInfo and customSpellInfo [2] or "*?*" if (spellName:find(STRING_ENVIRONMENTAL_DAMAGE_FALLING)) then if (UnitName ("player") == "Elphaba") then spellName = "Gravity Won!, Elphaba..." source = "" else source = "Gravity" end --/run for a,b in pairs(_G) do if (type(b)=="string" and b:find("Falling")) then print(a,b) end end end end spellName = spellName:gsub(L["STRING_DOT"], "") spellName = spellName:gsub("[*] ", "") source = source or "" line.sourceName:SetText(spellName .. " (" .. "|cFFC6B0D9" .. source .. "|r" .. ")") DetailsFramework:TruncateText (line.sourceName, 185) if (amount > 1000) then --line.amount:SetText("-" .. Details:ToK (amount)) line.amount:SetText("-" .. Details:comma_value(floor(amount))) else --line.amount:SetText("-" .. floor(amount)) line.amount:SetText("-" .. floor(amount)) end line.lifePercent:SetText(hp .. "%") line.lifeStatusBar:SetWidth(line:GetWidth() * (hp/100)) line.spellid = event [2] line:Show() if (Details.death_recap.show_life_percent) then line.lifePercent:Show() line.amount:SetPoint("left", line, "left", 240, 0) line.lifePercent:SetPoint("left", line, "left", 320, 0) else line.lifePercent:Hide() line.amount:SetPoint("left", line, "left", 280, 0) --line.lifePercent:SetPoint("left", line, "left", 320, 0) end end lineIndex = lineIndex - 1 end end local lastLine = Details.DeathRecap.Lines [lineIndex + 1] if (lastLine) then lastLine.TopFader:Show() end DeathRecapFrame.Unavailable:Hide() else if (not fromChat) then Details.GetDeathRecapFromChat() end end end hooksecurefunc (_G, "DeathRecap_LoadUI", function() hooksecurefunc (_G, "DeathRecapFrame_OpenRecap", function(RecapID) local currentCombat = Details:GetCurrentCombat() --get the player current death and link the death table with the death recapID local playerDeaths = currentCombat:GetPlayerDeaths(UnitName("player")) if (playerDeaths) then local latestDeath = playerDeaths[#playerDeaths] if (latestDeath) then latestDeath.RecapID = RecapID --synchronize last events from Details! and Blizzard recap local events = DeathRecap_GetEvents(recapID) --death is event index 1 (the event that killed the player) local evtData = events[1] if (evtData) then --recap by blizzard local spellName = evtData.spellName local spellId = evtData.spellId local event = evtData.event local environmentalType = evtData.environmentalType local timeStamp = evtData.timestamp local amountDamage = evtData.amount local overkill = evtData.overkill local absorbed = evtData.absorbed local resisted = evtData.resisted local blocked = evtData.blocked local currentHp = evtData.currentHP local hideCaster = evtData.hideCaster local sourceName = evtData.sourceName local casterPrestige = evtData.casterPrestige local spellSchool = evtData.school local spellId, spellName, texture = DeathRecapFrame_GetEventInfo(evtData) local format = Details:GetCurrentToKFunction() if (Details.death_recap.enabled) then if (Details:GetZoneType() == "party" or Details:GetZoneType() == "raid") then local msgText = "|cFFAAAAFFDeath Recap (Blizzard):" print(msgText, "|T" .. texture .. ":16:16:0:0:64:64:5:59:5:59|t", GetSpellLink(spellId) or spellName, format(_, amountDamage or 0)) end end --recap by Details! --[=[ local deathEventsDetails = latestDeath[1] for evIndex = #deathEventsDetails, 1, -1 do local ev = deathEventsDetails[evIndex] local evType = ev[1] local spellId = ev[2] local amount = ev[3] --is a damage? true boolean if (type(evType) == "boolean" and evType) then local spellName, _, spellIcon = Details.GetSpellInfo(spellId) if (spellName) then --print("Killed by (Details!-Debug): ", spellName, "amount:", amount) else --print("Killed by (Details!-Debug): spell not found") end break end end --]=] --Details:Msg("the message above are debugs of an Alpha version of Details!") --local whatKilledThePlayer = 0 end end end Details.OpenDetailsDeathRecap(nil, RecapID) end) end) --[=[ hooks not loaded at this point Details:InstallHook(DETAILS_HOOK_DEATH, function(_, _, _, _, _, _, _, targetName) if (targetName == UnitName("player")) then end end) --]=]