--[[ Recap 3.32 - Gello An AddOn for WoW to track and summarize all damage done around the user. ]] Recap_Version = 3.32 --[[ local tables ]] -- colors for the gauges local gaugecolor = { ["DmgIn"] = { r=.66,g=.25,b=.25 }, ["DmgOut"] = { r=.25,g=.66,b=.35 }, ["Heal"] = { r=.25,g=.5,b=.85 }, ["Time"] = { r=.75, g=.75, b=.75 }, ["Kills"] = { r=.75, g=.75, b=.75 }, ["MaxHit"] = { r=.75, g=.75, b=.75 }, ["DPS"] = { r=.25, g=.66, b=.35 }, ["Over"] = { r=.25, g=.5, b=.85 } } -- keys for (det)ails and (inc)oming data sets local detkey = { ["HitsDmg"]="d", ["Hits"]="n", ["HitsMax"]="x", ["CritsDmg"]="D", ["Crits"]="N", ["CritsMax"]="X", ["CritsEvents"]="e", ["Missed"]="m", ["TicksDmg"]="t", ["TicksMax"]="T" } local inckey = { ["MeleeDamage"]="a", ["MeleeMax"]="b", ["MeleeHits"]="c", ["MeleeCrits"]="d", ["MeleeMissed"]="e", ["MeleeDodged"]="f", ["MeleeParried"]="g", ["MeleeBlocked"]="h", ["NonMeleeDamage"]="i", ["NonMeleeMax"]="j", ["NonMeleeHits"]="k", ["NonMeleeCrits"]="l", ["NonMeleeMissed"]="m" } -- .Opt.x and its buttons local recapbuttons = { ["Minimized"] = "RecapMinimizeButton", ["Pinned"] = "RecapPinButton", ["Paused"] = "RecapPauseButton", ["SelfView"] = "RecapSelfViewButton" } --[[ Saved Variables ]] recap = {} -- options and current data recap_set = {} -- fight data sets --[[ Callback functions ]] function Recap_OnLoad() this:RegisterEvent("VARIABLES_LOADED") this:RegisterEvent("PLAYER_ENTERING_WORLD") this:RegisterEvent("UNIT_NAME_UPDATE") -- function overrides: recap.NormalExit is true on a successful /quit or /logout Recap_OldQuit = Quit Recap_OldLogout = Logout Recap_OldCancelLogout = CancelLogout Quit = function() recap.NormalExit = true; Recap_OldQuit(); end Logout = function() recap.NormalExit = true; Recap_OldLogout(); end CancelLogout = function() recap.NormalExit = nil; Recap_OldCancelLogout(); end end function Recap_OnEvent() if event=="VARIABLES_LOADED" then SlashCmdList["RecapCOMMAND"] = Recap_SlashHandler SLASH_RecapCOMMAND1 = "/Recap" elseif event=="PLAYER_ENTERING_WORLD" or event=="UNIT_NAME_UPDATE" then Recap_Initialize() elseif event=="PLAYER_REGEN_DISABLED" then if recap.Opt.LimitFights.value then Recap_StartFight() end elseif event=="PLAYER_REGEN_ENABLED" then Recap_EndFight() elseif event=="PARTY_MEMBERS_CHANGED" or event=="RAID_ROSTER_UPDATE" then Recap_MakeFriends() elseif event=="CHAT_MSG_CHANNEL_NOTICE" then if string.find(arg4,"recaplog"..string.lower(UnitName("player"))) and arg1=="YOU_JOINED" then RecapOpt_WriteLogLabel:SetText(RECAP_CHANNEL_JOINED_WRITING) ChatFrameLog(1) RecapFrame:UnregisterEvent("CHAT_MSG_CHANNEL_NOTICE") RecapFrame:RegisterEvent("CHAT_MSG_CHANNEL") Recap_WriteLog() end elseif event=="CHAT_MSG_CHANNEL" then if string.find(string.lower(arg4),"recaplog") and arg2==UnitName("player") and arg1=="EOF" then ChatFrameLog(0) RecapOpt_WriteLogLabel:SetText(RECAP_SAVE_TO_WOWCHATLOG_TXT) LeaveChannelByName("recaplog"..UnitName("player")) RecapFrame:UnregisterEvent("CHAT_MSG_CHANNEL") DEFAULT_CHAT_FRAME:AddMessage(recap_temp.Local.LogWritten) end end end function Recap_Idle_OnUpdate(arg1) -- timer to end idle fights if option checked if recap_temp.IdleTimer~=-1 and recap_temp.Loaded and recap.Opt.IdleFight.value then recap_temp.IdleTimer = recap_temp.IdleTimer + arg1 if recap_temp.IdleTimer > recap.Opt.IdleFightTimer.value then recap_temp.IdleTimer = -1 Recap_EndFight() end end -- if fighting and a plugin loaded or we're minimized, update min dps every half second if recap_temp.Loaded and recap_temp.UpdateTimer~=-1 and recap.Opt.State.value=="Active" and ((IB_Recap_Update or TitanPanelRecap_Update) or recap.Opt.Minimized.value) then recap_temp.UpdateTimer = recap_temp.UpdateTimer + arg1 if recap_temp.UpdateTimer>.5 then recap_temp.UpdateTimer = 0 Recap_UpdateMinimizedDPS() end end end function Recap_OnUpdate(arg1) -- update fade timer if option checked if recap_temp.Loaded and recap.Opt.AutoFade.value and not recap.Opt.Minimized.value and MouseIsOver(RecapFrame) and recap_temp.FadeTimer recap.Opt.AutoFadeTimer.value then RecapFrame:SetAlpha( max(1-min(2*(recap_temp.FadeTimer-recap.Opt.AutoFadeTimer.value),1),.1)) if recap_temp.FadeTimer > (recap.Opt.AutoFadeTimer.value+.5) then RecapFrame_Hide() end end end if recap_temp.Loaded and recap.Opt.AutoMinimize.value and recap_temp.Selected==0 then if not recap.Opt.Minimized.value and not MouseIsOver(RecapFrame) and not IsShiftKeyDown() then Recap_Minimize() elseif recap.Opt.Minimized.value and MouseIsOver(RecapFrame) and not IsShiftKeyDown() then Recap_Maximize() end end end function Recap_SlashHandler(arg1) Recap_Initialize() if arg1 and arg1=="reset" then RecapFrame:ClearAllPoints() RecapFrame:SetPoint("CENTER","UIParent","CENTER") RecapOptFrame:ClearAllPoints() RecapOptFrame:SetPoint("CENTER","UIParent","CENTER") Recap_SetView() elseif arg1=="debug" then if recap.debug then DEFAULT_CHAT_FRAME:AddMessage("recap.debug is ON. To turn it off: /recap debug off") for i=1,150 do if recap.debug_Filter[i] then DEFAULT_CHAT_FRAME:AddMessage("["..i.."] \""..recap.debug_Filter[i].pattern.."\" hits: "..recap.debug_Filter[i].hits..", total: "..recap.debug_Filter[i].total) end end DEFAULT_CHAT_FRAME:AddMessage("__ Filters not used __") Recap_DebugUnusedFilters("Filter") Recap_DebugUnusedFilters("HealFilter") Recap_DebugUnusedFilters("DeathFilter") else DEFAULT_CHAT_FRAME:AddMessage("recap.debug is OFF. To turn it on: /recap debug on") end elseif arg1=="debug on" then recap.debug = true DEFAULT_CHAT_FRAME:AddMessage("recap.debug is now ON.") elseif arg1=="debug off" then recap.debug = false DEFAULT_CHAT_FRAME:AddMessage("recap.debug is now OFF.") elseif arg1=="debug reset" then recap.debug_Filter = {} DEFAULT_CHAT_FRAME:AddMessage("recap.debug_Filter is RESET.") elseif string.find(arg1,"opt") then if RecapOptFrame:IsShown() then RecapOptFrame:Hide() else RecapOptFrame:Show() end elseif RecapFrame:IsShown() then RecapFrame_Hide() RecapOptFrame:Hide() else RecapFrame_Show() Recap_CheckWindowBounds() if recap.Opt.State.value == "Stopped" then Recap_SetState("Idle") recap.Opt.Paused.value = false Recap_SetButtons() end end end --[[ Window appearance functions ]] function Recap_SetState(arg1) if arg1 then recap.Opt.State.value = arg1 end if recap.Opt.State.value=="Stopped" then RecapStatusTexture:SetVertexColor(1,0,0) Recap_Unregister_CombatEvents() elseif recap.Opt.State.value=="Active" then RecapStatusTexture:SetVertexColor(0,1,0) Recap_Register_CombatEvents() else RecapStatusTexture:SetVertexColor(.5,.5,.5) Recap_Register_CombatEvents() end Recap_UpdatePlugins() end function RecapFrame_Hide() if not recap_temp.Loaded then Recap_Initialize() end recap_temp.FadeTimer = -1 RecapFrame:SetAlpha(1) RecapFrame:Hide() recap.Opt.Visible.value = false end function RecapFrame_Show() if not recap_temp.Loaded then Recap_Initialize() end RecapFrame:Show() recap.Opt.Visible.value = true end function RecapOptFrame_Hide() --[[ RecapSetEditBox:SetText("") RecapSetEditBox:ClearFocus() if RecapOptClipFrame:IsVisible() then RecapClipEditBox:ClearFocus() RecapOptClipFrame:Hide() RecapOptSubFrame4:Show() end ]] RecapOptFrame:Hide() end function RecapFrame_Toggle() if RecapFrame:IsShown() then RecapFrame_Hide() RecapOptFrame:Hide() else RecapFrame_Show() end end function Recap_Shutdown() recap.Opt.Paused.value = true Recap_EndFight() Recap_SetState("Stopped") Recap_SetButtons() RecapOptFrame:Hide() RecapFrame_Hide() RecapCombatEvents:UnregisterAll() end function Recap_ToggleView() if recap.Opt.View.value=="All" then Recap_SetView("Last") else Recap_SetView("All") end end -- changes button textures depending on their state function Recap_SetButtons() local i for i in recapbuttons do if recap.Opt[i].value then getglobal(recapbuttons[i]):SetNormalTexture("Interface\\AddOns\\Recap\\RecapButtons-Down") getglobal(recapbuttons[i]):SetPushedTexture("Interface\\AddOns\\Recap\\RecapButtons-Up") else getglobal(recapbuttons[i]):SetNormalTexture("Interface\\AddOns\\Recap\\RecapButtons-Up") getglobal(recapbuttons[i]):SetPushedTexture("Interface\\AddOns\\Recap\\RecapButtons-Down") end end if recap.Opt.View.value=="Last" then RecapShowAllButton:SetNormalTexture("Interface\\AddOns\\Recap\\RecapButtons-Up") RecapShowAllButton:SetPushedTexture("Interface\\AddOns\\Recap\\RecapButtons-Down") else RecapShowAllButton:SetNormalTexture("Interface\\AddOns\\Recap\\RecapButtons-Down") RecapShowAllButton:SetPushedTexture("Interface\\AddOns\\Recap\\RecapButtons-Up") end end -- this resizes the window width to the columns defined in options function Recap_SetColumns() local cx = 168 -- 8(edge)+120(name)+32(scroll)+8(edge) local i,j,icx,item RecapHeader_Name:Show() RecapTotals:Show() if recap.Opt.SelfView.value then for i in recap.Opt do if recap.Opt[i].ewidth then if recap.Opt[i].value then getglobal("RecapHeader_"..i):SetWidth(recap_temp.DefaultOpt[i].ewidth) getglobal("RecapHeader_"..i):Show() for j=1,15 do getglobal("RecapSelf"..j.."_"..i):SetWidth(recap_temp.DefaultOpt[i].ewidth) getglobal("RecapSelf"..j.."_"..i):Show() end cx = cx + recap_temp.DefaultOpt[i].ewidth else getglobal("RecapHeader_"..i):SetWidth(1) getglobal("RecapHeader_"..i):Hide() for j=1,15 do getglobal("RecapSelf"..j.."_"..i):SetWidth(1) getglobal("RecapSelf"..j.."_"..i):Hide() end cx = cx + 1 end elseif recap.Opt[i].width then getglobal("RecapHeader_"..i):Hide() end end RecapHeader_EName:Show() RecapHeader_Name:Hide() RecapTotals:Hide() for i=1,15 do getglobal("RecapList"..i):Hide() getglobal("RecapSelf"..i):Show() getglobal("RecapSelf"..i):SetWidth(cx-48) end RecapTotals_DPSIn:Hide() else for i in recap.Opt do if recap.Opt[i].width then if recap.Opt[i].value then item = getglobal("RecapHeader_"..i) item:SetWidth(recap_temp.DefaultOpt[i].width) item:Show() item = getglobal("RecapTotals_"..i) item:SetWidth(recap_temp.DefaultOpt[i].width) item:Show() for j=1,15 do item = getglobal("RecapList"..j.."_"..i) item:SetWidth(recap_temp.DefaultOpt[i].width) item:Show() end cx = cx + recap_temp.DefaultOpt[i].width else item = getglobal("RecapHeader_"..i) item:SetWidth(1) item:Hide() item = getglobal("RecapTotals_"..i) item:SetWidth(1) item:Hide() for j=1,15 do item = getglobal("RecapList"..j.."_"..i) item:SetWidth(1) item:Hide() end cx = cx + 1 end elseif recap.Opt[i].ewidth then getglobal("RecapHeader_"..i):Hide() end end for i=1,15 do getglobal("RecapSelf"..i):Hide() getglobal("RecapList"..i):Show() getglobal("RecapList"..i):SetWidth(cx-48) end RecapHeader_EName:Hide() if recap.Opt.DPSIn.value then RecapTotals_DPSIn:Show() else RecapTotals_DPSIn:Hide() end end RecapTotals:SetWidth(cx-48) if recap.Opt.GrowLeftwards.value and RecapFrame then i = RecapFrame:GetRight() j = RecapFrame:GetTop() if i and j then RecapFrame:ClearAllPoints() RecapFrame:SetPoint("TOPLEFT","UIParent","BOTTOMLEFT",i-cx,j) -- *** i not defined sometimes :( ** end end RecapTopBar:SetWidth(cx-8) RecapBottomBar:SetWidth(cx-16) RecapFrame:SetWidth(cx) RecapScrollBar:SetWidth(cx-16) recap_temp.GaugeWidth = cx-51 - ( (not recap.Opt.SelfView.value) and ((((recap.Opt.Faction.value and recap.Opt.Faction.width) or 1) + ((recap.Opt.Class.value and recap.Opt.Class.width) or 1) + ((recap.Opt.Ranks.value and recap.Opt.Ranks.width) or 1)) or 0) or 0) Recap_CheckWindowBounds() Recap_SetView() RecapScrollBar_Update() end -- changes view mode function Recap_SetView(arg1) local text if arg1 then recap.Opt.View.value = arg1 end Recap_SetButtons() Recap_ConstructList() cx = RecapFrame:GetWidth() -- change titlebar if cx and cx>300 and recap.Opt.SelfView.value then text = recap_temp.Player.."'s Details" elseif cx and cx>230 and recap.Opt.SelfView.value then text = recap_temp.Player elseif cx and cx<230 or recap.Opt.Minimized.value then text = "" if cx>180 and not recap.Opt.SelfView.value then text = recap.Opt.View.value end elseif cx and cx<260 then text = recap_temp.Local.LastAll[recap.Opt.View.value] else text = "Recap of "..recap_temp.Local.LastAll[recap.Opt.View.value] end RecapTitle:SetText(text) RecapHeader_Name:SetText((recap_temp.ListSize-1).." Combatants") Recap_ChangeBack() end function Recap_SetColors() if recap.Opt.UseColor.value then recap_temp.ColorDmgIn = recap_temp.ColorRed recap_temp.ColorDmgOut = recap_temp.ColorGreen recap_temp.ColorHeal = recap_temp.ColorBlue recap_temp.ColorHits = recap_temp.ColorCyan recap_temp.ColorTicks = recap_temp.ColorYellow recap_temp.ColorCrits = recap_temp.ColorLime recap_temp.ColorMiss = recap_temp.ColorPink else recap_temp.ColorDmgIn = recap_temp.ColorWhite recap_temp.ColorDmgOut = recap_temp.ColorNone recap_temp.ColorHeal = recap_temp.ColorWhite recap_temp.ColorHits = recap_temp.ColorWhite recap_temp.ColorTicks = recap_temp.ColorWhite recap_temp.ColorCrits = recap_temp.ColorWhite recap_temp.ColorMiss = recap_temp.ColorWhite end RecapTotals_DmgIn:SetTextColor(recap_temp.ColorDmgIn.r,recap_temp.ColorDmgIn.g,recap_temp.ColorDmgIn.b) RecapTotals_DmgOut:SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) RecapTotals_DPS:SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) RecapTotals_DPSvsAll:SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) RecapTotals_DPSIn:SetTextColor(recap_temp.ColorDmgIn.r,recap_temp.ColorDmgIn.g,recap_temp.ColorDmgIn.b) RecapTotals_Heal:SetTextColor(recap_temp.ColorHeal.r,recap_temp.ColorHeal.g,recap_temp.ColorHeal.b) RecapTotals_Over:SetTextColor(recap_temp.ColorHeal.r,recap_temp.ColorHeal.g,recap_temp.ColorHeal.b) RecapMinDPSIn_Text:SetTextColor(recap_temp.ColorDmgIn.r,recap_temp.ColorDmgIn.g,recap_temp.ColorDmgIn.b) RecapMinDPSOut_Text:SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) for i=1,15 do getglobal("RecapList"..i.."_HealP"):SetTextColor(recap_temp.ColorHeal.r,recap_temp.ColorHeal.g,recap_temp.ColorHeal.b) getglobal("RecapList"..i.."_Over"):SetTextColor(recap_temp.ColorHeal.r,recap_temp.ColorHeal.g,recap_temp.ColorHeal.b) getglobal("RecapList"..i.."_DmgInP"):SetTextColor(recap_temp.ColorDmgIn.r,recap_temp.ColorDmgIn.g,recap_temp.ColorDmgIn.b) getglobal("RecapList"..i.."_DmgOutP"):SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) getglobal("RecapSelf"..i.."_EHits"):SetTextColor(recap_temp.ColorHits.r,recap_temp.ColorHits.g,recap_temp.ColorHits.b) getglobal("RecapSelf"..i.."_EHitsAvg"):SetTextColor(recap_temp.ColorHits.r,recap_temp.ColorHits.g,recap_temp.ColorHits.b) getglobal("RecapSelf"..i.."_EHitsMax"):SetTextColor(recap_temp.ColorHits.r,recap_temp.ColorHits.g,recap_temp.ColorHits.b) getglobal("RecapSelf"..i.."_ETicks"):SetTextColor(recap_temp.ColorTicks.r,recap_temp.ColorTicks.g,recap_temp.ColorTicks.b) getglobal("RecapSelf"..i.."_ETicksAvg"):SetTextColor(recap_temp.ColorTicks.r,recap_temp.ColorTicks.g,recap_temp.ColorTicks.b) getglobal("RecapSelf"..i.."_ETicksMax"):SetTextColor(recap_temp.ColorTicks.r,recap_temp.ColorTicks.g,recap_temp.ColorTicks.b) getglobal("RecapSelf"..i.."_ECrits"):SetTextColor(recap_temp.ColorCrits.r,recap_temp.ColorCrits.g,recap_temp.ColorCrits.b) getglobal("RecapSelf"..i.."_ECritsAvg"):SetTextColor(recap_temp.ColorCrits.r,recap_temp.ColorCrits.g,recap_temp.ColorCrits.b) getglobal("RecapSelf"..i.."_ECritsMax"):SetTextColor(recap_temp.ColorCrits.r,recap_temp.ColorCrits.g,recap_temp.ColorCrits.b) getglobal("RecapSelf"..i.."_ECritsP"):SetTextColor(recap_temp.ColorCrits.r,recap_temp.ColorCrits.g,recap_temp.ColorCrits.b) getglobal("RecapSelf"..i.."_EMiss"):SetTextColor(recap_temp.ColorMiss.r,recap_temp.ColorMiss.g,recap_temp.ColorMiss.b) getglobal("RecapSelf"..i.."_EMissP"):SetTextColor(recap_temp.ColorMiss.r,recap_temp.ColorMiss.g,recap_temp.ColorMiss.b) end Recap_ChangeBack() end function Recap_ChangeBack() if recap.Opt.UseColor.value and (recap.Opt.MinBack.value or not recap.Opt.Minimized.value) then if recap.Opt.SelfView.value and not recap.Opt.Minimized.value then RecapTitleBack:SetVertexColor(0,0,.8) elseif recap.Opt.View.value=="Last" then RecapTitleBack:SetVertexColor(0,.66,0) else RecapTitleBack:SetVertexColor(.66,0,0) end RecapTitleBack:Show() else RecapTitleBack:Hide() end end --[[ Initialization ]] -- Can be called often, will immediately dump out if it ran through successfully function Recap_Initialize() local i,x local init_time if not recap_temp.Loaded then if UnitName("player") and UnitName("player")~=UNKNOWNOBJECT and RecapFrame and RecapOptFrame then init_time = GetTime() recap_temp.Player = UnitName("player") recap_temp.Server = GetCVar("realmName") -- recap index for this player recap_temp.p = recap_temp.Player..recap_temp.Server -- use for stuff that can be made global recap_temp.s = recap_temp.Player..recap_temp.Server -- use for stuff that should never be global if recap and recap.UseOneSettings and recap.User then recap_temp.p = recap.User end -- sources of damage/heals otherwise not declared in chat spam recap_temp.FilterIndex[6] = recap_temp.Player recap_temp.FilterIndex[7] = "Melee" recap_temp.FilterIndex[8] = "Damage Shields" recap_temp.FilterIndex[13] = 0 Recap_InitializeData() if not recap[recap_temp.p].WindowTop and RecapFrame then RecapFrame:ClearAllPoints() RecapFrame:SetPoint("CENTER","UIParent","CENTER") RecapOptFrame:ClearAllPoints() RecapOptFrame:SetPoint("CENTER", "UIParent", "CENTER") elseif recap[recap_temp.p].WindowTop and RecapFrame then RecapFrame:ClearAllPoints() RecapFrame:SetPoint("TOPLEFT","UIParent","BOTTOMLEFT",recap[recap_temp.p].WindowLeft,recap[recap_temp.p].WindowTop) RecapFrame:SetWidth(recap[recap_temp.p].WindowWidth) RecapFrame:SetHeight(recap[recap_temp.p].WindowHeight) end for i in recap.Combatant do recap.Combatant[i].WasInLast = false recap.Combatant[i].WasInCurrent = false end recap[recap_temp.p].LastDuration = 0 Recap_SetColors() -- if we loaded out of stopped state, force into idle state if recap.Opt.State.value ~= "Stopped" then recap.Opt.State.value = "Idle" end Recap_SetState() RecapTotals_Name:SetWidth(82) Recap_InitDataSets() if recap.Opt.LightData.value then recap.Opt.SelfView.value = false RecapSelfViewButton:Hide() end if recap.Opt.Minimized.value then Recap_SetButtons() Recap_ConstructList() Recap_Minimize() else Recap_Maximize() end -- we're in the world (in theory), register active events this:RegisterEvent("PLAYER_REGEN_DISABLED") this:RegisterEvent("PLAYER_REGEN_ENABLED") this:RegisterEvent("PARTY_MEMBERS_CHANGED") this:RegisterEvent("RAID_ROSTER_UPDATE") Recap_Register_CombatEvents() recap_temp.Loaded = true Recap_InitializeOptions() Recap_MoveMinimize() -- initialize panel recap_temp.Selected = 0 if recap.Opt.LightData.value then recap.Opt.PanelView.value = 3 RecapPanelTab1:SetAlpha(.5) RecapPanelTab2:SetAlpha(.5) end RecapPanel_SwitchPanels(recap.Opt.PanelView.value) if recap.Opt.PanelAnchor.value then RecapPanel:ClearAllPoints() RecapPanel:SetPoint(recap.Opt.PanelAnchor.Panel,"RecapFrame",recap.Opt.PanelAnchor.Main,Recap_PanelOffset("x"),Recap_PanelOffset("y")) end RecapPanelFaction:SetAlpha(.75) for i=1,15 do getglobal("RecapList"..i.."_Faction"):SetAlpha(.75) end if recap.Opt.Visible.value then RecapFrame_Show() else RecapFrame_Hide() end if recap.Opt.Paused.value then RecapFrame_Hide() end if recap.debug then DEFAULT_CHAT_FRAME:AddMessage("[recap.debug] Time to initialize: "..string.format("%.4f",GetTime()-init_time).." seconds.") end -- warn if user has a lot of data (over 500 combatants) x = 0 for i in recap.Combatant do x = x + 1 end if x>500 and recap.Opt.WarnData.value then StaticPopupDialogs["RECAP_LOTS_OF_DATA_WARNING"] = { text = TEXT(string.format(recap_temp.Local.LotsOfDataWarning,x)), button1 = TEXT(OKAY), timeout = 0, showAlert = 1, whileDead = 1 } StaticPopup_Show("RECAP_LOTS_OF_DATA_WARNING") end table.insert(UISpecialFrames,"RecapOptFrame") table.insert(UISpecialFrames,"RecapPanel") end end end -- arg1==1 to hide buttons, 16 to show function Recap_ShowButtons(arg1) RecapCloseButton:SetWidth(arg1) RecapPinButton:SetWidth(arg1) RecapPauseButton:SetWidth(arg1) RecapOptionsButton:SetWidth(arg1) RecapShowAllButton:SetWidth(arg1) if arg1==16 then RecapCloseButton:Show() RecapPinButton:Show() RecapPauseButton:Show() RecapOptionsButton:Show() RecapShowAllButton:Show() else RecapCloseButton:Hide() RecapPinButton:Hide() RecapPauseButton:Hide() RecapOptionsButton:Hide() RecapShowAllButton:Hide() end end function Recap_Minimize() local i,j local cx = 20 -- 8(edge)+4(space right of status)+8 recap.Opt.Minimized.value = true for i in recap.Opt do if recap.Opt[i].minwidth then if recap.Opt[i].value then item = getglobal("Recap"..i) item:SetWidth(recap.Opt[i].minwidth) item:Show() cx = cx + recap.Opt[i].minwidth else item = getglobal("Recap"..i) item:SetWidth(1) item:Hide() cx = cx + 1 end elseif recap.Opt[i].width or recap.Opt[i].ewidth then getglobal("RecapHeader_"..i):Hide() end end if recap.Opt.MinButtons.value then cx = cx + 108 Recap_ShowButtons(16) else Recap_ShowButtons(1) cx = cx + 23 -- 5 + 18 end RecapTitle:SetText(recap.Opt.View.value) RecapTopBar:Hide() RecapBottomBar:Hide() RecapTotals_DPSIn:Hide() RecapResetButton:Hide() for i=1,15 do getglobal("RecapList"..i):Hide() getglobal("RecapSelf"..i):Hide() end RecapTotals:Hide() RecapHeader_EName:Hide() RecapHeader_Name:Hide() RecapScrollBar:Hide() if recap.Opt.AutoMinimize.value then cx = cx-15 end if recap.Opt.GrowLeftwards.value and RecapFrame then i = RecapFrame:GetRight() j = RecapFrame:GetTop() if i and j then RecapFrame:ClearAllPoints() RecapFrame:SetPoint("TOPLEFT","UIParent","BOTTOMLEFT",i-cx,j) end end RecapFrame:SetWidth(cx) Recap_SetHeight(28) if recap.Opt.MinBack.value then RecapFrame:SetBackdropColor(1,1,1,1) RecapFrame:SetBackdropBorderColor(.5,.5,.5,1) else RecapFrame:SetBackdropColor(0,0,0,0) RecapFrame:SetBackdropBorderColor(0,0,0,0) end RecapSelfViewButton:Hide() RecapPanel_Hide(1) Recap_MoveMinimize() Recap_ChangeBack() RecapMinView:GetLeft() end function Recap_Maximize() recap.Opt.Minimized.value = false for i in recap.Opt do if recap.Opt[i].minwidth then item = getglobal("Recap"..i) item:SetWidth(recap.Opt[i].minwidth) item:Hide() end end RecapMinStatus:Show() RecapMinView:Show() Recap_ShowButtons(16) RecapTopBar:Show() RecapBottomBar:Show() RecapResetButton:Show() RecapTotals:Show() RecapHeader_Name:Show() RecapScrollBar:Show() Recap_SetColumns() RecapFrame:SetBackdropColor(1,1,1,1) RecapFrame:SetBackdropBorderColor(.5,.5,.5,1) if not recap.Opt.LightData.value then RecapSelfViewButton:Show() end Recap_MoveMinimize() end function Recap_SetHeight(newcy) local i,j if recap.Opt.GrowUpwards.value and RecapFrame then i = RecapFrame:GetBottom() j = RecapFrame:GetLeft() if i and j then RecapFrame:ClearAllPoints() RecapFrame:SetPoint("TOPLEFT","UIParent","BOTTOMLEFT",j,i+newcy) end end RecapFrame:SetHeight(newcy) Recap_CheckWindowBounds() end function RecapScrollBar_Update() local i, index, item local listsize = recap.Opt.SelfView.value and recap_temp.SelfListSize or recap_temp.ListSize if not recap.Opt.Minimized.value then i = 72 + ( math.max( math.min(listsize-1,recap.Opt.MaxRows.value),1 )*14 ) Recap_SetHeight(i) RecapScrollBar:SetHeight(i-63) FauxScrollFrame_Update(RecapScrollBar,listsize-1,recap.Opt.MaxRows.value,10) for i=1,recap.Opt.MaxRows.value do index = i + FauxScrollFrame_GetOffset(RecapScrollBar) if not recap.Opt.SelfView.value then if index < listsize then getglobal("RecapList"..i.."_Ranks"):SetText(index..".") Recap_SetFactionIcon(i,recap.Combatant[recap_temp.List[index].Name].Faction) Recap_SetClassIcon(i,recap.Combatant[recap_temp.List[index].Name].Class) if recap.Opt.Faction.value and recap.Combatant[recap_temp.List[index].Name].Level==-1 then getglobal("RecapList"..i.."_Level"):SetText("??") elseif recap.Opt.Faction.value and recap.Combatant[recap_temp.List[index].Name].Level and tonumber(recap.Combatant[recap_temp.List[index].Name].Level)>0 then getglobal("RecapList"..i.."_Level"):SetText(recap.Combatant[recap_temp.List[index].Name].Level) else getglobal("RecapList"..i.."_Level"):SetText(" ") end item = getglobal("RecapList"..i.."_Name") item:SetText(recap_temp.List[index].Name) if recap.Combatant[recap_temp.List[index].Name].Friend then item:SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) else item:SetTextColor(recap_temp.ColorWhite.r,recap_temp.ColorWhite.g,recap_temp.ColorWhite.b) end item = getglobal("RecapList"..i.."_Gauge") if recap.Opt.ShowGauges.value and recap_temp.GaugeMax>0 and recap.Combatant[recap_temp.List[index].Name].Friend and recap_temp.GaugeBy then item:SetWidth(1+recap_temp.GaugeWidth*recap_temp.List[index][recap_temp.GaugeBy]/recap_temp.GaugeMax) item:Show() else item:Hide() end getglobal("RecapList"..i.."_Kills"):SetText(recap_temp.List[index].Kills) getglobal("RecapList"..i.."_Time"):SetText(Recap_FormatTime(recap_temp.List[index].Time)) item = getglobal("RecapList"..i.."_Heal") item:SetText(recap_temp.List[index].Heal) if recap.Combatant[recap_temp.List[index].Name].Friend then item:SetTextColor(recap_temp.ColorHeal.r,recap_temp.ColorHeal.g,recap_temp.ColorHeal.b) else item:SetTextColor(recap_temp.ColorWhite.r,recap_temp.ColorWhite.g,recap_temp.ColorWhite.b) end getglobal("RecapList"..i.."_HealP"):SetText(recap.Combatant[recap_temp.List[index].Name].Friend and recap_temp.List[index].HealP.."%" or "") getglobal("RecapList"..i.."_Over"):SetText(recap.Combatant[recap_temp.List[index].Name].Friend and recap_temp.List[index].Over.."%" or "") getglobal("RecapList"..i.."_MaxHit"):SetText(recap_temp.List[index].MaxHit) item = getglobal("RecapList"..i.."_DmgIn") item:SetText(recap_temp.List[index].DmgIn) if recap.Combatant[recap_temp.List[index].Name].Friend then item:SetTextColor(recap_temp.ColorDmgIn.r,recap_temp.ColorDmgIn.g,recap_temp.ColorDmgIn.b) else item:SetTextColor(recap_temp.ColorWhite.r,recap_temp.ColorWhite.g,recap_temp.ColorWhite.b) end getglobal("RecapList"..i.."_DmgInP"):SetText(recap.Combatant[recap_temp.List[index].Name].Friend and recap_temp.List[index].DmgInP.."%" or "") item = getglobal("RecapList"..i.."_DmgOut") item:SetText(recap_temp.List[index].DmgOut) if recap.Combatant[recap_temp.List[index].Name].Friend then item:SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) else item:SetTextColor(recap_temp.ColorWhite.r,recap_temp.ColorWhite.g,recap_temp.ColorWhite.b) end getglobal("RecapList"..i.."_DmgOutP"):SetText(recap.Combatant[recap_temp.List[index].Name].Friend and recap_temp.List[index].DmgOutP.."%" or "") item = getglobal("RecapList"..i.."_DPS") item:SetText(format(recap_temp.List[index].DPS<1000 and "%.1f" or "%d",recap_temp.List[index].DPS)) if recap.Combatant[recap_temp.List[index].Name].Friend then item:SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) else item:SetTextColor(recap_temp.ColorWhite.r,recap_temp.ColorWhite.g,recap_temp.ColorWhite.b) end item = getglobal("RecapList"..i.."_DPSvsAll") item:SetText(format(recap_temp.List[index].DPSvsAll<1000 and "%.1f" or "%d",recap_temp.List[index].DPSvsAll)) if recap.Combatant[recap_temp.List[index].Name].Friend then item:SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) else item:SetTextColor(recap_temp.ColorWhite.r,recap_temp.ColorWhite.g,recap_temp.ColorWhite.b) end item = getglobal("RecapList"..i) item:Show() if recap_temp.Selected == index then item:LockHighlight() else item:UnlockHighlight() end else getglobal("RecapList"..i):Hide() getglobal("RecapList"..i):UnlockHighlight() end for i=recap.Opt.MaxRows.value+1,15 do getglobal("RecapList"..i):Hide() end elseif recap.Opt.SelfView.value then if index < listsize then getglobal("RecapSelf"..i.."_EName"):SetText(string.sub(recap_temp.SelfList[index].EName,2)) getglobal("RecapSelf"..i.."_ETotal"):SetText(recap_temp.SelfList[index].ETotal) getglobal("RecapSelf"..i.."_EHits"):SetText(recap_temp.SelfList[index].EHits) getglobal("RecapSelf"..i.."_ETicks"):SetText(recap_temp.SelfList[index].ETicks) getglobal("RecapSelf"..i.."_ECrits"):SetText(recap_temp.SelfList[index].ECrits) getglobal("RecapSelf"..i.."_EHitsAvg"):SetText(recap_temp.SelfList[index].EHitsAvg) getglobal("RecapSelf"..i.."_ETicksAvg"):SetText(recap_temp.SelfList[index].ETicksAvg) getglobal("RecapSelf"..i.."_ECritsAvg"):SetText(recap_temp.SelfList[index].ECritsAvg) getglobal("RecapSelf"..i.."_EHitsMax"):SetText(recap_temp.SelfList[index].EHitsMax) getglobal("RecapSelf"..i.."_ETicksMax"):SetText(recap_temp.SelfList[index].ETicksMax) getglobal("RecapSelf"..i.."_ECritsMax"):SetText(recap_temp.SelfList[index].ECritsMax) getglobal("RecapSelf"..i.."_ECritsP"):SetText(recap_temp.SelfList[index].ECritsP) getglobal("RecapSelf"..i.."_EMiss"):SetText(recap_temp.SelfList[index].EMiss) getglobal("RecapSelf"..i.."_EMissP"):SetText(recap_temp.SelfList[index].EMissP) getglobal("RecapSelf"..i.."_EMaxAll"):SetText(recap_temp.SelfList[index].EMaxAll) getglobal("RecapSelf"..i.."_ETotalP"):SetText(recap_temp.SelfList[index].ETotalP) if string.sub(recap_temp.SelfList[index].EName,1,1)<"3" then getglobal("RecapSelf"..i.."_EName"):SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) getglobal("RecapSelf"..i.."_ETotal"):SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) getglobal("RecapSelf"..i.."_ETotalP"):SetTextColor(recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) else getglobal("RecapSelf"..i.."_EName"):SetTextColor(recap_temp.ColorHeal.r,recap_temp.ColorHeal.g,recap_temp.ColorHeal.b) getglobal("RecapSelf"..i.."_ETotal"):SetTextColor(recap_temp.ColorHeal.r,recap_temp.ColorHeal.g,recap_temp.ColorHeal.b) getglobal("RecapSelf"..i.."_ETotalP"):SetTextColor(recap_temp.ColorHeal.r,recap_temp.ColorHeal.g,recap_temp.ColorHeal.b) end getglobal("RecapSelf"..i):Show() else getglobal("RecapSelf"..i):Hide() end for i=recap.Opt.MaxRows.value+1,15 do getglobal("RecapSelf"..i):Hide() end end end end end --[[ Fight functions ]] function Recap_CreateCombatant(arg1,is_source) if not arg1 then return end -- if arg1 not a .Combatant, add an entry for them if not recap.Combatant[arg1] then Recap_CreateBlankCombatant(arg1) end -- if they haven't fought this session, add a .Last entry for them if not recap_temp.Last[arg1] then recap_temp.Last[arg1] = { Start = 0, End = 0, DmgIn = 0, DmgOut = 0, MaxHit = 0, Kills = 0, Heal = 0 } end -- if arg1 is hitting others, update their start or end time if is_source then if recap_temp.FightStart==0 then recap_temp.FightStart = GetTime() recap_temp.FightEnd = recap_temp.FightStart else recap_temp.FightEnd = GetTime() end if recap_temp.Last[arg1].Start==0 then recap_temp.Last[arg1].Start = GetTime() recap_temp.Last[arg1].End = recap_temp.Last[arg1].Start else recap_temp.Last[arg1].End = GetTime() end end recap.Combatant[arg1].WasInCurrent = true end function Recap_StartFight() local i if recap.Opt.State.value=="Idle" then if recap.Opt.AutoHide.value and not recap.Opt.Minimized.value then RecapFrame_Hide() end for i in recap.Combatant do recap.Combatant[i].WasInCurrent = false end if not recap.Opt.LimitFights.value and recap.Opt.IdleFight.value then recap_temp.IdleTimer = 0 end RecapIdleFrame:Show() -- start idle OnUpdates Recap_SetState("Active") end end -- returns the current DPS of combatant named arg1 if it exists. UpdateDuration/DamageOut reused to save allocations function Recap_GetCurrentDPS(arg1) if arg1 and recap_temp.Last[arg1] and recap_temp.Last[arg1].DmgOut>0 then recap_temp.UpdateDuration = recap_temp.Last[arg1].End - recap_temp.Last[arg1].Start if recap.Opt.View.value=="All" then recap_temp.UpdateDuration = recap_temp.UpdateDuration + recap.Combatant[arg1].TotalTime end recap_temp.UpdateDamageOut = recap_temp.Last[arg1].DmgOut if recap.Opt.View.value=="All" then recap_temp.UpdateDamageOut = recap_temp.UpdateDamageOut + recap.Combatant[arg1].TotalDmgOut end if recap_temp.UpdateDuration > recap_temp.MinTime then return (recap_temp.UpdateDamageOut / recap_temp.UpdateDuration) end end return 0 end function Recap_UpdateMinimizedDPS() if recap.Opt.State.value=="Active" then if recap_temp.Last[recap_temp.Player] and recap_temp.Last[recap_temp.Player].DmgOut>0 then i = Recap_GetCurrentDPS(recap_temp.Player)+Recap_GetCurrentDPS(UnitName("pet")) RecapMinYourDPS_Text:SetText(string.format("%.1f",i)) end -- calculate running total DPS In and Out recap_temp.UpdateDuration = 0 if recap_temp.FightEnd>0 and recap_temp.FightStart>0 then recap_temp.UpdateDuration = recap_temp.FightEnd - recap_temp.FightStart end if recap.Opt.View.value=="All" then recap_temp.UpdateDuration = recap_temp.UpdateDuration + recap[recap_temp.p].TotalDuration end if recap_temp.UpdateDuration>recap_temp.MinTime then recap_temp.UpdateDmgIn = 0 recap_temp.UpdateDmgOut = 0 for i in recap_temp.Last do if recap.Combatant[i].Friend then recap_temp.UpdateDmgIn = recap_temp.UpdateDmgIn + recap_temp.Last[i].DmgIn recap_temp.UpdateDmgOut = recap_temp.UpdateDmgOut + recap_temp.Last[i].DmgOut end end if recap.Opt.View.value=="All" then for i in recap.Combatant do if recap.Combatant[i].Friend then recap_temp.UpdateDmgIn = recap_temp.UpdateDmgIn + recap.Combatant[i].TotalDmgIn recap_temp.UpdateDmgOut = recap_temp.UpdateDmgOut + recap.Combatant[i].TotalDmgOut end end end RecapMinDPSIn_Text:SetText(string.format("%.1f",recap_temp.UpdateDmgIn/recap_temp.UpdateDuration)) RecapMinDPSOut_Text:SetText(string.format("%.1f",recap_temp.UpdateDmgOut/recap_temp.UpdateDuration)) end Recap_UpdatePlugins() end end function Recap_AddPetToOwner(pet,owner) local earliest,latest local peteffect -- times are only for DAMAGE if (recap.Combatant[pet].WasInCurrent and recap_temp.Last[pet].DmgOut>0) and (recap.Combatant[owner].WasInCurrent and recap_temp.Last[owner].DmgOut>0) then -- both pet and owner were in fight earliest = math.min(recap_temp.Last[pet].Start,recap_temp.Last[owner].Start) latest = math.max(recap_temp.Last[pet].End,recap_temp.Last[owner].End) recap_temp.Last[owner].Start = earliest recap_temp.Last[owner].End = latest elseif (recap.Combatant[pet].WasInCurrent and recap_temp.Last[pet].DmgOut>0) and (not recap.Combatant[owner].WasInCurrent or recap_temp.Last[owner].DmgOut==0) then -- just the pet was in fight recap_temp.Last[owner].Start = recap_temp.Last[pet].Start recap_temp.Last[owner].End = recap_temp.Last[pet].End else return -- temp fix for attempt to index field ? (a nil value) in line below *** end recap_temp.Last[owner].DmgIn = recap_temp.Last[owner].DmgIn + recap_temp.Last[pet].DmgIn recap_temp.Last[owner].DmgOut = recap_temp.Last[owner].DmgOut + recap_temp.Last[pet].DmgOut recap_temp.Last[owner].MaxHit = math.max(recap_temp.Last[owner].MaxHit,recap_temp.Last[pet].MaxHit) Recap_AccumulateCombatant(owner) recap_temp.Last[pet].Start = 0 recap_temp.Last[pet].End = 0 recap_temp.Last[pet].DmgIn = 0 recap_temp.Last[pet].DmgOut = 0 recap_temp.Last[pet].MaxHit = 0 recap_temp.Last[pet].Kills = 0 recap_temp.Last[pet].Heal = 0 recap.Combatant[pet].WasInLast = false recap.Combatant[owner].WasInLast = true recap.Combatant[pet].WasInCurrent = false recap.Combatant[owner].WasInCurrent = false if not recap.Opt.LightData.value then for i in recap.Combatant[pet].Detail do if string.sub(i,1,1)=="1" then peteffect = "2"..pet.."'s "..string.sub(i,2) else peteffect = "4"..pet.."'s "..string.sub(i,2) end recap.Combatant[owner].Detail[peteffect] = { Hits = recap.Combatant[pet].Detail[i].Hits, HitsDmg = recap.Combatant[pet].Detail[i].HitsDmg, HitsMax = recap.Combatant[pet].Detail[i].HitsMax, Crits = recap.Combatant[pet].Detail[i].Crits, CritsEvents = recap.Combatant[pet].Detail[i].CritsEvents, CritsDmg = recap.Combatant[pet].Detail[i].CritsDmg, CritsMax = recap.Combatant[pet].Detail[i].CritsMax, Missed = recap.Combatant[pet].Detail[i].Missed, TicksDmg = recap.Combatant[pet].Detail[i].TicksDmg, TicksMax = recap.Combatant[pet].Detail[i].TicksMax } if owner==recap_temp.Player then recap.Self[recap_temp.s][peteffect] = { Hits = recap.Combatant[pet].Detail[i].Hits, HitsDmg = recap.Combatant[pet].Detail[i].HitsDmg, HitsMax = recap.Combatant[pet].Detail[i].HitsMax, Crits = recap.Combatant[pet].Detail[i].Crits, CritsEvents = recap.Combatant[pet].Detail[i].CritsEvents, CritsDmg = recap.Combatant[pet].Detail[i].CritsDmg, CritsMax = recap.Combatant[pet].Detail[i].CritsMax, Missed = recap.Combatant[pet].Detail[i].Missed, TicksDmg = recap.Combatant[pet].Detail[i].TicksDmg, TicksMax = recap.Combatant[pet].Detail[i].TicksMax } end end end end function Recap_AccumulateCombatant(i) recap.Combatant[i].LastDmgIn = recap_temp.Last[i].DmgIn recap.Combatant[i].LastDmgOut = recap_temp.Last[i].DmgOut recap.Combatant[i].LastTime = recap_temp.Last[i].End-recap_temp.Last[i].Start recap.Combatant[i].LastMaxHit = recap_temp.Last[i].MaxHit recap.Combatant[i].LastKills = recap_temp.Last[i].Kills recap.Combatant[i].LastHeal = recap_temp.Last[i].Heal recap_temp.Last[i].Start = 0 recap_temp.Last[i].End = 0 recap_temp.Last[i].DmgIn = 0 recap_temp.Last[i].DmgOut = 0 recap_temp.Last[i].MaxHit = 0 recap_temp.Last[i].Kills = 0 recap_temp.Last[i].Heal = 0 recap.Combatant[i].TotalDmgIn = recap.Combatant[i].TotalDmgIn + recap.Combatant[i].LastDmgIn recap.Combatant[i].TotalDmgOut = recap.Combatant[i].TotalDmgOut + recap.Combatant[i].LastDmgOut recap.Combatant[i].TotalTime = recap.Combatant[i].TotalTime + recap.Combatant[i].LastTime recap.Combatant[i].TotalKills = recap.Combatant[i].TotalKills + recap.Combatant[i].LastKills recap.Combatant[i].TotalHeal = recap.Combatant[i].TotalHeal + recap.Combatant[i].LastHeal if recap.Combatant[i].LastTime > recap_temp.MinTime then recap.Combatant[i].LastDPS = recap.Combatant[i].LastDmgOut/recap.Combatant[i].LastTime else recap.Combatant[i].LastDPS = 0 end if recap.Combatant[i].TotalTime > recap_temp.MinTime then recap.Combatant[i].TotalDPS = recap.Combatant[i].TotalDmgOut/recap.Combatant[i].TotalTime else recap.Combatant[i].TotalDPS = 0 end recap.Combatant[i].TotalMaxHit = math.max(recap.Combatant[i].LastMaxHit,recap.Combatant[i].TotalMaxHit) recap.Combatant[i].WasInLast = true end function Recap_EndFight() recap_temp.IdleTimer = -1 RecapIdleFrame:Hide() if recap.Opt.State.value=="Active" then recap.Opt.State.value = "Stopped" -- suspend logging to calculate local debug_time = GetTime() Recap_MakeFriends() if recap_temp.FightEnd>recap_temp.FightStart then recap[recap_temp.p].LastDuration = recap_temp.FightEnd-recap_temp.FightStart else recap[recap_temp.p].LastDuration = 0 end recap[recap_temp.p].TotalDuration = recap[recap_temp.p].TotalDuration + recap[recap_temp.p].LastDuration recap_temp.FightStart = 0 recap_temp.FightEnd = 0 recap_temp.ListSize = 1 for i in recap_temp.Last do if recap.Combatant[i].WasInCurrent then if recap.Combatant[i].OwnedBy and recap.Opt.MergePets.value then Recap_AddPetToOwner(i,recap.Combatant[i].OwnedBy) elseif recap.Combatant[i].OwnsPet and recap.Opt.MergePets.value then Recap_AddPetToOwner(recap.Combatant[i].OwnsPet,i) else Recap_AccumulateCombatant(i) end else recap.Combatant[i].WasInLast = false end end if recap.Opt.AutoPost.value then recap.Opt.SortBy.value = Recap_AutoPostGetStatID(recap.Opt.AutoPost.Stat) recap.Opt.SortDir.value = false end Recap_ConstructList() Recap_SetState("Idle") if not recap.Opt.Minimized.value and recap.Opt.AutoHide.value then RecapFrame_Show() if recap.Opt.AutoFade.value then recap_temp.FadeTimer = 0 end end if recap.Opt.AutoPost.value then Recap_PostFight() end if recap.Opt.AutoLeader.value then Recap_PostLeader() end if recap.debug then DEFAULT_CHAT_FRAME:AddMessage("[recap.debug] Fight processed in "..string.format("%.4f",GetTime()-debug_time).." seconds for "..(recap_temp.ListSize-1).." combatants.") end end end -- parses CHAT_MSG_SPELL/COMBAT messages to .Last running totals function Recap_DamageEvent(arg1) local i, source, dest, damage, miss, effect local found = false local blocked = false if recap.Opt.State.value~="Stopped" then blocked = string.find(arg1,string.gsub(BLOCK_TRAILER,"%%d","%%d+")) -- true if (%d blocked) arg1 = string.gsub(arg1," %(.+%)","") -- strip trailing ()'s we don't use arg1 = string.gsub(arg1,"%.$","") -- strip trailing .'s for i=1,recap_temp.FilterSize do found,_,recap_temp.FilterIndex[1],recap_temp.FilterIndex[2],recap_temp.FilterIndex[3],recap_temp.FilterIndex[4],recap_temp.FilterIndex[5] = string.find(arg1,recap_temp.Filter[i].pattern) if found then source=recap_temp.FilterIndex[recap_temp.Filter[i].source] dest=recap_temp.FilterIndex[recap_temp.Filter[i].dest] if recap_temp.Local.SelfPronouns[string.lower(dest)] then dest = recap_temp.Player end if recap_temp.Filter[i].damage then damage=tonumber(recap_temp.FilterIndex[recap_temp.Filter[i].damage]) end if recap_temp.Filter[i].effect then effect = recap_temp.FilterIndex[recap_temp.Filter[i].effect] end if (recap.Combatant[source] and recap.Combatant[source].Ignore) or (recap.Combatant[dest] and recap.Combatant[dest].Ignore) then return -- this is an ignored combatant, pretend the hit didn't happen at all end if not recap.Opt.LimitFights.value then if recap.Opt.IdleFight.value then recap_temp.IdleTimer = 0 end if recap.Opt.State.value=="Idle" then Recap_StartFight() end end if recap.debug then if not recap.debug_Filter then recap.debug_Filter = {} end if not recap.debug_Filter[i] then recap.debug_Filter[i] = { hits=1, total=(damage or 1), pattern=recap_temp.Filter[i].pattern } else recap.debug_Filter[i].hits = recap.debug_Filter[i].hits + 1 recap.debug_Filter[i].total = recap.debug_Filter[i].total + (damage or 1) end if recap_temp.Filter[i].watch then DEFAULT_CHAT_FRAME:AddMessage("["..i.."] \""..recap_temp.Filter[i].pattern.."\" triggered!") DEFAULT_CHAT_FRAME:AddMessage("source="..tostring(source)..", dest="..tostring(dest)..", damage="..tostring(damage)..", miss="..tostring(miss)) end end if damage~=0 then -- if this wasn't just a cast Recap_CreateCombatant(source,1) Recap_CreateCombatant(dest) -- remove friend flag from hostiles no longer charmed if recap.Combatant[source].Friend and recap.Combatant[dest].Friend then recap.Combatant[source].Friend = false end else if (not recap.Opt.LightData.value) and recap.Combatant[source] and recap.Combatant[source].Detail["1"..effect] then Recap_CreateCombatant(source,1) -- if this was a cast that's done damage before, start timer end end if damage and damage>0 then -- process totals recap_temp.Last[source].DmgOut = recap_temp.Last[source].DmgOut + damage if damage > recap_temp.Last[source].MaxHit then recap_temp.Last[source].MaxHit = damage end recap_temp.Last[dest].DmgIn = recap_temp.Last[dest].DmgIn + damage if recap_temp.Last[dest].HP then recap_temp.Last[dest].HP = recap_temp.Last[dest].HP - damage end if not recap.Opt.LightData.value then if recap_temp.Filter[i].effect==7 then -- melee damage recap.Combatant[dest].Incoming.MeleeDamage = (recap.Combatant[dest].Incoming.MeleeDamage or 0) + damage if recap_temp.Filter[i].crit==1 then recap.Combatant[dest].Incoming.MeleeCrits = (recap.Combatant[dest].Incoming.MeleeCrits or 0) + 1 else recap.Combatant[dest].Incoming.MeleeHits = (recap.Combatant[dest].Incoming.MeleeHits or 0) + 1 end recap.Combatant[dest].Incoming.MeleeMax = math.max(damage,recap.Combatant[dest].Incoming.MeleeMax or 0) if blocked then recap.Combatant[dest].Incoming.MeleeBlocked = (recap.Combatant[dest].Incoming.MeleeBlocked or 0)+ 1 end else recap.Combatant[dest].Incoming.NonMeleeDamage = (recap.Combatant[dest].Incoming.NonMeleeDamage or 0) + damage if recap_temp.Filter[i].crit==1 then recap.Combatant[dest].Incoming.NonMeleeCrits = (recap.Combatant[dest].Incoming.NonMeleeCrits or 0) + 1 else recap.Combatant[dest].Incoming.NonMeleeHits = (recap.Combatant[dest].Incoming.NonMeleeHits or 0) + 1 end recap.Combatant[dest].Incoming.NonMeleeMax = math.max(damage,recap.Combatant[dest].Incoming.NonMeleeMax or 0) end Recap_CreateEffect(source,effect,1,damage,recap_temp.Filter[i].crit) end elseif recap_temp.Filter[i].miss and not recap.Opt.LightData.value then if recap_temp.Filter[i].miss==9 and recap_temp.Filter[i].effect==7 then -- melee normal miss recap.Combatant[dest].Incoming.MeleeMissed = (recap.Combatant[dest].Incoming.MeleeMissed or 0) + 1 elseif recap_temp.Filter[i].miss==9 then -- non-melee miss recap.Combatant[dest].Incoming.NonMeleeMissed = (recap.Combatant[dest].Incoming.NonMeleeMissed or 0) + 1 elseif recap_temp.Filter[i].miss==10 then -- melee dodge recap.Combatant[dest].Incoming.MeleeDodged = (recap.Combatant[dest].Incoming.MeleeDodged or 0) + 1 elseif recap_temp.Filter[i].miss==11 then -- melee parry recap.Combatant[dest].Incoming.MeleeParried = (recap.Combatant[dest].Incoming.MeleeParried or 0) + 1 elseif recap_temp.Filter[i].miss==12 then -- melee block recap.Combatant[dest].Incoming.MeleeBlocked = (recap.Combatant[dest].Incoming.MeleeBlocked or 0) + 1 end Recap_CreateEffect(source,effect,1,0) end i=recap_temp.FilterSize+1 end end end end -- did_crit=1 for a crit, =0 for a normal hit but it could crit -- total = amount of hit/heal, 0 for a miss function Recap_CreateEffect(source,effect,type,total,did_crit) effect = type..effect -- skip misses that aren't a stored effect yet, to prevent logging debuff resists if not (total==0 and not recap.Combatant[source].Detail[effect]) then -- ChatFrame2:AddMessage("effect: "..effect..", source: "..source..", total: "..total..", did_crit: "..tostring(did_crit)) if not recap.Combatant[source].Detail[effect] then recap.Combatant[source].Detail[effect] = {} -- Hits=0, HitsDmg=0, HitsMax=0, Crits=0, CritsEvents=0, CritsDmg=0, CritsMax=0, Missed=0, TicksDmg, TicksMax } end if source==recap_temp.Player and not recap.Self[recap_temp.s][effect] then recap.Self[recap_temp.s][effect] = {} end if did_crit==1 then recap.Combatant[source].Detail[effect].CritsEvents = (recap.Combatant[source].Detail[effect].CritsEvents or 0) + 1 recap.Combatant[source].Detail[effect].Crits = (recap.Combatant[source].Detail[effect].Crits or 0) + did_crit recap.Combatant[source].Detail[effect].CritsDmg = (recap.Combatant[source].Detail[effect].CritsDmg or 0) + total recap.Combatant[source].Detail[effect].CritsMax = math.max(total,recap.Combatant[source].Detail[effect].CritsMax or 0) if source==recap_temp.Player then recap.Self[recap_temp.s][effect].CritsEvents = (recap.Self[recap_temp.s][effect].CritsEvents or 0) + 1 recap.Self[recap_temp.s][effect].Crits = (recap.Self[recap_temp.s][effect].Crits or 0) + did_crit recap.Self[recap_temp.s][effect].CritsDmg = (recap.Self[recap_temp.s][effect].CritsDmg or 0) + total recap.Self[recap_temp.s][effect].CritsMax = math.max(total,recap.Self[recap_temp.s][effect].CritsMax or 0) end elseif did_crit==0 then recap.Combatant[source].Detail[effect].CritsEvents = (recap.Combatant[source].Detail[effect].CritsEvents or 0) + 1 recap.Combatant[source].Detail[effect].Hits = (recap.Combatant[source].Detail[effect].Hits or 0) + 1 recap.Combatant[source].Detail[effect].HitsDmg = (recap.Combatant[source].Detail[effect].HitsDmg or 0) + total recap.Combatant[source].Detail[effect].HitsMax = math.max(total,recap.Combatant[source].Detail[effect].HitsMax or 0) if source==recap_temp.Player then recap.Self[recap_temp.s][effect].CritsEvents = (recap.Self[recap_temp.s][effect].CritsEvents or 0) + 1 recap.Self[recap_temp.s][effect].Hits = (recap.Self[recap_temp.s][effect].Hits or 0) + 1 recap.Self[recap_temp.s][effect].HitsDmg = (recap.Self[recap_temp.s][effect].HitsDmg or 0) + total recap.Self[recap_temp.s][effect].HitsMax = math.max(total,recap.Self[recap_temp.s][effect].HitsMax or 0) end elseif total==0 then recap.Combatant[source].Detail[effect].Missed = (recap.Combatant[source].Detail[effect].Missed or 0) + 1 if source==recap_temp.Player then recap.Self[recap_temp.s][effect].Missed = (recap.Self[recap_temp.s][effect].Missed or 0) + 1 end else recap.Combatant[source].Detail[effect].Hits = (recap.Combatant[source].Detail[effect].Hits or 0) + 1 recap.Combatant[source].Detail[effect].TicksDmg = (recap.Combatant[source].Detail[effect].TicksDmg or 0) + total recap.Combatant[source].Detail[effect].TicksMax = math.max(total,recap.Combatant[source].Detail[effect].TicksMax or 0) if source==recap_temp.Player then recap.Self[recap_temp.s][effect].Hits = (recap.Self[recap_temp.s][effect].Hits or 0) + 1 recap.Self[recap_temp.s][effect].TicksDmg = (recap.Self[recap_temp.s][effect].TicksDmg or 0) + total recap.Self[recap_temp.s][effect].TicksMax = math.max(total,recap.Self[recap_temp.s][effect].TicksMax or 0) end end end end function Recap_DeathEvent(arg1) local i, victim, spot local found = false if recap.Opt.State.value~="Stopped" then for i=1,recap_temp.DeathFilterSize do found,_,recap_temp.FilterIndex[1] = string.find(arg1,recap_temp.DeathFilter[i].pattern) if found then victim = recap_temp.FilterIndex[recap_temp.DeathFilter[i].victim] -- check for FD if recap.Combatant[victim] and recap.Combatant[victim].Class=="Hunter" then if UnitName("player")==victim then spot = "player" end for j=1,4 do if UnitName("party"..j)==victim then spot = "party"..j end end for j=1,40 do if UnitName("raid"..j)==victim then spot = "raid"..j end end if spot then for j=1,16 do if UnitBuff(spot,j)=="Interface\\Icons\\Ability_Rogue_FeignDeath" then victim = nil end end end end if victim and recap_temp.Last[victim] then recap_temp.Last[victim].Kills = recap_temp.Last[victim].Kills + 1 end if recap.debug then if not recap.debug_Filter then recap.debug_Filter = {} end if not recap.debug_Filter[i+60] then recap.debug_Filter[i+60] = { hits=1, total=1, pattern=recap_temp.DeathFilter[i].pattern } else recap.debug_Filter[i+60].hits = recap.debug_Filter[i+60].hits + 1 recap.debug_Filter[i+60].total = recap.debug_Filter[i+60].total + 1 end if recap_temp.Filter[i].watch then DEFAULT_CHAT_FRAME:AddMessage("["..i.."] \""..recap_temp.DeathFilter[i].pattern.."\" triggered!") DEFAULT_CHAT_FRAME:AddMessage("victim="..tostring(victim)) end end i = recap_temp.DeathFilterSize+1 end end end end function Recap_HealEvent(arg1) local i, source, dest, heal, effect, fullheal local found = false if recap.Opt.State.value~="Stopped" then -- strip out period at end of chat line, if one exists arg1 = string.gsub(arg1,"%.$","") for i=1,recap_temp.HealFilterSize do found,_,recap_temp.FilterIndex[1],recap_temp.FilterIndex[2],recap_temp.FilterIndex[3],recap_temp.FilterIndex[4],recap_temp.FilterIndex[5] = string.find(arg1,recap_temp.HealFilter[i].pattern) if found then if not recap.Opt.LimitFights.value then if recap.Opt.IdleFight.value then recap_temp.IdleTimer = 0 end if recap.Opt.State.value=="Idle" then Recap_StartFight() end end source=recap_temp.FilterIndex[recap_temp.HealFilter[i].source] dest=recap_temp.FilterIndex[recap_temp.HealFilter[i].dest] if recap_temp.Local.SelfPronouns[string.lower(dest)] then dest = recap_temp.Player end heal=tonumber(recap_temp.FilterIndex[recap_temp.HealFilter[i].heal]) if recap_temp.HealFilter[i].effect then effect = recap_temp.FilterIndex[recap_temp.HealFilter[i].effect] end Recap_CreateCombatant(source) if recap_temp.Last[dest] and recap_temp.Last[dest].HP then fullheal = heal heal = math.min(recap_temp.Last[dest].MaxHP-recap_temp.Last[dest].HP,heal) recap_temp.Last[dest].HP = recap_temp.Last[dest].HP + heal if recap.debug and heal~=fullheal then ChatFrame2:AddMessage("|cff3fbfff"..source.."'s "..effect.." actually healed "..dest.." for "..heal..". ("..fullheal.." reported)") end end recap_temp.Last[source].Heal = recap_temp.Last[source].Heal + heal if recap.debug then if not recap.debug_Filter then recap.debug_Filter = {} end if not recap.debug_Filter[i+75] then recap.debug_Filter[i+75] = { hits=1, total=heal, pattern=recap_temp.HealFilter[i].pattern } else recap.debug_Filter[i+75].hits = recap.debug_Filter[i+75].hits + 1 recap.debug_Filter[i+75].total = recap.debug_Filter[i+75].total + heal end if recap_temp.Filter[i].watch then DEFAULT_CHAT_FRAME:AddMessage("["..i.."] \""..recap_temp.HealFilter[i].pattern.."\" triggered!") DEFAULT_CHAT_FRAME:AddMessage("source="..tostring(source)..", dest="..tostring(dest)..", heal="..tostring(heal)) end end if not recap.Opt.LightData.value then Recap_CreateEffect(source,effect,3,heal,recap_temp.HealFilter[i].crit) if fullheal and heal~=fullheal and recap.Combatant[source].Detail["3"..effect] then -- reuse .Missed detail to store overhealing since heals never miss recap.Combatant[source].Detail["3"..effect].Missed = (recap.Combatant[source].Detail["3"..effect].Missed or 0) + math.max(0,fullheal-heal) end end i = recap_temp.HealFilterSize+1 end end end end local function Recap_SelfDamageSort(e1,e2) local effect1,effect2 = string.sub(e1.EName,1,1),string.sub(e2.EName,1,1) if e1 and e2 and ( ((e1.ETotal>e2.ETotal) and (effect1==effect2)) or (effect10) and ((recap.Self[recap_temp.s][i].HitsDmg or 0)/recap_temp.SelfList[idx].EHits) or 0)) recap_temp.SelfList[idx].ETicksAvg = string.format("%d",((recap_temp.SelfList[idx].ETicks>0) and ((recap.Self[recap_temp.s][i].TicksDmg or 0)/recap_temp.SelfList[idx].ETicks) or 0)) recap_temp.SelfList[idx].ECritsAvg = string.format("%d",((recap_temp.SelfList[idx].ECrits>0) and ((recap.Self[recap_temp.s][i].CritsDmg or 0)/recap_temp.SelfList[idx].ECrits) or 0)) recap_temp.SelfList[idx].ECritsP = string.format("%.1f%%",((recap.Self[recap_temp.s][i].CritsEvents or 0)>0) and (100*recap_temp.SelfList[idx].ECrits/recap.Self[recap_temp.s][i].CritsEvents) or 0) recap_temp.SelfList[idx].EMaxAll = math.max( recap_temp.SelfList[idx].EHitsMax, math.max(recap_temp.SelfList[idx].ETicksMax,recap_temp.SelfList[idx].ECritsMax) ) if tonumber(string.sub(i,1,1))<3 then -- damage event recap_temp.SelfList[idx].EMiss = recap.Self[recap_temp.s][i].Missed or 0 j = recap_temp.SelfList[idx].EHits + recap_temp.SelfList[idx].ECrits + recap_temp.SelfList[idx].EMiss recap_temp.SelfList[idx].EMissP = string.format("%.1f%%",(j>0) and (100*(recap_temp.SelfList[idx].EMiss/j)) or 0) damage = damage + recap_temp.SelfList[idx].ETotal else recap_temp.SelfList[idx].EMiss = "--" recap_temp.SelfList[idx].EMissP = "--" heal = heal + recap_temp.SelfList[idx].ETotal end if recap_temp.SelfList[idx].ETicks==0 then recap_temp.SelfList[idx].ETicks = "--" recap_temp.SelfList[idx].ETicksAvg = "--" recap_temp.SelfList[idx].ETicksMax = "--" end if not recap.Self[recap_temp.s][i].CritsEvents then recap_temp.SelfList[idx].ECrits = "--" recap_temp.SelfList[idx].ECritsAvg = "--" recap_temp.SelfList[idx].ECritsMax = "--" recap_temp.SelfList[idx].ECritsP = "--" recap_temp.SelfList[idx].EHits = "--" recap_temp.SelfList[idx].EHitsAvg = "--" recap_temp.SelfList[idx].EHitsMax = "--" end idx = idx + 1 end recap_temp.SelfListSize = idx if recap_temp.SelfListSize>1 then for i=1,recap_temp.SelfListSize-1 do if string.sub(recap_temp.SelfList[i].EName,1,1)<"3" and damage>0 then recap_temp.SelfList[i].ETotalP = string.format("%d%%",100*recap_temp.SelfList[i].ETotal/damage) elseif string.sub(recap_temp.SelfList[i].EName,1,1)>"2" and heal>0 then recap_temp.SelfList[i].ETotalP = string.format("%d%%",100*recap_temp.SelfList[i].ETotal/heal) else recap_temp.SelfList[i].ETotalP = "--" end end end table.sort(recap_temp.SelfList,Recap_SelfDamageSort) end function Recap_ConstructList() local i, j, dpsin, dpsout, entry, duration, tempname, over local maxhit = 0 local dmgin = 0 local dmgout = 0 local kills = 0 local heal = 0 local allover = 0 if recap.Opt.SelfView.value then Recap_ConstructSelf() end recap_temp.ListSize = 1 if recap_temp.Selected~=0 then tempname = recap_temp.List[recap_temp.Selected].Name end if recap.Opt.View.value=="Last" then duration = recap[recap_temp.p].LastDuration else duration = recap[recap_temp.p].TotalDuration end for i in recap.Combatant do if not recap_temp.List[recap_temp.ListSize] then recap_temp.List[recap_temp.ListSize] = {} end entry = false if (recap.Combatant[i].LastDmgIn==0 and recap.Combatant[i].LastDmgOut==0 and recap.Combatant[i].TotalDmgOut==0 and recap.Combatant[i].TotalDmgIn==0) or (recap.Opt.HideFoe.value and not recap.Combatant[i].Friend) or (recap.Opt.HideYardTrash.value and (not recap.Combatant[i].Friend and recap.Combatant[i].TotalKills~=1)) or (recap.Combatant[i].Ignore) then entry = false -- strip out unwanted combatants elseif recap.Opt.View.value=="Last" and recap.Combatant[i].WasInLast then if not recap.Opt.HideZero.value or recap.Combatant[i].LastTime>recap_temp.MinTime then recap_temp.List[recap_temp.ListSize].Name = i recap_temp.List[recap_temp.ListSize].Time = recap.Combatant[i].LastTime recap_temp.List[recap_temp.ListSize].MaxHit = recap.Combatant[i].LastMaxHit recap_temp.List[recap_temp.ListSize].DmgIn = recap.Combatant[i].LastDmgIn recap_temp.List[recap_temp.ListSize].DmgOut = recap.Combatant[i].LastDmgOut recap_temp.List[recap_temp.ListSize].DPS = recap.Combatant[i].LastDPS recap_temp.List[recap_temp.ListSize].DPSvsAll = duration>recap_temp.MinTime and recap.Combatant[i].LastDmgOut/duration or 0 recap_temp.List[recap_temp.ListSize].Kills = recap.Combatant[i].LastKills recap_temp.List[recap_temp.ListSize].Heal = recap.Combatant[i].LastHeal entry = true end elseif recap.Opt.View.value=="All" then if not recap.Opt.HideZero.value or recap.Combatant[i].TotalTime>recap_temp.MinTime then recap_temp.List[recap_temp.ListSize].Name = i recap_temp.List[recap_temp.ListSize].Time = recap.Combatant[i].TotalTime recap_temp.List[recap_temp.ListSize].MaxHit = recap.Combatant[i].TotalMaxHit recap_temp.List[recap_temp.ListSize].DmgIn = recap.Combatant[i].TotalDmgIn recap_temp.List[recap_temp.ListSize].DmgOut = recap.Combatant[i].TotalDmgOut recap_temp.List[recap_temp.ListSize].DPS = recap.Combatant[i].TotalDPS recap_temp.List[recap_temp.ListSize].DPSvsAll = duration>recap_temp.MinTime and recap.Combatant[i].TotalDmgOut/duration or 0 recap_temp.List[recap_temp.ListSize].Kills = recap.Combatant[i].TotalKills recap_temp.List[recap_temp.ListSize].Heal = recap.Combatant[i].TotalHeal entry = true end end if entry then recap_temp.List[recap_temp.ListSize].Over = 0 -- overhealing if recap.Combatant[recap_temp.List[recap_temp.ListSize].Name].Friend then if recap_temp.List[recap_temp.ListSize].MaxHit > maxhit then maxhit = recap_temp.List[recap_temp.ListSize].MaxHit end dmgin = dmgin + recap_temp.List[recap_temp.ListSize].DmgIn dmgout = dmgout + recap_temp.List[recap_temp.ListSize].DmgOut kills = kills + recap_temp.List[recap_temp.ListSize].Kills heal = heal + recap_temp.List[recap_temp.ListSize].Heal if (recap_temp.List[recap_temp.ListSize].Heal>0) and not recap.Opt.LightData.value then over = 0 for j in recap.Combatant[i].Detail do if string.sub(j,1,1)=="3" then -- a heal over = over + (recap.Combatant[i].Detail[j].Missed or 0) end end recap_temp.List[recap_temp.ListSize].Over = math.floor(((100*over)/(over+recap.Combatant[i].TotalHeal))+.5) allover = allover + over end end recap_temp.ListSize = recap_temp.ListSize + 1 end end if not recap_temp.List[recap_temp.ListSize] then recap_temp.List[recap_temp.ListSize] = {} end -- the final entry is the totals recap_temp.List[recap_temp.ListSize].Name = "Totals" recap_temp.List[recap_temp.ListSize].Time = duration RecapTotals_Time:SetText(Recap_FormatTime(duration)) recap_temp.List[recap_temp.ListSize].MaxHit = maxhit RecapTotals_MaxHit:SetText(maxhit) recap_temp.List[recap_temp.ListSize].DmgIn = dmgin RecapTotals_DmgIn:SetText(dmgin) recap_temp.List[recap_temp.ListSize].DmgOut = dmgout RecapTotals_DmgOut:SetText(dmgout) recap_temp.List[recap_temp.ListSize].Kills = kills RecapTotals_Kills:SetText(kills) recap_temp.List[recap_temp.ListSize].Heal = heal RecapTotals_Heal:SetText(heal) recap_temp.List[recap_temp.ListSize].Over = recap.Opt.View.value=="All" and ((100*allover)/(allover+heal)) or 0 RecapTotals_Over:SetText(string.format("%d%%",recap_temp.List[recap_temp.ListSize].Over)) if duration > recap_temp.MinTime then recap_temp.List[recap_temp.ListSize].DPSIn = dmgin/duration recap_temp.List[recap_temp.ListSize].DPSOut = dmgout/duration else recap_temp.List[recap_temp.ListSize].DPSIn = 0 recap_temp.List[recap_temp.ListSize].DPSOut = 0 end RecapTotals_DPS:SetText(string.format("%.1f",recap_temp.List[recap_temp.ListSize].DPSOut)) RecapTotals_DPSvsAll:SetText(string.format("%.1f",recap_temp.List[recap_temp.ListSize].DPSOut)) RecapTotals_DPSIn:SetText(string.format("%.1f",recap_temp.List[recap_temp.ListSize].DPSIn)) RecapMinDPSIn_Text:SetText(string.format("%.1f",recap_temp.List[recap_temp.ListSize].DPSIn)) RecapMinDPSOut_Text:SetText(string.format("%.1f",recap_temp.List[recap_temp.ListSize].DPSOut)) if recap.Combatant[recap_temp.Player] and recap.Opt.View.value=="Last" then i = recap.Combatant[recap_temp.Player].LastDPS if UnitName("pet") and UnitName("pet")~=UNKNOWNOBJECT and recap.Combatant[UnitName("pet")] then i = i + recap.Combatant[UnitName("pet")].LastDPS end RecapMinYourDPS_Text:SetText(string.format("%.1f",i)) elseif recap.Combatant[recap_temp.Player] and recap.Opt.View.value=="All" then i = recap.Combatant[recap_temp.Player].TotalDPS if UnitName("pet") and UnitName("pet")~=UNKNOWNOBJECT and recap.Combatant[UnitName("pet")] then i = i + recap.Combatant[UnitName("pet")].TotalDPS end RecapMinYourDPS_Text:SetText(string.format("%.1f",i)) else RecapMinYourDPS_Text:SetText("n/a") end -- calculate percentages for i=1,recap_temp.ListSize-1 do recap_temp.List[i].HealP = 0 recap_temp.List[i].DmgInP = 0 recap_temp.List[i].DmgOutP = 0 if recap.Combatant[recap_temp.List[i].Name].Friend then if recap_temp.List[recap_temp.ListSize].Heal>0 then recap_temp.List[i].HealP = math.floor(.5+100*recap_temp.List[i].Heal/recap_temp.List[recap_temp.ListSize].Heal) end if recap_temp.List[recap_temp.ListSize].DmgIn>0 then recap_temp.List[i].DmgInP = math.floor(.5+100*recap_temp.List[i].DmgIn/recap_temp.List[recap_temp.ListSize].DmgIn) end if recap_temp.List[recap_temp.ListSize].DmgOut>0 then recap_temp.List[i].DmgOutP = math.floor(.5+100*recap_temp.List[i].DmgOut/recap_temp.List[recap_temp.ListSize].DmgOut) end end end Recap_SortList() if tempname then -- follow name to pre-sort selected recap_temp.Selected = Recap_GetSelectedByName(tempname) if recap_temp.Selected~=0 then RecapPanel_Show(tempname) else RecapPanel_Hide() end end RecapScrollBar_Update() Recap_UpdatePlugins() end function Recap_DefineGauges() local i recap_temp.GaugeMax = 0 if recap_temp.ListSize>1 then recap_temp.GaugeBy = string.gsub(recap.Opt.SortBy.value,"P$","") recap_temp.GaugeBy = recap_temp.GaugeBy=="DPSvsAll" and "DmgOut" or recap_temp.GaugeBy if not gaugecolor[recap_temp.GaugeBy] then recap_temp.GaugeBy = nil else for i=1,recap_temp.ListSize-1 do recap_temp.GaugeMax = math.max(recap.Combatant[recap_temp.List[i].Name].Friend and recap_temp.List[i][recap_temp.GaugeBy] or 0,recap_temp.GaugeMax) end for i=1,15 do getglobal("RecapList"..i.."_Gauge"):SetVertexColor(gaugecolor[recap_temp.GaugeBy].r,gaugecolor[recap_temp.GaugeBy].g,gaugecolor[recap_temp.GaugeBy].b) end end end end function Recap_GetSelectedByName(arg1) local sel,i = 0 if arg1 and recap_temp.ListSize>1 then for i=1,recap_temp.ListSize-1 do if recap_temp.List[i].Name==arg1 then sel = i end end end return sel end --[[ Sorting functions ]] -- initial sort by field done with table.sort for speed, then -- friends shifted to top with an insertion sort for "stable" list function Recap_SortList() local temp,tempname if recap_temp.Selected~=0 then tempname = recap_temp.List[recap_temp.Selected].Name end temp = recap_temp.List[recap_temp.ListSize] recap_temp.List[recap_temp.ListSize] = nil if recap.Opt.SortDir.value then table.sort(recap_temp.List,function(e1,e2) if e1 and e2 and ( e1[recap.Opt.SortBy.value] < e2[recap.Opt.SortBy.value] ) then return true else return false end end) else table.sort(recap_temp.List,function(e1,e2) if e1 and e2 and ( e1[recap.Opt.SortBy.value] > e2[recap.Opt.SortBy.value] ) then return true else return false end end) end Recap_SortFriends() recap_temp.List[recap_temp.ListSize] = temp Recap_DefineGauges() recap_temp.Selected = Recap_GetSelectedByName(tempname) end function Recap_SortDown(e1,e2) if e1 and e2 and ( e1[recap.Opt.SortBy.value] < e2[recap.Opt.SortBy.value] ) then return true else return false end end function Recap_SortUp(e1,e2) if e1 and e2 and ( e1[recap.Opt.SortBy.value] > e2[recap.Opt.SortBy.value] ) then return true else return false end end -- perform stable insertion sort on the list function Recap_SortFriends() local i,j local changed = true local temp = {} if recap_temp.ListSize>2 then for i=2,(recap_temp.ListSize-1) do temp = recap_temp.List[i] j=i while (j>1) and (not recap.Combatant[recap_temp.List[j-1].Name].Friend and recap.Combatant[temp.Name].Friend) do recap_temp.List[j] = recap_temp.List[j-1] j = j - 1 end recap_temp.List[j] = temp end end end --[[ Window movement functions ]] function Recap_OnMouseDown(arg1) if recap_temp.Loaded and arg1=="LeftButton" and not recap.Opt.Pinned.value then RecapFrame:StartMoving() end end function Recap_OnMouseUp(arg1) if recap_temp.Loaded and arg1=="LeftButton" and not recap.Opt.Pinned.value then RecapFrame:StopMovingOrSizing() Recap_CheckWindowBounds() elseif arg1=="RightButton" and recap.Opt.Minimized.value then RecapCreateMenu(recap_temp.MinMenu) end end -- repositions RecapFrame if any part of it goes off the screen function Recap_CheckWindowBounds() local x1, y1, x2, y2, cx, cy local needs_moved = false if recap_temp.Loaded and RecapFrame then x1 = RecapFrame:GetLeft() y1 = RecapFrame:GetTop() cx = RecapFrame:GetWidth() cy = RecapFrame:GetHeight() if x1 and y1 and cx and cy then x2 = RecapFrame:GetRight() y2 = RecapFrame:GetBottom() uix2 = UIParent:GetRight() uix1 = UIParent:GetLeft() uiy1 = UIParent:GetTop() uiy2 = UIParent:GetBottom() if x2 and uix2 and x2 > uix2 then x1 = x1 + uix2 - x2 needs_moved = true elseif uix1 and uix1 > x1 then x1 = x1 + uix1 - x1 needs_moved = true end if y1 and y1 > uiy1 then y1 = y1 + uiy1 - y1 needs_moved = true elseif uiy2 and uiy2 > y2 then y1 = y1 + uiy2 - y2 needs_moved = true end if needs_moved then RecapFrame:ClearAllPoints() RecapFrame:SetPoint("TOPLEFT","UIParent","BOTTOMLEFT",x1,y1) end recap[recap_temp.p].WindowTop = RecapFrame:GetTop() recap[recap_temp.p].WindowLeft = RecapFrame:GetLeft() recap[recap_temp.p].WindowHeight = RecapFrame:GetHeight() recap[recap_temp.p].WindowWidth = RecapFrame:GetWidth() end end end --[[ Dialog control functions ]] function Recap_OnClick(arg1) if not recap_temp.Loaded then return end local fight_count = 0 local total_fight_count = 0 local filen = RecapSetEditBox:GetText() local set_friend, set_dmgin, set_dmgout, set_maxhit, set_kills, set_heal, set_time PlaySound("GAMEGENERICBUTTONPRESS") if arg1=="Close" then RecapFrame_Hide() elseif arg1=="Minimize" then if recap.Opt.Minimized.value then Recap_Maximize() else Recap_Minimize() end RecapFrame:SetAlpha(1) recap_temp.FadeTimer = -1 Recap_SetButtons() Recap_OnTooltip("Minimize") elseif arg1=="Pin" then recap.Opt.Pinned.value = not recap.Opt.Pinned.value Recap_SetButtons() Recap_OnTooltip("Pin") elseif arg1=="Pause" then if recap.Opt.Paused.value then recap.Opt.Paused.value = false Recap_SetState("Idle") else recap.Opt.Paused.value = true Recap_EndFight() Recap_SetState("Stopped") end Recap_SetButtons() Recap_OnTooltip("Pause") elseif arg1=="ShowAll" then if recap.Opt.SelfView.value then recap.Opt.SelfView.value = false if not recap.Opt.Minimized.value then Recap_SetColumns() end end if recap.Opt.View.value=="Last" then Recap_SetView("All") else Recap_SetView("Last") end Recap_OnTooltip("ShowAll") elseif arg1=="Options" then if RecapOptFrame:IsShown() then RecapOptFrame:Hide() else RecapOptFrame:Show() end elseif arg1=="Reset" then if recap.Opt.SelfView.value then recap.Self[recap_temp.s] = {} Recap_SetView() elseif recap.Opt.View.value=="All" then -- wipe everything -- Recap_ResetAllCombatants() Recap_SetView() Recap_MakeFriends() elseif recap.Opt.View.value=="Last" then -- remove just the last fight -- for i in recap.Combatant do if recap.Combatant[i].WasInLast then Recap_ResetLastFight(i) end end recap[recap_temp.p].TotalDuration = recap[recap_temp.p].TotalDuration - recap[recap_temp.p].LastDuration recap[recap_temp.p].LastDuration = 0 Recap_SetView() end elseif arg1=="SaveSet" then RecapSetEditBox:ClearFocus() if filen and filen~="" then filen = string.gsub(filen,"\"","'") -- convert "s to 's filen = string.gsub(filen,"%[","(") -- convert [s to (s filen = string.gsub(filen,"%]",")") -- convert ]s to )s end RecapSetEditBox:SetText("") Recap_SaveCombatants(filen,recap.Opt.ReplaceSet.value) Recap_BuildFightSets() recap_temp.FightSetSelected = 0 RecapFightSetsScrollBar_Update() elseif arg1=="LoadSet" then RecapSetEditBox:SetText("") RecapSetEditBox:ClearFocus() Recap_LoadCombatants(filen,recap.Opt.ReplaceSet.value) Recap_MakeFriends() Recap_SetView("All") elseif arg1=="DeleteSet" then RecapSetEditBox:SetText("") RecapSetEditBox:ClearFocus() recap_set[filen] = nil Recap_BuildFightSets() elseif arg1=="SelfView" then recap.Opt.SelfView.value = not recap.Opt.SelfView.value RecapPanel_Hide(1) Recap_SetColumns() Recap_OnTooltip("SelfView") end end -- removes combatant i from last fight function Recap_ResetLastFight(i) recap.Combatant[i].TotalTime = recap.Combatant[i].TotalTime - recap.Combatant[i].LastTime recap.Combatant[i].TotalDmgIn = recap.Combatant[i].TotalDmgIn - recap.Combatant[i].LastDmgIn recap.Combatant[i].TotalDmgOut = recap.Combatant[i].TotalDmgOut - recap.Combatant[i].LastDmgOut recap.Combatant[i].TotalHeal = recap.Combatant[i].TotalHeal - recap.Combatant[i].LastHeal recap.Combatant[i].TotalKills = recap.Combatant[i].TotalKills - recap.Combatant[i].LastKills if recap.Combatant[i].TotalTime> recap_temp.MinTime then recap.Combatant[i].TotalDPS = recap.Combatant[i].TotalDmgOut/recap.Combatant[i].TotalTime else recap.Combatant[i].TotalDPS = 0 end recap.Combatant[i].WasInLast = false recap.Combatant[i].LastTime = 0 recap.Combatant[i].LastDmgIn = 0 recap.Combatant[i].LastDmgOut = 0 recap.Combatant[i].LastDPS = 0 recap.Combatant[i].LastMaxHit = 0 recap.Combatant[i].LastKills = 0 recap.Combatant[i].LastHeal = 0 end function RecapHeader_OnEnter() local msg=string.gsub(this:GetName(),"RecapHeader_","Header") Recap_OnTooltip(msg) end function RecapHeader_OnMouseUp(arg1) if arg1=="RightButton" then RecapCreateMenu(recap_temp.ColumnMenu) end end -- sort column, toggle dir for new headers, name=ascending, rest=descending function RecapHeader_OnClick() local text="" local channel = "" -- "Guild" "Say" etc or "Channel" local chatnumber = 0 -- if channel is "Channel", this is the channel numbers local arg1= string.gsub(this:GetName(),"RecapHeader_","") if not IsShiftKeyDown() then if recap.Opt.SortBy.value==string.gsub(arg1,"P$","") then recap.Opt.SortDir.value = not recap.Opt.SortDir.value else recap.Opt.SortBy.value = string.gsub(arg1,"P$","") if arg1=="Name" then recap.Opt.SortDir.value = true else recap.Opt.SortDir.value = false end end Recap_SortList() RecapScrollBar_Update() elseif ChatFrameEditBox:IsVisible() and recap_temp.ListSize>1 and arg1~="Name" then recap.Opt.SortBy.value = arg1 recap.Opt.SortDir.value = false Recap_SortList() RecapScrollBar_Update() if recap.Opt.SpamRows.value then channel = ChatFrameEditBox.chatType chatnumber = nil if channel=="WHISPER" then chatnumber = ChatFrameEditBox.tellTarget elseif channel=="CHANNEL" then chatnumber = ChatFrameEditBox.channelTarget end Recap_PostSpamRows(arg1,channel,chatnumber) else Recap_InsertChat(Recap_PostSpamLine(arg1)) end elseif not ChatFrameEditBox:IsVisible() then DEFAULT_CHAT_FRAME:AddMessage(recap_temp.Local.RankUsage) end end function Recap_List_OnClick(arg1) local id, index local text = "" id = this:GetID() index = id + FauxScrollFrame_GetOffset(RecapScrollBar) if index110 then Recap_Tooltip(recap_temp.List[index].Name) end if (index1 then for i=1,(recap_temp.ListSize-1) do if not recap.Combatant[recap_temp.List[i].Name].Friend then other_kills = other_kills + recap_temp.List[i].Kills end end GameTooltip:AddDoubleLine("Combatants:",recap_temp.ListSize-1,r,g,b,r,g,b) GameTooltip:AddDoubleLine("Time Fighting:",Recap_FormatTime(recap_temp.List[recap_temp.ListSize].Time),r,g,b,r,g,b) GameTooltip:AddDoubleLine("Max Hit:",recap_temp.List[recap_temp.ListSize].MaxHit,r,g,b,r,g,b) GameTooltip:AddDoubleLine("Deaths:",recap_temp.List[recap_temp.ListSize].Kills,r,g,b,r,g,b) GameTooltip:AddDoubleLine("Kills:",other_kills,r,g,b,r,g,b) GameTooltip:AddDoubleLine("Heals:",recap_temp.List[recap_temp.ListSize].Heal,r,g,b,r,g,b) GameTooltip:AddDoubleLine("Damage In:",recap_temp.List[recap_temp.ListSize].DmgIn,recap_temp.ColorDmgIn.r,recap_temp.ColorDmgIn.g,recap_temp.ColorDmgIn.b,recap_temp.ColorDmgIn.r,recap_temp.ColorDmgIn.g,recap_temp.ColorDmgIn.b) GameTooltip:AddDoubleLine("DPS In:",string.format("%.1f",recap_temp.List[recap_temp.ListSize].DPSIn),recap_temp.ColorDmgIn.r,recap_temp.ColorDmgIn.g,recap_temp.ColorDmgIn.b,recap_temp.ColorDmgIn.r,recap_temp.ColorDmgIn.g,recap_temp.ColorDmgIn.b) GameTooltip:AddDoubleLine("Damage Out:",recap_temp.List[recap_temp.ListSize].DmgOut,recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b,recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) GameTooltip:AddDoubleLine("DPS Out:",string.format("%.1f",recap_temp.List[recap_temp.ListSize].DPSOut),recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b,recap_temp.ColorDmgOut.r,recap_temp.ColorDmgOut.g,recap_temp.ColorDmgOut.b) else GameTooltip:AddLine("Combatants: none",r,g,b) end GameTooltip:Show() end end function Recap_TooltipAnchor() local anchor = "ANCHOR_LEFT" if GetCursorPosition("UIParent")<(UIParent:GetWidth()/2) then anchor = "ANCHOR_RIGHT" end return anchor end --[[ Plug-in functions ]] function Recap_GetIB_Tooltip() return recap_temp.Local.LastAll[recap.Opt.View.value]..":\nYour DPS: "..RecapMinYourDPS_Text:GetText().."\nMax hit: "..RecapTotals_MaxHit:GetText().."\nTotal DPS Out: "..RecapTotals_DPS:GetText().."\nTotal DPS In: "..RecapTotals_DPSIn:GetText() end function Recap_UpdatePlugins() local yourdps = RecapMinYourDPS_Text:GetText() local dpsin = RecapMinDPSIn_Text:GetText() local dpsout = RecapMinDPSOut_Text:GetText() if IB_Recap_Update then IB_Recap_Update("DPS: "..yourdps) end if TitanPanelRecap_Update then TitanPanelRecap_Update(recap.Opt.State.value,yourdps,dpsin,dpsout) end end --[[ Misc functions ]] -- if this is a pet, pass owner's name to ownedby function Recap_AddFriend(arg1,ownedby) if arg1 and arg~=UNKNOWNOBJECT and recap.Combatant[arg1] then recap.Combatant[arg1].Friend = true if recap.Combatant[arg1] and ownedby then -- pet could potentially do damage without owner, add owner if so if not recap.Combatant[ownedby] then Recap_CreateBlankCombatant(ownedby) recap.Combatant[ownedby].Friend = true end if not recap_temp.Last[ownedby] then recap_temp.Last[ownedby] = { Start = 0, End = 0, DmgIn = 0, DmgOut = 0, MaxHit = 0, Kills = 0, Heal = 0 } end recap.Combatant[arg1].OwnedBy = ownedby recap.Combatant[ownedby].OwnsPet = arg1 end end end function Recap_MakeFriends() local i,item,u Recap_GetUnitInfo("player") Recap_AddFriend(recap_temp.Player) if UnitExists("pet") then Recap_GetUnitInfo("pet") Recap_AddFriend(UnitName("pet"),UnitName("player")) end for i=1,4 do if UnitExists("party"..i) then Recap_GetUnitInfo("party"..i) Recap_AddFriend(UnitName("party"..i)) if UnitExists("partypet"..i) then Recap_GetUnitInfo("partypet"..i) Recap_AddFriend(UnitName("partypet"..i),UnitName("party"..i)) end end end if (GetNumRaidMembers()>0) then for i=1,40 do if UnitExists("raid"..i) then Recap_GetUnitInfo("raid"..i) Recap_AddFriend(UnitName("raid"..i)) if UnitExists("raidpet"..i) then Recap_GetUnitInfo("raidpet"..i) Recap_AddFriend(UnitName("raidpet"..i),UnitName("raid"..i)) end end end end end -- returns a string of seconds converted to 0:00:00 format function Recap_FormatTime(arg1) local hours, minutes, seconds local text seconds = math.floor(arg1+.5) hours = math.floor(seconds/3600) seconds = seconds - hours*3600 minutes = math.floor(seconds/60) seconds = seconds - minutes*60 return ((hours>0) and (hours..":") or "") .. string.format("%02d:",minutes) .. string.format("%02d",seconds) end function Recap_SetClassIcon(id,class) if class and recap_temp.ClassIcons[class] then getglobal("RecapList"..id.."_Class"):SetTexCoord(recap_temp.ClassIcons[class].left,recap_temp.ClassIcons[class].right,recap_temp.ClassIcons[class].top,recap_temp.ClassIcons[class].bottom) else getglobal("RecapList"..id.."_Class"):SetTexCoord(.9,1,.9,1) end end function Recap_SetFactionIcon(id,faction) item = getglobal("RecapList"..id.."_Faction") if faction and recap_temp.FactionIcons[faction] then item:SetTexture(recap_temp.FactionIcons[faction]) else item:SetTexture("") end end function Recap_GetUnitInfo(unit) local u=UnitName(unit) if u then if recap.Combatant[u] then _,recap.Combatant[u].Class = UnitClass(unit) _,recap.Combatant[u].Faction = UnitFactionGroup(unit) if UnitCreatureFamily(unit) and recap.Combatant[u].Faction then recap.Combatant[u].Class = "Pet" end recap.Combatant[u].Level = UnitLevel(unit) end end if unit~="target" and unit~="mouseover" and recap_temp.Last[u] then if UnitIsVisible(unit) then recap_temp.Last[u].HP = UnitHealth(unit) recap_temp.Last[u].MaxHP = UnitHealthMax(unit) else recap_temp.Last[u].HP = nil -- discredit end end end -- creates a new .Combatant[arg1] that is a copy of DefaultCombatant function Recap_CreateBlankCombatant(arg1) if not recap.Combatant[arg1] then recap.Combatant[arg1] = { TotalTime = 0, TotalDmgIn = 0, TotalDmgOut = 0, TotalDPS = 0, TotalMaxHit = 0, TotalKills = 0, TotalHeal = 0, LastTime = 0, LastDmgIn = 0, LastDmgOut = 0, LastDPS = 0, LastMaxHit = 0, LastKills = 0, LastHeal = 0, WasInLast = false, Friend = false, Ignore = nil, Owner = nil, Incoming = {}, Detail = {} } end end -- populates .Opt with a copy of DefaultOpt function Recap_LoadDefaultOpt() recap.Opt = {} for i in recap_temp.DefaultOpt do recap.Opt[i] = {} for j in recap_temp.DefaultOpt[i] do recap.Opt[i][j] = recap_temp.DefaultOpt[i][j] end end end function Recap_SaveOpt(user) if user and string.len(user)>0 then recap[user].Opt = {} for i in recap.Opt do text = "" for j in recap.Opt[i] do text = text..tostring(j).."="..tostring(recap.Opt[i][j]).." " end recap[user].Opt[i] = text end end end function Recap_LoadOpt(user) if user and recap[user] and recap[user].Opt then for i in recap[user].Opt do if recap_temp.DefaultOpt[i] then for t,v in string.gfind(recap[user].Opt[i],"(%w+)=(%d-%--%w+) ") do if v=="true" then v = true elseif v=="false" then v = false elseif tonumber(v) then v = tonumber(v) end if t=="type" and recap_temp.DefaultOpt[i][t] then v = recap_temp.DefaultOpt[i][t] end if recap.Opt[i] then recap.Opt[i][t] = v end end end end end end -- saves current data to data set "filen", overwrite~=nil to overwrite existing data function Recap_SaveCombatants(filen,overwrite) local sd = {} if not filen or string.len(filen)<1 then return end if not recap_set[filen] then recap_set[filen] = {} recap_set[filen].TimeStamp = date() recap_set[filen].TotalDuration = 0 recap_set[filen].Combatant = {} end recap_set[filen] = {} recap_set[filen].TimeStamp = date() recap_set[filen].TotalDuration = recap[recap_temp.p].TotalDuration recap_set[filen].Combatant = {} for i in recap.Combatant do if (not recap.Opt.SaveFriends.value or recap.Combatant[i].Friend) then recap_set[filen].Combatant[i] = string.format("%s %d %d %d %d %d %.3f ~%d %d %d", tostring(recap.Combatant[i].Friend), recap.Combatant[i].TotalDmgIn, recap.Combatant[i].TotalDmgOut, recap.Combatant[i].TotalMaxHit, recap.Combatant[i].TotalHeal, recap.Combatant[i].TotalKills, recap.Combatant[i].TotalTime, Recap_MakeKey(recap.Combatant[i].Faction), Recap_MakeKey(recap.Combatant[i].Class), recap.Combatant[i].Level or 0) if recap.Opt.LightData and not recap.Opt.LightData.value then -- save .Incoming recap_set[filen].Combatant[i] = recap_set[filen].Combatant[i].."^" for k in recap.Combatant[i].Incoming do if recap.Combatant[i].Incoming[k]>0 then recap_set[filen].Combatant[i] = recap_set[filen].Combatant[i]..inckey[k]..recap.Combatant[i].Incoming[k] end end recap_set[filen].Combatant[i] = recap_set[filen].Combatant[i].."^" for j in recap.Combatant[i].Detail do recap_set[filen].Combatant[i] = recap_set[filen].Combatant[i].."["..j..">" for k in recap.Combatant[i].Detail[j] do recap_set[filen].Combatant[i] = recap_set[filen].Combatant[i]..detkey[k]..recap.Combatant[i].Detail[j][k] end recap_set[filen].Combatant[i] = recap_set[filen].Combatant[i].."]" end end end end fight_count = 0 for i in recap_set[filen].Combatant do fight_count = fight_count + 1 end recap_set[filen].ListSize = fight_count end function Recap_MakeKey(arg1) local key = 0 for i in recap_temp.Keys do if arg1==recap_temp.Keys[i] then key = i end end return key end function Recap_GetKey(arg1) local key = nil if not arg1 or not tonumber(arg1) or arg1==0 then key=nil else key=recap_temp.Keys[tonumber(arg1)] end return key end function Recap_LoadCombatants(filen,overwrite) local sd = {} -- temp holding place for fields that may not exist local found,set_friend,set_dmgin,set_dmgout,set_maxhit,set_heal,set_kills,set_time,set_faction,set_class,set_level if not filen or string.len(filen)<1 or not recap_set[filen] then return end Recap_ResetAllCombatants() recap[recap_temp.p].TotalDuration = recap[recap_temp.p].TotalDuration + recap_set[filen].TotalDuration for i in recap_set[filen].Combatant do if not recap.Combatant[i] then Recap_CreateBlankCombatant(i) end found,_,set_friend,set_dmgin,set_dmgout,set_maxhit,set_heal,set_kills,set_time = string.find(recap_set[filen].Combatant[i],"(%w+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+%.?%d+)") if found then if set_friend == "true" then recap.Combatant[i].Friend = true end if tonumber(set_maxhit) > recap.Combatant[i].TotalMaxHit then recap.Combatant[i].TotalMaxHit = tonumber(set_maxhit) end recap.Combatant[i].TotalDmgIn = recap.Combatant[i].TotalDmgIn + tonumber(set_dmgin) recap.Combatant[i].TotalDmgOut = recap.Combatant[i].TotalDmgOut + tonumber(set_dmgout) recap.Combatant[i].TotalKills = recap.Combatant[i].TotalKills + tonumber(set_kills) recap.Combatant[i].TotalHeal = recap.Combatant[i].TotalHeal + tonumber(set_heal) recap.Combatant[i].TotalTime = recap.Combatant[i].TotalTime + tonumber(set_time) if recap.Combatant[i].TotalTime > recap_temp.MinTime then recap.Combatant[i].TotalDPS = recap.Combatant[i].TotalDmgOut/recap.Combatant[i].TotalTime else recap.Combatant[i].TotalDPS = 0 end end found,_,set_faction,set_class,set_level = string.find(recap_set[filen].Combatant[i],"~(%d+) (%d+) (%d+)") if not found then found,_,set_faction,set_class = string.find(recap_set[filen].Combatant[i],"~(%d+) (%d+)") end if found then recap.Combatant[i].Faction = Recap_GetKey(set_faction) recap.Combatant[i].Class = Recap_GetKey(set_class) recap.Combatant[i].Level = recap.Combatant[i].Level or set_level or 0 end if not recap.Opt.LightData.value then -- process incoming: ^a000b000c000^ for k in sd do sd[k] = nil end -- wipe temp buffer found,_,j = string.find(recap_set[filen].Combatant[i],"%^(.-)%^") if found then for k in inckey do _,_,sd[k] = string.find(j,inckey[k].."(%d+)") end elseif string.find(recap_set[filen].Combatant[i],"%^%d+ %d+ %d+ %d+ %d+ %d+ %d+ %d+ %d+ %d+ %d+ %d+ %d+") then found,_,sd.MeleeDamage,sd.MeleeMax,sd.MeleeHits,sd.MeleeCrits,sd.MeleeMissed,sd.MeleeDodged,sd.MeleeParried,sd.MeleeBlocked, sd.NonMeleeDamage,sd.NonMeleeMax,sd.NonMeleeHits,sd.NonMeleeCrits,sd.NonMeleeMissed = string.find(recap_set[filen].Combatant[i],"%^(%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+)") end if found then for k in sd do if sd[k] and tonumber(sd[k])>0 then recap.Combatant[i].Incoming[k] = tonumber(sd[k]) end end end -- process details: [name:a000b000c000] for j in string.gfind(recap_set[filen].Combatant[i],"%[.-%]") do for k in sd do sd[k] = nil end -- wipe temp buffer found,_,set_name = string.find(j,"%[(.-)%>") if found then -- new saved method recap.Combatant[i].Detail[set_name] = {} for k in detkey do _,_,sd[k] = string.find(j,detkey[k].."(%d+)") end else found,_,set_name = string.find(j,"%[(.-) %d") if found then -- old saved method recap.Combatant[i].Detail[set_name] = {} _,_,sd.HitsDmg,sd.Hits,sd.HitsMax,sd.CritsDmg,sd.Crits,sd.CritsMax,sd.CritsEvents,sd.Missed = string.find(j,"%[.+ (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+) (%d+)") -- old method end end if found then for k in sd do if sd[k] and tonumber(sd[k])>0 then recap.Combatant[i].Detail[set_name][k] = tonumber(sd[k]) end end end end end end end function Recap_ResetAllCombatants() local current_state = recap.Opt.State.value recap.Opt.State.value = "Stopped" recap.Combatant = {} recap_temp.IdleTimer = -1 recap_temp.Last = {} recap[recap_temp.p].LastDuration = 0 recap[recap_temp.p].TotalDuration = 0 recap_temp.FightStart = 0 recap_temp.FightEnd = 0 recap_temp.ListSize = 0 recap.Opt.State.value = current_state end local function Recap_LoadSelf() recap.Self = recap.Self or {} recap.Self[recap_temp.s] = recap.Self[recap_temp.s] or {} recap_temp.SelfList = {} recap_temp.SelfListSize = 1 end function Recap_InitializeData() local i,j,k,l,m local temp_user = recap_temp.p local oldkeys = { ["Krieger"]="WARRIOR", ["Magier"]="MAGE", ["Schurke"]="ROGUE", ["Druide"]="DRUID", ["J\195\164ger"]="HUNTER", ["Schamane"]="SHAMAN", ["Priester"]="PRIEST", ["Hexenmeister"]="WARLOCK", ["Guerrier"]="WARRIOR", ["Voleur"]="ROGUE", ["Chasseur"]="HUNTER", ["Chaman"]="SHAMAN", ["PrĂȘtre"]="PRIEST", ["DĂ©moniste"]="WARLOCK", ["Familier"]="Pet" } if not recap.DataVersion then -- wipe all pre-2.6 data recap = {} recap.DataVersion = 3.2 elseif recap.DataVersion < 3.0 then -- convert 2.6 to 3.0, make classes uppercase for i in recap.Combatant do if recap.Combatant[i].Faction=="Allianz" then recap.Combatant[i].Faction = "Alliance" end if recap.Combatant[i].Class then -- convert classes to english, which all locales will use for icon reference if oldkeys[recap.Combatant[i].Class] then recap.Combatant[i].Class = oldkeys[recap.Combatant[i].Class] end recap.Combatant[i].Class = string.upper(recap.Combatant[i].Class) end end recap.DataVersion = 3.0 end -- if this user hasn't been made before if not recap[recap_temp.p] then recap[recap_temp.p] = {} recap[recap_temp.p].TotalDuration = 0 recap[recap_temp.p].LastDuration = 0 end -- if this is a different/first-time user, or if this is first run of a new version, -- save the current combatants and options and then load them based on default. -- any changes in combatant or option format must come with a version change if (recap.User ~= recap_temp.p) or recap.DataVersion .2 then recap_temp.MenuTimer = 0 RecapMenu:Hide() if recap_temp.SelectedEffect then for i=1,15 do getglobal("RecapSelf"..i):UnlockHighlight() end end end end --[[ Fight report functions ]] function Recap_AutoPostGetStatID(arg1) if arg1=="Damage" then return "DmgOut" elseif arg1=="Tanking" then return "DmgIn" elseif arg1=="Healing" then return "Heal" end return "DPS" end function Recap_PostFight() local print_chat = SendChatMessage local chatchan, chatnum, text if recap.Opt.SpamRows.value then Recap_PostSpamRows(Recap_AutoPostGetStatID(recap.Opt.AutoPost.Stat),"recap auto") else chatchan = recap.Opt.AutoPost.Channel _,_,chatnum = string.find(chatchan,"(%d+)") if chatnum then chatchan = "CHANNEL" end if chatchan=="Self" then print_chat = Recap_Print end text = Recap_PostSpamLine(Recap_AutoPostGetStatID(recap.Opt.AutoPost.Stat)) if string.find(text,"%d") then print_chat(Recap_PostSpamLine(Recap_AutoPostGetStatID(recap.Opt.AutoPost.Stat)),chatchan,nil,chatnum) end end end function Recap_PostLeader() local print_chat = SendChatMessage local chatchan, chatnum, leader, statid, i if recap_temp.ListSize>2 then chatchan = recap.Opt.AutoPost.Channel _,_,chatnum = string.find(chatchan,"(%d+)") if chatnum then chatchan = "CHANNEL" end if chatchan=="Self" then print_chat = Recap_Print end statid = Recap_AutoPostGetStatID(recap.Opt.AutoPost.Stat) if not recap.Combatant[recap_temp.Leader] then -- in case leader reset recap_temp.Leader = nil end if not recap_temp.Leader and recap.Combatant[recap_temp.List[1].Name].Friend then recap_temp.Leader = recap_temp.List[1].Name leader = recap_temp.Leader -- spam initial leader end if recap_temp.Leader then for i in recap.Combatant do if (recap.Combatant[i]["Total"..statid] > recap.Combatant[recap_temp.Leader]["Total"..statid]) and recap.Combatant[i].Friend then leader = i end end if leader then recap_temp.Leader = leader print_chat(string.format("New leader for %s: %s with %s",recap.Opt.AutoPost.Stat,leader,Recap_FormatStat(statid,leader)),chatchan,nil,chatnum) end end end end -- returns 'text' to be spammed in autopost or linked in chat function Recap_PostSpamLine(arg1) local text,i text = recap_temp.Local.LinkRank[arg1].." for "..recap_temp.Local.LastAll[recap.Opt.View.value]..":" for i=1,recap.Opt.MaxRank.value do if i0 then text = text.." ["..i.."."..recap_temp.List[i].Name.." "..Recap_FormatStat(arg1,i).."]" end end end return text end -- arg1 = stat to report by (DPS, DmgOut, etc) function Recap_PostSpamRows(arg1,chatchan,chatnum) local headertext = nil local print_chat = SendChatMessage if chatchan=="recap auto" then chatchan = recap.Opt.AutoPost.Channel end arg1 = string.gsub(arg1,"P$","") -- strip trailing P from % id's if not chatnum then _,_,chatnum = string.find(chatchan,"(%d+)") if chatnum then chatchan = "CHANNEL" end end if chatchan=="Self" then print_chat = Recap_Print end headertext = "__ "..recap_temp.Local.LinkRank[arg1].." for "..recap_temp.Local.LastAll[recap.Opt.View.value].." __" for i=1,recap.Opt.MaxRank.value do if i 0 then if headertext then print_chat(headertext,chatchan,nil,chatnum) headertext = nil end print_chat(text,chatchan,nil,chatnum) end end end end -- returns a formatted string for arg1 stat ("DPS" "Time" etc) for combatant arg2 (number is .List[], non-number is name) function Recap_FormatStat(arg1,arg2) local i arg1 = string.gsub(arg1,"P$","") if not tonumber(arg2) then for i=1,(recap_temp.ListSize-1) do if recap_temp.List[i].Name==arg2 then arg2 = i i = recap_temp.ListSize end end end if tonumber(arg2) then if arg1=="DPS" then return string.format("%.1f",recap_temp.List[arg2].DPS) elseif arg1=="DPSvsAll" then return string.format("%.1f",recap_temp.List[arg2].DPSvsAll) elseif arg1=="Time" then return Recap_FormatTime(recap_temp.List[arg2].Time) elseif arg1=="DmgOut" then return recap_temp.List[arg2].DmgOut.." ("..recap_temp.List[arg2].DmgOutP.."%)" elseif arg1=="DmgIn" then return recap_temp.List[arg2].DmgIn.." ("..recap_temp.List[arg2].DmgInP.."%)" elseif arg1=="Heal" then return recap_temp.List[arg2].Heal.." ("..recap_temp.List[arg2].HealP.."%)" elseif arg1=="Over" then return recap_temp.List[arg2].Over.."%" else return recap_temp.List[arg2][arg1] end end return "" end function Recap_Print(arg1) DEFAULT_CHAT_FRAME:AddMessage(tostring(arg1)) end --[[ Debug ]] function Recap_DebugUnusedFilters(filter) local i,j,found for i in recap_temp[filter] do found = false for j in recap.debug_Filter do if recap_temp[filter][i].pattern==recap.debug_Filter[j].pattern then found = true end end if not found then DEFAULT_CHAT_FRAME:AddMessage(filter..": "..recap_temp[filter][i].pattern) end end end function Recap_MoveMinimize() RecapCloseButton:ClearAllPoints() RecapCloseButton:SetPoint("TOPRIGHT","RecapFrame","TOPRIGHT",-6,-6) RecapMinStatus:ClearAllPoints() RecapMinStatus:SetPoint("TOPLEFT", "RecapFrame", "TOPLEFT", 6,-7) RecapResetButton:ClearAllPoints() RecapResetButton:SetPoint("BOTTOMLEFT", "RecapFrame", "BOTTOMLEFT", 5,4) RecapMinimizeButton:ClearAllPoints() if recap.Opt.GrowLeftwards.value and not recap.Opt.GrowUpwards.value then -- topright RecapMinimizeButton:SetPoint("TOPRIGHT", "RecapFrame", "TOPRIGHT", -6, -6) RecapCloseButton:SetPoint("TOPRIGHT", "RecapMinimizeButton", "TOPLEFT", -2, 0) elseif recap.Opt.GrowLeftwards.value and recap.Opt.GrowUpwards.value then -- bottomright RecapMinimizeButton:SetPoint("BOTTOMRIGHT", "RecapFrame", "BOTTOMRIGHT", -6, 6) if recap.Opt.Minimized.value then RecapCloseButton:SetPoint("TOPRIGHT", "RecapMinimizeButton", "TOPLEFT", -2, 0) end elseif not recap.Opt.GrowLeftwards.value and not recap.Opt.GrowUpwards.value then -- topleft RecapMinimizeButton:SetPoint("TOPLEFT", "RecapFrame", "TOPLEFT", 6, -6) RecapMinStatus:SetPoint("TOPLEFT", "RecapMinimizeButton", "TOPRIGHT", 2, -1) else -- bottomleft RecapMinimizeButton:SetPoint("BOTTOMLEFT", "RecapFrame", "BOTTOMLEFT", 6, 6) RecapResetButton:SetPoint("BOTTOMLEFT", "RecapFrame", "BOTTOMLEFT", 23, 4) end if recap.Opt.Minimized.value and not recap.Opt.GrowLeftwards.value then RecapMinStatus:SetPoint("TOPLEFT", "RecapMinimizeButton", "TOPRIGHT", 2, -1) end if recap.Opt.AutoMinimize.value then RecapMinimizeButton:SetWidth(1) RecapMinimizeButton:Hide() else RecapMinimizeButton:SetWidth(16) RecapMinimizeButton:Show() end end function RecapMenu_SetCheck(id,arg1) if arg1 then getglobal("RecapMenu"..id.."_Check"):Show() else getglobal("RecapMenu"..id.."_Check"):Hide() end end function RecapMenu_OnClick() local id,index = this:GetID() if recap_temp.Menu==recap_temp.ColumnMenu or recap_temp.Menu==recap_temp.MinMenu or recap_temp.Menu==recap_temp.EffectOptMenu then index = recap_temp.Menu[id].Info -- .Info of menu item selected if recap.Opt[index] then recap.Opt[index].value = not recap.Opt[index].value getglobal("RecapOptCheck_"..recap_temp.Menu[id].Info):SetChecked(0) if recap.Opt[index].value then getglobal("RecapOptCheck_"..recap_temp.Menu[id].Info):SetChecked(1) end RecapMenu_SetCheck(id,recap.Opt[index].value) if recap.Opt.Minimized.value then Recap_Minimize() else Recap_Maximize() end elseif index=="Pin" then recap.Opt.Pinned.value = not recap.Opt.Pinned.value Recap_SetButtons() RecapMenu:Hide() end end if recap_temp.Menu==recap_temp.AddMenu or recap_temp.Menu==recap_temp.DropMenu then RecapMenu:Hide() index = recap_temp.List[recap_temp.Selected].Name -- name selected if id==1 and recap_temp.Menu==recap_temp.DropMenu and index~=recap_temp.Player then recap.Combatant[index].Friend = false elseif id==1 and index~=recap_temp.Player then recap.Combatant[index].Friend = not recap.Combatant[index].Friend elseif id==2 and recap.Opt.View.value=="All" then -- reset recap.Combatant[index] = nil Recap_CreateBlankCombatant(index) elseif id==2 and recap.Opt.View.value=="Last" then if recap.Combatant[index].WasInLast then Recap_ResetLastFight(index) end elseif id==3 and index~=recap_temp.Player then recap.Combatant[index] = nil Recap_CreateBlankCombatant(index) recap.Combatant[index].Ignore = true end Recap_SetView() end if recap_temp.Menu==recap_temp.EffectMenu then RecapMenu:Hide() for i=1,15 do getglobal("RecapSelf"..i):UnlockHighlight() end if recap_temp.SelectedEffect and recap.Self[recap_temp.s][recap_temp.SelectedEffect] then recap.Self[recap_temp.s][recap_temp.SelectedEffect] = nil recap_temp.SelectedEffect = nil Recap_SetView() end end if recap_temp.Menu==recap_temp.DetailMenu then if recap_temp.DetailsList and recap_temp.DetailsList[1][recap_temp.Menu[id].Info] then recap.Opt.PanelDetail.value = recap_temp.Menu[id].Info RecapPanel_Populate(recap_temp.List[recap_temp.Selected].Name) end RecapMenu:Hide() end end -- offset=1 to move window so it's under pointer function RecapCreateMenu(menu,offset) local i,cy,x,y,lines recap_temp.Menu = menu if recap_temp.Menu==recap_temp.ColumnMenu or recap_temp.Menu==recap_temp.MinMenu or recap_temp.Menu==recap_temp.EffectOptMenu then for i in recap_temp.Menu do if recap.Opt[recap_temp.Menu[i].Info] then recap_temp.Menu[i].Check = recap.Opt[recap_temp.Menu[i].Info].value end end end if recap_temp.Menu==recap_temp.MinMenu then recap_temp.Menu[1].Check = recap.Opt.Pinned.value end if recap_temp.Menu==recap_temp.DetailMenu then for i in recap_temp.Menu do recap_temp.Menu[i].Check = recap.Opt.PanelDetail.value==recap_temp.Menu[i].Info end end lines = min(table.getn(recap_temp.Menu),16) cy = 44 -- 12+32 for i=1,lines do getglobal("RecapMenu"..i.."_Text"):SetText(recap_temp.Menu[i].Text) RecapMenu_SetCheck(i,recap_temp.Menu[i].Check) getglobal("RecapMenu"..i):Show() cy = cy + 14 end for i=(lines+1),16 do getglobal("RecapMenu"..i):Hide() end RecapMenu:SetHeight(cy) RecapDropSubFrame:SetHeight(cy-32) RecapMenu:ClearAllPoints() x,y = GetCursorPosition() if recap.Opt.GrowUpwards.value and not offset then y = this:GetBottom()*UIParent:GetScale() RecapMenu:SetPoint("BOTTOMRIGHT","UIParent","BOTTOMLEFT",(x/UIParent:GetScale())+20,(y/UIParent:GetScale())-4) else y = this:GetTop()*UIParent:GetScale() RecapMenu:SetPoint("TOPRIGHT","UIParent","BOTTOMLEFT",(x/UIParent:GetScale())+20,(y/UIParent:GetScale())+(offset and 16 or 4)) end RecapMenu:Show() end function RecapMenu_OnEnter() id = this:GetID() if recap_temp.Menu[id] and recap_temp.Menu[id].Info then if recap_temp.Menu==recap_temp.AddMenu or recap_temp.Menu==recap_temp.DropMenu then Recap_OnTooltip(recap_temp.Menu[id].Info,recap_temp.List[recap_temp.Selected].Name) elseif recap_temp.Menu==recap_temp.EffectMenu and recap_temp.SelectedEffect then Recap_OnTooltip(recap_temp.Menu[id].Info,string.sub(recap_temp.SelectedEffect,2)) else Recap_OnTooltip(recap_temp.Menu[id].Info) end end end function RecapEffectsHeader_OnEnter() local s _,_,s = string.find(this:GetName(),"RecapHeader_(.+)") if s then Recap_OnTooltip("Header"..s) end end function RecapSelf_OnMouseUp(arg1) local index,i recap_temp.SelectedEffect = nil Recap_OnMouseUp(arg1) if arg1=="RightButton" then _,_,i = string.find(this:GetName(),"(%d+)") if i and tonumber(i) then i = tonumber(i) index = i + FauxScrollFrame_GetOffset(RecapScrollBar) if index < recap_temp.SelfListSize then this:LockHighlight() recap_temp.SelectedEffect = recap_temp.SelfList[index].EName end end RecapCreateMenu(recap_temp.EffectMenu,1) end end function RecapEffectsHeader_OnMouseUp(arg1) if arg1=="RightButton" then RecapCreateMenu(recap_temp.EffectOptMenu) end end function RecapEffectsHeader_OnClick() local idx,i local alltext,text = "" local channel,chatnumber = ChatFrameEditBox.chatType local hasdata if IsShiftKeyDown() and ChatFrameEditBox:IsVisible() then if channel=="WHISPER" then chatnumber = ChatFrameEditBox.tellTarget elseif channel=="CHANNEL" then chatnumber = ChatFrameEditBox.channelTarget end _,_,idx = string.find(tostring(this:GetName()),"RecapHeader_(.+)") if idx and idx~="EName" then alltext = (recap.Opt.SpamRows.value and "__ " or "")..recap_temp.Player.."'s "..Recap_GetTooltip("Header"..idx)..(recap.Opt.SpamRows.value and " __" or ":") for i=1,recap_temp.SelfListSize-1 do if recap_temp.SelfList[i][idx]~="0.0%" and recap_temp.SelfList[i][idx]~="--" and tostring(recap_temp.SelfList[i][idx])~="0" then if not hasdata and recap.Opt.SpamRows.value then SendChatMessage(alltext,channel,nil,chatnumber) end hasdata = true text = string.sub(recap_temp.SelfList[i].EName,2)..(string.sub(recap_temp.SelfList[i].EName,1,1)=="3" and "*" or "")..(recap.Opt.SpamRows.value and ": " or " ")..recap_temp.SelfList[i][idx]..(idx=="ETotal" and (" ("..recap_temp.SelfList[i].ETotalP..")") or "") if not recap.Opt.SpamRows.value then alltext = alltext.." ["..text.."]" else SendChatMessage(text,channel,nil,chatnumber) end end end if not recap.Opt.SpamRows.value and hasdata then Recap_InsertChat(alltext) end end end end function RecapSelf_OnClick() local id = this:GetID() local index = id + FauxScrollFrame_GetOffset(RecapScrollBar) local linkformat = recap_temp.Local.DamageDetailLink local text = "" if IsShiftKeyDown() and index