--[[ CombatStats3 - Stat Damage Tracking AUTHOR: DmgInc on most forums / Glacier on official WoW forums THANKS TO: The dude(ette) who made DPSPlus for showing me the light on how to parse the combat log The dude(ette) who made Clock for the time conversion routines Rev. 3.3 - ReEnabled the option to only show the stats on a mouseclick 2.16.05 - DPS caluculated is now 15 seconds w/no option to change - Added end of fight stats option to turn on/off - Slash commands will save between sessions when not using w/cosmos Rev. 3.2 - Added end of fight statistics 2.09.05 - Using PLAYER_REGEN_DISABLED ENABLED to tell when you are in/out of combat for end of fight info Rev. 3.1 - Lots of fixes to track pet stats 2.07.05 Rev. 3.0 - Initial version to track Defensive DPS 12.xx.04 Rev 2.03 - Now really really works w/o cosmos 11.15.04 Rev 2.02 - Now works w/o cosmos 11.14.04 - Changed the text display frame - Fixed the crit % running out of the frame when it was 100% - Put "Default" attack at top of the list - Added in a "Total", put it at the bottom of the list - UI is now movalbe - UI will update itself while you are attacking if it is visible - Fixed a bug where the close "X" button couldn't be pressed - Now uses OnEvent and OnUpdate - Pet damage is now tracked - DOT damage totals are correctly shown - Hopefully got rid of bogus entries Rev 2.01 - First release w/new UI 11.05.04 ]] if ( CT_AddMovable ) then CT_AddMovable("CombatStatsFrame", "CombatStats", "TOPLEFT", "TOPLEFT", "UIParent", 150, 0, function(status) end); end -- -- Cosmos Cofig variables -- CombatStats_Config = { }; CombatStats_Config.CombatStats_OnOff = 1; CombatStats_Config.CombatStats_HideOnNoTarget = 0; CombatStats_Config.CombatStats_EndOfFight = 0; CombatStats_Config.CombatStats_UseMouseOver = 0; CombatStats_LastUpdate = 0; CombatStats_UpdateFreq = 0.1; CombatStats_DPSLen = 15; -- Calculate DPS over the last 60 seconds defcritCount = 0; speccritCount= 0; timestamps = {}; takenTimestamps = {}; players = {}; playersTaken = {}; dmg = {}; dmgTaken = {}; dpstotals = {}; dpsTakenTotals = {}; defCrits = {0}; specCrits = {0}; defCritTotals = {}; specCritTotals = {}; bInCombat = 0; bHasDefault = 0; totalDamage = 0; -- -- Last fight info -- lastFightStart = 0; lastFightFinish = 0; lastFightPlayerDamage = 0; lastFightPetDamage = 0; mobDied = 0; regenEnabled = 0; leaveCombat = 0; overallCombatTime = 0; overallSwings = 0; overallMisses = 0; overallDodged = 0; overallParried = 0; overallEvaded = 0; overallBlocked = 0; overallResisted = 0; overallImmuned = 0; overallDeflected = 0; overallHits = 0; overallNonCrits = 0; overallCrits = 0; overallmaxCrit = 0; overallminCrit = 0; overallmaxReg = 0; overallminReg = 0; overallRegDmg = 0; overallCritDmg = 0; overallLastcrit = 0; attackNames = {}; specialAttacks = {}; specialAttackLog = {}; totalHits = 0; totalCrits = 0; specialsCount = 0; combatTime = 1; CombatStats_Old_TargetFrame_OnShow = nil; CombatStats_Old_TargetFrame_OnHide = nil; CombatStats_ChatCommandHandlers={}; bFirstTime = 1; CombatStatsVars = { }; CombatStatsSessionVars = { }; DeathCount = 0; DeathLog = { }; CombatStatsRecentVars = { }; CombatStatsByName = { }; CombatStatsSessionByName = { }; CombatStatsDisplay = { }; function CombatStats_ChatCommandHandler(msg) msg = string.lower(msg); local firsti, lasti, command, setStr = string.find (msg, "(%w+) ([%w%.]+)"); if ((not command) and msg) then command = msg; end if (command) then for curCommand in CombatStats_ChatCommandHandlers do if (command == curCommand) then if (setStr) then CombatStats_ChatCommandHandlers[curCommand](setStr); else CombatStats_ChatCommandHandlers[curCommand](); end return; end end end Print("All slash command can start with either /cs or /combatstats example: /cs enable or /combatstats enable"); Print("Then you can pass on or off to them, or pass a number for ones that need a number ex."); Print("/cs enable on"); Print("/cs enable off"); Print(""); Print("enable [on | off] - 'Enable/disabwle CombatStats, on or off'"); Print("target [on | off] - 'Only show DPS meter when you have a target'"); Print("mouseover [on | off] - 'Show detailed window on mouseover'"); Print("endoffight [on | off] - 'Show end of fight information'"); Print("reset yes - 'Rest all stats to 0'"); end -- -- Slash command handler -- function CombatStats_Enable_ChatCommandHandler(msg) if (msg) then msg = string.upper(msg); -- Toggle appropriately if (string.find(msg, "ON")) then CombatStats_Config.CombatStats_OnOff = 1; elseif (string.find(msg, "OFF")) then CombatStats_Config.CombatStats_OnOff = 0; end end if(Cosmos_RegisterConfiguration ~= nil) then Cosmos_UpdateValue("COMBATSTATS_CONFIG_ONOFF", CSM_CHECKONOFF, CombatStats_Config.CombatStats_OnOff); end CombatStats_UpdateVisibility(); end CombatStats_ChatCommandHandlers["enable"] = CombatStats_Enable_ChatCommandHandler; function CombatStats_Target_ChatCommandHandler(msg) if (msg) then msg = string.upper(msg); -- Toggle appropriately if (string.find(msg, "ON")) then CombatStats_Config.CombatStats_HideOnNoTarget = 1; elseif (string.find(msg, "OFF")) then CombatStats_Config.CombatStats_HideOnNoTarget = 0; end end if(Cosmos_RegisterConfiguration ~= nil) then Cosmos_UpdateValue("COMBATSTATS_CONFIG_HIDEONNOTARGET", CSM_CHECKONOFF, CombatStats_Config.CombatStats_HideOnNoTarget); end CombatStats_UpdateVisibility(); end CombatStats_ChatCommandHandlers["target"] = CombatStats_Target_ChatCommandHandler; function CombatStats_Mouseover_ChatCommandHandler(msg) if (msg) then msg = string.upper(msg); -- Toggle appropriately if (string.find(msg, "ON")) then CombatStats_Config.CombatStats_UseMouseOver = 1; elseif (string.find(msg, "OFF")) then CombatStats_Config.CombatStats_UseMouseOver = 0; end end if(Cosmos_RegisterConfiguration ~= nil) then Cosmos_UpdateValue("COMBATSTATS_CONFIG_USEMOUSEOVER", CSM_CHECKONOFF, CombatStats_Config.CombatStats_UseMouseOver); end CombatStats_UpdateVisibility(); end CombatStats_ChatCommandHandlers["mouseover"] = CombatStats_Target_ChatCommandHandler; function CombatStats_Endoffight_ChatCommandHandler(msg) if (msg) then msg = string.upper(msg); -- Toggle appropriately if (string.find(msg, "ON")) then CombatStats_Config.CombatStats_EndOfFight = 1; elseif (string.find(msg, "OFF")) then CombatStats_Config.CombatStats_EndOfFight = 0; end end if(Cosmos_RegisterConfiguration ~= nil) then Cosmos_UpdateValue("COMBATSTATS_CONFIG_ENDOFFIGHT", CSM_CHECKONOFF, CombatStats_Config.CombatStats_EndOfFight); end CombatStats_UpdateVisibility(); end CombatStats_ChatCommandHandlers["endoffight"] = CombatStats_Target_ChatCommandHandler; function CombatStats_Reset_ChatCommandHandler(msg) if (msg) then msg = string.upper(msg); -- Toggle appropriately if (string.find(msg, "YES")) then CombatStats_Reset(); end end end CombatStats_ChatCommandHandlers["reset"] = CombatStats_Reset_ChatCommandHandler; -- -- Cosmos Config Handlers -- function CombatStats_HideOnNoTarget_OnOff(toggle) CombatStats_Config.CombatStats_HideOnNoTarget = toggle; CombatStats_UpdateVisibility(); end function CombatStats_Watch_OnOff(toggle) CombatStats_Config.CombatStats_OnOff = toggle; CombatStats_UpdateVisibility(); end function CombatStats_UseMouseOver_OnOff(toggle) CombatStats_Config.CombatStats_UseMouseOver = toggle; CombatStats_UpdateVisibility(); end function CombatStats_EndOfFight_OnOff(toggle) CombatStats_Config.CombatStats_EndOfFight = toggle; CombatStats_UpdateVisibility(); end function CombatStats_UpdateVisibility(hasTarget) if (not hasTarget) then if (TargetFrame:IsVisible()) then hasTarget = 1; else hasTarget = 0; end end if (CombatStats_Config.CombatStats_OnOff == 1) then if (CombatStats_Config.CombatStats_HideOnNoTarget == 1) then if (hasTarget == 1) then CombatStatsFrame:Show(); else CombatStatsFrame:Hide(); end else CombatStatsFrame:Show(); end -- -- Register the events to watch -- else CombatStatsFrame:Hide(); end end function CombatStats_Reset() defcritCount = 0; speccritCount= 0; timestamps = {}; players = {}; dmg = {}; dpstotals = {}; defCrits = {0}; specCrits = {0}; defCritTotals = {}; specCritTotals = {}; totalDamage = 0; attackNames = {}; specialAttacks = {}; specialAttackLog = {}; totalHits = 0; totalCrits = 0; specialsCount = 0; bHasDefault = 0; overallSwings = 0; overallMisses = 0; overallDodged = 0; overallParried = 0; overallEvaded = 0; overallBlocked = 0; overallResisted = 0; overallImmuned = 0; overallDeflected = 0; overallHits = 0; overallNonCrits = 0; overallCrits = 0; overallmaxCrit = 0; overallminCrit = 0; overallmaxReg = 0; overallminReg = 0; overallRegDmg = 0; overallCritDmg = 0; overallLastcrit = 0; CombatStatsText:SetText("Overall DPS :: "); CombatStatsGeneralNameTextLabel:SetText("N/A"); CombatStatsNonCritHitsStatText:SetText("0"); CombatStatsNonCritDamageStatText:SetText("0"); CombatStatsNonCritMinMaxStatText:SetText("0 / 0"); CombatStatsNonCritAvgStatText:SetText("0.0"); CombatStatsNonCritPercentDamageStatText:SetText("0.0 %"); CombatStatsCritHitsStatText:SetText("0"); CombatStatsCritDamageStatText:SetText("0"); CombatStatsCritMinMaxStatText:SetText("0 / 0"); CombatStatsCritAvgStatText:SetText("0.0"); CombatStatsCritPercentDamageStatText:SetText("0.0 %"); CombatStatsGeneralTotalHitsHits:SetText("0"); CombatStatsGeneralSwingsLabel:SetText("0"); CombatStatsGeneralMissesTextLabel:SetText("0"); CombatStatsGeneralMissesPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralDodgesTextLabel:SetText("0"); CombatStatsGeneralDodgesPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralParriedTextLabel:SetText("0"); CombatStatsGeneralParriedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralBlockedTextLabel:SetText("0"); CombatStatsGeneralBlockedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralResistedTextLabel:SetText("0"); CombatStatsGeneralResistedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralImmunedTextLabel:SetText("0"); CombatStatsGeneralImmunedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralEvadedTextLabel:SetText("0"); CombatStatsGeneralEvadedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralPercentDmgPctLabel:SetText("0.0%"); CombatStatsGeneralTimeLastCritTimeLabel:SetText(GREEN_FONT_COLOR_CODE.."N/A"); CombatStatsOverallCritPctLabel:SetText(RED_FONT_COLOR_CODE.."0.0 %"); CombatStatsAttackNonCritPctLabel:SetText(GREEN_FONT_COLOR_CODE.."0.0 %"); CombatStatsAttackCritPctLabel:SetText(RED_FONT_COLOR_CODE.."0.0 %"); UIDropDownMenu_SetText(CS_DROPDOWN_SELECT_TEXT,CombatStatsAttackDropDown); end function CombatStatDPSLen(checked,value) CombatStats_DPSLen = value; end -- Register w/ Cosmos Config and set up a chat watch function CombatStats_RegisterCosmos() if( (Cosmos_RegisterConfiguration ~= nil)) then Cosmos_RegisterConfiguration( "COS_COMBATSTATS", "SECTION", COMBATSTATS_CONFIG_HEADER, COMBATSTATS_CONFIG_HEADER_INFO ); Cosmos_RegisterConfiguration( "COS_COMBATSTATS_HEADER", "SEPARATOR", COMBATSTATS_CONFIG_HEADER, COMBATSTATS_CONFIG_HEADER_INFO ); Cosmos_RegisterConfiguration( "COS_COMBATSTATS_ONOFF", "CHECKBOX", COMBATSTATS_CONFIG_ONOFF, COMBATSTATS_CONFIG_ONOFF_INFO, CombatStats_Watch_OnOff, CombatStats_Config.CombatStats_OnOff ); Cosmos_RegisterConfiguration( "COS_COMBATSTATS_USEMOUSEOVER_ONOFF", "CHECKBOX", COMBATSTATS_CONFIG_USEMOUSEOVER, COMBATSTATS_CONFIG_USEMOUSEOVER_INFO, CombatStats_UseMouseOver_OnOff, CombatStats_Config.CombatStats_UseMouseOver, 0 ); Cosmos_RegisterConfiguration( "COS_COMBATSTATS_HIDEONNOTARGET_ONOFF", "CHECKBOX", COMBATSTATS_CONFIG_HIDEONNOTARGET, COMBATSTATS_CONFIG_HIDEONNOTARGET_INFO, CombatStats_HideOnNoTarget_OnOff, CombatStats_Config.CombatStats_HideOnNoTarget ); Cosmos_RegisterConfiguration( "COS_COMBATSTATS_ENDOFFIGHT_ONOFF", "CHECKBOX", COMBATSTATS_CONFIG_ENDOFFIGHT, COMBATSTATS_CONFIG_ENDOFFIGHT_INFO, CombatStats_EndOfFight_OnOff, CombatStats_Config.CombatStats_EndOfFight ); Cosmos_RegisterChatCommand ( "COMBATSTATS_COMMANDS", {"/cs", "/combatsats"}, CombatStats_ChatCommandHandler, CS_CHAT_COMMAND_INFO ); end end function ShowLastFightDPS() -- -- Show the last fight DPS -- local totalFightTime local playerDPS local petDPS local petPct local playerText = "%.1f sec.\nTotal Damage : %d\nOverall Fight DPS : %.1f\n"; local petText = "Your pet did %d or %.1f%% of your overall damage.\nPet DPS : %.1f"; local text = "Fight Statistics\nDuration : "; if( (bInCombat == 0) and (lastFightFinish > lastFightStart)) then totalFightTime = lastFightFinish - lastFightStart; petDPS = lastFightPetDamage / totalFightTime; playerDPS = lastFightPlayerDamage / totalFightTime; if(lastFightPetDamge ~=0) then petPct = (lastFightPetDamage / lastFightPlayerDamage) * 100; end text = text ..format(playerText, totalFightTime,lastFightPlayerDamage,playerDPS); if(lastFightPetDamage ~= 0) then text = text ..format(petText,lastFightPetDamage,petPct,petDPS); end if(DEFAULT_CHAT_FRAME) then DEFAULT_CHAT_FRAME:AddMessage(text); end end end function CombatStats_OnEvent() -- -- Don't do all this unless -- combat stats is turned on -- if ( not CombatStats_Config.CombatStats_OnOff ) then return; end if (event == "PLAYER_REGEN_ENABLED") then regenEnabled = GetTime(); if( (lastFightPlayerDamage > 0) and (bInCombat == 1) ) then lastFightFinish = GetTime(); bInCombat = 0; if(CombatStats_Config.CombatStats_EndOfFight == 1) then ShowLastFightDPS(); end end end -- if (event == "PLAYER_LEAVE_COMBAT") then -- leaveCombat = GetTime(); -- if( (lastFightPlayerDamage > 0) and (bInCombat == 1) ) then -- lastFightFinish = GetTime(); -- bInCombat = 0; -- if(CombatStats_Config.CombatStats_EndOfFight == 1) then -- ShowLastFightDPS(); -- end -- end -- end if (event == "PLAYER_REGEN_DISABLED") then if (bInCombat == 0) then lastFightStart = GetTime(); bInCombat = 1; lastFightPlayerDamage = 0; lastFightPetDamage = 0; end end local p, d; local curtime = combatTime; if( event == "CHAT_MSG_COMBAT_SELF_HITS" or event == "CHAT_MSG_COMBAT_SELF_MISSES" or event == "CHAT_MSG_SPELL_SELF_DAMAGE" or event == "CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE" or event == "CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE" ) then for creatureName, damage,damageType, spell in string.gfind(arg1, "(.+) suffers (%d+) (.+) damage from your (.+).") do CombatStats_AddSpecialData(spell,"dot",damage,curtime); CombatStats_AddDPSEntry("Your", damage); return; end for spell, creatureName, damage in string.gfind(arg1, "Your (.+) hits (.+) for (%d+).") do CombatStats_AddSpecialData(spell,"hit",damage,curtime); CombatStats_AddDPSEntry("Your", damage); return; end for creatureName, damage in string.gfind(arg1, "You hit (.+) for (%d+)") do CombatStats_AddSpecialData("Default","hit",damage,curtime); CombatStats_AddDPSEntry("Your", damage); return; end for spell, creatureName, damage in string.gfind(arg1, "Your (.+) crits (.+) for (%d+).") do CombatStats_AddSpecialData(spell,"crit",damage,curtime); CombatStats_AddDPSEntry("Your", damage); return; end for creatureName, damage in string.gfind(arg1, "You crit (.+) for (%d+)") do CombatStats_AddSpecialData("Default","crit",damage,curtime); CombatStats_AddDPSEntry("Your", damage); return; end for creatureName in string.gfind(arg1, "You miss (.+).") do CombatStats_AddSpecialData("Default","miss",0,curtime); return; end for creatureName in string.gfind(arg1, "You attack. (.+) parries.") do CombatStats_AddSpecialData("Default","parry",0,curtime); return; end for creatureName in string.gfind(arg1, "You attack. (.+) evades.") do CombatStats_AddSpecialData("Default","evade",0,curtime); return; end for creatureName in string.gfind(arg1, "You attack. (.+) dodges.") do CombatStats_AddSpecialData("Default","dodge",0,curtime); return; end for creatureName in string.gfind(arg1, "You attack. (.+) deflects.") do CombatStats_AddSpecialData("Default","deflect",0,curtime); return; end for creatureName in string.gfind(arg1, "You attack. (.+) blocks.") do CombatStats_AddSpecialData("Default","block",0,curtime); return; end for spell, creatureName in string.gfind(arg1, "Your (.+) was blocked by (.+).") do CombatStats_AddSpecialData(spell,"block",0,curtime); return; end for spell, creatureName in string.gfind(arg1, "Your (.+) was deflected by (.+).") do CombatStats_AddSpecialData(spell,"deflect",0,curtime); return; end for spell, creatureName in string.gfind(arg1, "Your (.+) was dodged by (.+).") do CombatStats_AddSpecialData(spell,"dodge",0,curtime); return; end for spell, creatureName in string.gfind(arg1, "Your (.+) was evaded by (.+).") do CombatStats_AddSpecialData(spell,"evade",0,curtime); return; end for spell, creatureName in string.gfind(arg1, "Your (.+) is parried by (.+)") do CombatStats_AddSpecialData(spell,"parry",0,curtime); return; end for spell, creatureName in string.gfind(arg1, "Your (.+) was resisted by (.+).") do CombatStats_AddSpecialData(spell,"resist",0,curtime); return; end for spell, creatureName in string.gfind(arg1, "Your (.+) failed. (.+) is immune.") do CombatStats_AddSpecialData(spell,"immune",0,curtime); return; end for spell, creatureName in string.gfind(arg1, "Your (.+) missed (.+).") do CombatStats_AddSpecialData(spell,"miss",0,curtime); return; end end if( event == "CHAT_MSG_COMBAT_PET_HITS" ) then bInCombat = 1; for petName, creatureName, damage in string.gfind(arg1, "(.+) crits (.+) for (%d+).") do CombatStats_AddSpecialData("[Pet] Default","crit",damage,curtime); CombatStats_AddDPSEntry("Your", damage); return; end for petName, creatureName, damage in string.gfind(arg1, "(.+) hits (.+) for (%d+).") do CombatStats_AddSpecialData("[Pet] Default","hit",damage,curtime); CombatStats_AddDPSEntry("Your", damage); return; end end if (event == "CHAT_MSG_SPELL_PET_DAMAGE") then for petName, spell, creatureName, damage in string.gfind(arg1, "(.+)'s (.+) hits (.+) for (%d+).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"hit",damage,curtime); CombatStats_AddDPSEntry("Your", damage); end return; end for petName, spell, creatureName, damage in string.gfind(arg1, "(.+)'s (.+) crits (.+) for (%d+).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"crit",damage,curtime); CombatStats_AddDPSEntry("Your", damage); end return; end for petName, spell, creatureName in string.gfind(arg1, "(.+)'s (.+) was blocked by (.*).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"block",0,curtime); end return; end for petName, spell, creatureName in string.gfind(arg1, "(.+)'s (.+) was dodged by (.*).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"dodge",0,curtime); end return; end for petName, spell, creatureName in string.gfind(arg1, "(.+)'s (.+) was evaded by (.*).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"evade",0,curtime); end return; end for petName, spell, creatureName in string.gfind(arg1, "(.+)'s (.+) fails. (.+) is immune.") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"immune",0,curtime); end return; end for petName, spell, creatureName in string.gfind(arg1, "(.+)'s (.+) was resisted by (.*).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"resist",0,curtime); end return; end for petName, spell, creatureName in string.gfind(arg1, "(.+)'s (.+) misses (.*).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"miss",0,curtime); end return; end for petName, spell, creatureName in string.gfind(arg1, "(.+)'s (.+) missed (.*).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"miss",0,curtime); end return; end for petName, spell, creatureName in string.gfind(arg1, "(.+)'s (.+) failed. (.+) is immune.") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"immune",0,curtime); end return; end for petName, spell, creatureName in string.gfind(arg1, "(.+)'s (.+) missed (.+).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"miss",0,curtime); end return; end for petName, spell, creatureName in string.gfind(arg1, "(.+)'s (.+) was deflected by (.+).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] "..spell,"deflect",0,curtime); end return; end end if (event == "CHAT_MSG_COMBAT_PET_MISSES") then bInCombat = 1; for petName, creatureName in string.gfind(arg1, "(.+) misses (.*).") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] Default","miss",0,curtime); end return; end for petName, creatureName in string.gfind(arg1, "(.+) attacks. (.+) parries.") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] Default","parry",0,curtime); end return; end for petName, creatureName in string.gfind(arg1, "(.+) attacks. (.+) evades.") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] Default","evade",0,curtime); end return; end for petName, creatureName in string.gfind(arg1, "(.+) attacks. (.+) dodges.") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] Default","dodge",0,curtime); end return; end for petName, creatureName in string.gfind(arg1, "(.+) attacks. (.+) deflects.") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] Default","deflect",0,curtime); end return; end for petName, creatureName in string.gfind(arg1, "(.+) attacks. (.+) blocks.") do if (petName == UnitName('pet') or petName == 'your pet') then CombatStats_AddSpecialData("[Pet] Default","block",0,curtime); end return; end end if(event == "CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS") then bInCombat = 1; for creatureName, damage,tmpStr in string.gfind(arg1, "(.+) hits you for (%d+). (.+) blocked") do CombatStats_AddDefDPSEntry("Your",damage); CombatStats_AddSpecialData("Defensive","hit",damage,curtime); CombatStats_AddSpecialData("Defensive","block",0,curtime); return; end for creatureName, damage in string.gfind(arg1, "(.+) hits you for (%d+)") do CombatStats_AddDefDPSEntry("Your",damage); CombatStats_AddSpecialData("Defensive","hit",damage,curtime); return; end for creatureName, damage in string.gfind(arg1, "(.+) crits you for (%d+).") do CombatStats_AddDefDPSEntry("Your",damage); CombatStats_AddSpecialData("Defensive","crit",damage,curtime); return; end end if( event == "CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE") then for creatureName, spell, damage in string.gfind(arg1, "(.+)'s (.+) hits you for (%d+).") do CombatStats_AddDefDPSEntry("Your",damage); CombatStats_AddSpecialData("Defensive","hit",damage,curtime); return; end for creatureName, spell, damage in string.gfind(arg1, "(.+)'s (.+) crits you for (%d+).") do CombatStats_AddDefDPSEntry("Your",damage); CombatStats_AddSpecialData("Defensive","crit",damage,curtime); return; end for creatureName, spell in string.gfind(arg1, "(.+)'s (.+) was blocked%.") do CombatStats_AddSpecialData("Defensive","block",0,curtime); return; end for creatureName, spell in string.gfind(arg1, "(.+)'s (.+) was deflected%.") do CombatStats_AddSpecialData("Defensive","deflect",0,curtime); return; end for creatureName, spell in string.gfind(arg1, "(.+)'s (.+) was dodged%.") do CombatStats_AddSpecialData("Defensive","dodge",0,curtime); return; end for creatureName, spell in string.gfind(arg1, "(.+)'s (.+) was evaded%.") do CombatStats_AddSpecialData("Defensive","evade",0,curtime); return; end for creatureName, spell in string.gfind(arg1, "(.+)'s (.+) failed. You are immune.") do CombatStats_AddSpecialData("Defensive","immune",0,curtime); return; end for creatureName, spell in string.gfind(arg1, "(.+)'s (.+) misses you.") do CombatStats_AddSpecialData("Defensive","miss",0,curtime); return; end for creatureName, spell in string.gfind(arg1, "You parry (.+)'s (.+)") do CombatStats_AddSpecialData("Defensive","parry",0,curtime); return; end for creatureName, spell in string.gfind(arg1, "(.+)'s (.+) was resisted%.") do CombatStats_AddSpecialData("Defensive","resist",0,curtime); return; end end if (event == "CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES") then for creatureName in string.gfind(arg1, "(.+) misses you.") do CombatStats_AddSpecialData("Defensive","miss",0,curtime); return; end for creatureName in string.gfind(arg1, "(.+) attacks. You parry.") do CombatStats_AddSpecialData("Defensive","parry",0,curtime); return; end for creatureName in string.gfind(arg1, "(.+) attacks. You evade.") do CombatStats_AddSpecialData("Defensive","evade",0,curtime); return; end for creatureName in string.gfind(arg1, "(.+) attacks. You dodge.") do CombatStats_AddSpecialData("Defensive","dodge",0,curtime); return; end for creatureName in string.gfind(arg1, "(.+) attacks. You deflect.") do CombatStats_AddSpecialData("Defensive","deflect",0,curtime); return; end for creatureName in string.gfind(arg1, "(.+) attacks. You block.") do CombatStats_AddSpecialData("Defensive","block",0,curtime); return; end end if ( event == "CHAT_MSG_SPELL_SELF_BUFF" or event == "CHAT_MSG_SPELL_PARTY_BUFF" or event == "CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF" ) then local useless, useless, spell, amount = string.find(arg1, "Your (.+) critically heals .+ for (%d+)%."); if ( spell and amount ) then CombatStats_AddSpecialData("[Heal] Total","crit",amount,curtime, 1); CombatStats_AddSpecialData("[Heal] "..spell,"crit",amount,curtime, 1); elseif ( string.find(arg1, "Your (.+) heals .+ for (%d+)%.") ) then local useless, useless, spell, amount = string.find(arg1, "Your (.+) heals .+ for (%d+)%."); if ( spell and amount ) then CombatStats_AddSpecialData("[Heal] Total","hit",amount,curtime, 1); CombatStats_AddSpecialData("[Heal] "..spell,"hit",amount,curtime, 1); end end end if ( event == "CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS" or event == "CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS" ) then local useless, useless, amount, spell = string.find(arg1, ".+ gains (%d+) health from your (.+)%."); if ( spell and amount ) then CombatStats_AddSpecialData("[Heal] Total","hit",amount,curtime, 1); CombatStats_AddSpecialData("[Heal] "..spell,"hot",amount,curtime, 1); end end if ( event == "CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS" ) then local useless, useless, amount, spell = string.find(arg1, "You gain (%d+) health from (.+)%."); if ( not string.find(arg1, "'s") and spell and amount ) then CombatStats_AddSpecialData("[Heal] Total","hit",amount,curtime, 1); CombatStats_AddSpecialData("[Heal] "..spell,"hot",amount,curtime, 1); end end end -- -- Add/Check for attack(s) -- function CombatStats_AddSpecialData(specialName,type,dmg,time, heal) -- -- If we haven't logged this attack -- Create a record in the table for it -- --print2("Adding : "..specialName .." with damage : "..dmg.."at : "..time); if(specialName ~= "Defensive" and not heal ) then lastFightPlayerDamage = lastFightPlayerDamage + dmg; totalDamage = totalDamage + dmg; end for creatureName,tempJunk in string.gfind(specialName, "(.+)Pet(.+)") do -- print2("creatureName : "..creatureName); -- print2("tempJunk : "..tempJunk); -- print2("Adding pet special : "..specialName.. " with damage of : "..dmg); lastFightPetDamage = lastFightPetDamage + dmg; end if (type == "dot") then specialName = specialName .." [DOT]"; elseif ( type == "hot" ) then specialName = specialName .." [HOT]"; end if(specialName == "Default") then bHasDefault = 1; end if ( not specialAttacks[specialName] ) then specialsCount = specialsCount + 1; table.insert(attackNames,specialName); specialAttackLog[specialsCount] = { index = specialsCount, name = specialName, isDOT = 0, dotDmg = 0, dotTicks = 0, totalSwings = 0, totalMisses = 0, totalDodged = 0, totalParried = 0, totalEvaded = 0, totalBlocked = 0, totalResisted = 0, totalImmuned = 0, totalDeflected = 0, totalHits = 0, totalNonCrits = 0, totalCrits = 0, maxCrit = 0, minCrit = 0, maxReg = 0, minReg = 0, totalRegDmg = 0, totalCritDmg = 0, lastCrit = 0, } specialAttacks[specialName] = specialAttackLog[specialsCount]; local info; info = {}; info.text = specialName; info.func = CombatStatsAttack_OnClick; UIDropDownMenu_AddButton(info); end -- -- Now add the data -- if(specialName ~= "Defensive" and not heal ) then specialAttacks[specialName].totalSwings = specialAttacks[specialName].totalSwings + 1; overallSwings = overallSwings + 1; if(type == "crit") then totalHits = totalHits + 1; totalCrits = totalCrits + 1; specialAttacks[specialName].totalCrits = specialAttacks[specialName].totalCrits +1; specialAttacks[specialName].totalCritDmg = specialAttacks[specialName].totalCritDmg + dmg; specialAttacks[specialName].lastCrit = time; specialAttacks[specialName].totalHits = specialAttacks[specialName].totalHits + 1; overallCrits = overallCrits + 1; overallCritDmg = overallCritDmg + dmg; overallLastcrit = time; -- -- Set the initial min/max -- if(specialAttacks[specialName].maxCrit == 0) then specialAttacks[specialName].maxCrit = dmg; end if(specialAttacks[specialName].minCrit == 0) then specialAttacks[specialName].minCrit = dmg; end if(overallmaxCrit == 0) then overallmaxCrit = dmg; end if(overallminCrit == 0) then overallminCrit = dmg; end -- -- Check to see if this dmg -- is a new min or max -- if(tonumber(dmg) < tonumber(specialAttacks[specialName].minCrit)) then specialAttacks[specialName].minCrit = dmg; end if(tonumber(dmg) > tonumber(specialAttacks[specialName].maxCrit)) then specialAttacks[specialName].maxCrit = dmg; end if(tonumber(dmg) < tonumber(overallminCrit)) then overallminCrit = dmg; end if(tonumber(dmg) > tonumber(overallmaxCrit)) then overallmaxCrit = dmg; end end if(type == "hit") then totalHits = totalHits + 1; specialAttacks[specialName].isDOT = 0; specialAttacks[specialName].totalNonCrits = specialAttacks[specialName].totalNonCrits +1; specialAttacks[specialName].totalRegDmg = specialAttacks[specialName].totalRegDmg + dmg; specialAttacks[specialName].totalHits = specialAttacks[specialName].totalHits + 1; overallNonCrits = overallNonCrits + 1; overallRegDmg = overallRegDmg + dmg; -- -- Set the initial min/max -- if(specialAttacks[specialName].maxReg == 0) then specialAttacks[specialName].maxReg = dmg; end if(specialAttacks[specialName].minReg == 0) then specialAttacks[specialName].minReg = dmg; end if(overallmaxReg == 0) then overallmaxReg = dmg; end if(overallminReg == 0) then overallminReg = dmg; end -- -- Check to see if this dmg -- is a new min or max -- if(tonumber(dmg) < tonumber(specialAttacks[specialName].minReg)) then specialAttacks[specialName].minReg = dmg; end if(tonumber(dmg) > tonumber(specialAttacks[specialName].maxReg)) then specialAttacks[specialName].maxReg = dmg; end if(tonumber(dmg) < tonumber(overallminReg)) then overallminReg = dmg; end if(tonumber(dmg) > tonumber (overallmaxReg)) then overallmaxReg = dmg; end end if(type == "dot") then totalHits = totalHits + 1; specialAttacks[specialName].isDOT = 1; specialAttacks[specialName].dotTicks = specialAttacks[specialName].dotTicks +1; specialAttacks[specialName].dotDmg = specialAttacks[specialName].dotDmg + dmg; specialAttacks[specialName].totalHits = specialAttacks[specialName].totalHits + 1; overallNonCrits = overallNonCrits + 1; overallRegDmg = overallRegDmg + dmg; -- -- Set the initial min/max -- if(specialAttacks[specialName].maxReg == 0) then specialAttacks[specialName].maxReg = dmg; end if(specialAttacks[specialName].minReg == 0) then specialAttacks[specialName].minReg = dmg; end if(overallmaxReg == 0) then overallmaxReg = dmg; end if(overallminReg == 0) then overallminReg = dmg; end -- -- Check to see if this dmg -- is a new min or max -- if(tonumber(dmg) < tonumber(specialAttacks[specialName].minReg)) then specialAttacks[specialName].minReg = dmg; end if(tonumber(dmg) > tonumber(specialAttacks[specialName].maxReg)) then specialAttacks[specialName].maxReg = dmg; end if(tonumber(dmg) < tonumber(overallminReg)) then overallminReg = dmg; end if(tonumber(dmg) > tonumber (overallmaxReg)) then overallmaxReg = dmg; end end if(type == "miss") then specialAttacks[specialName].totalMisses = specialAttacks[specialName].totalMisses + 1; overallMisses = overallMisses +1; end if(type == "dodge") then specialAttacks[specialName].totalDodged = specialAttacks[specialName].totalDodged + 1; overallDodged = overallDodged + 1; end if(type == "parry") then specialAttacks[specialName].totalParried = specialAttacks[specialName].totalParried + 1; overallParried = overallParried + 1; end if(type == "block") then specialAttacks[specialName].totalBlocked = specialAttacks[specialName].totalBlocked + 1; overallBlocked = overallBlocked + 1; end if(type == "evade") then specialAttacks[specialName].totalEvaded = specialAttacks[specialName].totalEvaded + 1; overallEvaded = overallEvaded + 1; end if(type == "resist") then specialAttacks[specialName].totalResisted = specialAttacks[specialName].totalResisted + 1; overallResisted = overallResisted + 1; end if(type == "immune") then specialAttacks[specialName].totalImmuned = specialAttacks[specialName].totalImmuned + 1; overallImmuned = overallImmuned + 1; end if(type == "deflect") then specialAttacks[specialName].totalDeflected = specialAttacks[specialName].totalDeflected + 1; overallDeflected = overallDeflected + 1; end else -- -- Defesnsive info -- Don't add to overall stats and overa -- specialAttacks[specialName].totalSwings = specialAttacks[specialName].totalSwings + 1; if(type == "crit") then specialAttacks[specialName].totalCrits = specialAttacks[specialName].totalCrits +1; specialAttacks[specialName].totalCritDmg = specialAttacks[specialName].totalCritDmg + dmg; specialAttacks[specialName].lastCrit = time; specialAttacks[specialName].totalHits = specialAttacks[specialName].totalHits + 1; -- -- Set the initial min/max -- if(specialAttacks[specialName].maxCrit == 0) then specialAttacks[specialName].maxCrit = dmg; end if(specialAttacks[specialName].minCrit == 0) then specialAttacks[specialName].minCrit = dmg; end -- -- Check to see if this dmg -- is a new min or max -- if(tonumber(dmg) < tonumber(specialAttacks[specialName].minCrit)) then specialAttacks[specialName].minCrit = dmg; end if(tonumber(dmg) > tonumber(specialAttacks[specialName].maxCrit)) then specialAttacks[specialName].maxCrit = dmg; end end if(type == "hit") then specialAttacks[specialName].isDOT = 0; specialAttacks[specialName].totalNonCrits = specialAttacks[specialName].totalNonCrits +1; specialAttacks[specialName].totalRegDmg = specialAttacks[specialName].totalRegDmg + dmg; specialAttacks[specialName].totalHits = specialAttacks[specialName].totalHits + 1; -- -- Set the initial min/max -- if(specialAttacks[specialName].maxReg == 0) then specialAttacks[specialName].maxReg = dmg; end if(specialAttacks[specialName].minReg == 0) then specialAttacks[specialName].minReg = dmg; end -- -- Check to see if this dmg -- is a new min or max -- if(tonumber(dmg) < tonumber(specialAttacks[specialName].minReg)) then specialAttacks[specialName].minReg = dmg; end if(tonumber(dmg) > tonumber(specialAttacks[specialName].maxReg)) then specialAttacks[specialName].maxReg = dmg; end end if(type == "hot") then specialAttacks[specialName].isDOT = 2; specialAttacks[specialName].dotTicks = specialAttacks[specialName].dotTicks +1; specialAttacks[specialName].dotDmg = specialAttacks[specialName].dotDmg + dmg; specialAttacks[specialName].totalHits = specialAttacks[specialName].totalHits + 1; -- -- Set the initial min/max -- if(specialAttacks[specialName].maxReg == 0) then specialAttacks[specialName].maxReg = dmg; end if(specialAttacks[specialName].minReg == 0) then specialAttacks[specialName].minReg = dmg; end -- -- Check to see if this dmg -- is a new min or max -- if(tonumber(dmg) < tonumber(specialAttacks[specialName].minReg)) then specialAttacks[specialName].minReg = dmg; end if(tonumber(dmg) > tonumber(specialAttacks[specialName].maxReg)) then specialAttacks[specialName].maxReg = dmg; end end if(type == "miss") then specialAttacks[specialName].totalMisses = specialAttacks[specialName].totalMisses + 1; end if(type == "dodge") then specialAttacks[specialName].totalDodged = specialAttacks[specialName].totalDodged + 1; end if(type == "parry") then specialAttacks[specialName].totalParried = specialAttacks[specialName].totalParried + 1; end if(type == "block") then specialAttacks[specialName].totalBlocked = specialAttacks[specialName].totalBlocked + 1; end if(type == "evade") then specialAttacks[specialName].totalEvaded = specialAttacks[specialName].totalEvaded + 1; end if(type == "resist") then specialAttacks[specialName].totalResisted = specialAttacks[specialName].totalResisted + 1; end if(type == "immune") then specialAttacks[specialName].totalImmuned = specialAttacks[specialName].totalImmuned + 1; end if(type == "deflect") then specialAttacks[specialName].totalDeflected = specialAttacks[specialName].totalDeflected + 1; end end if ( CombatStatsDataFrame.currAttack and CombatStatsDataFrame.currAttack == specialName ) then CombatStats_UpdateDetails(specialName); end end -- CombatStats Event Watcher -- -- Update Handler -- function CombatStats_OnUpdate(elapsed) local curtime = GetTime(); local oldesttime = 0; local oldesttimeTaken = 0; local deleteindex = 0; local deleteindexTaken = 0; local playerFrame; if ( bInCombat == 1 ) then combatTime = combatTime + elapsed; end --print2("In Combat == " ..bInCombat); if (bInCombat == 1) then -- Check to see if its time to update the on screen DPS and only update if there are dps entries to save CPU if ( ((curtime - CombatStats_LastUpdate) > CombatStats_UpdateFreq) and (table.getn(timestamps) > 0) ) then -- TODO: Change this to a high to low loop so we can do our subtracts and deletes in the same run -- -- Offensive -- for k,v in pairs(timestamps) do -- Get rid of old dps entries and adjust the totals if ( (curtime - CombatStats_DPSLen) > v ) then -- Subtract this entry from the totals dpstotals[players[k]] = dpstotals[players[k]] - dmg[k]; -- Mark for later removal *We can't do the remove here cause table.remove reindexes the list and bones our loop deleteindex = k; else -- were into the good stuff now, stop oldesttime = v; break; end end -- Remove entries from deleteindex down so we don't miss em while (deleteindex > 0) do table.remove(timestamps, deleteindex); table.remove(players, deleteindex); table.remove(dmg, deleteindex); deleteindex = deleteindex -1; end end if ( ((curtime - CombatStats_LastUpdate) > CombatStats_UpdateFreq) and (table.getn(takenTimestamps) > 0) ) then -- -- Defensive -- for w,y in pairs(takenTimestamps) do -- Get rid of old dps entries and adjust the totals if ( (curtime - CombatStats_DPSLen) > y ) then -- Subtract this entry from the totals dpsTakenTotals[playersTaken[w]] = dpsTakenTotals[playersTaken[w]] - dmgTaken[w]; -- Mark for later removal *We can't do the remove here cause table.remove reindexes the list and bones our loop deleteindexTaken = w; else -- were into the good stuff now, stop oldesttimeTaken = y; break; end end -- Remove entries from deleteindex down so we don't miss em while (deleteindexTaken > 0) do table.remove(takenTimestamps, deleteindexTaken); table.remove(playersTaken, deleteindexTaken); table.remove(dmgTaken, deleteindexTaken); deleteindexTaken = deleteindexTaken -1; end end -- NOTE: Everyone calcs off the same oldest time, not their own oldest time. -- This should give more accurate dps on a per group fight basis. if ( ((curtime - CombatStats_LastUpdate) > CombatStats_UpdateFreq) and (table.getn(timestamps) > 0) ) then --local text = "CurTime - Oldesettime : %.1f"; --text = format(text,(curtime - oldesttime)); --print2(text); -- Update player DPS if ( dpstotals["Your"] ~= nil ) then if(dpsTakenTotals["Your"] ~= nil) then CombatStatsText:SetText( RED_FONT_COLOR_CODE.. format(TEXT(DPS_DISPLAY), (dpsTakenTotals["Your"] / (curtime - oldesttimeTaken) )) ..NORMAL_FONT_COLOR_CODE.. " / " ..GREEN_FONT_COLOR_CODE.. format(TEXT(DPS_DISPLAY), (dpstotals["Your"] / (curtime - oldesttime) )) ); else CombatStatsText:SetText( RED_FONT_COLOR_CODE.. "0.0" ..NORMAL_FONT_COLOR_CODE.. " / " ..GREEN_FONT_COLOR_CODE.. format(TEXT(DPS_DISPLAY), (dpstotals["Your"] / (curtime - oldesttime) )) ); end end CombatStats_LastUpdate = curtime; end -- -- If the data frame is visible -- update the selected attack "Real time" -- if (CombatStatsDataFrame:IsVisible()) then if( UIDropDownMenu_GetText(CombatStatsAttackDropDown) ~= CS_DROPDOWN_SELECT_TEXT) then CombatStats_UpdateDetails( UIDropDownMenu_GetText(CombatStatsAttackDropDown)); end end end end -- Called from XML function CombatStats_OnLoad() if ( Cosmos_RegisterConfiguration ~= nil) then CombatStats_RegisterCosmos(); HookFunction("TargetFrame_OnShow", "CombatStats_TargetFrame_OnShow", "after"); HookFunction("TargetFrame_OnHide", "CombatStats_TargetFrame_OnHide", "after"); else -- Standalone (chatwatch) CombatStats_Old_TargetFrame_OnShow = TargetFrame_OnShow; CombatStats_Old_TargetFrame_OnHide = TargetFrame_OnHide; TargetFrame_OnShow = CombatStats_TargetFrame_OnShow; TargetFrame_OnHide = CombatStats_TargetFrame_OnHide; SLASH_CSSLASH1 = "/combatstats"; SLASH_CSSLASH2 = "/cs"; SlashCmdList["CSSLASH"] = CombatStats_ChatCommandHandler; end if (not Print) then setglobal("Print", function(msg, r, g, b, frame, id) if (not r) then r = 1.0; end if (not g) then g = 1.0; end if (not b) then b = 1.0; end if (not frame) then frame = DEFAULT_CHAT_FRAME; end if (frame) then if (not id) then frame:AddMessage(msg,r,g,b); else frame:AddMessage(msg,r,g,b,id); end end end); end this:RegisterEvent("CHAT_MSG_COMBAT_SELF_HITS"); this:RegisterEvent("CHAT_MSG_COMBAT_SELF_MISSES"); this:RegisterEvent("CHAT_MSG_COMBAT_PET_HITS"); this:RegisterEvent("CHAT_MSG_COMBAT_PET_MISSES"); this:RegisterEvent("CHAT_MSG_SPELL_SELF_DAMAGE"); this:RegisterEvent("CHAT_MSG_SPELL_PET_DAMAGE"); this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_DAMAGE"); this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE"); this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILEPLAYER_HITS"); this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILEPLAYER_MISSES"); this:RegisterEvent("CHAT_MSG_COMBAT_CREATURE_VS_SELF_HITS"); this:RegisterEvent("CHAT_MSG_COMBAT_CREATURE_VS_SELF_MISSES"); this:RegisterEvent("CHAT_MSG_SPELL_HOSTILEPLAYER_DAMAGE"); this:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_SELF_DAMAGE"); this:RegisterEvent("CHAT_MSG_SPELL_CREATURE_VS_SELF_BUFF"); this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_HOSTILEPLAYER_BUFFS"); this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_CREATURE_DAMAGE"); this:RegisterEvent("CHAT_MSG_SYSTEM"); this:RegisterEvent("PLAYER_REGEN_ENABLED"); this:RegisterEvent("PLAYER_REGEN_DISABLED"); this:RegisterEvent("PLAYER_LEAVE_COMBAT"); this:RegisterEvent("CHAT_MSG_COMBAT_XP_GAIN"); this:RegisterEvent("CHAT_MSG_COMBAT_LOG_ENEMY"); this:RegisterEvent("CHAT_MSG_COMBAT_HOSTILE_DEATH"); -- Heals this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_FRIENDLYPLAYER_BUFFS"); this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_PARTY_BUFFS"); this:RegisterEvent("CHAT_MSG_SPELL_PERIODIC_SELF_BUFFS"); this:RegisterEvent("CHAT_MSG_SPELL_SELF_BUFF"); this:RegisterEvent("CHAT_MSG_SPELL_PARTY_BUFF"); this:RegisterEvent("CHAT_MSG_SPELL_FRIENDLYPLAYER_BUFF"); CombatStatsText:SetText("Overall DPS :: "); CombatStats_UpdateVisibility(); end function CombatStatsAttack_OnClick() local attackID = this:GetID(); UIDropDownMenu_SetSelectedID(CombatStatsAttackDropDown, attackID); --print2("GetID :: ".. UIDropDownMenu_GetSelectedID(CombatStatsAttackDropDown)); local attackName = UIDropDownMenu_GetText(CombatStatsAttackDropDown); UIDropDownMenu_SetSelectedValue(CombatStatsAttackDropDown, attackName); --print2("GetValue :: ".. UIDropDownMenu_GetSelectedValue(CombatStatsAttackDropDown)); UIDropDownMenu_SetText(attackName,CombatStatsAttackDropDown); --this:SetText(CombatStatsDetailTypes[detailID].value); --this.text = CombatStatsDetailTypes[detailID].value; CombatStats_UpdateDetails(attackName); end function CombatStatsAttackDropDown_OnLoad() UIDropDownMenu_Initialize(this, CombatStatsAttackDropDown_Initialize); end function CombatStatsAttackDropDown_Initialize() CombatStats_LoadAttackNames(); end function CombatStats_LoadAttackNames() local info; if(table.getn(attackNames) ~= 0) then if(bHasDefault == 1) then info = {}; info.text = "Default"; info.func = CombatStatsAttack_OnClick; UIDropDownMenu_AddButton(info); end end for i=1, table.getn(attackNames), 1 do if(attackNames[i] ~= "Default") then info = {}; info.text = attackNames[i]; info.func = CombatStatsAttack_OnClick; UIDropDownMenu_AddButton(info); end end if(table.getn(attackNames) ~= 0) then info = {}; info.text = "Total"; info.func = CombatStatsAttack_OnClick; UIDropDownMenu_AddButton(info); end end -- -- Add the damage to the DPS table -- function CombatStats_AddDPSEntry(p, d) table.insert(timestamps, GetTime()); table.insert(players, p); table.insert(dmg, d); -- Keep running totals on group members to shorten calculation times -- We'll subtract off the expired entries during OnUpdate if (dpstotals[p] == nil) then -- print2("dpstotals[p] == nil"); dpstotals[p] = d; else -- print2("dpstotals[p] == " ..dpstotals[p] ); dpstotals[p] = dpstotals[p] + d; -- print2("AFTER : dpstotals[p] == " ..dpstotals[p] ); end --print2("Total : " ..dpstotals[p]); end -- -- Add damage taken to the DPS table -- function CombatStats_AddDefDPSEntry(p, d) --print2("Adding Entry[" .. p .. "] = " .. d); -- debug table.insert(takenTimestamps, GetTime()); table.insert(playersTaken, p); table.insert(dmgTaken, d); -- Keep running totals on group members to shorten calculation times -- We'll subtract off the expired entries during OnUpdate if (dpsTakenTotals[p] == nil) then -- print2("dpstotals[p] == nil"); dpsTakenTotals[p] = d; else -- print2("dpstotals[p] == " ..dpstotals[p] ); dpsTakenTotals[p] = dpsTakenTotals[p] + d; -- print2("AFTER : dpstotals[p] == " ..dpstotals[p] ); end --print2("Total : " ..dpstotals[p]); end -- Show the stats collected function CombatStatsText_OnClick() if (CombatStatsDataFrame:IsVisible()) then CombatStatsDataFrame:Hide(); else if (CombatStats_Config.CombatStats_UseMouseOver == 0) then CombatStatsText_ShowFrame(); end end end function CombatStatsText_OnEnter() if (CombatStats_Config.CombatStats_UseMouseOver == 1) then CombatStatsText_ShowFrame(); end end function CombatStatsText_ShowFrame() if(bFirstTime == 1) then -- -- Set all the default values -- CombatStatsGeneralNameLabel:SetText(TEXT(CS_FRAME_GEN_ATTACK_NAME)); CombatStatsGeneralHitsTextLabel:SetText(CS_FRAME_HITS_TEXT); CombatStatsGeneralSwingsTextLabel:SetText(CS_FRAME_SWINGS_TEXT); CombatStatsGeneralMissesLabel:SetText(CS_FRAME_MISSES_TEXT); CombatStatsGeneralDodgesLabel:SetText(CS_FRAME_DODGES_TEXT); CombatStatsGeneralParriedLabel:SetText(CS_FRAME_PARRIES_TEXT); CombatStatsGeneralBlockedLabel:SetText(CS_FRAME_BLOCKS_TEXT); CombatStatsGeneralResistedLabel:SetText(CS_FRAME_RESISTS_TEXT); CombatStatsGeneralImmunedLabel:SetText(CS_FRAME_IMMUNE_TEXT); CombatStatsGeneralEvadedLabel:SetText(CS_FRAME_EVADES_TEXT ); CombatStatsGeneralDeflectedLabel:SetText(CS_FRAME_DEFLECTS_TEXT); CombatStatsGeneralPercentDmgLabel:SetText(CS_FRAME_PERCENT_OVERALL_TEXT); CombatStatsGeneralTimeLastCritLabel:SetText(CS_FRAME_TIME_LASTCRIT_TEXT); CombatStatsNonCritHitsLabel:SetText(CS_FRAME_TOTAL_TEXT); CombatStatsNonCritDamageLabel:SetText(CS_FRAME_DAMAGE_TEXT); CombatStatsNonCritMinMaxLabel:SetText(CS_FRAME_MINMAX_TEXT); CombatStatsNonCritAvgLabel:SetText(CS_FRAME_AVGDMG_TEXT); CombatStatsNonCritPercentDamageLabel:SetText(CS_FRAME_PERCENTDMG_TEXT); CombatStatsCritHitsLabel:SetText(CS_FRAME_TOTAL_TEXT); CombatStatsCritDamageLabel:SetText(CS_FRAME_DAMAGE_TEXT); CombatStatsCritMinMaxLabel:SetText(CS_FRAME_MINMAX_TEXT); CombatStatsCritAvgLabel:SetText(CS_FRAME_AVGDMG_TEXT); CombatStatsCritPercentDamageLabel:SetText(CS_FRAME_PERCENTDMG_TEXT); CombatStatsGeneralNameTextLabel:SetText("N/A"); CombatStatsNonCritHitsStatText:SetText("0"); CombatStatsNonCritDamageStatText:SetText("0"); CombatStatsNonCritMinMaxStatText:SetText("0 / 0"); CombatStatsNonCritAvgStatText:SetText("0.0"); CombatStatsNonCritPercentDamageStatText:SetText("0.0 %"); CombatStatsCritHitsStatText:SetText("0"); CombatStatsCritDamageStatText:SetText("0"); CombatStatsCritMinMaxStatText:SetText("0 / 0"); CombatStatsCritAvgStatText:SetText("0.0"); CombatStatsCritPercentDamageStatText:SetText("0.0 %"); CombatStatsGeneralTotalHitsHits:SetText("0"); CombatStatsGeneralSwingsLabel:SetText("0"); CombatStatsGeneralMissesTextLabel:SetText("0"); CombatStatsGeneralMissesPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralDodgesTextLabel:SetText("0"); CombatStatsGeneralDodgesPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralParriedTextLabel:SetText("0"); CombatStatsGeneralParriedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralBlockedTextLabel:SetText("0"); CombatStatsGeneralBlockedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralResistedTextLabel:SetText("0"); CombatStatsGeneralResistedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralImmunedTextLabel:SetText("0"); CombatStatsGeneralImmunedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralEvadedTextLabel:SetText("0"); CombatStatsGeneralEvadedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralDeflectedTextLabel:SetText("0"); CombatStatsGeneralDeflectedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); CombatStatsGeneralPercentDmgPctLabel:SetText("0.0%"); CombatStatsGeneralTimeLastCritTimeLabel:SetText(GREEN_FONT_COLOR_CODE.."N/A"); CombatStatsOverallCritPctLabel:SetText(RED_FONT_COLOR_CODE.."0.0 %"); CombatStatsAttackNonCritPctLabel:SetText(GREEN_FONT_COLOR_CODE.."0.0 %"); CombatStatsAttackCritPctLabel:SetText(RED_FONT_COLOR_CODE.."0.0 %"); UIDropDownMenu_SetText(CS_DROPDOWN_SELECT_TEXT,CombatStatsAttackDropDown); bFirstTime = 0; end if( UIDropDownMenu_GetText(CombatStatsAttackDropDown) ~= CS_DROPDOWN_SELECT_TEXT) then CombatStats_UpdateDetails( UIDropDownMenu_GetText(CombatStatsAttackDropDown)); end CombatStatsDataFrame:Show(); end function CS_ToggleGameMenu(clicked) if ( clicked ) then if ( OptionsFrame:IsVisible() ) then OptionsFrameCancel:Click(); end if ( GameMenuFrame:IsVisible() ) then PlaySound("igMainMenuQuit"); HideUIPanel(GameMenuFrame); else CloseMenus(); CloseAllWindows() PlaySound("igMainMenuOpen"); ShowUIPanel(GameMenuFrame); end return; end if ( StaticPopup_EscapePressed() ) then elseif ( OptionsFrame:IsVisible() ) then OptionsFrameCancel:Click(); elseif ( GameMenuFrame:IsVisible() ) then PlaySound("igMainMenuQuit"); HideUIPanel(GameMenuFrame); elseif ( CloseMenus() ) then elseif ( SpellStopCasting() ) then elseif ( SpellStopTargeting() ) then elseif ( CloseAllWindows() ) then CombatStatsDataFrame:Hide(); elseif ( ClearTarget() ) then else if ( CombatStatsDataFrame:IsVisible() ) then CombatStatsDataFrame:Hide(); return; end PlaySound("igMainMenuOpen"); ShowUIPanel(GameMenuFrame); end end ToggleGameMenu = CS_ToggleGameMenu; function CombatStats_UpdateDetails(attackName) CombatStatsDataFrame.currAttack = attackName; if ( strsub(attackName, 0, 6) == "[Heal]" ) then CS_TT_NONCRIT_HITSPCT_TEXT = CS_TT_NONCRIT_HITSPCT_TEXT_HEAL; CS_TT_CRIT_HITSPCT_TEXT = CS_TT_CRIT_HITSPCT_TEXT_HEAL; CS_TT_OVERALLDMGPCT_TEXT = CS_TT_OVERALLDMGPCT_TEXT_HEAL; CS_TT_CRIT_DMGPCT_TEXT = CS_TT_CRIT_DMGPCT_TEXT_HEAL; CS_TT_NONCRIT_DMGPCT_TEXT = CS_TT_NONCRIT_DMGPCT_TEXT_HEAL; CombatStatsGeneralHitsTextLabel:SetText(CS_FRAME_HITS_TEXT_HEAL); CombatStatsGeneralPercentDmgLabel:SetText(CS_FRAME_PERCENT_OVERALL_TEXT_HEAL); CombatStatsNonCritDamageLabel:SetText(CS_FRAME_DAMAGE_TEXT_HEAL); CombatStatsNonCritAvgLabel:SetText(CS_FRAME_AVGDMG_TEXT_HEAL); CombatStatsNonCritPercentDamageLabel:SetText(CS_FRAME_PERCENTDMG_TEXT_HEAL); CombatStatsCritDamageLabel:SetText(CS_FRAME_DAMAGE_TEXT_HEAL); CombatStatsCritAvgLabel:SetText(CS_FRAME_AVGDMG_TEXT_HEAL); CombatStatsCritPercentDamageLabel:SetText(CS_FRAME_PERCENTDMG_TEXT_HEAL); CombatStatsGeneralSwingsTextLabel:Hide(); else CS_TT_NONCRIT_HITSPCT_TEXT = CS_TT_NONCRIT_HITSPCT_TEXT_NONHEAL; CS_TT_CRIT_HITSPCT_TEXT = CS_TT_CRIT_HITSPCT_TEXT_NONHEAL; CS_TT_OVERALLDMGPCT_TEXT = CS_TT_OVERALLDMGPCT_TEXT_NONHEAL; CS_TT_CRIT_DMGPCT_TEXT = CS_TT_CRIT_DMGPCT_TEXT_NONHEAL; CS_TT_NONCRIT_DMGPCT_TEXT = CS_TT_NONCRIT_DMGPCT_TEXT_NONHEAL; CombatStatsGeneralHitsTextLabel:SetText(CS_FRAME_HITS_TEXT); CombatStatsGeneralPercentDmgLabel:SetText(CS_FRAME_PERCENT_OVERALL_TEXT); CombatStatsNonCritDamageLabel:SetText(CS_FRAME_DAMAGE_TEXT); CombatStatsNonCritAvgLabel:SetText(CS_FRAME_AVGDMG_TEXT); CombatStatsNonCritPercentDamageLabel:SetText(CS_FRAME_PERCENTDMG_TEXT); CombatStatsCritDamageLabel:SetText(CS_FRAME_DAMAGE_TEXT); CombatStatsCritAvgLabel:SetText(CS_FRAME_AVGDMG_TEXT); CombatStatsCritPercentDamageLabel:SetText(CS_FRAME_PERCENTDMG_TEXT); CombatStatsGeneralSwingsTextLabel:Show(); end local x,y,info; -- -- Draw the text for the hits/swings -- if(attackName ~= "Total") then -- -- Calculate % of hits that are crits -- if( (totalCrits) ~= 0) then CombatStatsOverallCritPctLabel:SetText( format(RED_FONT_COLOR_CODE.."%.2f %%", ( totalCrits / totalHits) * 100.0)); end CombatStatsGeneralNameTextLabel:SetText(attackName); CombatStatsGeneralTotalHitsHits:SetText(specialAttacks[attackName].totalHits); if ( strsub(attackName, 0, 6) ~= "[Heal]" ) then CombatStatsGeneralSwingsLabel:SetText(specialAttacks[attackName].totalSwings); CombatStatsGeneralSwingsLabel:Show(); else CombatStatsGeneralSwingsLabel:Hide(); end CombatStatsGeneralMissesTextLabel:SetText(specialAttacks[attackName].totalMisses); if(specialAttacks[attackName].totalMisses ~= 0) then CombatStatsGeneralMissesPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (specialAttacks[attackName].totalMisses / (specialAttacks[attackName].totalSwings) * 100))); else CombatStatsGeneralMissesPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralDodgesTextLabel:SetText(specialAttacks[attackName].totalDodged); if(specialAttacks[attackName].totalDodged ~= 0) then CombatStatsGeneralDodgesPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (specialAttacks[attackName].totalDodged / (specialAttacks[attackName].totalSwings) * 100))); else CombatStatsGeneralDodgesPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralBlockedTextLabel:SetText(specialAttacks[attackName].totalBlocked); if(attackName == "Defensive") then if(specialAttacks[attackName].totalBlocked ~= 0) then CombatStatsGeneralBlockedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (specialAttacks[attackName].totalBlocked / (specialAttacks[attackName].totalHits) * 100))); else CombatStatsGeneralBlockedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end else if(specialAttacks[attackName].totalBlocked ~= 0) then CombatStatsGeneralBlockedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (specialAttacks[attackName].totalBlocked / (specialAttacks[attackName].totalSwings) * 100))); else CombatStatsGeneralBlockedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end end CombatStatsGeneralParriedTextLabel:SetText(specialAttacks[attackName].totalParried); if(specialAttacks[attackName].totalParried ~= 0) then CombatStatsGeneralParriedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (specialAttacks[attackName].totalParried / (specialAttacks[attackName].totalSwings) * 100))); else CombatStatsGeneralParriedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralResistedTextLabel:SetText(specialAttacks[attackName].totalResisted); if(specialAttacks[attackName].totalResisted ~= 0) then CombatStatsGeneralResistedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (specialAttacks[attackName].totalResisted / (specialAttacks[attackName].totalSwings) * 100))); else CombatStatsGeneralResistedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralImmunedTextLabel:SetText(specialAttacks[attackName].totalImmuned); if(specialAttacks[attackName].totalImmuned ~= 0) then CombatStatsGeneralImmunedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (specialAttacks[attackName].totalImmuned / (specialAttacks[attackName].totalSwings) * 100))); else CombatStatsGeneralImmunedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralEvadedTextLabel:SetText(specialAttacks[attackName].totalEvaded); if(specialAttacks[attackName].totalEvaded ~= 0) then CombatStatsGeneralEvadedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (specialAttacks[attackName].totalEvaded / (specialAttacks[attackName].totalSwings) * 100))); else CombatStatsGeneralEvadedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralDeflectedTextLabel:SetText(specialAttacks[attackName].totalDeflected); if(specialAttacks[attackName].totalDeflected ~= 0) then CombatStatsGeneralDeflectedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (specialAttacks[attackName].totalDeflected / (specialAttacks[attackName].totalSwings) * 100))); else CombatStatsGeneralDeflectedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end -- -- Percent of total damage -- if(attackName ~= "Defensive") then if ( attackName == "[Heal] Total" ) then CombatStatsGeneralPercentDmgPctLabel:SetText("100.0%"); elseif ( strsub(attackName, 0, 6) == "[Heal]" ) then if ( specialAttacks[attackName].totalHits ~= 0 ) then CombatStatsGeneralPercentDmgPctLabel:SetText( format("%.2f %%", ((specialAttacks[attackName].totalRegDmg + specialAttacks[attackName].totalCritDmg + specialAttacks[attackName].dotDmg) / (specialAttacks["[Heal] Total"].totalRegDmg + specialAttacks["[Heal] Total"].totalCritDmg + specialAttacks["[Heal] Total"].dotDmg)) * 100) ); else CombatStatsGeneralPercentDmgPctLabel:SetText("0.0%"); end else if(specialAttacks[attackName].totalHits ~=0) then CombatStatsGeneralPercentDmgPctLabel:SetText( format("%.2f %%", ((specialAttacks[attackName].totalRegDmg + specialAttacks[attackName].totalCritDmg + specialAttacks[attackName].dotDmg) / totalDamage) * 100) ); else CombatStatsGeneralPercentDmgPctLabel:SetText("0.0%"); end end end -- -- Time since last crit -- local timeNow; timeNow = combatTime; if(specialAttacks[attackName].lastCrit ~= 0) then CombatStatsGeneralTimeLastCritTimeLabel:SetText(GREEN_FONT_COLOR_CODE ..Clock_FormatTime( (timeNow - specialAttacks[attackName].lastCrit))); else CombatStatsGeneralTimeLastCritTimeLabel:SetText(GREEN_FONT_COLOR_CODE.."N/A"); end -- -- Attack Crit % -- if (specialAttacks[attackName].totalHits ~= 0) and (specialAttacks[attackName].totalCrits ~= 0) then CombatStatsAttackCritPctLabel:SetText(format(RED_FONT_COLOR_CODE.."%.1f%%", ( (specialAttacks[attackName].totalCrits) / (specialAttacks[attackName].totalHits)) * 100.0 )); else CombatStatsAttackCritPctLabel:SetText(RED_FONT_COLOR_CODE.."0.0 %"); end -- -- Attack Non Crit % -- if (specialAttacks[attackName].totalHits ~= 0) and (specialAttacks[attackName].totalNonCrits ~= 0) then CombatStatsAttackNonCritPctLabel:SetText( format(GREEN_FONT_COLOR_CODE.."%.1f%%", ( (specialAttacks[attackName].totalNonCrits) / (specialAttacks[attackName].totalHits)) * 100.0 )); else CombatStatsAttackNonCritPctLabel:SetText(GREEN_FONT_COLOR_CODE.."0.0 %"); end -- -- Non Crit stats -- CombatStatsNonCritHitsStatText:SetText(specialAttacks[attackName].totalNonCrits); CombatStatsNonCritDamageStatText:SetText(specialAttacks[attackName].totalRegDmg); CombatStatsNonCritMinMaxStatText:SetText(specialAttacks[attackName].minReg .." / "..specialAttacks[attackName].maxReg); if( specialAttacks[attackName].totalRegDmg ~= 0) then if( (specialAttacks[attackName].totalHits - specialAttacks[attackName].totalCrits) < 0) then CombatStatsNonCritAvgStatText:SetText(format("%.1f", specialAttacks[attackName].totalRegDmg / (specialAttacks[attackName].totalCrits - specialAttacks[attackName].totalHits ) )); end if( (specialAttacks[attackName].totalHits - specialAttacks[attackName].totalCrits) == 0 ) then CombatStatsNonCritAvgStatText:SetText(format("%1.f", specialAttacks[attackName].totalRegDmg / (specialAttacks[attackName].totalCrits) )); end if( (specialAttacks[attackName].totalHits - specialAttacks[attackName].totalCrits) > 0 ) then CombatStatsNonCritAvgStatText:SetText(format("%1.f",specialAttacks[attackName].totalRegDmg / (specialAttacks[attackName].totalHits - specialAttacks[attackName].totalCrits) )); end else CombatStatsNonCritAvgStatText:SetText("0.0"); end if(specialAttacks[attackName].totalNonCrits ~=0) then CombatStatsNonCritPercentDamageStatText:SetText( format("%.2f %%", ( specialAttacks[attackName].totalRegDmg / (specialAttacks[attackName].totalRegDmg + specialAttacks[attackName].totalCritDmg )) * 100.0)); else CombatStatsNonCritPercentDamageStatText:SetText("0.0 %"); end -- -- Crit stats -- CombatStatsCritHitsStatText:SetText(specialAttacks[attackName].totalCrits); CombatStatsCritDamageStatText:SetText(specialAttacks[attackName].totalCritDmg); CombatStatsCritMinMaxStatText:SetText(specialAttacks[attackName].minCrit .." / "..specialAttacks[attackName].maxCrit); if( specialAttacks[attackName].totalCritDmg ~= 0) then CombatStatsCritAvgStatText:SetText(format("%1.f", (specialAttacks[attackName].totalCritDmg / specialAttacks[attackName].totalCrits) )); else CombatStatsCritAvgStatText:SetText("0.0"); end if(specialAttacks[attackName].totalCrits ~=0) then CombatStatsCritPercentDamageStatText:SetText(format("%.2f %%", (specialAttacks[attackName].totalCritDmg / ( specialAttacks[attackName].totalRegDmg + specialAttacks[attackName].totalCritDmg )) * 100.10 )); else CombatStatsCritPercentDamageStatText:SetText("0.0 %"); end -- -- Show DOT Stats -- if (specialAttacks[attackName].isDOT ==1) then CombatStatsGeneralHitsTextLabel:SetText(CS_FRAME_TICKS_TEXT); CombatStatsGeneralSwingsTextLabel:SetText(""); CombatStatsGeneralSwingsLabel:SetText(""); CombatStatsGeneralTotalHitsHits:SetText(specialAttacks[attackName].dotTicks); CombatStatsNonCritHitsStatText:SetText(specialAttacks[attackName].dotTicks); CombatStatsNonCritDamageStatText:SetText(specialAttacks[attackName].dotDmg); CombatStatsNonCritMinMaxStatText:SetText(specialAttacks[attackName].minReg .." / "..specialAttacks[attackName].maxReg); CombatStatsNonCritAvgStatText:SetText(format("%.1f", specialAttacks[attackName].dotDmg / specialAttacks[attackName].dotTicks )); CombatStatsNonCritPercentDamageStatText:SetText("100.0 %"); CombatStatsAttackNonCritPctLabel:SetText(GREEN_FONT_COLOR_CODE.."100.0%"); -- -- Should never be a 0 tick entry but just in case -- -- if(specialAttacks[attackNames[y]].dotTicks ~= 0) then -- text = text.."\n"..format(TEXT(DOT_AVERAGE),(specialAttacks[attackNames[y]].dotDmg / specialAttacks[attackNames[y]].dotTicks)); -- end elseif ( specialAttacks[attackName].isDOT ==2) then CombatStatsGeneralHitsTextLabel:SetText(CS_FRAME_HOT_TEXT); CombatStatsGeneralSwingsTextLabel:SetText(""); CombatStatsGeneralSwingsLabel:SetText(""); CombatStatsGeneralTotalHitsHits:SetText(specialAttacks[attackName].dotTicks); CombatStatsNonCritHitsStatText:SetText(specialAttacks[attackName].dotTicks); CombatStatsNonCritDamageStatText:SetText(specialAttacks[attackName].dotDmg); CombatStatsNonCritMinMaxStatText:SetText(specialAttacks[attackName].minReg .." / "..specialAttacks[attackName].maxReg); CombatStatsNonCritAvgStatText:SetText(format("%.1f", specialAttacks[attackName].dotDmg / specialAttacks[attackName].dotTicks )); CombatStatsNonCritPercentDamageStatText:SetText("100.0 %"); CombatStatsAttackNonCritPctLabel:SetText(GREEN_FONT_COLOR_CODE.."100.0%"); end else -- -- Calculate % of hits that are crits -- if( (totalCrits) ~= 0) then CombatStatsOverallCritPctLabel:SetText( format(RED_FONT_COLOR_CODE.."%.2f %%", ( totalCrits / totalHits) * 100.0)); end CombatStatsGeneralNameTextLabel:SetText("Total"); CombatStatsGeneralTotalHitsHits:SetText(totalHits); CombatStatsGeneralSwingsLabel:SetText(overallSwings); CombatStatsGeneralMissesTextLabel:SetText(overallMisses); if(overallMisses ~= 0) then CombatStatsGeneralMissesPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (overallMisses / (overallSwings) * 100))); else CombatStatsGeneralMissesPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralDodgesTextLabel:SetText(overallDodged); if(overallDodged ~= 0) then CombatStatsGeneralDodgesPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (overallDodged / (overallSwings) * 100))); else CombatStatsGeneralDodgesPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralParriedTextLabel:SetText(overallParried); if(overallParried ~= 0) then CombatStatsGeneralParriedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (overallParried / (overallSwings) * 100))); else CombatStatsGeneralParriedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralResistedTextLabel:SetText(overallResisted); if(overallResisted ~= 0) then CombatStatsGeneralResistedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (overallResisted / (overallSwings) * 100))); else CombatStatsGeneralResistedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralImmunedTextLabel:SetText(overallImmuned); if(overallImmuned ~= 0) then CombatStatsGeneralImmunedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (overallImmuned / (overallSwings) * 100))); else CombatStatsGeneralImmunedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralEvadedTextLabel:SetText(overallEvaded); if(overallEvaded ~= 0) then CombatStatsGeneralEvadedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (overallEvaded / (overallSwings) * 100))); else CombatStatsGeneralEvadedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end CombatStatsGeneralDeflectedTextLabel:SetText(overallDeflected); if(overallDeflected ~= 0) then CombatStatsGeneralDeflectedPercentLabel:SetText( format(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.. "%.1f%%" .. NORMAL_FONT_COLOR_CODE.." ]", (overallDeflected / (overallSwings) * 100))); else CombatStatsGeneralDeflectedPercentLabel:SetText(NORMAL_FONT_COLOR_CODE.."[ "..WHITE_FONT_COLOR_CODE.."0.0%"..NORMAL_FONT_COLOR_CODE.." ]"); end -- -- Percent of total damage -- if(totalHits ~=0) then CombatStatsGeneralPercentDmgPctLabel:SetText( format("%.2f %%", ((overallRegDmg + overallCritDmg ) / totalDamage) * 100) ); else CombatStatsGeneralPercentDmgPctLabel:SetText("0.0%"); end -- -- Time since last crit -- local timeNow; timeNow = GetTime(); if(overallLastcrit ~= 0) then CombatStatsGeneralTimeLastCritTimeLabel:SetText(GREEN_FONT_COLOR_CODE ..Clock_FormatTime( (timeNow - overallLastcrit))); else CombatStatsGeneralTimeLastCritTimeLabel:SetText(GREEN_FONT_COLOR_CODE.."N/A"); end -- -- Attack Crit % -- if (totalHits ~= 0) and (overallCrits ~= 0) then CombatStatsAttackCritPctLabel:SetText(format(RED_FONT_COLOR_CODE.."%.1f%%", ( (overallCrits) / (totalHits)) * 100.0 )); else CombatStatsAttackCritPctLabel:SetText(RED_FONT_COLOR_CODE.."0.0 %"); end -- -- Attack Non Crit % -- if (totalHits ~= 0) and (overallNonCrits ~= 0) then CombatStatsAttackNonCritPctLabel:SetText( format(GREEN_FONT_COLOR_CODE.."%.1f%%", ( (overallNonCrits) / (totalHits)) * 100.0 )); else CombatStatsAttackNonCritPctLabel:SetText(GREEN_FONT_COLOR_CODE.."0.0 %"); end -- -- Non Crit stats -- CombatStatsNonCritHitsStatText:SetText(overallNonCrits); CombatStatsNonCritDamageStatText:SetText(overallRegDmg); CombatStatsNonCritMinMaxStatText:SetText(overallminReg .." / "..overallmaxReg); if( overallRegDmg ~= 0) then if( (totalHits - overallCrits) < 0) then CombatStatsNonCritAvgStatText:SetText(format("%.1f", overallRegDmg / (overallCrits - totalHits ) )); end if( (totalHits - overallCrits) == 0 ) then CombatStatsNonCritAvgStatText:SetText(format("%1.f", overallRegDmg / (overallCrits) )); end if( (totalHits - overallCrits) > 0 ) then CombatStatsNonCritAvgStatText:SetText(format("%1.f", overallRegDmg / (totalHits - overallCrits) )); end else CombatStatsNonCritAvgStatText:SetText("0.0"); end if(overallNonCrits ~=0) then CombatStatsNonCritPercentDamageStatText:SetText( format("%.2f %%", ( overallRegDmg / (overallRegDmg + overallCritDmg )) * 100.0)); else CombatStatsNonCritPercentDamageStatText:SetText("0.0 %"); end -- -- Crit stats -- CombatStatsCritHitsStatText:SetText(overallCrits); CombatStatsCritDamageStatText:SetText(overallCritDmg); CombatStatsCritMinMaxStatText:SetText(overallminCrit .." / "..overallmaxCrit); if( overallCritDmg ~= 0) then CombatStatsCritAvgStatText:SetText(format("%1.f", (overallCritDmg / overallCrits) )); else CombatStatsCritAvgStatText:SetText("0.0"); end if(overallCrits ~=0) then CombatStatsCritPercentDamageStatText:SetText(format("%.2f %%", (overallCritDmg / ( overallRegDmg + overallCritDmg )) * 100.10 )); else CombatStatsCritPercentDamageStatText:SetText("0.0 %"); end end end -- -- Time functions -- from Clock.lua -- local function Clock_FormatPart(fmt, val) local part; part = format(TEXT(fmt), val); if( val ~= 1 ) then part = part.."s"; end return part; end function Clock_FormatTime(time) local d, h, m, s; local text = ""; local skip = 1; if ( time == 0 ) then return Clock_FormatPart(CLOCK_TIME_SECOND, 0); end d, h, m, s = ChatFrame_TimeBreakDown(time); if( d > 0 ) then text = text..Clock_FormatPart(CLOCK_TIME_DAY, d)..", "; skip = 0; end if( (skip == 0) or (h > 0) ) then text = text..Clock_FormatPart(CLOCK_TIME_HOUR, h)..", "; skip = 0; end if( (skip == 0) or (m > 0) ) then text = text..Clock_FormatPart(CLOCK_TIME_MINUTE, m)..", "; skip = 0; end if( (skip == 0) or (s > 0) ) then text = text..Clock_FormatPart(CLOCK_TIME_SECOND, s); end return text; end function CombatStats_TargetFrame_OnShow() if (CombatStats_Old_TargetFrame_OnShow) then CombatStats_Old_TargetFrame_OnShow(); end CombatStats_UpdateVisibility(1); end function CombatStats_TargetFrame_OnHide() if (CombatStats_Old_TargetFrame_OnHide) then CombatStats_Old_TargetFrame_OnHide(); end CombatStats_UpdateVisibility(0); end